var SortingTable = new Class({

  Implements: Options,
  
  options: {
    zebra: true,
    details: false,
    paginator: false,
    dont_sort_class: 'nosort',
    forward_sort_class: 'forward_sort',
    reverse_sort_class: 'reverse_sort'
  },

  initialize: function( table, options ) {
    this.table = document.id(table);
    this.setOptions(options);
	this.defaultSort = [];
    
    this.tbody = this.table.getElement('tbody');
    if (this.options.zebra) {
      SortingTable.stripe_table(this.tbody.getChildren());
    }

    this.headers = this.table.getElement('thead').getElements('th');
    this.headers.each(function( header, index ) {
      if (!header.hasClass( this.options.dont_sort_class )){			
		  header.store( 'column', index )
		  header.addEvent( 'click', function(evt){
			var header = evt.target;
			if ( header.tagName !== 'TH' ){
				header = document.id(header).getElement('! th');
			}
			this.sort_by_header( header );
			if ( this.options.paginator) this.options.paginator.to_page( 1 );
		  }.bind( this ) );
		  if( header.hasClass(this.options.forward_sort_class) || header.hasClass(this.options.reverse_sort_class) ){
			  this.defaultSort.push(header);
		  }
  	  }
    }, this);

    this.load_conversions();

	this.defaultSort.each( function(elm){
		this.sort_by_header(elm);
	}.bind(this));
  },

  sort_by_header: function( header ){
    var rows = [];
    
    var before = this.tbody.getPrevious();
    this.tbody.dispose();
    
    var trs = this.tbody.getChildren();
    while ( row = trs.shift() ) {
      row = { row: row.dispose() };
      if ( this.options.details ) {
        row.detail = trs.shift().dispose();
      }
      rows.unshift( row );
    }
    
    if ( this.sort_column >= 0 &&
         this.sort_column == header.retrieve('column') ) {
      if ( header.hasClass( this.options.reverse_sort_class ) ) {
        header.removeClass( this.options.reverse_sort_class );
        header.addClass( this.options.forward_sort_class );
      } else {
        header.removeClass( this.options.forward_sort_class );
        header.addClass( this.options.reverse_sort_class );
      }
    } else {
      this.headers.each(function(h){
        h.removeClass( this.options.forward_sort_class );
        h.removeClass( this.options.reverse_sort_class );
      }, this);
      this.sort_column = header.retrieve('column');
      if (header.retrieve('conversion_function')) {
        this.conversion_matcher = header.retrieve('conversion_matcher');
        this.conversion_function = header.retrieve('conversion_function');
      } else {
        this.conversion_function = false;
        rows.some(function(row){
          var to_match = document.id(row.row.getElements('td')[this.sort_column]).get('text');
          if (to_match == '') return false;
          this.conversions.some(function(conversion){
            if (conversion.matcher.test( to_match )){
              this.conversion_matcher = conversion.matcher;
              this.conversion_function = conversion.conversion_function;
              return true;
            }
            return false;
          }, this);
          return !!(this.conversion_function);
        }, this);
        header.store('conversion_function', this.conversion_function );
        header.store('conversion_matcher', this.conversion_matcher );
      }
      header.addClass( this.options.forward_sort_class );
      rows.each(function(row){
        var compare_value = this.conversion_function( row );
        row.toString = function(){
          return compare_value;
        };
      }, this);
      rows.sort();
    }

    var index = 0;
    while ( row = rows.shift() ) {
      this.tbody.appendChild(row.row);
      if (row.detail) this.tbody.appendChild(row.detail);
      if ( this.options.zebra ) {
        row.row.className = row.row.className.replace( this.removeAltClassRe, '$1').clean();
        if (row.detail)
          row.detail.className = row.detail.className.replace( this.removeAltClassRe, '$1').clean();
        if (index % 2) {
          row.row.addClass( 'alt' ); 
          if (row.detail) row.detail.addClass( 'alt' );
        }
      }
      index++;
    }
   this.tbody.inject(before, 'after');
  },

  load_conversions: function() {
    this.conversions = ([
      // 1.75 MB, 301 GB, 34 KB, 8 TB
      { matcher: /([0-9.]{1,8}).*([KMGT]{1})B/,
        conversion_function: function( row ) {
          var cell = document.id(row.row.getElementsByTagName('td')[this.sort_column]).get('text');
          cell = this.conversion_matcher.exec( cell );
          if (!cell) { return '0' }
          if (cell[2] == 'M') {
            sort_val = '1';
          } else if (cell[2] == 'G') {
            sort_val = '2';
          } else if (cell[2] == 'T') {
            sort_val = '3';
          } else {
            sort_val = '0';
          }
          var i = cell[1].indexOf('.')
          if (i == -1) {
            post = '00'
          } else {
            var dec = cell[1].split('.');
            cell[1] = dec[0];
            post = dec[1].concat('00'.substr(0,2-dec[1].length));
          }
          return sort_val.concat('00000000'.substr(0,2-cell[1].length).concat(cell[1])).concat(post);
        }
      },
      // 1 day ago, 4 days ago, 38 years ago, 1 month ago
      { matcher: /(\d{1,2}) (.{3,6}) ago/,
        conversion_function: function( row ) {
          var cell = document.id(row.row.getElementsByTagName('td')[this.sort_column]).get('text');
          cell = this.conversion_matcher.exec( cell );
          if (!cell) { return '0' }
          var sort_val;
          if (cell[2].indexOf('month') != -1) {
            sort_val = '1';
          } else if (cell[2].indexOf('year') != -1) {
            sort_val = '2';
          } else {
            sort_val = '0';
          }
          return sort_val.concat('00'.substr(0,2-cell[1].length).concat(cell[1]));
        }
      },
      // Currency
      { matcher: /((\d{1}\.\d{2}|\d{2}\.\d{2}|\d{3}\.\d{2}|\d{4}\.\d{2}|\d{5}\.\d{2}|\d{6}\.\d{2}))/,
        conversion_function: function( row ) {
          var cell = document.id(row.row.getElementsByTagName('td')[this.sort_column]).get('text');
          cell = cell.replace(/[^\d]/g, "");
          return '00000000000000000000000000000000'.substr(0,32-cell.length).concat(cell);
        }
      },
      // YYYY-MM-DD, YYYY-m-d
      { matcher: /(\d{4})-(\d{1,2})-(\d{1,2})/,
        conversion_function: function( row ) {
          var cell = document.id(row.row.getElementsByTagName('td')[this.sort_column]).get('text');
          cell = this.conversion_matcher.exec( cell );
          return cell[1]+
                 '00'.substr(0,2-cell[2].length).concat(cell[2])+
                 '00'.substr(0,2-cell[3].length).concat(cell[3]);
        }
      },
      // Numbers
      { matcher: /^\d+$/,
        conversion_function: function( row ) {
          var cell = document.id(row.row.getElementsByTagName('td')[this.sort_column]).get('text');
          return '00000000000000000000000000000000'.substr(0,32-cell.length).concat(cell);
        }
      },
      // Fallback 
      { matcher: /.*/,
        conversion_function: function( row ) {
          return document.id(row.row.getElementsByTagName('td')[this.sort_column]).get('text');
        }
      }
    ]);
  }

});

SortingTable.removeAltClassRe = new RegExp('(^|\\s)alt(?:\\s|$)');
SortingTable.implement({ removeAltClassRe: SortingTable.removeAltClassRe });

SortingTable.stripe_table = function ( tr_elements  ) {
  var counter = 0;
  tr_elements.each( function( tr ) {
    if ( !tr.hasClass('collapsed') ) counter++;
    tr.className = tr.className.replace( this.removeAltClassRe, '$1').clean();
    if (counter % 2) tr.addClass( 'alt' );
  });
}

var PaginatingTable = new Class({

  Implements: Options,
  
  options: {
    per_page: 10,
    current_page: 1,
    offset_el: false,
    cutoff_el: false,
    details: false
  },
  
  initialize: function( table, ids, options ) {
    this.table = document.id(table);
    alert(table);
    this.setOptions(options);
    
    this.tbody = this.table.getElement('tbody');
    
    if (this.options.offset_el)
      this.options.offset_el = document.id(this.options.offset_el);
    if (this.options.cutoff_el)
      this.options.cutoff_el = document.id(this.options.cutoff_el);

    this.paginators = (typeof(ids) == 'array') ? ids.map($) : [document.id(ids)];

    if (this.options.details) {
      this.options.per_page = this.options.per_page * 2
    }

    this.update_pages();
  },

  update_pages: function(){
    this.pages = Math.ceil( this.tbody.getChildren().length / this.options.per_page );
    this.create_pagination();
    this.to_page( 1 );
  },

  to_page: function( page_num ) {
    page_num = page_num.toInt();
    if (page_num > this.pages || page_num < 1) return;
    this.current_page = page_num;
    this.low_limit  = this.options.per_page * ( this.current_page - 1 );
    this.high_limit = this.options.per_page * this.current_page;
    var trs = this.tbody.getChildren();
    if (trs.length < this.high_limit) this.high_limit = trs.length;
    for (var i = 0, j = trs.length; i < j; i++) {
      trs[i].style.display = (this.low_limit  <= i && this.high_limit > i) ? '' : 'none';
    }
    this.paginators.each(function(paginator){
      var as = paginator.getElements('a').removeClass('currentPage');
      as[this.current_page].addClass('currentPage');
    }, this);
    if (this.options.offset_el)
      this.options.offset_el.set('text', Math.ceil( this.low_limit / ( this.options.details ? 2 : 1 ) + 1 ) );
    if (this.options.cutoff_el)
      this.options.cutoff_el.set('text', ( this.high_limit / ( this.options.details ? 2 : 1 ) ) );
  },

  to_next_page: function() {
    this.to_page( this.current_page + 1 );
  },

  to_prev_page: function() {
    this.to_page( this.current_page - 1 );
  },

  create_pagination: function() {
    this.paginators.each(function(paginator){
      paginator.empty();
      this.create_pagination_node( '&#171;', function(evt){
        var evt = new Event( evt );
        this.to_prev_page();
        evt.stop();
        return false;
      }).injectInside( paginator );
      for (var page=1; page <= this.pages; page++){
        this.create_pagination_node( page, function(evt){
          var evt = new Event( evt );
          this.to_page( evt.target.get( 'text' ) );
          evt.stop();
          return false;
        }).injectInside( paginator );  
      }
      this.create_pagination_node( '&#187;', function(evt){
        var evt = new Event( evt );
        this.to_next_page();
        evt.stop();
        return false;
      }).injectInside( paginator );
    }.bind( this ));
  },

  create_pagination_node: function( text, evt ) {
    var span = new Element( 'span' ).set( 'html', text );
    if (text == '&#171;'){
      var a = new Element( 'a', { 'href': '#', 'class': 'previous-page' }).addEvent( 'click', evt.bind( this ) );
    } else if (text == '&#187;'){
      var a = new Element( 'a', { 'href': '#', 'class': 'next-page' }).addEvent( 'click', evt.bind( this ) );
    } else {
      var a = new Element( 'a', { 'href': '#'}).addEvent( 'click', evt.bind( this ) );
    }
    var li   = new Element( 'li' );
    span.injectInside( a.injectInside( li ) );
    return li;
  }

});
