/** SortableListItem is
*  a sort of "dummy" class which has a listItem that is a DragObj.
*/
SortableListItem = function(el) {

    this.el = el;
    this.el.oncontextmenu = function() {
	return false;
    };

    this.listItem = DragObj.getInstance(el, DragObj.constraints.VERT);
    this.listItem.isRel = true;
    this.listItem.keepInContainer = true;

    this.dragPane = DragPane.getInstance(findAncestorWithClass(el, "dragPane"));

    var dragPane = this.dragPane;
    this.listItem.onbeforedragstart = function() {
      //document.getElementById('DEBUGINFO').innerHTML = "";

	if(DragPane.focusedElement != this.el) {
	    if(DragPane.focusedElement != null)
	      removeClass(DragPane.focusedElement, "focusedItem");
	    addClass(this.el,"focusedItem");
	    DragPane.focusedElement = this.el;
	}
	//document.getElementById('DEBUGINFO').innerHTML +=
	//"onbeforedragstart: " + DragPane.focusedElement.id + " " + DragPane.focusedElement.className + "<br/>";

	return true;
    };

    this.listItem.onfocus = function() {

    };

    this.listItem.ondragstart = function() {
	addClass(this.el,"activeDrag");
	this.el.style.cursor = "move";
	this.el.style.zIndex = 1000;
	//document.getElementById('DEBUGINFO').innerHTML +=
	//"ondragstart: " + this.el.id + " " + this.el.className + "<br/>";
    };


    var items = this.dragPane.items();

    for(var i = 0; i < items.length; i++)
      if(el != items[i])
	this.listItem.addDropTarget(items[i]);


    // define accessible variable;
    var dragPane = this.dragPane;

    // all done dragging
      this.listItem.ondragend = function() {
	  removeClass(this.el, "activeDrag");
	  this.el.style.cursor = "default";
	  this.el.style.top=0;
	  this.el.style.zIndex = "";
	  //document.getElementById('DEBUGINFO').innerHTML +=
	  //"ondraged: " + this.el.id + " " + this.el.className + "<br/>";
      };


    // we hit a drop target.
      this.listItem.ondragdrop = function(e) {
	//document.getElementById('DEBUGINFO').innerHTML += "ON_DRAGDROP<br/>";
	  if (e.dropTarget.id.indexOf('DropOnly')>=0)
	    e.dropTarget.update(this);
	  else {
	    dragPane.resort(this, e.dropTarget);
	  }
	  //document.getElementById('DEBUGINFO').innerHTML +=
	  //"ondragstop: " + this.id + " hit " + e.dropTarget.id + "<br/>";
      };


};

SortableListItem.instances =  {};

SortableListItem.prototype = {

    onfocus : function(){},

    focus : function() {
	this.listItem.onbeforedragstart();
	this.onfocus();
    }

};


SortableListItem.getInstance = function(el) {
    var x = SortableListItem.instances[el.id];
    if(!x)
      x = SortableListItem.instances[el.id] = new SortableListItem(el);
    return x;
};


DragPane = function(el) {
    this.el = el;

    if(typeof this.el.style.MozUserSelect == "string")
      this.el.style.MozUserSelect = "none";
    //this.form = document.getElementById(this.el.id+"Form");
    //this.elements = document.getElementById(this.el.id+"Fields").getElementsByTagName("input");

    this.id = el.id;
    //this.el.onselectstart = function() { return false; };


    this.position = {
	top : el.offsetTop,
	left : el.offsetLeft,
	bottom : el.offsetTop + el.offsetHeight,
	right : el.offsetWidth + el.offsetLeft
    };


    DragPane.instances[this.id] = this;
};
DragPane.instances = {};
DragPane.getInstance = function(el) {
    var instance = DragPane.instances[el.id];
    if(instance == null)
      instance = DragPane.instances[el.id] = new DragPane(el);
    return instance;
};

DragPane.prototype = {

    id : "",
    form : null,
    elements : null,

    position : { top: 0, left : 0, bottom : 0, right : 0 },

    items : function() { return getElementsWithClass(this.el, "div", "orderingItem"); },

    resort : function(listItem, dropTarget) {

      // If the element is on the top half of the drop target, insert it before.
      // otherwise, append it.

      var listItemBottom = listItem.y + listItem.el.offsetTop + listItem.el.offsetHeight;
      var dropTargetBottom = dropTarget.el.offsetTop + dropTarget.el.offsetHeight;

      var above = false;
      if(listItemBottom > dropTargetBottom) { //>=
	this.el.insertBefore(listItem.el, dropTarget.el.nextSibling);
      }
      else {
	this.el.insertBefore(listItem.el, dropTarget.el);
	above = true;
      }

      listItem.el.style.top = dropTarget.el.style.top = 0;

      document.documentElement.style.cursor = "auto";

      //document.getElementById('DEBUGINFO').innerHTML +=
      //"RESORT: " +
      //"b1=" + listItemBottom + " b2=" + dropTargetBottom + " " +
      //"startY1=" + DragHandlers.startY1 + " endY1=" + DragHandlers.endY1 + " " +
      //"startY2=" + DragHandlers.startY2 + " endY2=" + DragHandlers.endY2 + "<br/>";

      this.update_order(listItem, dropTarget, above);
    },

    update_order : function(listItem, dropTarget, above) {
      //document.getElementById('DEBUGINFO').innerHTML +=
      //"above=" + above + " " +
      //listItem.id + "("+document.getElementById("RL_art_order_" + listItem.id)+") " +
      //dropTarget.id + "("+document.getElementById("RL_art_order_" + dropTarget.id)+") || "+
      //"move_y=" + listItem.y + " target_y=" + dropTarget.el.offsetTop +" dh_y=" + DragHandlers.y+" dh_oldY=" + DragHandlers.oldY + " diffY="+DragHandlers.diffY;
      //document.getElementById('DEBUGINFO').innerHTML +=
      //"<br/>startY1=" + DragHandlers.startY1 +
      //" startY2=" + DragHandlers.startY2 +
      //" endY1=" + DragHandlers.endY1 +
      //" endY2=" + DragHandlers.endY2;
      //document.getElementById('DEBUGINFO').innerHTML +="<br/>";

      //var arr = new Array();
      //for (i=1; i<=parseInt(document.getElementById("RL_num_art").value); i++) {
      //	arr[i-1] = document.getElementById("RL_art_order_B" + i).value;
      //}

      var target_id = parseInt(dropTarget.id.substr(1));
      var move_id = parseInt(listItem.id.substr(1));
      var move_pos = -1;
      var target_pos = -1;

      for (i=1; i<=parseInt(document.getElementById("RL_num_art").value); i++) {
	t = parseInt(document.getElementById("RL_art_order_B" + i).value);
	if (t==target_id && above) target_pos = i;
	else if (t==target_id && !above) target_pos = i;
	if (t==move_id) move_pos = i;
      }
      //document.getElementById('DEBUGINFO').innerHTML +=
      //"1: move_up=?? above="+above+" target_id="+target_id+" target_pos="+target_pos+" target_pos1="+target_pos1+" target_pos2="+target_pos2+" move_id="+move_id+" move_pos="+move_pos+"<br/>";

      if (target_pos == move_pos) return; //nothing to do...
      var move_up = (target_pos < move_pos);

      if (move_up && !above) target_pos+=1; //target_pos = target_pos2;
      else if (!move_up && above) target_pos-=1;//target_pos = target_pos1;
      //document.getElementById('DEBUGINFO').innerHTML +=
      //"2: move_up="+move_up+" above="+above+" target_id="+target_id+" target_pos="+target_pos+" target_pos1="+target_pos1+" target_pos2="+target_pos2+" move_id="+move_id+" move_pos="+move_pos+"<br/>";
      if (target_pos == move_pos) return; //nothing to do...


      if (move_up) {
	///document.getElementById('DEBUGINFO').innerHTML += "MOVE UP ("+DragHandlers.startY2+">"+DragHandlers.endY2+")<br/>";
	var tmp = document.getElementById("RL_art_order_B" + move_pos).value;
	for (i=move_pos; i>target_pos; i--) {
	  //document.getElementById('DEBUGINFO').innerHTML +=
	  //"  move_up: " + document.getElementById("RL_art_order_B" + i).value + " = " + document.getElementById("RL_art_order_B" + (i-1)).value + "<br/>";
	  document.getElementById("RL_art_order_B" + i).value = document.getElementById("RL_art_order_B" + (i-1)).value;
	}
	document.getElementById("RL_art_order_B" + target_pos).value = tmp;
      }

      else {
	///document.getElementById('DEBUGINFO').innerHTML += "MOVE DOWN ("+DragHandlers.startY2+"<"+DragHandlers.endY2+")<br/>";
	var tmp = document.getElementById("RL_art_order_B" + move_pos).value;
	for (i=move_pos; i<target_pos; i++) {
	  ///document.getElementById('DEBUGINFO').innerHTML +=
	  ///"  move_down: " + document.getElementById("RL_art_order_B" + i).value + " = " + document.getElementById("RL_art_order_B" + (i+1)).value + "<br/>";
	  document.getElementById("RL_art_order_B" + i).value = document.getElementById("RL_art_order_B" + (i+1)).value;
	}
	document.getElementById("RL_art_order_B" + target_pos).value = tmp;
      }

      //for (i=1; i<=parseInt(document.getElementById("RL_num_art").value); i++) {
      //	document.getElementById('DEBUGINFO').innerHTML +=
      //	  "Article " + i + ": " + arr[i-1] + ' -> ' + document.getElementById("RL_art_order_B" + i).value+"<br/>";
      //}
    }

};
keyPressed = function(e) {
  if(DragPane.focusedElement == null ||
     DragPane.focusedElement.id.indexOf('DropOnly')>=0)
  return;

  if(!e)
  e = window.event;

  var sibling;

  var isUpArrow = e.keyCode == 38;
  var isDownArrow = e.keyCode == 40;

  if(isUpArrow) { // up arrow key.

    sibling = findPreviousSiblingWithClass(DragPane.focusedElement, "orderingItem");
  }
  else if(isDownArrow) { // down arrow key.

    sibling = findNextSiblingWithClass(DragPane.focusedElement, "orderingItem");

  }

  if(sibling != null) {
    if (sibling.id.indexOf('DropOnly')>=0) {
      return;
    }
    var sli = SortableListItem.getInstance(sibling);

    //if(e.ctrlKey) {
    if(e.ctrlKey || e.altKey) {
      if(isUpArrow)
	sli.dragPane.el.insertBefore(DragPane.focusedElement, sibling);
      else if(isDownArrow)
	sli.dragPane.el.insertBefore(sibling, DragPane.focusedElement);
      sli.dragPane.update_order(DragPane.focusedElement, sibling, isUpArrow);
    }
    else
    sli.focus();
  }

};

Listener.add(document, "onkeydown", keyPressed);


DragPane.hoveredElement = null;
DragPane.focusedElement = null;

/**
* DragPane.documentMouseMove handles mousemove for the dragPanes parent element
 * so we can track when the cursor leaves the dragPane element.
 */
DragPane.documentMouseMove = function(e) {
  var target = getTarget(e);

  var dragPaneTarget = null;
  if(target.className && hasToken(target.className, "dragPane"))
    dragPaneTarget = target;
  else
    dragPaneTarget = findAncestorWithClass(target, "dragPane");
  if(dragPaneTarget == null)
    return;

  var dragPane = DragPane.getInstance(dragPaneTarget);
  if(!contains(dragPane.el, target) && DragPane.hoveredElement != null){
    removeClass(DragPane.hoveredElement, "hoveredItem");
    DragPane.hoveredElement = null;
  }

};
///Listener.add(document, "onmousemove", DragPane.documentMouseMove);



//---------------------------------------------------------------------------


function findPreviousSiblingWithClass(el, className) {

  for(var ps = el.previousSibling; ps != null; ps = ps.previousSibling)
    if(hasToken(ps.className, className))
      return ps;
  return null;
}

function findNextSiblingWithClass(el, className) {

  for(var ns = el.nextSibling; ns != null; ns = ns.nextSibling)
    if(hasToken(ns.className, className))
      return ns;
  return null;
}

/**
 * Returns an Array of elements with the specified tagName and className.
 */
function getElementsWithClass(parent, tagName, klass){
  var returnedCollection = [];

  var exp = getTokenizedExp(klass,"");
  var collection = (tagName == "*" && parent.all) ?
    parent.all : parent.getElementsByTagName(tagName);

  for(var i = 0, counter = 0, len = collection.length; i < len; i++){

    if(exp.test(collection[i].className))
      returnedCollection[counter++] = collection[i];
  }
  return returnedCollection;
}


function findAncestorWithClass(el, klass) {

  if(el == null)
    return null;
  var exp = getTokenizedExp(klass,"");
  for(var parent = el.parentNode; parent != null;){

    if( exp.test(parent.className) )
      return parent;

    parent = parent.parentNode;
  }
  return null;
}

