/*

On page load, the SortableManager:

- Finds the table by its id (sortierbareTabelle).
- Parses its thead for columns with a "mochi:format" attribute.
- Parses the data out of the tbody based upon information given in the
"mochi:format" attribute, and clones the tr elements for later re-use.
- Clones the column header th elements for use as a template when drawing
sort arrow columns.
- Stores away a reference to the tbody, as it will be replaced on each sort.
- Performs the first sort.


On sort request:

- Sorts the data based on the given key and direction
- Creates a new tbody from the rows in the new ordering
- Replaces the column header th elements with clickable versions, adding an
indicator (↑ or ↓) to the most recently sorted column.

*/

SortableManager = function () {
   this.thead = null;
   this.tbody = null;
   this.columns = [];
   this.rows = [];
   this.sortState = {};
   this.sortkey = 0;
};

mouseOverFunc = function () {
   addElementClass(this, "over");
};

mouseOutFunc = function () {
   removeElementClass(this, "over");
};

ignoreEvent = function (ev) {
   if (ev && ev.preventDefault) {
       ev.preventDefault();
       ev.stopPropagation();
   } else if (typeof(event) != 'undefined') {
   event.cancelBubble = false;
   event.returnValue = false;
}
};


update(SortableManager.prototype, {

   "initWithTable": function (table) {
       /***

       Initialize the SortableManager with a table object

       ***/
       // Ensure that it's a DOM element
       table = getElement(table);
       // Find the thead
       this.thead = table.getElementsByTagName('thead')[0];
       // get the mochi:format key and contents for each column header
       var cols = this.thead.getElementsByTagName('th');
       for (var i = 0; i < cols.length; i++) {
           var node = cols[i];
           var attr = null;
           try {
               attr = node.getAttribute("mochi:format");
           } catch (err) {
           // pass
       }
       var o = node.childNodes;
       this.columns.push({
           "format": attr,
           "element": node,
           "proto": node.cloneNode(true)
       });
   }
   // scrape the tbody for data
   this.tbody = table.getElementsByTagName('tbody')[0];
   // every row
   var rows = this.tbody.getElementsByTagName('tr');
   for (var i = 0; i < rows.length; i++) {
       // every cell
       var row = rows[i];
       var cols = row.getElementsByTagName('td');
       var rowData = [];
       for (var j = 0; j < cols.length; j++) {
           // scrape the text and build the appropriate object out of it
           var cell = cols[j];
           var obj = scrapeText(cell);
           switch (this.columns[j].format) {
               case 'isodate':
               obj = isoDate(obj);
               break;
               case 'str':
               break;
               case 'istr':
               obj = obj.toLowerCase();
               break;
               case 'int' :
               obj = parseInt( obj );
               case 'gdate' :

               // cases for numbers, etc. could be here
               default:
               break;
           }
           rowData.push(obj);
       }
       // stow away a reference to the TR and save it
       rowData.row = row.cloneNode(true);
       this.rows.push(rowData);

   }

   // do initial sort on first column
   this.drawSortedRows(this.sortkey, true, false);

},

"onSortClick": function (name) {
   /***

   Return a sort function for click events

   ***/
   return method(this, function () {
       log('onSortClick', name);
       var order = this.sortState[name];
       if (order == null) {
           order = true;
       } else if (name == this.sortkey) {
       order = !order;
   }
   this.drawSortedRows(name, order, true);
});
},

"drawSortedRows": function (key, forward, clicked) {
   /***

   Draw the new sorted table body, and modify the column headers
   if appropriate

   ***/
   log('drawSortedRows', key, forward);
   this.sortkey = key;
   // sort based on the state given (forward or reverse)
   var cmp = (forward ? keyComparator : reverseKeyComparator);
   this.rows.sort(cmp(key));
   // save it so we can flip next time
   this.sortState[key] = forward;
   // get every "row" element from this.rows and make a new tbody
   var newBody = TBODY(null, map(itemgetter("row"), this.rows));
   // swap in the new tbody
   this.tbody = swapDOM(this.tbody, newBody);
   for (var i = 0; i < this.columns.length; i++) {
       var col = this.columns[i];
       var node = col.proto.cloneNode(true);
       // remove the existing events to minimize IE leaks
       col.element.onclick = null;
       col.element.onmousedown = null;
       col.element.onmouseover = null;
       col.element.onmouseout = null;
       // set new events for the new node
       node.onclick = this.onSortClick(i);
       node.onmousedown = ignoreEvent;
       node.onmouseover = mouseOverFunc;
       node.onmouseout = mouseOutFunc;
       // if this is the sorted column
       if (key == i) {
           // \u2193 is down arrow, \u2191 is up arrow
           // forward sorts mean the rows get bigger going down
           var arrow = (forward ? "\u2193" : "\u2191");
           // add the character to the column header
           node.appendChild(SPAN(null, arrow));
           if (clicked) {
               node.onmouseover();
           }
       }

       // swap in the new th
       col.element = swapDOM(col.element, node);
   }
}
});

sortableManager = new SortableManager();

addLoadEvent(function () {
   sortableManager.initWithTable('sortierbareTabelle');
});

// rewrite the view-source links
addLoadEvent(function () {
   var elems = getElementsByTagAndClassName("A", "view-source");
   var page = "sortable_tables/";
   for (var i = 0; i < elems.length; i++) {
       var elem = elems[i];
       var href = elem.href.split(/\//).pop();
       elem.target = "_blank";
       elem.href = "../view-source/view-source.html#" + page + href;
   }
});


germanDate = function (d) {
   d = d + "";
   if (typeof(d) != "string" || d.length === 0) {
       return null;
   }
   var a = d.split('.');
   return new Date(a[0], a[1], a[2]);
};