/**------------------------------------------------------------------------
 * Set of function and classes which deal with currency cross rates matrix 
 *
 * Dependencies:
 *  dojo.js, version 0.9 
 *
 * Author: 
 *  Bartlomiej.Pawlowski@swx.com
 *
 * @version $Id: currencyOfficialRatesMatrix.js,v 1.3 2010/05/07 12:36:30 obo Exp $
 *
 *-----------------------------------------------------------------------*/

dojo.declare("CurrencyRatesMatrix", null, {

    // index 0 - row odd original background color
    // index 1 - row even original background color
    _colors: ["white", "white"],

    // keeps currently selected currency codes
    _currentlySelected: {},
    
    statics: {
        SELECTED:   1, 
        UNSELECTED: 0,
        
        cellColors: {"highlight":{
        				"bg":{"cell":"ffffcc","diag":"ffffcc","head":"ffffcc"},
    					"fg":{"cell":"black", "diag":"black", "head":"black"}},
    			      "normal":{
         				"bg":{"cell":"white", "diag":"eeeeee","head":"cccccc"},
     					"fg":{"cell":"black", "diag":"black", "head":"black"}}
         }
    },

    /**
     * @param currencyTableId id of the html table showing currency rates
     *          String
     *
     * @param currNamesTabId id of the html table showing currency names
     *          String
     *
     * @param currCodes array with the main currency codes
     *          [CHF, USD,.....]
     *
     * @param otherCurrCode array with the other currency codes
     *          [SEK, NOK,.....]
     *
     * @param allCurrencies map with all currency codes with the display names
     *          {CHF: 'Franc Swiss', USD: 'US Dollar',..... }
     *
     * @param allRates map with all rates calculated for all currencies
     *          {CHF: {CHF: 1, USD: 1.2, GBP: 2.33},
     *           USD: {CHF: 1.2, USD: 1. ........ },
     *           ........ }
     *
     * @param option map with configuration parameters
     *        it should contain the following keys:
     *           row_odd_class_name       
     *           row_even_class_name      
     *           shown_elem_class_name    
     *           hidden_elem_class_name   
     *
     */
    constructor: function(currencyTableId, currNamesTabId,
                          currCodes, currIcons, otherCurrCodes, allCurrencies,
                          allRates, options) {
        this.currencyTableId    = currencyTableId;
        this.currNamesTabId     = currNamesTabId;
        this.currCodes          = currCodes;
        this.currIcons          = currIcons;
        this.otherCurrCodes     = otherCurrCodes;
        this.allCurrencies      = allCurrencies;
        this.allRates           = allRates;
        this.options            = options;
        
        // console.log("allRates: " + allRates);

        // init currenltySelected
        for (var i = 0; i < this.otherCurrCodes.length; i++) 
            this._currentlySelected[this.otherCurrCodes[i]] = this.statics.UNSELECTED;
        
    },

    /**
     * @param moreCurrButtonId id of an element representing more currencies
     *        button
     */
    initPage: function(moreCurrButtonId) {
        //dojo.style(dijit.byId(moreCurrButtonId).domNode, "display", "");
        dojo.style(dojo.byId(moreCurrButtonId), "display", "");
        
        
        dojo.query('table#'+this.currencyTableId +' tr').forEach(
        		function(node){        			
                    node.onmouseover = this._highlightFun();
                    node.onmouseout = this._unhighlightFun();                    
        		},this);
    },

    /**
     * Show or hide one currency selected on the menu dialog
     * 
     * @param currency (swx.widget.MenuItemCheckBox)
     */
    showCurrency: function(currency) {
        var display = currency.checked;
        var code = currency.id;
        var table = dojo.byId(this.currencyTableId);

        var row, cell;
        if ( display ) {
            this._currentlySelected[code] = this.statics.SELECTED;
            this._updateColumns(table, this.options["shown_elem_class_name"], code);
        }
        else {
            this._updateColumns(table, this.options["hidden_elem_class_name"], code);
            this._currentlySelected[code] = this.statics.UNSELECTED;
        }

        // refresh rows

        // remove all rows displaying additional currencies
        for (i = 0; i < this.otherCurrCodes.length; i++) {
            row = table.rows[this.otherCurrCodes[i]];
            
            if ( row ) {
                row.onmouseover = null;
                row.onmouseout  = null;
                for (var j = 0; j < row.cells.length; j++) {
                    cell = row.deleteCell(j);
                    cell = null;
                }
                table.deleteRow(row.rowIndex);
                row = null;
            }
        }

        // add rows displaying selected currencies
        //for (i = 0; i < this.currentlySelected.length; i++) {
        for (var _code in this._currentlySelected) {
            if ( this._currentlySelected[_code] == this.statics.SELECTED ) {
                row = table.insertRow(table.rows.length);
                row.id = _code;
                this._setRowClass(row);

                row.onmouseover = this._highlightFun(); 
                row.onmouseout = this._unhighlightFun();

                cell = row.insertCell(0);
                cell.id = "n" + _code;
                cell.innerHTML = '<span style="float: left">1 ' + _code + '</span>'
                  + '<span style="float: right; padding-top: 1px;"><img src="' + this.currIcons[_code] + '"></span>';
                cell.className = this.options["shown_elem_class_name"] + " firstCol";

                // go through default currencies
                for (j = 0; j < this.currCodes.length; j++) {
                    cell = row.insertCell(j+1);
                    cell.id = this.currCodes[j];
                    cell.align = "right";
                    cell.vAlign = "top";
                    cell.className = this.options["shown_elem_class_name"];
                    cell.innerHTML = this._decodeCurrValue(this.allRates[_code][this.currCodes[j]]);
                }
                // go through _currentlySelected
                for (var __code in this._currentlySelected) {
                    if ( this._currentlySelected[__code] == this.statics.SELECTED ) {
                        cell = row.insertCell(row.cells.length);
                        cell.id = __code;
                        cell.align = "right";
                        cell.vAlign = "top";
                        cell.className = this.options["shown_elem_class_name"];
                        cell.innerHTML = this._decodeCurrValue(this.allRates[_code][__code]);
                        if ( this.allRates[_code][__code] == -1 ) 
                            cell.className = this.options["shown_elem_class_name"] + " noRate";
                    }
                }
            }
        }

        // display currency names
        this._displayCurrencyNames(this._onlySelected(this._currentlySelected));

    },

    /**
     * Get only currenlty selected currencies
     *
     * @param currencies map (_currentlySelected)
     * @return array with currenlty selected currency code
     */
    _onlySelected: function(currencies) {
        var arr = [];
        for (var code in currencies) {
            if ( currencies[code] == this.statics.SELECTED )
            arr.push(code);
        }
        return arr;
    },

    /**
     * Shows or hides currency selected on the tooltip dialog
     * 
     * Used in case when multichoice menu is used
     *
     * @param currencies hash representation of the form submited on the 
     *        tooltip dialog (coming from dojo)
     *        example:  
     *          {
     *               NOK: [],           not selected
     *               SEK: [],           not selected
     *               PLN: ["PLN"]       selected
     *          }
     */
    showCurrencies: function (currencies) {

        var table = dojo.byId(this.currencyTableId);
        var ccsClassName;

        var toBeShown = [];         // which currencies should be displayed
        var toBeShownCounter = 0;
        
        var row, cell;
        var i, j;
            
        var code;
        for (i = 0; i < this.otherCurrCodes.length; i++) {
            code = this.otherCurrCodes[i];
            if ( currencies[code].length > 0 ) {
                cssClassName = this.options["shown_elem_class_name"];
                toBeShown[toBeShownCounter++] = code;
            }
            else 
                cssClassName = this.options["hidden_elem_class_name"];

            this._updateColumns(table, cssClassName, code);

        }
        
        // remove all rows displaying additional currencies
        for (i = 0; i < this.otherCurrCodes.length; i++) {
            row = table.rows[this.otherCurrCodes[i]];
            
            if ( row ) {
                row.onmouseover = null;
                row.onmouseout  = null;
                for (var j = 0; j < row.cells.length; j++) {
                    cell = row.deleteCell(j);
                    cell = null;
                }
                table.deleteRow(row.rowIndex);
                row = null;
            }
        }

        // add rows displaying selected currencies
        for (i = 0; i < toBeShown.length; i++) {
            row = table.insertRow(table.rows.length);
            row.id = toBeShown[i];
            this._setRowClass(row);

            row.onmouseover = this._highlightFun(); 
            row.onmouseout = this._unhighlightFun();

            cell = row.insertCell(0);
            cell.id = "n" + toBeShown[i];
            cell.innerHTML = toBeShown[i];
            cell.className = this.options["shown_elem_class_name"] + " firstCol";

            // go through default currencies
            for (j = 0; j < this.currCodes.length; j++) {
                cell = row.insertCell(j+1);
                cell.id = this.currCodes[j];
                cell.align = "right";
                cell.vAlign = "top";
                cell.className = this.options["shown_elem_class_name"];
                cell.innerHTML = this._decodeCurrValue(this.allRates[toBeShown[i]][this.currCodes[j]]);
            }
            // go through toBeShown
            for (j = 0; j < toBeShown.length; j++) {
                cell = row.insertCell(row.cells.length);
                cell.id = toBeShown[j];
                cell.align = "right";
                cell.vAlign = "top";
                cell.className = this.options["shown_elem_class_name"];
                cell.innerHTML = this._decodeCurrValue(this.allRates[toBeShown[i]][toBeShown[j]]);
                if ( this.allRates[toBeShown[i]][toBeShown[j]] == -1 ) 
                    cell.className = this.options["shown_elem_class_name"] + " noRate";
            }
        }

        // display currency names
        this._displayCurrencyNames(toBeShown);

    },

    /**
     * Set css class for all columns and rows which display the
     * main currencies
     *
     * @param table table which displays rates (dom node)
     * @param cssClassName css class name to be applied to the table cell
     * @param currencyCode currency code, which is the id of a cell
     */
    _updateColumns: function(table, cssClassName, currencyCode) {
        // update header column for a given code
        var cell;
        
        // for some strange reasons the line below does not work under IE
        //var cell = table.rows[0].cells[currencyCode];
        // that is why, in oder to find a cell, the for loop is used
        var found = false;
        var _cells = table.rows[0].cells;
        var i,j;
        for (i = 0; i < _cells.length && !found; i++) {
            if ( _cells[i].id == currencyCode ) {
                cell = _cells[i];
                found = true;
            }
        }
   
        cell.className = cssClassName;
        
        // update columns
        for (i = 0; i < this.currCodes.length; i++) {
            // for some strange reasons the line below does not work under IE
            //cell = table.rows[this.currCodes[i]].cells[currencyCode];
            // that is why, in oder to find a cell, the for loop is used
            found = false;
            _cells = table.rows[this.currCodes[i]].cells;
            for (j = 0; j < _cells.length && !found; j++) {
                if ( _cells[j].id == currencyCode ) {
                    cell = _cells[j];
                    found = true;
                }
            }
            cell.className = cssClassName;
        }
    },

    /**
     * @param value - currency price to be dispalyed (number)
     * @return currency price prepared to be display on the page
     */
    _decodeCurrValue: function(value) {
        var PRECISION = 4;

        if ( value == -1 )
            return " ";
        else
            return value.toFixed(PRECISION);
    },

    /**
     * Show the currently displayed currency names
     * @param shownCurr array with currency codes selected by user
     */
    _displayCurrencyNames: function(shownCurr) {

        var table = dojo.byId(this.currNamesTabId);

        var currentlyShown = this.currCodes.concat(shownCurr);

        // clear table
        while (table.rows.length > 0)
            table.deleteRow(0);

        for (var i = 0; i < Math.floor(currentlyShown.length/2) + currentlyShown.length%2; i++) {
            var row = table.insertRow(i);
            this._setRowClass(row);

            var cell = row.insertCell(0);
            cell.innerHTML = currentlyShown[i*2] + ": " + this.allCurrencies[currentlyShown[i*2]];
            cell = row.insertCell(1);

            if ( i*2+1 < currentlyShown.length )
                cell.innerHTML = currentlyShown[i*2+1] + ": " + this.allCurrencies[currentlyShown[i*2+1]];
            else 
                cell.innerHTML = '&nbsp;';
        }
    },

    /**
     * @param row returned by table.insertRow method
     */
    _setRowClass: function(row) {
        if ( row.rowIndex % 2 == 0 )
            row.className = this.options['row_odd_class_name'];
        else
            row.className = this.options['row_even_class_name'];
    },

    /**
     * Function returns first node ancestor of given type
     * @param srcnode node to start from
     * @param type ancestor type we are looking for
     */
    _getAncestor: function(srcnode, type) {
    	if(type == null)
    		return srcnode;
    	var t = type.toLowerCase();
    	var parent = srcnode ;    		
    	while(parent != null){
    		parent = parent.parentNode;
    		if(parent.nodeName.toLowerCase() == t){
    			return parent;
    		}
        }
    	return srcnode;
    },

    /**
     * flips between highlighted and not highlighted style for cells in the same row+column as currently hovered cell  
     * 
     */
    
    _flipHighlighting: function (src, state) {    	
    	var _row = this._getAncestor(src,'tr');                
        var _table = this._getAncestor(_row,'table'); 
        var _cell;

        var _isHeaderRow = (_row.id == 'head') ? true: false;

        // ROW 
        // highlight all cells in a row
        if (_row.cells != null && !_isHeaderRow){
        
            for (var ii = 0; ii < _row.cells.length; ii++) {
            	_cell = _row.cells[ii];
            	if ( _cell )
                    if ( ii == 0 ){ 					// header 
                        //_cell.style.color           = this.statics.cellColors[state]["fg"]["head"];;                        
                        _cell.style.backgroundColor = 	this.statics.cellColors[state]["bg"]["head"];
                    }else if (_cell.id == _row.id ) { 	// diagonal
                        //_cell.style.color           = this.statics.cellColors[state]["fg"]["diag"] ;
                       	_cell.style.backgroundColor = this.statics.cellColors[state]["bg"]["diag"] ;
                    }else{          					// cell
                  		_cell.style.backgroundColor = this.statics.cellColors[state]["bg"]["cell"] ;
                    }
            }
        }
        // COLUMN
        // highlight one cell on all rows
        if (_table.rows != null && src.cellIndex != 0){                
            for (ii = 0; ii < _table.rows.length; ii++) {
                _cell = _table.rows[ii].cells[src.id];
                if ( _cell ){	                        
                    if ( ii == 0 ){ 								// header 
                        //_cell.style.color           = this.statics.cellColors[state]["fg"]["head"] ;
                       	_cell.style.backgroundColor = this.statics.cellColors[state]["bg"]["head"] ;
                    } else if (_table.rows[ii].id == _cell.id ) { 	// diagonal cell
                        //_cell.style.color           = this.statics.cellColors[state]["fg"]["diag"] ;
                       	_cell.style.backgroundColor = this.statics.cellColors[state]["bg"]["diag"] ;
                    } else {          								// cell
                   		_cell.style.backgroundColor = this.statics.cellColors[state]["bg"]["cell"] ;
                    }
                }
            }
        }
    
    },
    
    /**
     * @return function used to highlight the row and column
     */
    _highlightFun: function() {
    	var objRef = this;
        var fun = function(evt) {
                if ( !evt ) evt = window.event;
                var src = evt.target != null ? evt.target : evt.srcElement;
                objRef._flipHighlighting(src,'highlight');                
            };
        return fun;
    },
        
    
    /**
     * @return function used to unhighlight the row and column
     */       
    _unhighlightFun: function() {
        var objRef = this;
        var fun = function(evt) {
                if ( !evt ) evt = window.event;
                var src = evt.target != null ? evt.target : evt.srcElement;
                objRef._flipHighlighting(src,'normal');                
            };
        return fun;
    }

});

