(function() {

  // applegate.datatable ======================================================

  YAHOO.namespace("applegate.datatable");

  var applegate = YAHOO.applegate,
      global = YAHOO.applegate.global;

  // DwrDataSource ============================================================

  /**
   * DwrDataSource class.
   * Use to back YAHOO DataTable widgets with data from a Dwr Object.
   * @param method ServiceBean.methodName - note no
   * @param args
   * @param fields
   */
  applegate.datatable.DwrDataSource = function(method, args, fields) {
    applegate.datatable.DwrDataSource.superclass.constructor.call(this);
    // forces the parseArrayData to be called in handleResponse
    this.responseType = YAHOO.util.DataSource.TYPE_JSARRAY;

    this._dwrMethod = method;
    this._dwrArgs = args;
    this.responseSchema = {fields:fields};

    this.createEvent("dwrArgumentsChangedEvent");
  };
  YAHOO.lang.extend(applegate.datatable.DwrDataSource, YAHOO.util.DataSourceBase, {

  /* override  makeConnection in YAHOO.util.DataSource */
  makeConnection : function(oRequest, oCallback, oCaller) {
    YAHOO.log("DwrDataSource.makeConnection request:" + oRequest + " oCallback:" + oCallback + " oCaller:" + oCaller);
    // from the super.makeConnection()
    this.fireEvent("requestEvent", {request:oRequest,callback:oCallback,caller:oCaller});
    var tId = YAHOO.util.DataSource._nTransactionId++;

    // copy the args... and add the last parameter as the dwr options block
    var args = global.copyArray(this._dwrArgs);
    var thisDataSource = this;
    args.push({
      callback:function(response) {
        thisDataSource.handleResponse(oRequest, response, oCallback, oCaller, tId);
      }
    });
    // run the request, for a description of apply():
    // see http://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Function/apply)
    this._dwrMethod.apply(this, args);
  },

  /**
   * Changes the underlying dataSource argument(s)
   */
  setDwrArguments : function() {
    this._dwrArgs = global.copyArray(arguments);
    this.fireEvent("dwrArgumentsChangedEvent", {source:this,arguments:this._dwrArgs});
    return this;
  }
  });
  // ~DwrDataSource ===========================================================

  // DataTable ================================================================

  /**
   * Applegate extention of the YAHOO.widget.DataTable.
   * Provides basic default behaviour plus some integration with the
   * DwrDataSource object from the applegate.global name space.
   *
   * @param elContainer {HTMLElement} Container element for the TABLE.
   * @param aColumnDefs {Object[]} Array of object literal Column definitions.
   * @param oDataSource {YAHOO.util.DataSource} DataSource instance.
   * @param oConfigs {object} (optional) Object literal of configuration values.
   */
  applegate.datatable.DataTable = function(elContainer, aColumnDefs, oDataSource, oConfigs) {
    YAHOO.log('Creating DataTable', 'debug', 'global-datatable.js');

    // apply applegate defaults
    var configs = YAHOO.lang.merge({
      scrollable:true,
      draggableColumns:true
      /* renderLoopSize:30 yuibug #2287294: means that setting renderLoopSize
                                            will cause an error in IE when the result set is empty */  
    }, oConfigs);
    applegate.datatable.DataTable.superclass.constructor.call(this, elContainer, aColumnDefs, oDataSource, configs);

    YAHOO.log('Subscribing DataTable to events', 'debug', 'global-datatable.js');
    if (oDataSource.hasEvent("dwrArgumentsChangedEvent")) {
      oDataSource.subscribe("dwrArgumentsChangedEvent", this.reloadAll, this, true);
    }
    // default behaviour
    // Enables single-mode row selection
    //    this.set("selectionMode","single");
    this.subscribe("rowClickEvent", this.onEventSelectRow);
    // enables row highlighting
    this.subscribe("rowMouseoverEvent", this.onEventHighlightRow);
    this.subscribe("rowMouseoutEvent", this.onEventUnhighlightRow);

    YAHOO.log('DataTable configuration complete', 'debug', 'global-datatable.js');

  };

  YAHOO.lang.extend(applegate.datatable.DataTable, YAHOO.widget.ScrollingDataTable, {

    /**
     * Force this DataTable to ask the datasource to reload everything.
     */
    reloadAll : function() {
      YAHOO.log('Reloading DataTable', 'debug', 'global-datatable.js');
      // clear backing store..
      this.getRecordSet().reset();
      this.showTableMessage(this.get("MSG_LOADING"), YAHOO.widget.DataTable.CLASS_LOADING);
      // Send a simple initialLoad request copied from the DataSource constructor
      var oCallback = {
        success : this.onDataReturnSetRows,
        failure : this.onDataReturnSetRows,
        scope   : this,
        argument: {}
      };
      this._oDataSource.sendRequest(this.get("initialRequest"), oCallback);
    },

    /**
     * Override of DataTable onShow and should be invoked after making a table visible.
     */
    onShow : function() {
      applegate.datatable.DataTable.superclass.onShow.call(this);

      // reset the heights of all the resize widgets that exist.
      // this is done because they will be wrong if the table was contructed in a hidden
      // div
      var columns = this.getColumnSet().flat ;
      for( var i in columns){
        if(columns[i]._ddResizer){
          columns[i]._ddResizer.resetResizerEl();
        }
      }
    }

  });

  // ~DataTable ===============================================================

  // PagableDataTable =========================================================
  applegate.datatable.PageableDataTable = function(elContainer, aColumnDefs, oDataSource, oConfigs) {
    // apply applegate defaults
    var configs = YAHOO.lang.merge({
      dynamicData:true,
      // standard paginator settings
      paginator : new YAHOO.widget.Paginator({
          rowsPerPage    : 25,
          template : "{PreviousPageLink} <strong>{CurrentPageReport}</strong> {NextPageLink} {RowsPerPageDropdown}",
          rowsPerPageOptions : [25,50,100]
      }),
      /**
       * Over for the generate request to convert the YUI DT oState object into a PagingParameter object.
       */
      generateRequest:function(oState, oSelf){
        oState = oState || {pagination:null, sortedBy:null};

        var sort = (oState.sortedBy) ? oState.sortedBy.key : oSelf.getColumnSet().keys[0].getKey();
        var dir = (oState.sortedBy && oState.sortedBy.dir === YAHOO.widget.DataTable.CLASS_DESC) ? "DESCENDING" : "ASCENDING";
        var startIndex = (oState.pagination) ? oState.pagination.recordOffset : 0;
        var itemsPerPage = (oState.pagination) ? oState.pagination.rowsPerPage : null;

        // Build the request
        return  {
          sortProperty:sort,
          sortDirection:dir,
          page: (itemsPerPage !== null ? (startIndex / itemsPerPage) + 1 : 1),
          itemsPerPage: itemsPerPage // will be null if no paging
        };
      },
      initialLoad:false // don't attempt to auto load a PageableDataTable as it'll all go wrong.
    }, oConfigs);

    applegate.datatable.PageableDataTable.superclass.constructor.call(this, elContainer, aColumnDefs, oDataSource, configs);
  };

  YAHOO.lang.extend(applegate.datatable.PageableDataTable, applegate.datatable.DataTable, {

    /**
     * Force this DataTable to ask the datasource to reload everything.
     */
    reloadAll : function() {
      // clear backing store..
      this.getRecordSet().reset();
      this.showTableMessage(this.get("MSG_LOADING"), YAHOO.widget.DataTable.CLASS_LOADING);
      // Send a simple initialLoad request copied from the DataSource constructor
      var oState = this.getState();

      var oCallback = {
        success : this.onDataReturnSetRows,
        failure : this.onDataReturnSetRows,
        scope   : this,
        argument: oState
      };

      var request = this.get("generateRequest")(oState, this);
      this._oDataSource.sendRequest(request, oCallback);
    },
    handleDataReturnPayload :function(oRequest, oResponse, oPayload) {
      oPayload.totalRecords = oResponse.meta.maxNumberOfItems;
      return oPayload;
    }
  });

  // ~PageableDataTable =======================================================

  // package level methods

  // cell formater in UK style DD/MM/YYYY
  //noinspection JSUnusedLocalSymbols
  applegate.datatable.formatDate = function(el, oRecord, oColumn, oData) {
    if(oData != 'Invalid Date' && !isNaN(oData)) {
      el.innerHTML = YAHOO.util.Date.format(oData, {format:"DD/MM/YYYY"});
    } else {
      el.innerHTML = '';
    }
  };

  /**
   * package function to 'fix' the width of a single DataTable column to take up the
   * remaining space.
   * @param key name of column to adjust
   * @param tableWidth required with of table
   * @param columns column definitions
   */
  applegate.datatable.calculateColumnWidth = function(key, tableWidth, columns) {
    // basically there is 20px extra on top of the width specified here mimus 25 for good luck
    var numberOfColumns = columns.length;
    var columnToChange;
    var totalWidthOtherColumns = 0;

    for (var i = 0; i < columns.length; i++) {
      if (columns[i].key == key) {
        columnToChange = columns[i];
      } else {
        totalWidthOtherColumns = totalWidthOtherColumns + columns[i].width;
      }
    }
    columnToChange.width = tableWidth - totalWidthOtherColumns - (numberOfColumns * 20) - 25;
  };
  // for backwards compat after spelling correction
  applegate.datatable.calulateColumnWidth = applegate.datatable.calculateColumnWidth ;
  // ~applegate.datatable =====================================================
})();