GM.namespace('GM.cms.general');

// Init

GM.cms.general.init = function ()
{
  var toolbar = document.getElementById('toolbar');
  
  if (toolbar) {
	  var container = GM.dom.getElementsByClassName('scroller', 'div', toolbar);
	      
	  if (container[0]) {
	    new GM.cms.util.Scroller(container[0]);
	  }
	  
	  var button = GM.dom.getElementsByClassName('modify-order', 'a', toolbar);
    
    if (button[0]) {
      new GM.cms.general.MenuSorterController(button[0]);
    }
	}
}

// MenuSorterController

GM.cms.general.MenuSorterController = function (element)
{
  this.addHandlers(element);
}

GM.cms.general.MenuSorterController.prototype.addHandlers = function (element)
{
  GM.event.register(element, 'click', this.clickOpen, this);   
}

GM.cms.general.MenuSorterController.prototype.clickOpen = function (e)
{
  GM.event.preventDefault(e);

  var target = GM.event.getTarget(e);
  var href   = target.href.replace('site/', 'async/');
  var lock   = new GM.dom.Lock({color: 'FFF', opacity: 0, cursor: 'wait', zIndex: 90});
  
  GM.request.send( {
    method:   'get',
    url:      href,
    callback: this.openPopup,
    context:  this,
    object:   {lock: lock}
  } );
}

GM.cms.general.MenuSorterController.prototype.openPopup = function (e, object)
{
  new GM.cms.general.MenuSorterPopupController(object.request.responseText, object.lock);
}

// MenuSorterPopup

GM.cms.general.MenuSorterPopupController = function (string, lock)
{
  GM.cms.popup.PopupController.call(this, string, lock);
  
  var sorter = GM.dom.getElementsByClassName('menu-sorter', 'div', this.popup);
  
  if (sorter[0]) {
    GM.cms.general.MenuSorter.addHandlers(sorter[0]);
  }
  
  var form = this.popup.getElementsByTagName('form');
  
  if (form[0]) {
    GM.event.register(form[0], 'submit', this.submitAnalyze, this);
  }
}
GM.cms.general.MenuSorterPopupController.inherit(GM.cms.popup.PopupController);

GM.cms.general.MenuSorterPopupController.prototype.submitAnalyze = function (e)
{
  var sorter = GM.dom.getElementsByClassName('menu-sorter', 'div', this.popup);
  
  if (sorter[0]) {
    var result = {};
    
    for (var i = 0; i < sorter[0].childNodes.length; i += 1) {
      var id    = sorter[0].childNodes[i].id;
      var level = parseInt(sorter[0].childNodes[i].className.substring(1), 10);
      
      result[id] = level;
    }
    
    var inputs = this.popup.getElementsByTagName('input');
    
    for (var j = 0; j < inputs.length; j += 1) {
      if (inputs[j].name === 'order') {
        inputs[j].value = JSON.stringify(result);
        
        break;
      }
    }
  }  
}

GM.cms.general.MenuSorterPopupController.prototype.closePopup = function (e)
{
  var sorter = GM.dom.getElementsByClassName('menu-sorter', 'div', this.popup);
  
  if (sorter[0]) {
    GM.cms.general.MenuSorter.removeHandlers(sorter[0]);
  }
  
  var form = this.popup.getElementsByTagName('form');
  
  if (form[0]) {
    GM.event.unregister(form[0], 'submit', this.submitAnalyze);
  }

  GM.cms.popup.PopupController.prototype.closePopup.call(this, e);
}

// MenuSorter

GM.cms.general.MenuSorter =
{
  objects: [],
  
  begin: {},
  
  zIndex: 1,
  
  parent: null,
  
  scrollInterval : null,
  
  addHandlers: function (object)
  {
    object.boundaries = new GM.dom.Boundaries(0, object.scrollWidth - 26, 0, object.scrollHeight);
    GM.cms.general.MenuSorter.parent = object;
  
    for (var i = 0; i < object.childNodes.length; i += 1) {
      GM.event.register(object.childNodes[i], 'mousedown', GM.cms.general.MenuSorter.startSort, object.childNodes[i]);
    }
  },
  
  removeHandlers: function (object)
  {
    for (var i = 0; i < object.childNodes.length; i += 1) {
      GM.event.unregister(object.childNodes[i], 'mousedown', GM.cms.general.MenuSorter.startSort);
    }
  },
  
  startSort: function (e)
  {
    if (GM.event.mouseClicked(e, 1) ) {
      GM.cms.general.MenuSorter.setProperties(this);
      GM.cms.general.MenuSorter.objects.push(this);
      
      var thisLevel = GM.cms.general.MenuSorter.getLevel(this.className);
      var next      = this.nextSibling;
      
      while (next) {
        var nextLevel = GM.cms.general.MenuSorter.getLevel(next.className);
        
        if (nextLevel > thisLevel) {
          GM.cms.general.MenuSorter.setProperties(next);              
          GM.cms.general.MenuSorter.objects.push(next);
          
          next = next.nextSibling;
        } else {            
          next = null;
        }
      }            
    
      GM.cms.general.MenuSorter.begin = GM.event.getPosition(e);
                  
      GM.event.register(document, 'mousemove', GM.cms.general.MenuSorter.sort);
      GM.event.register(document, 'mouseup', GM.cms.general.MenuSorter.stopSort);
    }
    
    return GM.event.preventDefault(e);
  },
          
  sort: function (e)
  {
    var position = GM.event.getPosition(e),
        difX     = position.x - GM.cms.general.MenuSorter.begin.x,
        difY     = position.y - GM.cms.general.MenuSorter.begin.y
  
    if (Math.abs(difY) > 0) {
      GM.cms.general.MenuSorter.doSort(difX, difY);
      GM.cms.general.MenuSorter.scrollParent(difX, difY);

      GM.cms.general.MenuSorter.begin = position;           
    }
    
    if (Math.abs(difX) > 7) {
      GM.cms.general.MenuSorter.doLevel(difX);
      
      GM.cms.general.MenuSorter.begin = position;
    }
    
    return GM.event.preventDefault(e);
  },
  
  stopSort: function (e)
  {
    for (var i = 0; i < GM.cms.general.MenuSorter.objects.length; i += 1) { 
      GM.cms.general.MenuSorter.resetProperties(GM.cms.general.MenuSorter.objects[i]);
    }
  
    GM.cms.general.MenuSorter.objects = [];
  
    if (GM.cms.general.MenuSorter.scrollInterval) {
      clearInterval(GM.cms.general.MenuSorter.scrollInterval);
      
      GM.cms.general.MenuSorter.scrollInterval = null;
    }
  
    GM.event.unregister(document, 'mousemove', GM.cms.general.MenuSorter.sort);
    GM.event.unregister(document, 'mouseup', GM.cms.general.MenuSorter.stopSort);
  },        
  
  scrollParent: function (difX, difY)
  {
    var objectBoundaries = GM.cms.general.MenuSorter.getObjectBoundaries(difX, difY);        
  
    var parent = GM.cms.general.MenuSorter.parent;        
  
    if (parent.scrollTop + parent.offsetHeight < parent.scrollHeight && objectBoundaries.bottom > parent.scrollTop + parent.offsetHeight - 15) {
      if (!GM.cms.general.MenuSorter.scrollInterval && difY > 0) {
        GM.cms.general.MenuSorter.scrollInterval = setInterval(function(){GM.cms.general.MenuSorter.doScroll(3)}, 5);
      }
    } else if (parent.scrollTop > 0 && objectBoundaries.top < parent.scrollTop + 5) {
      if (!GM.cms.general.MenuSorter.scrollInterval && difY < 0) {
        GM.cms.general.MenuSorter.scrollInterval = setInterval(function(){GM.cms.general.MenuSorter.doScroll(-3)}, 5);
      }          
    } else if (GM.cms.general.MenuSorter.scrollInterval) {
      clearInterval(GM.cms.general.MenuSorter.scrollInterval);
      
      GM.cms.general.MenuSorter.scrollInterval = null;
    }
  },
  
  doSort: function (difX, difY)
  {
    var objectBoundaries = GM.cms.general.MenuSorter.getObjectBoundaries(difX, difY);

    for (var i = 0; i < GM.cms.general.MenuSorter.objects.length; i += 1) {  
      if (GM.cms.general.MenuSorter.parent.boundaries.checkX(objectBoundaries)) {
        GM.cms.general.MenuSorter.objects[i].style.left = (parseInt(GM.cms.general.MenuSorter.objects[i].style.left, 10) + difX) + 'px';
      }
        
      if (GM.cms.general.MenuSorter.parent.boundaries.checkY(objectBoundaries)) {
        GM.cms.general.MenuSorter.objects[i].style.top = (parseInt(GM.cms.general.MenuSorter.objects[i].style.top, 10) + difY) + 'px';
      }
    }
    
    if (difY < 0) { // Up
      var previous = GM.cms.general.MenuSorter.getPrevious();
        
      if (previous) {
        objectBoundaries = new GM.dom.Boundaries(0, 0, objectBoundaries.top, objectBoundaries.top);
        referenceBoundaries = new GM.dom.Boundaries(0, 0, previous.offsetTop, previous.offsetTop + 7);  
        
        if (referenceBoundaries.checkY(objectBoundaries)) {             
          for (var i = 0; i < GM.cms.general.MenuSorter.objects.length; i += 1) {
            GM.cms.general.MenuSorter.objects[i].style.top = '7px';
            previous.parentNode.insertBefore(GM.cms.general.MenuSorter.objects[i], previous);
          }
          
          GM.cms.general.MenuSorter.setLevel();
        }
      }
    } else { // Down
      var next = GM.cms.general.MenuSorter.getNext();   
      
      if (next) {
        objectBoundaries = new GM.dom.Boundaries(0, 0, objectBoundaries.bottom, objectBoundaries.bottom);
        referenceBoundaries = new GM.dom.Boundaries(0, 0, next.offsetTop + next.offsetHeight - 7, next.offsetTop + next.offsetHeight);  
        
        if (referenceBoundaries.checkY(objectBoundaries)) {
          next.parentNode.insertBefore(next, GM.cms.general.MenuSorter.objects[0]);
                     
          for (var i = 0; i < GM.cms.general.MenuSorter.objects.length; i += 1) {
            GM.cms.general.MenuSorter.objects[i].style.top = '-7px';
          }
          
          GM.cms.general.MenuSorter.setLevel();
        }
      }       
    }    
  },        
  
  doScroll: function (amount)
  {
    GM.cms.general.MenuSorter.parent.scrollTop += amount;
    GM.cms.general.MenuSorter.doSort(0, amount);
  },

  doLevel: function (difX)
  {
    if (difX < 0) { // Left
      var next = GM.cms.general.MenuSorter.getNext();
      
      var level     = GM.cms.general.MenuSorter.getLevel(GM.cms.general.MenuSorter.objects[0].className);
      var nextLevel = (next) ? GM.cms.general.MenuSorter.getLevel(next.className) : null;
      
      if (level > nextLevel) {
       GM.cms.general.MenuSorter.dedent(level, 1);
      }
    } else { // Right
      var previous = GM.cms.general.MenuSorter.getPrevious();
      
      if (previous) {
        var level         = GM.cms.general.MenuSorter.getLevel(GM.cms.general.MenuSorter.objects[0].className);
        var previousLevel = GM.cms.general.MenuSorter.getLevel(previous.className); 
        
        if (level <= previousLevel) {
          GM.cms.general.MenuSorter.indent(level, 1);
        }
      }
    }        
  },

  indent: function (level, amount)
  {
    for (var i = 0; i < GM.cms.general.MenuSorter.objects.length; i += 1) {
      var level = GM.cms.general.MenuSorter.getLevel(GM.cms.general.MenuSorter.objects[i].className);
              
      GM.cms.general.MenuSorter.objects[i].className = GM.cms.general.MenuSorter.objects[i].className.replace('l' + level, 'l' + (level + amount));
      GM.cms.general.MenuSorter.objects[i].style.paddingLeft = ( (level + amount) * 15) + 'px';
      GM.cms.general.MenuSorter.objects[i].style.width = (257 - (level + amount) * 15) + 'px';
    }
  },
  
  dedent: function (level, amount)
  {
    for (var i = 0; i < GM.cms.general.MenuSorter.objects.length; i += 1) {
      var level = GM.cms.general.MenuSorter.getLevel(GM.cms.general.MenuSorter.objects[i].className);
              
      GM.cms.general.MenuSorter.objects[i].className = GM.cms.general.MenuSorter.objects[i].className.replace('l' + level, 'l' + (level - amount));
      GM.cms.general.MenuSorter.objects[i].style.paddingLeft = ( (level - amount) * 15) + 'px';
      GM.cms.general.MenuSorter.objects[i].style.width = (257 - (level - amount) * 15) + 'px';
    }         
  },
  
  getPrevious: function ()
  {
    if (GM.cms.general.MenuSorter.objects[0] && GM.cms.general.MenuSorter.objects[0].previousSibling) {
      return GM.cms.general.MenuSorter.objects[0].previousSibling;
    }
  },
  
  getNext: function ()
  {
    var index = GM.cms.general.MenuSorter.objects.length - 1;
    
    if (GM.cms.general.MenuSorter.objects[index] && GM.cms.general.MenuSorter.objects[index].nextSibling) {
      return GM.cms.general.MenuSorter.objects[index].nextSibling;
    }
  },
  
  getObjectBoundaries: function (x, y)
  {
    var left = 0,
        width = 0,
        top = 0,
        height = 0;
  
    for (var i = 0; i < GM.cms.general.MenuSorter.objects.length; i += 1) {
      if (GM.cms.general.MenuSorter.objects[i].offsetLeft > left) {
        left = GM.cms.general.MenuSorter.objects[i].offsetLeft;
      }
      
      if (GM.cms.general.MenuSorter.objects[i].offsetWidth > width) {
        width = GM.cms.general.MenuSorter.objects[i].offsetWidth;
      }
      
      top = (i === 0) ? GM.cms.general.MenuSorter.objects[i].offsetTop : top;
      height += GM.cms.general.MenuSorter.objects[i].offsetHeight;
    }            
    
    var newLeft   = left + x,
        newRight  = newLeft + width,
        newTop    = top + y,
        newBottom = newTop + height;
        
    return new GM.dom.Boundaries(newLeft, newRight, newTop, newBottom);          
  },
  
  resetProperties: function (object)
  {
    object.style.zIndex   = object.oldZIndex;
    object.style.cursor   = '';
    object.style.position = object.oldPosition;                
  },
  
  setProperties: function (object)
  {
    object.oldPosition = object.style.position;
    object.oldZIndex   = object.style.zIndex;
            
    object.style.zIndex   = GM.cms.general.MenuSorter.zIndex;
    object.style.cursor   = 'move';
    object.style.position = (!object.style.position) ? 'relative' : object.style.position;
  
    object.style.top  = (object.style.position === 'relative') ? 0 : object.offsetTop - parseInt(object.style.marginTop, 10) + 'px';
    object.style.left = (object.style.position === 'relative') ? 0 : object.offsetLeft - parseInt(object.style.marginLeft, 10) + 'px';
  
    object.direction = {};        
  },
 
  getLevel: function (className)
  {
    return parseInt(className.substring(className.indexOf(' l') + 2), 10);
  },
  
  setLevel: function ()
  {
    var next  = GM.cms.general.MenuSorter.getNext();
    var level = GM.cms.general.MenuSorter.getLevel(GM.cms.general.MenuSorter.objects[0].className);
            
    if (next) {
      var nextLevel = GM.cms.general.MenuSorter.getLevel(next.className);

      if (nextLevel > level) {
        GM.cms.general.MenuSorter.indent(level, nextLevel - level);
      } else if (nextLevel < level) {
        GM.cms.general.MenuSorter.dedent(level, level - nextLevel);
      }
    }        
  }        
} 

GM.event.register(window, 'load', GM.cms.general.init);
