/*!
 * jquery.dad.js v1 (http://konsolestudio.com/dad)
 * Author William Lima
 */

(function ($) {
  'use strict';
  var supportsTouch = 'ontouchstart' in window || navigator.msMaxTouchPoints;

  $.fn.dad = function (opts) {
    var _this = this;

    var defaults = {
      target: '>div',
      draggable: false,
      placeholder: '',
      callback: false,
      containerClass: 'dad-container',
      childrenClass: 'dads-children',
      cloneClass: 'dads-children-clone',
      active: true,
    };

    var options = $.extend({}, defaults, opts);
      options.draggable ? $(options.draggable, this).attr('title', '按住鼠标左键拖动更换位置') : $(this).attr('title', '按住鼠标左键拖动更换位置');
    
    $(this).each(function () {
      var active = options.active;
      var $daddy = $(this);
      var childrenClass = options.childrenClass;
      var cloneClass = options.cloneClass;
      var jQclass = '.' + childrenClass;
      var $target = $daddy.find(options.target);
      var placeholder = options.placeholder;
      var callback = options.callback;
      var dragClass = 'dad-draggable-area';
      var holderClass = 'dads-children-placeholder';

      // HANDLE MOUSE
      var mouse = {
        x: 0,
        y: 0,
        target: false,
        clone: false,
        placeholder: false,
        cloneoffset: {
          x: 0,
          y: 0,
        },
        updatePosition: function (e) {
          this.x = e.pageX;
          this.y = e.pageY;
        },

        move: function (e) {
          this.updatePosition(e);
          if (this.clone !== false && _this.target !== false) {
            this.clone.css({
              left: this.x - this.cloneoffset.x,
              top: this.y - this.cloneoffset.y,
            });
          }
        },
      };

      $(window).on('mousemove touchmove', function (e) {
        var ev = e;

        if (mouse.clone !== false && mouse.target !== false) e.preventDefault();

        if (supportsTouch && e.type == 'touchmove') {
          ev = e.originalEvent.touches[0];
          var mouseTarget = document.elementFromPoint(ev.clientX, ev.clientY);

          $(mouseTarget).trigger('touchenter');
        }

        mouse.move(ev);
      });

      $daddy.addClass(options.containerClass);

      if (!$daddy.hasClass('dad-active') && active === true) {
        $daddy.addClass('dad-active');
      };

      _this.addDropzone = function (selector, func) {
        $(selector).on('mouseenter touchenter', function () {
          if (mouse.target !== false) {
            mouse.placeholder.css({ display: 'none' });
            mouse.target.css({ display: 'none' });
            $(this).addClass('active');
          }
        }).on('mouseup touchend', function () {
          if (mouse.target != false) {
            mouse.placeholder.css({ display: 'block' });
            mouse.target.css({ display: 'block' });
            func(mouse.target);
            dadEnd();
          };

          $(this).removeClass('active');
        }).on('mouseleave touchleave', function () {
          if (mouse.target !== false) {
            mouse.placeholder.css({ display: 'block' });
            mouse.target.css({ display: 'block' });
          }

          $(this).removeClass('active');
        });
      };

      // GET POSITION FUNCTION
      _this.getPosition = function () {
        var positionArray = [];
        $(this).find(jQclass).each(function () {
          positionArray[$(this).attr('data-dad-id')] = parseInt($(this).attr('data-dad-position'));
        });

        return positionArray;
      };

      _this.activate = function () {
        active = true;
        if (!$daddy.hasClass('dad-active')) {
          $daddy.addClass('dad-active');
        }

        return _this;
      };

      // DEACTIVATE FUNCTION
      _this.deactivate = function () {
        active = false;
        $daddy.removeClass('dad-active');
        return _this;
      };

      // DEFAULT DROPPING
      $daddy.on('DOMNodeInserted', function (e) {
        var $thisTarget = $(e.target);
        if (!$thisTarget.hasClass(childrenClass) && !$thisTarget.hasClass(holderClass)) {
          $thisTarget.addClass(childrenClass);
        }
        options.draggable && $(options.draggable, $thisTarget).addClass(dragClass);
      });

      $(document).on('mouseup touchend', function () {
        dadEnd();
      });

      // ORDER ELEMENTS
      var order = 1;
      $target.addClass(childrenClass).each(function () {
        if ($(this).data('dad-id') == undefined) {
          $(this).attr('data-dad-id', order);
        }

        $(this).attr('data-dad-position', order);
        order++;
      });

      // CREATE REORDER FUNCTION
      function updatePosition(e) {
        var order = 1;
        e.find(jQclass).each(function () {
          $(this).attr('data-dad-position', order);
          order++;
        });
      }

      // END EVENT
      function dadEnd() {
        if (mouse.target != false &&  mouse.clone != false) {
          if (callback != false) {
            callback(mouse.target);
          }

          var appear = mouse.target;
          var desappear = mouse.clone;
          var holder = mouse.placeholder;
          var bLeft = 0;
          var bTop = 0;

          // Maybe we will use this in the future
          //Math.floor(parseFloat($daddy.css('border-left-width')));
          //Math.floor(parseFloat($daddy.css('border-top-width')));
          if ($.contains($daddy[0], mouse.target[0])) {
            mouse.clone.animate({
              top: mouse.target.offset().top - $daddy.offset().top - bTop,
              left: mouse.target.offset().left - $daddy.offset().left - bLeft,
            }, 300, function () {
              appear.css({
                visibility: 'visible',
              }).removeClass('active');
              desappear.remove();
            });
          } else {
            mouse.clone.fadeOut(300, function () {
              desappear.remove();
            });
          }

          holder.remove();
          mouse.clone = false;
          mouse.placeholder = false;
          mouse.target = false;
          updatePosition($daddy);
        }

        $('html, body').removeClass('dad-noSelect');
      }

      // UPDATE EVENT
      function dadUpdate(obj) {
        if (mouse.target !== false && mouse.clone !== false) {
          var $origin = $('<span style="display:none"></span>');
          var $newplace = $('<span style="display:none"></span>');

          if (obj.prevAll().hasClass('active')) {
            obj.after($newplace);
          } else {
            obj.before($newplace);
          }

          mouse.target.before($origin);
          $newplace.before(mouse.target);

          // UPDATE PLACEHOLDER
          mouse.placeholder.css({
            top: mouse.target.offset().top - $daddy.offset().top,
            left: mouse.target.offset().left - $daddy.offset().left,
            width: mouse.target.outerWidth() - 10,
            height: mouse.target.outerHeight() - 10,
          });

          $origin.remove();
          $newplace.remove();
        }
      }

      // GRABBING EVENT
      var jq = (options.draggable !== false) ? options.draggable : jQclass;
      $daddy.find(jq).addClass(dragClass);
      $daddy.on('mousedown touchstart', jq, function (e) {
        // For touchstart we must update "mouse" position
        if (e.type == 'touchstart') {
          mouse.updatePosition(e.originalEvent.touches[0]);
        }

        if (mouse.target == false && active == true && (e.which == 1 || e.type == 'touchstart')) {
          var $self = $(this);

          // GET TARGET
          if (options.draggable !== false) {
            mouse.target = $daddy.find(jQclass).has(this);
          } else {
            mouse.target = $self;
          }

            // ADD CLONE
          mouse.clone = mouse.target.clone();
          mouse.target.css({ visibility: 'hidden' }).addClass('active');
          mouse.clone.addClass(cloneClass);
          $daddy.append(mouse.clone);

          // ADD PLACEHOLDER
          var $placeholder = $('<div></div>');
          mouse.placeholder = $placeholder;
          mouse.placeholder.addClass(holderClass);
          mouse.placeholder.css({
              top: mouse.target.offset().top - $daddy.offset().top,
              left: mouse.target.offset().left - $daddy.offset().left,
              width: mouse.target.outerWidth() - 10,
              height: mouse.target.outerHeight() - 10,
              lineHeight: mouse.target.height() - 18 + 'px',
              textAlign: 'center',
          }).text(placeholder);

          $daddy.append(mouse.placeholder);

          // GET OFFSET FOR CLONE
          var bLeft = Math.floor(parseFloat($daddy.css('border-left-width')));
          var bTop = Math.floor(parseFloat($daddy.css('border-top-width')));
          var difx = mouse.x - mouse.target.offset().left + $daddy.offset().left + bLeft;
          var dify = mouse.y - mouse.target.offset().top + $daddy.offset().top + bTop;
          mouse.cloneoffset.x = difx;
          mouse.cloneoffset.y = dify;

          // REMOVE THE CHILDREN DAD CLASS AND SET THE POSITION ON SCREEN
          mouse.clone.removeClass(childrenClass).css({
              position: 'absolute',
              top: mouse.y - mouse.cloneoffset.y,
              left: mouse.x - mouse.cloneoffset.x,
              width: mouse.target.outerWidth(),
          });

          // UNABLE THE TEXT SELECTION AND SET THE GRAB CURSOR
          $('html,body').addClass('dad-noSelect');
        }
      });

      $daddy.on('mouseenter touchenter', jQclass, function () {
        dadUpdate($(this));
      });
    });

    return this;
  };
})(jQuery);
