/*!
 * Waves v0.6.4
 * http://fian.my.id/Waves
 *
 * Copyright 2014 Alfiana E. Sibuea and other contributors
 * Released under the MIT license
 * https://github.com/fians/Waves/blob/master/LICENSE
 */

 ;(function(window) {
  'use strict';

  var Waves = Waves || {};
  var $$ = document.querySelectorAll.bind(document);

    // Find exact position of element
    function isWindow(obj) {
      return obj !== null && obj === obj.window;
    }

    function getWindow(elem) {
      return isWindow(elem) ? elem : elem.nodeType === 9 && elem.defaultView;
    }

    function offset(elem) {
      var docElem, win,
      box = {top: 0, left: 0},
      doc = elem && elem.ownerDocument;

      docElem = doc.documentElement;

      if (typeof elem.getBoundingClientRect !== typeof undefined) {
        box = elem.getBoundingClientRect();
      }
      win = getWindow(doc);
      return {
        top: box.top + win.pageYOffset - docElem.clientTop,
        left: box.left + win.pageXOffset - docElem.clientLeft
      };
    }

    function convertStyle(obj) {
      var style = '';

      for (var a in obj) {
        if (obj.hasOwnProperty(a)) {
          style += (a + ':' + obj[a] + ';');
        }
      }

      return style;
    }

    var Effect = {

        // Effect delay
        duration: 750,

        show: function(e, element) {

            // Disable right click
            if (e.button === 2) {
              return false;
            }

            var el = element || this;

            // Create ripple
            var ripple = document.createElement('div');
            ripple.className = 'u-waves-ripple';
            el.appendChild(ripple);

            // Get click coordinate and element witdh
            var pos         = offset(el);
            var relativeY   = (e.pageY - pos.top);
            var relativeX   = (e.pageX - pos.left);
            var scale       = 'scale('+((el.clientWidth / 100) * 10)+')';

            // Support for touch devices
            if ('touches' in e) {
              relativeY   = (e.touches[0].pageY - pos.top);
              relativeX   = (e.touches[0].pageX - pos.left);
            }

            // Attach data to element
            ripple.setAttribute('data-hold', Date.now());
            ripple.setAttribute('data-scale', scale);
            ripple.setAttribute('data-x', relativeX);
            ripple.setAttribute('data-y', relativeY);

            // Set ripple position
            var rippleStyle = {
              'top': relativeY+'px',
              'left': relativeX+'px'
            };

            ripple.className = ripple.className + ' u-waves-notransition';
            ripple.setAttribute('style', convertStyle(rippleStyle));
            ripple.className = ripple.className.replace('u-waves-notransition', '');

            // Scale the ripple
            rippleStyle['-webkit-transform'] = scale;
            rippleStyle['-moz-transform'] = scale;
            rippleStyle['-ms-transform'] = scale;
            rippleStyle['-o-transform'] = scale;
            rippleStyle.transform = scale;
            rippleStyle.opacity   = '1';

            rippleStyle['-webkit-transition-duration'] = Effect.duration + 'ms';
            rippleStyle['-moz-transition-duration']    = Effect.duration + 'ms';
            rippleStyle['-o-transition-duration']      = Effect.duration + 'ms';
            rippleStyle['transition-duration']         = Effect.duration + 'ms';

            rippleStyle['-webkit-transition-timing-function'] = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)';
            rippleStyle['-moz-transition-timing-function']    = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)';
            rippleStyle['-o-transition-timing-function']      = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)';
            rippleStyle['transition-timing-function']         = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)';

            ripple.setAttribute('style', convertStyle(rippleStyle));
          },

          hide: function(e) {
            TouchHandler.touchup(e);

            var el = this;
            var width = el.clientWidth * 1.4;

            // Get first ripple
            var ripple = null;
            var ripples = el.getElementsByClassName('u-waves-ripple');
            if (ripples.length > 0) {
              ripple = ripples[ripples.length - 1];
            } else {
              return false;
            }

            var relativeX   = ripple.getAttribute('data-x');
            var relativeY   = ripple.getAttribute('data-y');
            var scale       = ripple.getAttribute('data-scale');

            // Get delay beetween mousedown and mouse leave
            var diff = Date.now() - Number(ripple.getAttribute('data-hold'));
            var delay = 350 - diff;

            if (delay < 0) {
              delay = 0;
            }

            // Fade out ripple after delay
            setTimeout(function() {
              var style = {
                'top': relativeY+'px',
                'left': relativeX+'px',
                'opacity': '0',

                    // Duration
                    '-webkit-transition-duration': Effect.duration + 'ms',
                    '-moz-transition-duration': Effect.duration + 'ms',
                    '-o-transition-duration': Effect.duration + 'ms',
                    'transition-duration': Effect.duration + 'ms',
                    '-webkit-transform': scale,
                    '-moz-transform': scale,
                    '-ms-transform': scale,
                    '-o-transform': scale,
                    'transform': scale,
                  };

                  ripple.setAttribute('style', convertStyle(style));

                  setTimeout(function() {
                    try {
                      el.removeChild(ripple);
                    } catch(e) {
                      return false;
                    }
                  }, Effect.duration);
                }, delay);
          },

        // Little hack to make <input> can perform waves effect
        wrapInput: function(elements) {
          for (var a = 0; a < elements.length; a++) {
            var el = elements[a];

            if (el.tagName.toLowerCase() === 'input') {
              var parent = el.parentNode;

                    // If input already have parent just pass through
                    if (parent.tagName.toLowerCase() === 'i' && parent.className.indexOf('u-waves-effect') !== -1) {
                      continue;
                    }

                    // Put element class and style to the specified parent
                    var wrapper = document.createElement('i');
                    wrapper.className = el.className + ' u-waves-input-wrapper';

                    var elementStyle = el.getAttribute('style');

                    if (!elementStyle) {
                      elementStyle = '';
                    }

                    wrapper.setAttribute('style', elementStyle);

                    el.className = 'u-waves-button-input';
                    el.removeAttribute('style');

                    // Put element as child
                    parent.replaceChild(wrapper, el);
                    wrapper.appendChild(el);
                  }
                }
              }
            };


    /**
     * Disable mousedown event for 500ms during and after touch
     */
     var TouchHandler = {
        /* uses an integer rather than bool so there's no issues with
         * needing to clear timeouts if another touch event occurred
         * within the 500ms. Cannot mouseup between touchstart and
         * touchend, nor in the 500ms after touchend. */
         touches: 0,
         allowEvent: function(e) {
          var allow = true;

          if (e.type === 'touchstart') {
                TouchHandler.touches += 1; //push
              } else if (e.type === 'touchend' || e.type === 'touchcancel') {
                setTimeout(function() {
                  if (TouchHandler.touches > 0) {
                        TouchHandler.touches -= 1; //pop after 500ms
                      }
                    }, 500);
              } else if (e.type === 'mousedown' && TouchHandler.touches > 0) {
                allow = false;
              }

              return allow;
            },
            touchup: function(e) {
              TouchHandler.allowEvent(e);
            }
          };


    /**
     * Delegated click handler for .u-waves-effect element.
     * returns null when .u-waves-effect element not in "click tree"
     */
     function getWavesEffectElement(e) {
      if (TouchHandler.allowEvent(e) === false) {
        return null;
      }

      var element = null;
      var target = e.target || e.srcElement;

      while (target.parentNode !== null) {
        if (!(target instanceof SVGElement) && target.className.indexOf('u-waves-effect') !== -1) {
          element = target;
          break;
        }
        target = target.parentNode;
      }
      return element;
    }

    /**
     * Bubble the click and show effect if .u-waves-effect elem was found
     */
     function showEffect(e) {
      var element = getWavesEffectElement(e);

      if (element !== null) {
        Effect.show(e, element);

        if ('ontouchstart' in window) {
          element.addEventListener('touchend', Effect.hide, false);
          element.addEventListener('touchcancel', Effect.hide, false);
        }

        element.addEventListener('mouseup', Effect.hide, false);
        element.addEventListener('mouseleave', Effect.hide, false);
        element.addEventListener('dragend', Effect.hide, false);
      }
    }

    Waves.displayEffect = function(options) {
      options = options || {};

      if ('duration' in options) {
        Effect.duration = options.duration;
      }

        //Wrap input inside <i> tag
        Effect.wrapInput($$('.u-waves-effect'));

        if ('ontouchstart' in window) {
          document.body.addEventListener('touchstart', showEffect, false);
        }

        document.body.addEventListener('mousedown', showEffect, false);
      };

    /**
     * Attach Waves to an input element (or any element which doesn't
     * bubble mouseup/mousedown events).
     *   Intended to be used with dynamically loaded forms/inputs, or
     * where the user doesn't want a delegated click handler.
     */
     Waves.attach = function(element) {
        //FUTURE: automatically add waves classes and allow users
        // to specify them with an options param? Eg. light/classic/button
        if (element.tagName.toLowerCase() === 'input') {
          Effect.wrapInput([element]);
          element = element.parentNode;
        }

        if ('ontouchstart' in window) {
          element.addEventListener('touchstart', showEffect, false);
        }

        element.addEventListener('mousedown', showEffect, false);
      };

      window.Waves = Waves;

      document.addEventListener('DOMContentLoaded', function() {
        Waves.displayEffect();
      }, false);

    })(window);