/*
 Copyright (C) 2008 Nu Echo Inc.

 This file requires the Prototype.js library.

 Implementation of a generic table with sortable columns.
*/


var SortableColumn = Class.create({
   initialize: function(label, contentProvider, sorter, width) {
      this.label = label;
      this.contentProvider = contentProvider;
      this.sorter = sorter;
      this.width = width;
   },

   getLabel: function () {
      return this.label;
   },

   getContent: function(data) {
      return this.contentProvider(data);
   },

   getSorter: function() {
      return this.sorter;
   },

   getWidth: function() {
	   return this.width;
   }
});

var SortableTable = Class.create({
	initialize: function(dataProvider, columns, parentId, options) {
      this.dataProvider = dataProvider;
      this.columns = columns;
      this.data = [];
      this.parentId = parentId;
      this.sortedColumnIndex = 0;
      this.sortUp = false;
      this.page = 0;
      this.lastpage = 0;
      this.itemsPerPage = 10;
      this.options = options ? options : {};
      this.failed = false;
      $(this.parentId)['$tableController'] = this;
      this.updateData();
   },

   displayRefreshStatus: function(status)
   {
      var refreshStatus = document.getElementById('refresh_status');

	  if (refreshStatus != null)
	  {
		  for (var child = refreshStatus.firstChild; child != null; child = child.nextSibling)
		  {
			  refreshStatus.removeChild(child);
		  }

		  refreshStatus.appendChild(document.createTextNode(status));
	  }
   },

   refresh: function(newData) {
      this.displayRefreshStatus('...refreshing...');

      var container = this.createContainer();
      this.createTableHeaders(container);
      this.displayRows(container);
      this.displayPageControls(container);
      $(this.parentId).innerHTML = this.createInnerHTML(container);

      if (this.failed)
      {
	  this.updateFailed();
      }
   },

   updateFailed: function() {
            if (this.options.hideControls) return;
	   if (! this.failed)
	   {
		   this.failed = true;
	   }

	   $('refresh_status').innerHTML = "<span class='error_status'>Table update failed</span>";
       $('error_diagnosis').innerHTML = "<p class='error_message'>Unable to connect to NuGram Server. Try refreshing the page using the browser. If the error persists, contact the <a href='/html_app/doc/support'>support team</a>.</p>.";
   },

   createInnerHTML: function(container) {
	   var table = "<table class='dynamic'>" + container.innerHTML + "</table>";
	   var control = this.createTableSizeControls();
           if (control) {
               return  control.innerHTML + table + "<div id='error_diagnosis'></div>";
           } else {
               return table;
           }
   },


   createContainer: function() {
	   var container = document.createElement('container');
	   this.incorporateColumnsWidth(container);

       return container;
   },

   incorporateColumnsWidth: function(container) {
	   for ( columnIndex = this.columns.length - this.tableNumberColumns();
		 columnIndex < this.columns.length; columnIndex++ )
	   {
		   var col = document.createElement("col");
		   col.setAttribute('width', this.columns[columnIndex].getWidth());
		   container.appendChild(col);
	   }
   },

   tableNumberColumns: function() {
	   return this.columns.length;
   },

   createTableSizeControls: function() {
            if (this.options.hideControls) return false;
	   var parentId = this.parentId;

	   var controlsDiv = document.createElement('div');
	   var container = document.createElement('container');
	   controlsDiv.setAttribute('class', 'table_size_control');

	   var statusDiv = document.createElement('div');
	   statusDiv.setAttribute('id', 'refresh_status');

	   var test = 2;

	   var selectorDiv = document.createElement('div');
	   selectorDiv.setAttribute('id', 'nb_items_selector');

	   // Download button
	   if ( ! this.failed && this.options.canDownload)
	   {
	      var downloadButton = document.createElement('span');
	      downloadButton.setAttribute('class', 'button');
	      downloadButton.setAttribute('id', 'download-button');
	      downloadButton.setAttribute('title', 'Download the selected grammars');
	      downloadButton.setAttribute('onclick', 'download_zip(account_scope)');
	      var image = document.createElement('img');
	      image.setAttribute('src', '/icons/compress.png');
	      downloadButton.appendChild(image);
	      downloadButton.appendChild(document.createTextNode("Download"));
	   }


	   // Refresh button
	   if ( ! this.failed )
	   {
	      var refreshButton = document.createElement('span');
	      refreshButton.setAttribute('id', 'refresh_button');
	      refreshButton.setAttribute('title', 'Refresh table');
	      refreshButton.setAttribute('class', 'button');
	      refreshButton.setAttribute('onclick', '$("' + parentId + '").$tableController.updateData();');
	      var image = document.createElement('img');
	      image.setAttribute('src', '/icons/arrow_refresh_small.png');
	      refreshButton.appendChild(image);
	   }


	   if (downloadButton)
	   {
		   controlsDiv.appendChild(downloadButton);
	   }


	   if (this.refreshTimestamp)
	   {
		   statusDiv.appendChild(document.createTextNode(this.refreshTimestamp.toDateString()
				   + ', '+ this.refreshTimestamp.toLocaleTimeString()
		   ));
	   }

           controlsDiv.appendChild(statusDiv);

	   if (refreshButton)
	   {
		   controlsDiv.appendChild(refreshButton);
	   }


	   controlsDiv.appendChild(selectorDiv);
	   container.appendChild(controlsDiv);

	   var currentSize = this.itemsPerPage;
	   var createButton = function(size) {
		   var sizeLabel = size == Infinity ? "All" : size;
		   if (size == currentSize) {
			   return " <span class='disabled-button'>" + sizeLabel + "</span>";
		   }
		   else {
			   return " <span class='button' onclick='$(\"" + parentId + "\").$tableController.setItemsPerPage(" + size + ")'>" + sizeLabel + "</span>";
		   }
	   };
	   selectorDiv.innerHTML = "Items per page:" + createButton(10) + createButton(20) + createButton(50) + createButton(100) + createButton(Infinity);

	   return container;
   },

   createColumnHeader: function(tr, columnIndex) {
       if (this.options.hideHeaders) return;

       var th = document.createElement('th');
       th.setAttribute('class', 'clickable');
       th.setAttribute('id', 'column-' + columnIndex);
       th.setAttribute('onclick', "$(\"" + this.parentId + "\").$tableController.sortColumn(" + columnIndex + ")");
       th.setAttribute('title', 'Click to sort');
       var sortDirection = "";
       if (columnIndex == this.sortedColumnIndex) {
	 sortDirection = (this.sortUp ? " \u25BC" : " \u25B2");
       }

       var label = document.createElement('span');
       label.setAttribute('class', 'label');
       label.appendChild(document.createTextNode(this.columns[columnIndex].getLabel()));
       th.appendChild(label);

       th.appendChild(document.createTextNode(sortDirection));
       tr.appendChild(th);
       return th;
   },

   createTableHeaders: function(container)  {
	    var tr = document.createElement('tr');
	    for(columnIndex = 0; columnIndex < this.columns.length; columnIndex++) {
		this.createColumnHeader(tr, columnIndex)
		    }
	    
	    container.appendChild(tr);
   },

   updateData: function() {
	   this.displayRefreshStatus('...updating...');
	   this.dataProvider(true);
   },

   dataUpdated: function() {
	   this.refreshTimestamp = new Date();

	   this.data = this.dataProvider(false).concat([]);
	   this.sortData();

	   var nbElements = this.data.length;
	   this.lastpage = (Math.ceil( nbElements / this.itemsPerPage));
	   if (this.lastpage > 0) {
		   this.lastpage--;
	   }
	   if (this.page > this.lastpage) {
		   this.page = this.lastpage;
	   }

	   this.refresh(true);
   },

   displayRows: function(container) {
	   var data = this.data;
	   if (data.length == 0) {
		   // Warn that there is no data to be displayed
		   var tr = document.createElement('tr');
		   var td = document.createElement('td');

		   td.setAttribute('colspan', this.tableNumberColumns());
		   td.appendChild(document.createTextNode("No data to display."));

		   tr.appendChild(td);
		   container.appendChild(tr);
		   return;
	   }

	   var start = 0;
	   var end = data.length;
	   if (this.itemsPerPage != Infinity) {
		   start = this.page * this.itemsPerPage;
		   end = Math.min((this.page + 1) * this.itemsPerPage, data.length);
	   }

	   for(rowIndex = start; rowIndex < end; rowIndex++) {
		   var entry = data[rowIndex];
		   this.displayRow(container, entry, rowIndex);
	   }
   },

   displayRow: function(container, entry, rowIndex) {

	   var tr = document.createElement('tr');
	   for(columnIndex = 0; columnIndex < this.columns.length; columnIndex++) {
		   this.displayRowItem(tr, entry, rowIndex, columnIndex);
	   }
	   container.appendChild(tr);
   },

   displayRowItem: function(container, entry, rowIndex, columnIndex) {
	   var column = this.columns[columnIndex];
	   var td = document.createElement('td');
	   td.setAttribute('class', (rowIndex % 2 == 0) ? 'odd' : 'even');
	   td.appendChild(column.contentProvider(entry));
	   container.appendChild(td);
	   return td;
   },

   displayPageControls: function(container) {
            if (this.options.hideControls) return;
	   if (this.data.length <= 0)
		   return;

	   var id = this.parentId;
	   var createButton = function(img, tooltip, enabled, funName) {
		   var button = document.createElement('span');
		   button.setAttribute('class', enabled ? 'button' : 'disabled-button');
		   button.setAttribute('title', tooltip);
		   if (enabled) {
			   button.setAttribute('onclick', "$(\"" + id + "\").$tableController." + funName + "()");
		   }
		   var image = document.createElement('img');
		   image.setAttribute('class', 'button');
		   image.setAttribute('src', '/icons/' + img + '.png');
		   button.appendChild(image);
		   return button;
	   };

	   var tr = document.createElement('tr');
	   var separator = document.createElement('td');
	   separator.setAttribute('colspan', this.tableNumberColumns() );
	   separator.setAttribute('height', '0px');
	   separator.setAttribute('class', 'rowseparator');

	   tr.appendChild(separator);
	   container.appendChild(tr);


	   var tr = document.createElement('tr');
	   var td = document.createElement('td');
	   var tdDiv = document.createElement('div');
	   td.appendChild(tdDiv);
	   td.setAttribute('align', 'center');
	   td.setAttribute('width', "100%");
	   td.setAttribute('colspan', this.tableNumberColumns());
	   tr.appendChild(td);
	   container.appendChild(tr);
	   var page = this.page;
	   var lastpage = this.lastpage;
	   var data = this.data;

	   var innerTable = document.createElement('table');
	   innerTable.setAttribute('width', '100%');
	   td.appendChild(innerTable);
	   var innerTr = document.createElement('tr');
	   innerTr.setAttribute('width', '100%');
	   innerTable.appendChild(innerTr);

	   var leftDiv = document.createElement('td');
	   leftDiv.setAttribute('align', 'left');
	   leftDiv.appendChild(createButton('resultset_first', 'Go to first page', page > 0, 'firstPage'));
	   leftDiv.appendChild(document.createTextNode("  "));
	   leftDiv.appendChild(createButton('resultset_previous', 'Go to previous page', page > 0, 'previousPage'));
	   innerTr.appendChild(leftDiv);

	   var pageIndicator = document.createElement('td');
	   pageIndicator.setAttribute('align', 'center');

	   var start = 1;
	   var end = data.length;
	   if (this.itemsPerPage != Infinity) {
		   start = (page * this.itemsPerPage) + 1;
		   end = Math.min((page + 1) * this.itemsPerPage, data.length);
	   }
	   var total = data.length;
	   pageIndicator.innerHTML = "<b> " + start + '-' + end + ' of ' + total + " </b>";
	   innerTr.appendChild(pageIndicator);

	   var rightDiv = document.createElement('td');
	   rightDiv.setAttribute('align', 'right');
	   rightDiv.appendChild(createButton('resultset_next', 'Go to next page', page < lastpage, 'nextPage'));
	   rightDiv.appendChild(document.createTextNode("  "));
	   rightDiv.appendChild(createButton('resultset_last', 'Go to last page', page < lastpage, 'lastPage'));
	   innerTr.appendChild(rightDiv);
   },

   sortColumn: function(columnIndex) {
      if (this.sortedColumnIndex == columnIndex)
      {
	  this.selectSortedColumn(columnIndex, !(this.sortUp));
      }
      else {
	 this.selectSortedColumn(columnIndex, false);
      }
   },

   selectSortedColumn: function(columnIndex, up) {
      this.sortedColumnIndex = columnIndex;
      this.sortUp = up;
      this.page = 0;
      this.sortData();
      this.refresh(false);
   },

   sortData: function() {
           if (this.options.disableSort) return;
	   this.data.sort(this.columns[this.sortedColumnIndex].getSorter()(this.sortUp));
   },

   setItemsPerPage: function(itemsPerPage) {
      this.itemsPerPage = itemsPerPage;
      this.page = 0;
      this.refresh(false);
   },

   nextPage: function() {
      this.page++;
      this.refresh(false);
   },

   previousPage: function() {
      this.page--;
      this.refresh(false);
   },

   firstPage: function() {
      this.page = 0;
      this.refresh(false);
   },

   lastPage: function() {
      this.page = this.lastpage;
      this.refresh(false);
   }
});


/*
 CONTENT PROVIDERS
*/

function stringContent(x) {
   return document.createTextNode(x == null ? "" : x.toString());
}

function propertyContent(propertyName) {
   return function(x) {
      return stringContent(x[propertyName]);
   };
}


/*
 SORTERS
*/

function propertySorter(property) {
   return function(a, b) {
      var a_prop = a[property];
      var b_prop = b[property];
      if (a_prop < b_prop)
	 return -1;
      if (a_prop > b_prop)
	 return 1;
      return 0;
   }
}

function propertySorterGenerator(property) {
	return function(sortUp) {
		return function(a,b){
			var result = (propertySorter(property))(a, b);
			return sortUp ? -1 * result :  result;
		}
	}
}

function propertySorterGenerator(first_property, second_property) {
	return function(sortUp) {
		return function(a,b) {
			var result = propertySorter(first_property)(a, b);

			if (result != 0) {
				return sortUp ? -1 * result :  result;
			}
			else {
				return propertySorter(second_property)(a, b)
			}
		}
	}
}

/*
 * SPECIALIZED TABLES
 */

/*
 * Table displaying cells over two rows
 * (the first cell is displayed on its own row)
 */
var TwoRowsSortableTable = Class.create();

Object.extend(TwoRowsSortableTable.prototype, SortableTable.prototype);

Object.extend(TwoRowsSortableTable.prototype, {

	createTableHeaders : function(container)  { 
        if (this.options.hideHeaders) return;
	var tr = document.createElement('tr');

	topHeader = this.createColumnHeader(tr, 0);
	topHeader.setAttribute('colspan', this.tableNumberColumns());
	container.appendChild(tr);

	tr = document.createElement('tr');
	tr.setAttribute('class', 'smaller');

	for(columnIndex = 1; columnIndex < this.columns.length; columnIndex++) {
		var cell = this.createColumnHeader(tr, columnIndex);

		if (columnIndex == 1)
		{
			cell.setAttribute('class', cell.getAttribute('class') + " indented" );
		}
	}

	container.appendChild(tr);
},

displayRow: function(container, entry, rowIndex) {

	var tr = document.createElement('tr');
	var separator = document.createElement('td');
	separator.setAttribute('colspan', this.tableNumberColumns() );
	separator.setAttribute('height', '0px');
	separator.setAttribute('class', 'rowseparator');

	tr.appendChild(separator);
	container.appendChild(tr);

	tr = document.createElement('tr');
	var topCell = this.displayRowItem(tr, entry, rowIndex, 0);
	topCell.setAttribute('colspan', this.tableNumberColumns() );
	container.appendChild(tr);

	tr = document.createElement('tr');
	tr.setAttribute('class', 'smaller');

	for(columnIndex = 1; columnIndex < this.columns.length; columnIndex++) {
		var cell = this.displayRowItem(tr, entry, rowIndex, columnIndex);

		if (columnIndex == 1)
		{
			cell.setAttribute('class', cell.getAttribute('class') + " indented" );
		}
	}

	container.appendChild(tr);
},

tableNumberColumns: function() {
	   return this.columns.length - 1;
}

});

