//*************** GLOBAL VARS  *****************

var helpDoc = MM.HELP_cmdSortTable;

var HAVE_SORTED_BY = new Array(7);

//******************* API **********************

function commandButtons(){
   var tableObj = findTable();
   var retArr = new Array(BTN_OK,     "sortAndClose()",
                          BTN_Apply,   "sortTable()",
                          BTN_Cancel,  "window.close()",
                          BTN_Help,    "displayHelp()");

   //display buttons that can only close the dialog if there are problems with table format
   if (hasSpans(tableObj) || isInvalidTable(tableObj) || hasCaption(tableObj))  
     retArr=new Array(BTN_OK,"window.close()",BTN_Cancel,"window.close()");

     return retArr;
}

function canAcceptCommand(){
  if (dw.getDocumentDOM() == null)
    return false;
  else if (dw.getDocumentDOM().getShowLayoutView())
    return false;
  if (findTable())
    return true;
  else
    return false;
}
//***************** LOCAL FUNCTIONS  ******************

function findTable(){
  var tableObj="";
  var selArr = dreamweaver.getSelection();
  var selObj = dreamweaver.offsetsToNode(selArr[0],selArr[1]);

  while (tableObj=="" && selObj.parentNode){
    if (selObj.nodeType == Node.ELEMENT_NODE && selObj.tagName=="TABLE")
	  tableObj=selObj;
	else
	  selObj = selObj.parentNode;
  }
  return tableObj;
}

function sortAndClose(){
  //If the current sort has already been applied, close the dialog
  //otherwise, sort
  if (findObject("sortCol").selectedIndex==HAVE_SORTED_BY[0] &&
      findObject("subsortCol").selectedIndex-1==HAVE_SORTED_BY[1] &&
      findObject("sortType").selectedIndex==HAVE_SORTED_BY[2] &&
      findObject("subsortType").selectedIndex==HAVE_SORTED_BY[3] &&
      findObject("sortOrder").selectedIndex==HAVE_SORTED_BY[4] &&
      findObject("subsortOrder").selectedIndex==HAVE_SORTED_BY[5]&&
	  findObject("sortFirstRow").checked==HAVE_SORTED_BY[6]){
      window.close();
	  }
   else{
     sortTable();
     window.close();
   }

}

function sortTable(){
    var tableObj, rowCount, rowIter, rowArray, tdIter;
    var rowNode, colIter, sortCol,subsortCol,rowHTML,bSkipFirstRow;
    var textString,startCount,currRow,bMoveRowAttrs;
    
	MM.setBusyCursor();
	
    // Get the selected table
    tableObj = findTable();

 
    // Determine number of rows 
    rowIter = tableObj.childNodes; //rowIter is array of TR tags in this table
    rowCount = rowIter.length;
    bSkipFirstRow = !findObject("sortFirstRow").checked;
	bMoveRowAttrs = findObject("moveRowAttrs").checked;
	rowCount = (bSkipFirstRow)?rowCount-1:rowCount;

    // Determine column and subsort column
    sortCol = findObject("sortCol").selectedIndex;
    subsortCol = findObject("subsortCol").selectedIndex-1;

    //Create a two-dimensional array containing rowCount rows and 3 columns.
    //The first column contains the HTML text for the row,the second
    //column contains the contents of column number sortCol for that row,
    //and the third column contains the contents of column number subsortColumn
    //for that row. 

    rowArray = new Array();
    for (i=0;i<rowCount;i++) {

       // Copy row text into rowArray
       rowArray[i] = new Array();
       rowHTML = (bSkipFirstRow)?rowIter.item(i+1):rowIter.item(i);  
       rowArray[i][0] = (bMoveRowAttrs)?rowHTML.outerHTML:rowHTML.innerHTML;

       // Copy sort key into rowArray
       colIter = rowHTML.childNodes;
       textString=getTextNode(colIter.item(sortCol));
       rowArray[i][1] = findObject("sortType").selectedIndex==0 ?
         gobbleWhiteSpace(textString):parseNumber(gobbleWhiteSpace(textString));
	  
	   //copy subsort key into rowArray, if applicable
       if (findObject("subsortCol").selectedIndex > 0){
         textString=getTextNode(colIter.item(subsortCol));
         rowArray[i][2]= findObject("subsortType").selectedIndex==0 ?
            gobbleWhiteSpace(textString):parseNumber(gobbleWhiteSpace(textString));

       }        
    }

    // Sort the rowArray, based on sort key
    rowArray.sort(compareCallback);

    // Copy the contents of the sorted rowArray back into the HTML document
    for (i = 0; i < rowCount; i++) {
	  currRow=(bSkipFirstRow)?rowIter.item(i+1):rowIter.item(i);
      if (bMoveRowAttrs)
	    currRow.outerHTML=rowArray[i][0];
	  else
	    currRow.innerHTML=rowArray[i][0];
    }

    //plug sort information into global HAVE_SORTED_BY variable
    HAVE_SORTED_BY[0]=sortCol;
	HAVE_SORTED_BY[1]=subsortCol;
    HAVE_SORTED_BY[2]=findObject("sortType").selectedIndex;
    HAVE_SORTED_BY[3]=findObject("subsortType").selectedIndex;
    HAVE_SORTED_BY[4]=findObject("sortOrder").selectedIndex;
    HAVE_SORTED_BY[5]=findObject("subsortOrder").selectedIndex;
	HAVE_SORTED_BY[6]=findObject("sortFirstRow").checked;
	
	//restore original selection
	selArr = dreamweaver.nodeToOffsets(tableObj);
	dreamweaver.setSelection(selArr[0],selArr[1]);
	
	MM.clearBusyCursor();
}

function compareCallback(a,b){
   var retVal=0;
   var result=0;
   //determine whether to switch a and b based on a and b values and specified sort order
   //if -1 is returned: order stays the same, if 1: values are switched, if 0: values are equal

  if (findObject("sortType").selectedIndex==0)
     result = LocaleSort.compareString(a[1],b[1]);
   else
     if (a[1]!=b[1])
       result = (a[1]<b[1])?-1:1; 

   if (result!=0)
     retVal=(result)*(findObject("sortOrder").selectedIndex==0?1:-1);
   else { 
     if (findObject("subsortType").selectedIndex==0)
       result = LocaleSort.compareString(a[2],b[2])  
     else {
       if (a[2]!=b[2])
		 result = (a[2]<b[2])?-1:1;
	 }
     if (result!=0)
	   retVal=(result )*(findObject("subsortOrder").selectedIndex==0?1:-1);
   }


   return retVal;
}

function initializeUI(){
   var colCount;
   var tableObj = findTable();
   var errMsg = "";
   
   if (hasSpans(tableObj)){ //if table has rowspans or colspans
     errMsg = MSG_SpansArePresent;
   } else if (hasCaption(tableObj)){
     errMsg = MSG_CaptionIsPresent;
   } else if (isUltraDev() && hasServerBehaviorApplied(tableObj,true)) {
     errMsg = MM.MSG_SomeServerBehaviorsNotAllowed;
   } else if (isInvalidTable(tableObj)){ //if table is invalid
     errMsg = MSG_IsInvalidTable;
   }
      
    if (errMsg) {
      findObject("ErrMsgLayer").innerHTML="<p>&nbsp;</p>" + errMsg;
      findObject("formLayer").visibility = "hidden";
      findObject("ErrMsgLayer").visibility="visible";
    } else { //if everything is okay

      //dynamically update all form elements
      //dynamically update sort order and type
      with (findObject("sortType")){
        options[0]= new Option(MENU_TypeAlphabetical);
        options[1]= new Option(MENU_TypeNumerical);
      }
      with (findObject("subsortType")){
        options[0]= new Option(MENU_TypeAlphabetical);
        options[1]= new Option(MENU_TypeNumerical);
      }
      with (findObject("sortOrder")){
        options[0]= new Option(MENU_OrderAscending);
        options[1]= new Option(MENU_OrderDescending);
      }
      with (findObject("subsortOrder")){
        options[0]= new Option(MENU_OrderAscending);
        options[1]= new Option(MENU_OrderDescending);
      }
      //dynamically update sortCol and subsortCol menus
      colCount=tableObj.childNodes.item(0).childNodes.length;
      for (i=0;i<colCount;i++)
        findObject("sortCol").options[i]=new Option(MENU_Column + " " + (i+1)); 
      findObject("subsortCol").options[0]=new Option(" ");
      for (i=0;i<colCount;i++)
        findObject("subsortCol").options[i+1]=new Option(MENU_Column + " " + (i+1)); 
   }
}

function parseNumber(value){

  var retVal=value;
  var numLength = retVal.length;
  var k=0;

  //before sorting as numbers, remove % and $ symbols 
  if (retVal.charAt(0)=="$")
    retVal=retVal.slice(1);
  else if (retVal.charAt(numLength-1)=="%" || retVal.charAt(numLength-1)=="$")
    retVal=retVal.slice(0,-1);
  
  //before sorting as numbers, remove spaces and turn commas into decimal points
  while( retVal.charAt(k) ){ 
    if (retVal.charAt(k)==" "){ 
      retVal=retVal.substring(0,k) + retVal.substring(k+1);continue; 
    }
    if (retVal.charAt(k)==","){ 
       retVal=retVal.substring(0,k) + retVal.substring(k+1);continue; 
	}   
    k++;
  }
   
  //following lines exist to work around Netscape crash caused by comparing
  //two values that are both NaN. Workaround: Non-numbers are treated as strings.
  if (parseFloat(retVal) == retVal)
    retVal = parseFloat(retVal);
	
  return retVal;
}



function hasSpans(theObj){ //checks for rowspans and colspans
   var hasSpans=false;
   var tdIter=theObj.getElementsByTagName("TD");
   var iterLength=tdIter.length;
   
   for (i=0;i<iterLength;i++){  //if any rowspan or colspan attributes are found, return true
      if(tdIter.item(i).getAttribute("ROWSPAN") || tdIter.item(i).getAttribute("COLSPAN")){
        hasSpans=true;
        break;
      }
   }
   return hasSpans;
}

function hasCaption(theObj){
  if (theObj.childNodes.item(0).tagName && theObj.childNodes.item(0).tagName=="CAPTION")
    return true;
  return false;
}

function isInvalidTable(theObj){
 
  var retVal=false;
  var trIter=theObj.childNodes;
  var trIterLen = trIter.length;
  var widthOfFirstRow=trIter.item(0).childNodes.length;

  //check that each child node of table is TR tag
  //and that each TR has same number of children
  //note that we use the childNodes to check the children number
  //instead of getElementsByTagName("TD").length, because the latter
  //would give deceiving results in the case of nested tables
  for (i=0;i<trIterLen;i++){
    if (trIter.item(i).tagName != "TR" || trIter.item(i).childNodes.length==0
	        || trIter.item(i).childNodes.length!=widthOfFirstRow){
      retVal=true; break;
    }
  }
  return retVal;
}


function getTextNode(theObj){
    var iter=theObj.childNodes;
	var counter=0;
    var child=iter.item(counter);
    var retVal="";

   while (child) {
      retVal+=getTextNode(child);
      child=iter.item(++counter);
   }
     if (theObj.nodeType == Node.TEXT_NODE)
     retVal+=theObj.data;
   
   return retVal;
}

function gobbleWhiteSpace(textstring){
  var lastChar,counter=0;
  var whiteSpaceChars = " \n\r\f\t";

  //gobble whitespace from beginning of string
  while (  textstring && whiteSpaceChars.indexOf( textstring.charAt(0) ) !=  -1  ){
    textstring = textstring.substring(1);
  }
	
  //gobble whitespace from end of string
  lastChar = textstring.length-1;
  while (  textstring && whiteSpaceChars.indexOf( textstring.charAt(lastChar) ) != -1  ){
     textstring = textstring.substring(0,lastChar--);
  }
        
  return textstring;  
}	

//**************** GENERIC FUNCTIONS ****************

function findObject(objName,  parentObj) {
  var i,tempObj="",found=false,curObj = "";
  var NS = (navigator.appName.indexOf("Netscape") != -1);
  if (!NS && document.all) curObj = document.all[objName]; //IE4
  else {
    parentObj = (parentObj != null)? parentObj.document : document;
    if (parentObj[objName] != null) curObj = parentObj[objName]; //at top level
    else { //if in form
      if (parentObj.forms) for (i=0; i<parentObj.forms.length; i++) {  //search level for form object
        if (parentObj.forms[i][objName]) {
          curObj = parentObj.forms[i][objName];
          found = true; break;
      } }
      if (!found && NS && parentObj.layers && parentObj.layers.length > 0) {
        parentObj = parentObj.layers;
        for (i=0; i<parentObj.length; i++) { //else search for child layers
          tempObj = findObject(objName,parentObj[i]); //recurse
          if (tempObj) { curObj = tempObj; break;} //if found, done
  } } } }
  return curObj;
}



