/**
* A whole grid page controller.
* Uses 'globals' object!
*/
function GridController(mediator, dataTableContainer, paginatorContainers, gridsMenu, instrumentSelector, unitTesting) {
    this.mediator = mediator;
    this.dataTableContainer = dataTableContainer;
    this.paginatorContainers = paginatorContainers;
    this.gridsMenu = gridsMenu;
    this.instrumentSelector = instrumentSelector;

    this.unitTesting = unitTesting || false;

    this.getDataUrl = globals.siteUrl + '?rm=ajax_get_data&';
    this.currentFiltersRowClassName = 'currentFiltersRow';
    this.currentFiltersTextClassName = 'currentFilterText';
    this.inputFiltersClassName = 'inputFiltersRow';
    this.filterInputBoxTDClassName = 'filterInputBoxTd';
    this.filterInputBoxClassName = 'filterInputBox';
    this.FILTERS_BODY_ID = "id_filtersBody";
    this.FILTERS_ROW_ID = "id_filtersRow";
    this.fillNewColumnsInDialog = true;
    this.nameOfGrid = '';
    this.searchFunction = null;
    this.getGridFunction = null;

    this.createFilterInputDivId = function(key) {
        return "id_filterInputDiv_" + key;
    },
    this.createFilterInputId = function(key) {
        return "id_filterInput_" + key;
    },


    /**
    * Creates a grid from its JSON description object 
    *
    * @method createGridAjax 
    * @param jsonGridDescriptionObject {columnDefs : [{key:"systemName",className:"grid_column",resizeable:true,sortable:true,label:"System"},{key:"graph",className:"grid_column",label:"Graph",formatter:graphImgFormatter},{key:"riskImg",className:"grid_column",sortable:true,label:"Hidden Risk",formatter:riskImgFormatter},{key:"popularityImg",className:"grid_column",sortable:true,sortOptions:{defaultDir:YAHOO.widget.DataTable.CLASS_DESC},label:"Popularity",formatter:popularityImgFormatter}],schema: { resultsList: "data", fields : ["systemName","graph","riskImg","popularityImg"]},sortedBy : {key:"popularityImg", dir:YAHOO.widget.DataTable.CLASS_DESC}}*
    */
     this.createGridAjax = function(aJsonGridDescriptionObject) {
         var jsonGridDescriptionObject = aJsonGridDescriptionObject.gridDescr;
         this.setColumnsDef(jsonGridDescriptionObject.columnDefs);
         this.setResponseSchema(jsonGridDescriptionObject.schema);
         this.setInitialySortedBy(jsonGridDescriptionObject.sortedBy);
         this.instrumentSelector.setStates(jsonGridDescriptionObject.instruments);
         this.createDataTable(!YAHOO.lang.isObject(aJsonGridDescriptionObject.data));
         this.setfillNewColumnsInDialog(true);
         if (aJsonGridDescriptionObject.data) {
        	 this.newData(aJsonGridDescriptionObject.data);
             this.mediator.setPageState(aJsonGridDescriptionObject);
         }
     },


    this.createGridFromStateAjax = function(pageState) {
        this.createGridAjax(pageState);
        this.mediator.setPageState(pageState);
        //this.newData(pageState.data);
    },

    /**
    * 
    * What properties we need for creating a whole grid: 
    * - columnsDef
    * - responseSchema
    * - initialySortedBy
    * - (data)
    *
    * - table container
    * - paginator container(s)
    *
    * @method createDataTable
    */
    this.createDataTable = function(readData) {

        var dataSource;
        if (this.unitTesting) {
            var c2Data = this.unitTestingData();
            dataSource = new YAHOO.util.DataSource(c2Data.systems_data);
            dataSource.responseType = YAHOO.util.DataSource.TYPE_JSARRAY;
            dataSource.responseSchema = this.getResponseSchema();
        }
        else {
            if (readData) {
                dataSource = new YAHOO.util.ScriptNodeDataSource(globals.getDataUrl());
            }
            else {
                dataSource = new YAHOO.util.ScriptNodeDataSource(globals.getNullUrl());
            }
            dataSource.scriptCallbackParam = "callback";
            dataSource.responseSchema = this.getResponseSchema();
        }
        //dataSource.maxCacheEntries = 0;
        this.dataSource = dataSource;

        var columnsDef = this.getColumnsDef();
        var initialySortedBy = this.getInitialySortedBy();  // sortedBy : {key:"popularity", dir:YAHOO.widget.DataTable.CLASS_DESC}  // sortedBy is an initial order provided by SERVER!

        var gridPaginator = this.createPaginator();

        var dataTableConfig =
            {
                //caption: "The Grid",
                paginator: gridPaginator,
                draggableColumns: true,
                sortedBy: initialySortedBy,
                numberOptions: { decimalPlaces: 2 }, //default for table 
                owner: this // a key for success :-)
            };

        this.dataTable = new YAHOO.widget.DataTable(this.dataTableContainer, columnsDef, dataSource, dataTableConfig);

        // Subscribe to ColumnReoder event to reoder our data
        this.dataTable.on('columnReorderEvent', this.columnReorderEvent);

        this.dataTable.on("rowClickEvent", function(oArgs) {
            var elTarget = oArgs.target;
            var oRecord = this.getRecord(elTarget);
            var systemId = oRecord.getData("graph");

	    // if gMouseDownDate is set, there is a drag-n-drop happening 
	    if (!gMouseDownDate)
	    {
            	window.location = globals.systemsUrl + '?want=p&systemid=' + systemId;
	    }
        });

        // Enable row highlighting
        this.dataTable.on("rowMouseoverEvent", this.dataTable.onEventHighlightRow);
        this.dataTable.on("rowMouseoutEvent", this.dataTable.onEventUnhighlightRow);

        // Add our data for current columns
        this.addFiltersRow(this.dataTable.getColumnSet().headers);

        // Custom sort is signalised on button
        // Eliminate this for default initial sorting 
        this.sortingForTheFirstTime = true;
        this.dataTable.on("columnSortEvent", this.columnSortEvent, this, true);

        return this.dataTable;
    },

    this.columnSortEvent = function() {
        if (this.sortingForTheFirstTime) {
            this.sortingForTheFirstTime = false;
        }
        else {
            this.mediator.widgetChanged(globals.SORT_GRID, this);
            this.saveState();
        }
    },

    /**
    * 
    * Returns inner dataTable
    *
    * @method getDataTable
    */
    this.getDataTable = function() {
        return this.dataTable;
    },

    /**
    * 
    * Unit testing data
    *
    * @method unitTestingData
    */
    this.unitTestingData = function() {
        var c2Data = { systems_data: [
{ guid: 40131652, systemName: "play bank stock options", numtrades: 36, tradefreq: 21879900.000000, avgTradeLength: "1.0 weeks", sharpe: 2.521, annReturn: 1822.3, last30Days: -33.0, last60Days: 0.0, last90Days: 0.0, instrument: "Options", hiddenRisk: 88.699003, popular1440: 8557, ageDays: 93.900000, profitFactor: 1.1, avgPipsLong: 0.00, avgPipsShort: 0.00, avgPips: 0.00, cumuPipsLong: 0, cumuPipsShort: 0, cumuPips: 0, apd: 0.09, maxdrawdownPcnt: 84.4, realism: 56.2, graph: 'http:\/\/preview.collective2.com\/cgi-perl\/dashcharts.mpl?notext=1&amp;sid=40131652&amp;width=55&amp;height=35', popularityImg: 'http:\/\/preview.collective2.com\/cgi-perl\/xcharts200.mpl?want=horiz&percent=0.99&width=80&systemid=$sid&pictype=gc', riskImg: 'http:\/\/preview.collective2.com\/cgi-perl\/xcharts200.mpl?want=horiz&percent=0.74&width=60&systemid=40131652&pictype=rs' },
{ guid: 36590219, systemName: "The Smarter Option", numtrades: 25, tradefreq: 98518500.000000, avgTradeLength: "6.5 weeks", sharpe: 2.678, annReturn: 487.9, last30Days: -11.1, last60Days: 17.6, last90Days: 59.2, instrument: "Options", hiddenRisk: 56.409000, popular1440: 8550, ageDays: 254.900000, profitFactor: 7.3, avgPipsLong: 0.00, avgPipsShort: 0.00, avgPips: 0.00, cumuPipsLong: 0, cumuPipsShort: 0, cumuPips: 0, apd: 0.71, maxdrawdownPcnt: 47.4, realism: 72.9, graph: 'http:\/\/preview.collective2.com\/cgi-perl\/dashcharts.mpl?notext=1&amp;sid=36590219&amp;width=55&amp;height=35', popularityImg: 'http:\/\/preview.collective2.com\/cgi-perl\/xcharts200.mpl?want=horiz&percent=0.99&width=80&systemid=$sid&pictype=gc', riskImg: 'http:\/\/preview.collective2.com\/cgi-perl\/xcharts200.mpl?want=horiz&percent=0.47&width=60&systemid=36590219&pictype=rs' },
{ guid: 36624687, systemName: "Shorting Options", numtrades: 17, tradefreq: 55250500.000000, avgTradeLength: "5.4 weeks", sharpe: 2.549, annReturn: 59.3, last30Days: 3.8, last60Days: 15.6, last90Days: 20.2, instrument: "Options", hiddenRisk: 1.770000, popular1440: 8528, ageDays: 254.000000, profitFactor: -1.0, avgPipsLong: 0.00, avgPipsShort: 0.00, avgPips: 0.00, cumuPipsLong: 0, cumuPipsShort: 0, cumuPips: 0, apd: 0.91, maxdrawdownPcnt: 16.1, realism: 96.3, graph: 'http:\/\/preview.collective2.com\/cgi-perl\/dashcharts.mpl?notext=1&amp;sid=36624687&amp;width=55&amp;height=35', popularityImg: 'http:\/\/preview.collective2.com\/cgi-perl\/xcharts200.mpl?want=horiz&percent=0.99&width=80&systemid=$sid&pictype=gc', riskImg: 'http:\/\/preview.collective2.com\/cgi-perl\/xcharts200.mpl?want=horiz&percent=0.01&width=60&systemid=36624687&pictype=rs' },
{ guid: 31466326, systemName: "Bachata", numtrades: 51, tradefreq: 63848000.000000, avgTradeLength: "2.1 weeks", sharpe: 0.697, annReturn: 294.5, last30Days: 0.0, last60Days: -0.1, last90Days: -27.5, instrument: "Options", hiddenRisk: 130.885004, popular1440: 5662, ageDays: 478.000000, profitFactor: 1.3, avgPipsLong: 0.00, avgPipsShort: 0.00, avgPips: 0.00, cumuPipsLong: 0, cumuPipsShort: 0, cumuPips: 0, apd: 0.20, maxdrawdownPcnt: 91.9, realism: 51.0, graph: 'http:\/\/preview.collective2.com\/cgi-perl\/dashcharts.mpl?notext=1&amp;sid=31466326&amp;width=55&amp;height=35', popularityImg: 'http:\/\/preview.collective2.com\/cgi-perl\/xcharts200.mpl?want=horiz&percent=0.66&width=80&systemid=$sid&pictype=gc', riskImg: 'http:\/\/preview.collective2.com\/cgi-perl\/xcharts200.mpl?want=horiz&percent=1&width=60&systemid=31466326&pictype=rs'}]
        };
        return c2Data;
    },

    /**
    * 
    * If this.responseSchema is set, returns it. If not, returns a default schema.
    *
    * @method getResponseSchema 
    */
    this.getResponseSchema = function() {
        if (YAHOO.lang.isObject(this.responseSchema)) {
            return this.responseSchema;
        }
        else {
            //return '{ fields: ["systemName", "profitFactor", "graph", "riskImg", "popularityImg", "sharpe"] }';
            var defaultResponseSchema = {
                resultsList: "data",
                fields: ["graph", "systemName", "ageDays", "numtrades", "avgTradeLength", "profitFactor", "sharpe", "annReturn", "last90Days", "last60Days", "last30Days", "instrument", "apd", "maxdrawdownPcnt", "realism", "riskImg", "popularityImg"]
            };
            return defaultResponseSchema;
        }
    },

    this.setResponseSchema = function(value) {
        this.responseSchema = value;
    },


    this.unitTestsColumnsDef =
    [{ gridData: { type: "string", canHaveFilter: false }, key: "systemName", className: "grid_column", resizeable: true, sortable: true, label: "System" },
        { gridData: { type: "number", canHaveFilter: true, filterRelation: ">=", filterValue: "1.1" }, key: "profitFactor", className: "grid_number", resizeable: true, sortable: true, formatter: myFormatNumber, label: "Profit Factor", numberOptions: { decimalPlaces: 1} },
        { gridData: { type: "number", canHaveFilter: true, filterRelation: ">=", filterValue: "2.5" }, key: "sharpe", className: "grid_number", resizeable: true, sortable: true, formatter: myFormatNumber, label: "Sharpe", numberOptions: { decimalPlaces: 2} },
        { gridData: { type: "string", canHaveFilter: false }, key: "riskImg", className: "grid_column", sortable: true, label: "Hidden Risk", formatter: riskImgFormatter },
        { gridData: { type: "string", canHaveFilter: false }, key: "popularityImg", className: "grid_column", sortable: true, sortOptions: { defaultDir: YAHOO.widget.DataTable.CLASS_DESC }, label: "Popularity", formatter: popularityImgFormatter }
        ];

    this.defaultColumnDefs =
        [
        { gridData: { type: "string", canHaveFilter: false }, key: "graph", className: "grid_column", label: "Graph", formatter: graphImgFormatter },
        { gridData: { type: "string", canHaveFilter: true }, key: "systemName", className: "grid_column", resizeable: true, sortable: true, label: "System" },
        { gridData: { type: "number", canHaveFilter: true }, key: "ageDays", className: "grid_number", resizeable: true, sortable: true, formatter: myFormatNumber, label: "Age" },
        { gridData: { type: "number", canHaveFilter: true }, key: "numtrades", className: "grid_number", resizeable: true, sortable: true, formatter: myFormatNumber, label: "# Trades" },
        { gridData: { type: "string", canHaveFilter: false }, key: "avgTradeLength", className: "grid_column", resizeable: true, label: "Avg Trade Length" },
        { gridData: { type: "number", canHaveFilter: true }, key: "profitFactor", className: "grid_number", resizeable: true, sortable: true, formatter: myFormatNumber, label: "Profit Factor", numberOptions: { decimalPlaces: 1} },
        { gridData: { type: "number", canHaveFilter: true }, key: "sharpe", className: "grid_number", resizeable: true, sortable: true, formatter: myFormatNumber, label: "Sharpe" },
        { gridData: { type: "number", canHaveFilter: true }, key: "annReturn", className: "grid_number", resizeable: true, sortable: true, formatter: myFormatNumber, label: "Ann Return" },
        { gridData: { type: "number", canHaveFilter: true }, key: "last90Days", className: "grid_number", resizeable: true, sortable: true, formatter: myFormatNumber, label: "Last 90 Days" },
        { gridData: { type: "number", canHaveFilter: true }, key: "last60Days", className: "grid_number", resizeable: true, sortable: true, formatter: myFormatNumber, label: "Last 60 Days" },
        { gridData: { type: "number", canHaveFilter: true }, key: "last30Days", className: "grid_number", resizeable: true, sortable: true, formatter: myFormatNumber, label: "Last 30 Days" },
        { gridData: { type: "string", canHaveFilter: false }, key: "instrument", className: "grid_column", resizeable: true, sortable: true, label: "Trades" },
        { gridData: { type: "number", canHaveFilter: true }, key: "apd", className: "grid_number", resizeable: true, sortable: true, formatter: myFormatNumber, label: "APD" },
        { gridData: { type: "number", canHaveFilter: true }, key: "maxdrawdownPcnt", className: "grid_number", resizeable: true, sortable: true, formatter: myFormatNumber, label: "Max Drawdown" },
        { gridData: { type: "number", canHaveFilter: true }, key: "realism", className: "grid_number", resizeable: true, sortable: true, formatter: myFormatNumber, label: "Realism Factor" },
        { gridData: { type: "string", canHaveFilter: false }, key: "riskImg", className: "grid_column", sortable: true, label: "Hidden Risk", formatter: riskImgFormatter },
        { gridData: { type: "string", canHaveFilter: false }, key: "popularityImg", className: "grid_column", sortable: true, sortOptions: { defaultDir: YAHOO.widget.DataTable.CLASS_DESC }, label: "Popularity", formatter: popularityImgFormatter }
        ];

    /**
    * 
    * If this.columnsDefs set, returns it. If not, returns a default columnsDef.
    *
    * @method getColumnsDef
    */
        this.getColumnsDef = function() {
            if (this.unitTesting) {
                return this.unitTestsColumnsDef;
            }
            else {
                if (YAHOO.lang.isObject(this.columnsDef)) {
                    return this.columnsDef;
                }
                else {
                    return this.defaultColumnDefs;
                }
            }
        },


        /**
        * 
        * ColumnsDef setter
        *
        * @method setColumnsDef
        */
    this.setColumnsDef = function(value) {
        this.columnsDef = value;
    },


        /**
        * 
        * Creates a paginator
        *
        * @method createPaginator
        */
    this.createPaginator = function() {
        var gridPaginator = new YAHOO.widget.Paginator({
            containers: this.paginatorContainers,
            template: "{CurrentPageReport}&nbsp;&nbsp;{FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}",
            //              ,pageReportTemplate : "Showing {startRecord} - {endRecord} out of <b>{totalRecords}</b> systems that match criteria."
            pageReportTemplate: "<b>{totalRecords}</b> systems match criteria.",
            pageLinks: 5,
            rowsPerPage: 20,
            rowsPerPageOptions: [20, 50, 100], //, 'All'
            initialPage: 1,
            pageLabelBuilder: function(page, paginator) {
                var recs = paginator.getPageRecords(page);
                return (recs[0] + 1) + ' - ' + (recs[1] + 1);
            }
        });
        return gridPaginator;
    },

        /**
        * 
        * Info about initial sort from C2 server.
        * Initial sorting must be performed by server!
        *
        * @method getInitialySortedBy
        */
    this.getInitialySortedBy = function() {
        if (YAHOO.lang.isObject(this.initialySortedBy)) {
            return this.initialySortedBy;
        }
        else {
            return undefined;
        }

    },

        /**
        * 
        * Info about initial sort from C2 server.
        * Initial sorting must be performed by server!
        *
        * @method setInitialySortedBy
        */
    this.setInitialySortedBy = function(value) {
        // sortedBy : {key:"popularity", dir:YAHOO.widget.DataTable.CLASS_DESC}  // sortedBy is an initial order provided by SERVER!
        this.initialySortedBy = value;
    },

        /**
        * 
        * For given key returns ColumnDef Object 
        *
        * @method getColumnDef
        * @param string : aKey of column {string}
        */
    this.getColumnDef = function(key) {
        var columnsDef = this.dataTable.getColumnSet().getDefinitions();
        for (var i = 0; i < columnsDef.length; i++) {
            if (key === columnsDef[i].key) {
                return columnsDef[i];
            }
        }
        return null;
    },


     this.setFilter = function(aColumnDef, relation, value) {
         var columnDef = this.getColumnDef(aColumnDef.key);
         columnDef.gridData.filterRelation = relation;
         columnDef.gridData.filterValue = value;
     },


        /**
        * 
        * Inserts our rows to the table
        *
        * @method addFiltersRow
        * @param aHeadersList {array} The origin of aHeadersList is this.dataTable.getColumnSet().headers which returns String[]
        */
     this.addFiltersRow = function(aHeadersList) {
         //Shortcut
         var dom = YAHOO.util.Dom;

         // flat array values
         var headersList = [];
         for (var h = 0; h < aHeadersList.length; h++) {
             headersList.push(aHeadersList[h][0]);
         }
         // get DataTable's Message TBody element
         var messageTBodyHTMLElement = this.dataTable.getMsgTbodyEl();

         // append our TBody element
         var bodyElement = document.createElement('tbody');
         bodyElement.setAttribute("id", this.FILTERS_BODY_ID);

         //add TR for current filters
         //var showFiltersTrElement = document.createElement('tr');
         //dom.addClass(showFiltersTrElement, this.currentFiltersRowClassName);
         //bodyElement.appendChild(showFiltersTrElement);

         var columnsDef = this.getColumnsDef();

         /*
         // This is another line for filters above that row with input boxes. But it is a duplicity.
         // add TDs for read only filter texts
         for (var i = 0; i < headersList.length; i++) {
         var key = headersList[i];
         var column = this.dataTable.getColumn(key);
         var columnDef = this.getColumnDef(key);
         var value = '&nbsp;';
         if (YAHOO.lang.isObject(columnDef)
         && YAHOO.lang.isObject(columnDef.gridData)
         && YAHOO.lang.isString(columnDef.gridData.filterText)) {
         value = columnDef.gridData.filterText;
         }
         var tTdElement = document.createElement('td');
         tTdElement.setAttribute("id", this.createFilterTextId(key));
         tTdElement.innerHTML = value;
         dom.addClass(tTdElement, this.currentFiltersTextClassName);
         showFiltersTrElement.appendChild(tTdElement);
         }
         */
         //add TR for input boxes
         var inputFiltersTrElement = document.createElement('tr');
         inputFiltersTrElement.id = this.FILTERS_ROW_ID;
         dom.addClass(inputFiltersTrElement, this.inputFiltersClassName);
         bodyElement.appendChild(inputFiltersTrElement);

         // add TDs
         for (var i = 0; i < headersList.length; i++) {
             var key = headersList[i];
             var column = this.dataTable.getColumn(key);
             var columnDef = this.getColumnDef(key);

             var value = '';
             if (YAHOO.lang.isObject(columnDef)
                && YAHOO.lang.isObject(columnDef.gridData)
                && YAHOO.lang.isString(columnDef.gridData.filterRelation)
                && YAHOO.lang.isValue(columnDef.gridData.filterValue)
                && columnDef.gridData.filterRelation != ''
                && String(columnDef.gridData.filterValue) != '') {
                 value = columnDef.gridData.filterRelation + " " + columnDef.gridData.filterValue;
             }

             // table cell
             var tTdElement = document.createElement('td');
             dom.addClass(tTdElement, this.filterInputBoxTDClassName);
             tTdElement.setAttribute("id", key);
             // div in a table cell
             var divForAutocomplete = document.createElement('div');
             divForAutocomplete.id = this.createFilterInputDivId(key);
             tTdElement.appendChild(divForAutocomplete);

             inputFiltersTrElement.appendChild(tTdElement);
             var id = this.createFilterInputId(key);
             var filter = new ColumnFilter(this.mediator, divForAutocomplete, id, this, columnDef, value, this.searchFunction);
             var filterElement = filter.createFilterElement();

             if (column.hidden) {
                 YAHOO.util.Dom.setStyle(filterElement, "display", "none");
                 YAHOO.util.Dom.addClass(filterElement, "yui-dt-hidden");
                 YAHOO.util.Dom.addClass(tTdElement, "yui-dt-hidden");
             }

         }
         dom.insertAfter(bodyElement, messageTBodyHTMLElement);
         return bodyElement;
     },

        /**
        * 
        * Handles datatable.columnReorderEvent
        *
        * @method columnReorderEvent
        */
    this.columnReorderEvent = function() {
        // We are now in the DataTable scope!!!!
        var config = this.configs;
        var controller = config.owner;
        var visibilityData = controller.getVisibility();
        var tableElement = this.getTableEl();
        var ourTBody = YAHOO.util.Dom.get(controller.FILTERS_BODY_ID);
        YAHOO.util.Event.purgeElement(ourTBody, true);
        tableElement.removeChild(ourTBody);
        controller.addFiltersRow(this.getColumnSet().headers);
        controller.setVisibility(visibilityData);
        controller.setfillNewColumnsInDialog(true);
        controller.saveState();
    },


        /**
        * 
        * Gets visibility of our cells. Returned data {key:'aa',visible:true} are used in the setVisibility method.
        *
        * @method getVisibility
        */
    this.getVisibility = function() {
        var columnSet = this.dataTable.getColumnSet();
        var keys = columnSet.keys;
        var result = [];
        for (var i = 0; i < keys.length; i++) {
            var column = columnSet.getColumn(i);
            var visibility = {};
            visibility.key = column.key;
            visibility.visible = !column.hidden;
            result.push(visibility);
        }
        return result;
    },

        /**
        * 
        * Sets visibility of our cells
        *
        * @method setVisibility
        * @param visibilityArray - object from getVisibility method
        */
    this.setVisibility = function(visibilityArray) {
        var columnSet = this.dataTable.getColumnSet();
        for (var i = 0; i < visibilityArray.length; i++) {
            //var column = columnSet.getColumn(visibilityArray[i].key);
            //column.hidden = !visibilityArray[i].visible;
            this.setVisibleOurRowForColum(visibilityArray[i].key, visibilityArray[i].visible);
        }
    },


        /**
        * 
        * Get a value of switch for Columns Selection dialog
        *
        * @method getfillNewColumnsInDialog
        */
    this.getfillNewColumnsInDialog = function() {
        return this.fillNewColumnsInDialog;
    },

        /**
        * 
        * Set a value of switch for Columns Selection dialog
        *
        * @method setfillNewColumnsInDialog 
        */
    this.setfillNewColumnsInDialog = function(value) {
        this.fillNewColumnsInDialog = value;
        if (value) {
            YAHOO.util.Event.purgeElement("dt-dlg-picker", true);
            YAHOO.util.Dom.get("dt-dlg-picker").innerHTML = "";
        }
    },

        /**
        * 
        * Handles hiding column from Columns Selection dialog. We need hide our row.
        *
        * @method hideColumn
        * @param key
        */
    this.hideColumn = function(key) {
        this.dataTable.hideColumn(key);
        this.mediator.widgetChanged(globals.GRID_CONTROLLER, this);
        this.setVisibleOurRowForColum(key, false);
    },

        /**
        * 
        * Handles unhiding column from Columns Selection dialog. We need show our row.
        *
        * @method hideColumn
        * @param key
        */
    this.showColumn = function(key) {
        this.dataTable.showColumn(key);
        this.mediator.widgetChanged(globals.GRID_CONTROLLER, this);
        this.setVisibleOurRowForColum(key, true);
    },


        /**
        * Hides column filters when visibility of column changed.
        */
    this.setVisibleOurRowForColum = function(key, visible) {
        var columnDef = this.getColumnDef(key);
        id = gridController.createFilterInputId(key);
        var td = YAHOO.util.Dom.getAncestorByTagName(id, "td");
        if (!columnDef.gridData.canHaveFilter || !visible) {
            YAHOO.util.Dom.setStyle(id, "display", "none");
            YAHOO.util.Dom.addClass(td, "yui-dt-hidden");
        }
        if (columnDef.gridData.canHaveFilter && visible) {
            YAHOO.util.Dom.setStyle(id, "display", "");
            YAHOO.util.Dom.removeClass(td, "yui-dt-hidden");
        }
        // ToDo: if column is not visible, but filter is in effect then what ????
        //if (!visible) {
        //  this.clearColumnFilter(); ??????????
        // }
    },

    this.recreateOurTBody = function() {
        var tableElement = this.dataTable.getTableEl();
        var ourTBody = YAHOO.util.Dom.get(this.FILTERS_BODY_ID);
        YAHOO.util.Event.purgeElement(ourTBody, true);
        tableElement.removeChild(ourTBody);
        this.addFiltersRow(this.dataTable.getColumnSet().headers);
    },

        /**
        * Fills table by new data
        *
        * @method newData 
        */
    this.newData = function(data) {
        var recordSet = this.dataTable.getRecordSet();
        this.dataTable.deleteRows(0, recordSet.getLength());
        if (data.data.length > 0) {
            this.dataTable.addRows(data.data);
            var sortedByState = this.dataTable.get("sortedBy");
            if (sortedByState) {
                var sortedColumn = this.dataTable.getColumn(sortedByState.key);
                this.dataTable.sortColumn(sortedColumn, sortedByState.dir);
            }
        }
        mediator.hideWaitingForDataState();
    },


    this.searchGridAjax = function(data) {
        this.newData(data);
    },

    this.getDataSuccessHandler = function(o) {
        o.purge(); //removes the script node immediately after executing;
    },

    this.getData = function() {
        this.dataTable.showTableMessage();
        YAHOO.util.Get.script(globals.getDataUrl(), { onSuccess: this.getDataSuccessHandler });
    },

    this.getInstrumentsData = function(buttonsStateUrlString) {
        this.dataTable.showTableMessage();
        YAHOO.util.Get.script(globals.getInstrumentsDataUrl(buttonsStateUrlString), { onSuccess: this.getDataSuccessHandler });
    },

    /**
    *
    * Send a state of grid to server
    *
    */
    this.saveState = function() {
        var gridDefinitionData = this.getGridDefinitionDataUrlEncoded();
        YAHOO.util.Get.script(globals.getSetStateUrl(gridDefinitionData), { onSuccess: this.getDataSuccessHandler });
    },


    this.instrumentSelectionClick = function(button) {
        this.instrumentSelector.clickButton(button);
        this.clearInstrumensColumnFilter();
    },

    this.allInstrumentsClick = function(button) {
        this.instrumentSelector.clickAllInstrumentsButton(button);
        this.clearInstrumensColumnFilter();
    },

    this.clearInstrumensColumnDefinitionFilter = function() {

        var columnDefinition = this.getColumnDef("instrument");
        if (YAHOO.lang.isObject(columnDefinition)) {
            columnDefinition.gridData.filterRelation = '';
            columnDefinition.gridData.filterValue = '';
        }
    },

    this.clearInstrumensColumnFilter = function() {
        var instrumentColumn = this.dataTable.getColumn("instrument");
        if (YAHOO.lang.isObject(instrumentColumn)) {
            id = gridController.createFilterInputId(instrumentColumn.key);
            tdElement = YAHOO.util.Dom.get(id);
            tdElement.setAttribute("value", "");
        }
        this.clearInstrumensColumnDefinitionFilter();
    },


        /**
        * Callback for response from server after grid saved
        *
        * @method saveGridAjax
        */
        this.saveGridAjax = function(data) {
            return true;
        },

        /**
        * Callback for response from server after grid dleted
        *
        * @method deleteGridAjax
        */
    this.deleteGridAjax = function(data) {
        return true;
    },


    this.saveStateAjax = function(data) {
        return true;
    },
    
    /**
    * Callback for response from server for getGridList request
    *
    * @method getGridListAjax
    */
    this.getGridListAjax = function(responseJsonData) {
        //this.gridsMenu.addGridSet(responseJsonData);
        this.gridsMenu.createMenuGroup(responseJsonData);
    },

    this.getSortedByState = function() {
        var sortedByState = this.dataTable.get("sortedBy");
        if (!sortedByState) {
            sortedByState.key = '';
            sortedByState.dir = '';
        }
        return sortedByState;
    },

    this.getGridDefinitionData = function() {
        var result = {};
        result.columnsVisibility = this.getVisibility();
        result.sortedByState = this.getSortedByState();
        result.nameOfGrid = this.nameOfGrid;
        return result;
    },

    this.getGridDefinitionDataUrlEncoded = function() {
        var data = this.getGridDefinitionData();
        var columnsVisibility = data.columnsVisibility;
        var result = 'keys=';
        var sortedByKey = '';
        var sortedByDir = '';
        for (var i = 0; i < columnsVisibility.length; i++) {
            var column = columnsVisibility[i];
            if (column.visible) {
                result += column.key + ",";
                if (column.key == data.sortedByState.key) {
                    sortedByKey = data.sortedByState.key;
                    sortedByDir = data.sortedByState.dir;
                }
            }
        }
        result = result.substring(0, result.length - 1);

        result += "&sortKey=" + sortedByKey;
        result += "&sortDir=" + sortedByDir;
        result += "&nameOfGrid=" + encodeURIComponent(this.nameOfGrid);
        return result;
    },

    this.setNameOfGrid = function(name) {
        this.nameOfGrid = name;
    },

        /**
        * 
        * Just alert for testing.
        *
        * @method show
        * @param msg
        */
    this.show = function(msg) {
        alert(msg);
    }

}


/**
*-------------------------------------------------------------------------------------------------------
* Formatters are global functions. They can be methods of the GridController object, but in that case
* must be 'this' keyword used in the ColumnDefinition object:
*  { key: "graph", className: "grid_column", label: "Graph", formatter: this.graphImgFormatter }
*-------------------------------------------------------------------------------------------------------
*/

/**
* graphImgFormatter formatter (its name is included in columnsDef!)
*
* @method graphImgFormatter
*/
function graphImgFormatter(elCell, oRecord, oColumn, oData) {
    var graphSourceUrl = globals.graphSourceUrl; //'http://preview.collective2.com/cgi-perl/dashcharts.mpl';
    var width = 55;
    var height = 35;
    var systemId = oData; //oRecord.getData("guid");
    var imgSpecif = 'notext=1&amp;sid=' + systemId + '&amp;width=' + width + '&amp;height=' + height;
    var url = graphSourceUrl + '?' + imgSpecif;
    elCell.innerHTML =
	'<div class="gridsys" id="gridsy' + systemId + '"><a href="#" onmousedown="handleMouseDown(\'gridsy' + systemId + '\'  );return false;" onmouseup="handleMouseUpURL( \'' + globals.systemsUrl + '?want=p&systemid=' + systemId + '\' );return false;">' +
        "<img src='" + url + "' border='0'/>"+
        '</a></div>';
};

/**
* Number formatter (its name is included in columnsDef!)
*
* @method myFormatNumber
*/
function myFormatNumber(elCell, oRecord, oColumn, oData) {
    elCell.innerHTML = YAHOO.util.Number.format(oData, oColumn.numberOptions);
};


function businnessModelFormatter(elCell, oRecord, oColumn, businessmodel) {
    var result = '';
	if (businessmodel)
	{
      switch (businessmodel)
      {
      case 1: result = 'Periodic'; break;
      case 2: result = 'Profitability guaranteed'; break;
      case 3: result = 'Pay only for profitable trades'; break;
      case 4: result = 'Free for AutoTraders'; break;
      default: result = 'Periodic'; break;
      }
    }
    elCell.innerHTML = result;
};

function calmarFormatter(elCell, oRecord, oColumn, oData) {
    var annReturn = oRecord.getData("annReturn");
    var maxDrawdown = oRecord.getData("maxdrawdownPcnt");
    var calmar = annReturn / maxDrawdown;
    elCell.innerHTML = YAHOO.util.Number.format(calmar, oColumn.numberOptions);
};

function profitFactorFormatter(elCell, oRecord, oColumn, oData) {
    var result;
    if (oData == -1) { result = 'n/a';}
    else  { result = YAHOO.util.Number.format(oData, oColumn.numberOptions);}
    elCell.innerHTML = result; 
};

/**
* riskImgFormatter formatter (its name is included in columnsDef!)
*
* @method riskImgFormatter 
*/
function riskImgFormatter(elCell, oRecord, oColumn, oData) {
    var risImgSourceUrl = globals.risImgSourceUrl; //'http://preview.collective2.com/cgi-perl/xcharts200.mpl?want=horiz&width=60&pictype=rs&;';
    var url = risImgSourceUrl + oData;
    elCell.innerHTML = "<img src='" + url + "'/>";
};

/**
* popularityImgFormatter formatter (its name is included in columnsDef - do not change!)
*
* @method popularityImgFormatter
*/
function popularityImgFormatter(elCell, oRecord, oColumn, oData) {
    var popularityImgSourceUrl = globals.popularityImgSourceUrl;   //'http://preview.collective2.com/cgi-perl/xcharts200.mpl?want=horiz&width=80&systemid=$sid&pictype=gc';
    var url = popularityImgSourceUrl + '&percent=' + oData;
    elCell.innerHTML = "<img src='" + url + "'/>";
};

/**
* popularityWeeImgFormatter formatter (its name is included in columnsDef - do not change!)
* Formats url for 'Popular Last Week' column
* @method popularityWeekImgFormatter
*/
function popularityWeekImgFormatter(elCell, oRecord, oColumn, oData) {
    var popularityImgSourceUrl = globals.popularityImgSourceUrl;   //'http://preview.collective2.com/cgi-perl/xcharts200.mpl?want=horiz&width=80&systemid=$sid&pictype=gc';
    var url = popularityImgSourceUrl + '&percent=' + oData;
    elCell.innerHTML = "<img src='" + url + "'/>";
};

/**
* Sort profit factor. -1 is the highest value
*/
function sortProfitFactor(a, b, desc) {
    var left = a.getData("profitFactor");
    var right = b.getData("profitFactor");
    if (left == -1) { left = Number.MAX_VALUE; }
    if (right == -1) { right = Number.MAX_VALUE; }
    return YAHOO.util.Sort.compare(left, right, desc);
};

/**
* Function for comparing a length of trades shown as: 	3.1 days, 13.9 hrs, 1.1 weeks, ...
*/
function sortTradeLength(a, b, desc) {
    // Deal with empty values
    if (!YAHOO.lang.isValue(a)) {
        return (!YAHOO.lang.isValue(b)) ? 0 : 1;
    }
    else if (!YAHOO.lang.isValue(b)) {
        return -1;
    }

    // First compare by: mins hrs days weeks
    var asplit = a.getData("avgTradeLength").split(" ");
    var bsplit = b.getData("avgTradeLength").split(" ");
    switch (asplit[1]) {
        case "mins":
            aTimeFrame = 10;
            break;
        case "hrs":
            aTimeFrame = 20;
            break;
        case "days":
            aTimeFrame = 30;
            break;
        case "weeks":
            aTimeFrame = 40;
            break;
        case "months":
            aTimeFrame = 50;
            break;
        default:
            aTimeFrame = 60;
            break;
    }

    switch (bsplit[1]) {
        case "mins":
            bTimeFrame = 10;
            break;
        case "hrs":
            bTimeFrame = 20;
            break;
        case "days":
            bTimeFrame = 30;
            break;
        case "weeks":
            bTimeFrame = 40;
            break;
        case "months":
            bTimeFrame = 50;
            break;
        default:
            bTimeFrame = 60;
            break;
    }

    var compState = YAHOO.util.Sort.compare(aTimeFrame, bTimeFrame, desc);

    // If time frames are equal, then compare by number
    return (compState !== 0) ? compState : YAHOO.util.Sort.compare(parseFloat(asplit[0]), parseFloat(bsplit[0]), desc);
};
