//
// new PaginatingTable( 'my_table', 'ul_for_paginating', {
//   per_page: 10,     // How many rows per page?
//   current_page: 1,  // What page to start on when initialized
//   offset_el: false, // What dom element to stick the offset in
//   cutoff_el: false, // What dom element to stick the cutoff in
//   details: false    // Do we have hidden/collapsable rows?
// });
//
// The above were the defaults.  You could also pass an array of paginators
// instead of just one.
//
// Requires mootools Class, Array, Function, Element, Element.Selectors,
// Element.Event, and you should probably get Window.DomReady if you're smart.
//

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 = table;
    this.table = $(table);
    this.setOptions(options);

    this.tbody = this.table.getElement('tbody');

    if (this.options.offset_el)
      this.options.offset_el = $(this.options.offset_el);
    if (this.options.cutoff_el)
      this.options.cutoff_el = $(this.options.cutoff_el);

    this.paginators = ($type(ids) == 'array') ? ids.map($) : [$(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';
      if ((this.low_limit  <= i && this.high_limit > i)) {
        if ($(trs[i]).hasClass('is_collapsed')) {
            trs[i].style.display = 'none';
        } else {
            trs[i].style.display = '';
        }
      } else {
        trs[i].style.display = 'none';
      }
      //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;
  }

});




//
// new SortingTable( 'my_table', {
//   zebra: true,                        // Stripe the table, also on initialize
//   details: false,                     // Has details every other row
//   paginator: false,                   // Pass a paginator object
//   dont_sort_class: 'nosort',          // Class name on th's that don't sort
//   forward_sort_class: 'forward_sort', // Class applied to forward sort th's
//   reverse_sort_class: 'reverse_sort'  // Class applied to reverse sort th's
// });
//
// The above were the defaults.  The regexes in load_conversions test a cell
// begin sorted for a match, then use that conversion for all elements on that
// column.
//
// Requires mootools Class, Array, Function, Element, Element.Selectors,
// Element.Event, and you should probably get Window.DomReady if you're smart.
//

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 = $(table);
    //this.table = table;

    this.setOptions(options);

    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 )) { return }
      header.store( 'column', index )
      header.addEvent( 'mousedown', function(evt){
        this.sort_by_header( evt.target );
        if ( this.options.paginator) this.options.paginator.to_page( 1 );
      }.bind( this ) );
    }, this);

    this.load_conversions();
  },

  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') ) {
      // They were pulled off in reverse
      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 = $(row.row.getElementsByTagName('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 = $A([
      // 1.75 MB, 301 GB, 34 KB, 8 TB
      { matcher: /([0-9.]{1,8}).*([KMGT]{1})B/,
        conversion_function: function( row ) {
          var cell = $(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 = $(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 = $(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 = $(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 = $(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 $(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' );
  });
}


window.addEvent('domready', function() {

    // Auto-Style all .grid tables

    var aGrids = $(document.body).getElements('table.grid');
    $each(aGrids, function(e, idx){
        gridId = e.get('id');
        paginatorId = 'paginator_' + gridId;
        // Look for paginator
        if ($(paginatorId)) {
            paginator = new PaginatingTable(
                gridId,
                paginatorId, {
                    details: true,
                    per_page: 10
                }
            );
        } else {
            paginator = false;
        }

        eSortTable = new SortingTable(e.get('id'), {
            zebra: true,                        // Stripe the table, also on initialize
            details: true,                      // Has details every other row
            paginator: paginator,               // Pass paginator instance
            dont_sort_class: 'nosort',          // Class name on th's that don't sort
            forward_sort_class: 'forward_sort', // Class applied to forward sort th's
            reverse_sort_class: 'reverse_sort'  // Class applied to reverse sort th's
        });//.sort_by_header(e.getElement('th'));

        // Automatically sort on first column
        if (eSortTable) {
            eSortTable.sort_by_header(eSortTable.headers[0]);
            if (eSortTable.options.paginator) eSortTable.options.paginator.to_page(1);
        }

    });

    // Handle visibility togglers

    var aTogglers = $(document.body).getElements('a.toggler');

    $each(aTogglers, function(e, idx){
        eTarget = $(e.get('href').split('#').getLast());
        if (eTarget) {
            e.store('target', eTarget);
            e.addEvent('click', function(event){
                if (event) {
                    event.stop();
                }
                eTarget = e.retrieve('target');
                if (eTarget.getStyle('display') != 'none') {
                    eTarget.setStyle('display', 'none');
                    e.set('html', 'View&nbsp;&rarr;');
                    eTarget.addClass('is_collapsed');
                } else {
                    if ((eTarget.get('tag') == 'tr') && (!Browser.Engine.trident)) {
                        eTarget.setStyle('display', 'table-row');
                    } else {
                        eTarget.setStyle('display', 'block');
                    }
                    e.set('html', '&larr;&nbsp;Hide');
                    eTarget.removeClass('is_collapsed');
                }

            });
            eTarget.setStyle('display', 'none');
            eTarget.addClass('is_collapsed');
        }
    });

});
