﻿//dGrid object (inherit from dhtmlXGridObject)
//dependant: dhtmlxGrid
//Ref: http://phrogz.net/JS/Classes/OOPinJS2.html
/*Khiem 20090810: a wrapper of DhtmlxGrid
-All new implemented members and methods are started with "x"
-The ID of every new row would be assigned at the created time, and start with "r", 
followed by a max row-index (monitored in xMaxInd).
*/

dGrid.prototype = new dhtmlXGridObject(); //inheritance
dGrid.prototype.constructor = dGrid;    //specify new constructor...

dGrid.xInstances = new Array();   //static member
dGrid.xInstanceCnt = 0;           //static member

var cnt=0; // for debug

function dGrid(oName) {
    //which calls to its parent's constructor
    dhtmlXGridObject.call(this, oName);
    
    dGrid.xInstances[oName] = this;
    dGrid.xInstanceCnt++
    
    this.attachEvent("onEditCell", this.xDefOnEditCell);
    this.attachEvent("onKeyPress", this.xDefOnKeyPress);
    this.attachEvent("onRowSelect", this.xDefOnRowSelect);
    this.attachEvent("onBeforeSelect", this.xDefOnBeforeSelect);
    this.attachEvent("onRowDblClicked", this.xDefOnDblClick);
    this.attachEvent("onValidationCorrect", this.xDefOnValidateCorrect);
    this.attachEvent("onValidationError", this.xDefOnValidateError);
    this.xPostCond = 'e'; // e: only edited rows, a: post all
    //this.xMaxInd = 0;     //to manage row's id // removed because currently not necessary
}

;
/*---------------------------------------Init Helper Properties + Methods---------------------------------------*/
dGrid.prototype.xInit = function(oInfo) {
    this.xId = oInfo.id;
    this._xRowTextStyleQ = "color:#0F0F0F";
    this._xRowTextStyleU = "color:#993333";
    this._xRowTextStyleI = "color:#3a6ea5";
    this.clones = new Array(0);
    this.useClones = false;

    this.setImagePath("/Common/dhtmlx/imgs/");
    this.setDelimiter(oInfo.delimiter);
    this.setEditable(!oInfo.readonly);
    this.xAllCaps = oInfo.allcaps;
    
    this.setColumnIds(oInfo.colID);
    this.xParseHeader(oInfo.colT, oInfo.delimiter);
    this.setInitWidths(oInfo.colW);
    this.setColAlign(oInfo.colA);
    this.setColHidden(oInfo.colH)
    this.setColTypes(oInfo.colTP);
    this.setColSorting(oInfo.colS);

    for (var i = 0; i < oInfo.colID.split(oInfo.delimiter).length; i++) {
        this.xColData(i)['DT'] = oInfo.colDT[i];    //DataType
        this.xColData(i)['R'] = oInfo.colR[i];      //Required
        this.xColData(i)['RO'] = oInfo.colRO[i];    //Readonly
        //this.xColData(i)['DV'] = oInfo.colDV[i];  
        this.defVal[i] = oInfo.colDV[i];            //DefaultValue
        this.xColData(i)['KP'] = oInfo.colKP[i];    //KeyProtected
        this.xColData(i)['AC'] = oInfo.colAC[i];    //AllCaps
        this.xColData(i)['CodeInfo'] = eval("(" + oInfo.colCodeInfo[i] + ")");
        this.xColData(i)['isCode'] = oInfo.colIsCode[i];
        this.xColData(i)['V'] = oInfo.colV[i];      //Validator
        this.xColData(i)['M'] = oInfo.colM[i];      //Mask
        if (oInfo.colM[i] && oInfo.colM[i] != '') {
            this.setNumberFormat(oInfo.colM[i], i);
        }

        if (oInfo.colComboData[i]) {
            var combo = this.getCombo(i);
            var data = oInfo.colComboData[i];

            //combo.clear();
            for (var j = 0; j < data.length; j++) {
                combo.put(data[j][0], data[j][1]);
            }
            //combo.save();
        }
    }

    // set up column input clones
    this.setColClone(oInfo.colClone);

    // enable validation
    this.enableValidation(true);

    // set column validation
    this.setColValidators(this._parseValidation(oInfo.colDT));

    // set so that readonly columns do not receive focus
    this.enableEditTabOnly(true);

    this.enableCellIds(true);

    // set date format
    this.setDateFormat("%Y-%m-%d");

    // allow column move
    //this.enableColumnMove(true);

    //call default init
    this.init();

    var colIds = oInfo.colID.split(oInfo.delimiter);
    for (var i = 0; i < colIds.length; i++) {
        var handler = eval('self.' + this.xId + "_" + colIds[i] + '_AfterEdit');
        if (handler) {
            this.attachEvent("xOnAfterEdit" + colIds[i], handler);
        }
    }

    //colClone
}
;

//Parse header information
dGrid.prototype.xParseHeader = function(aTitle, delimiter) {
    try {
        if (aTitle[0].indexOf(delimiter) < 0) {
            this.setHeader(aTitle.join(delimiter));
        } else {
            var nRows = aTitle[0].split(delimiter).length;
            var nCols = aTitle.length;

            var aRowOk = new Array();       //2 dimension array to row's titles.
            for (var i = 0; i < nRows; i++) {
                aRowOk[i] = new Array();
            }
            var aTmp;
            for (var j = 0; j < nCols; j++) {
                aTmp = aTitle[j].split(delimiter);
                for (var i = 0; i < nRows; i++) {
                    aRowOk[i][j] = aTmp[i];
                }
            }
            //set first row header
            this.setHeader(aRowOk[0].join(delimiter));
            for (i = 1; i < nRows; i++) {
                this.attachHeader(aRowOk[i].join(delimiter));
            }
        }
    } catch (err) {
        alert('Could not parse grid header. Err: ' + err);
    }
}
;

dGrid.prototype.setColClone = function(cInfo) {

    var length = cInfo.length;
    if (length==undefined) { return; }

    var cloneDef = cInfo;
    var grid     = this;

    // defer execution until all DOM has loaded and other init logics have executed
    // TODO: this logic will currently execute immediately because document is already ready at this point
    $(document).ready(function (){
        for (var i = 0; i < length; i++) {
            if (cloneDef[i] && cloneDef[i].trim()!='') {
                // create clone
                var clone = grid.getClone(i);
                grid.useClones = true;
                
                // init clone
                clone.copy(cloneDef[i]);
                
                // if combo column, init combo data
                if (clone.shape=='SELECT') {
                    var combo = grid.getCombo(i);
                    var data = clone.getComboData();

                    for (var j=0; j<data.length; j++) {
                        combo.put(data[j][0], data[j][1]);
                    }
                }
            }
        }
    });    
};


/*--------------------------------------- UTILS : New API methods + properties for dGrid---------------------------------------*/
// set row as changed (manage insflag
dGrid.prototype.xSetRowIsChanged = function(rId) {
    if (typeof rId != 'string') { alert('Cannot set row changed flag! Invalid row ID!'); return; }
    var curFlag = this.xGetInsFlag(rId)
    if (curFlag == 'Q') { this.xSetInsFlag(rId,'U') };
    if (curFlag == '') { this.xSetInsFlag(rId,'I') };
    gDocModified = true;
}
;

//access to array of row's associated data
dGrid.prototype.xRowData = function(id) {
    if (typeof (id) == "number") { id = this.getRowId(id)} //passed index
    if (!this._wgRowData) { this._wgRowData = new Array(); }
    if (!this._wgRowData[id]) { this._wgRowData[id] = new Object(); }
    return this._wgRowData[id];
}
;
//access to array of column's associated data
dGrid.prototype.xColData = function(id) {
    if (!this._wgColData) { this._wgColData = new Array(); }
    if (!this._wgColData[id]) { this._wgColData[id] = new Object(); }
    return this._wgColData[id];
}
;

dGrid.prototype.matrix = function(row, col) {
    var rowId, colInd;
    
    if (typeof (row) == "number") { rowId = this.getRowId(row); } else { rowId = row; }
    if (typeof (col) == "string") { colInd = this.getColIndexById(col); }  else { colInd = col; }
    
    if (!rowId) { alert('Invalid Row'); return null; }
    if (isNaN(colInd)||colInd==-1) { alert('Invalid Column'); return null; }
    
    return this.cells(rowId,colInd);

};

dGrid.prototype.xMoveTo = function(rInd, col) {
    var cInd=-1;
    if (typeof (col) == "string") { cInd = this.getColIndexById(col); }  else { cInd = col; }
    if (isNaN(cInd)||cInd==-1) { alert('Invalid Column'); return null; }

    if (cInd >= this.xCols()) {
        if (rInd >= this.xRows() - 1) {
            if (this.isEditable) {
                this.xAddRow();
                this.xMoveTo(rInd + 1, 0);
                return;
            } else {
                //Pending: move focus to next control
            }
        } else {
            this.xMoveTo(rInd + 1, 0);
            return;
        }
    }

    if (cInd < 0) {
        if (rInd <= 0) {
            //Move focus to previous control  
        } else {
            this.xMoveTo(rInd - 1, this.xCols() - 1)
            return;
        }
        
    }

    //normal moving
    if (this.isColumnHidden(cInd)) {
        this.xMoveTo(rInd, cInd + 1);
        return;
    } else {
        this.selectCell(rInd, cInd, false, false, this.isEditable, true);
        //this.editCell();
    }
}
;
dGrid.prototype.xMoveNext = function() {
    this.xMoveTo(this.xRow(), this.xCol() + 1);
    return;
}
;
dGrid.prototype.xMovePrev = function() {
    this.xMoveTo(this.xRow(),this.xCol()-1);
    return;
}
;
dGrid.prototype.xAddRow = function() {
    //this.xMaxInd++;
    //var newId = "r" + this.xMaxInd;

    var newId = "r" + this.getRowsNum();
    if (window.event && window.event.ctrlKey) {
        this.addRow(newId, '', this.getRowIndex(this.getSelectedRowId()));
    } else {
        this.addRow(newId, '');
    }

    var newInd = this.xRow(newId);
    this.xSetInsFlag(newInd, "I");

    if (this.xDefOnRowAdded(newId) != false) {
        //Focus to first visible cell
        var cols = this.xCols();
        for (var j = 0; j < cols; j++) {
            if (!this.isColumnHidden(j)) {
                var grid = this;
                //grid.xMoveTo(newInd, j);
                window.setTimeout(function() {
                    grid.xMoveTo(newInd, j);
                }, 10);
                break;
            }
        }
    }

    if (event) { event.cancelBubble = true };
    return newId;
}
;
dGrid.prototype.xDeleteRow = function(rind) {
    if (isNaN(rind)) {rind = this.xRow(this.getSelectedRowId())}
    var rowId = this.xRowId(rind);
    
    if (!rowId) return;
    
    var insFlag = this.xGetInsFlag(rind);
    if (insFlag == "Q" || insFlag == "U") {
        this.setRowHidden(rowId, true); //Just hide it
        this.xSetInsFlag(rind,"D");
    } else {
        this.deleteRow(rowId); //truly delete ^^
    }
}
;

//get the current column index
dGrid.prototype.xCol = function(cId) {
    return cId ? this.getColIndexById(cId) : this.getSelectedCellIndex();
}
;
//get current row index
dGrid.prototype.xRow = function(rId) {
    return rId?this.getRowIndex(rId):this.getRowIndex(this.getSelectedRowId());
}
;
//get current col id
dGrid.prototype.xColId = function(cInd) {
return (cInd == null || cInd == undefined || isNaN(cInd)) ? this.getColumnId(this.getSelectedCellIndex()) : this.getColumnId(cInd);
}

//get current row index
dGrid.prototype.xRowId = function(rInd) {
return (rInd == null || rInd == undefined || isNaN(rInd)) ? this.getSelectedRowId() : this.getRowId(rInd);
}
;
//get the number of rows
dGrid.prototype.xRows = function() {
    return this.getRowsNum();
}
;
//get the number of columns
dGrid.prototype.xCols = function() {
    return this.getColumnsNum();
}
;
dGrid.prototype.xValue = function(rInd, cInd) {
    //pending: handling complex cell type
    return this.cells2(rInd, cInd).getValue();
}
;
//Set insert flag of row
dGrid.prototype.xSetInsFlag = function(rId, flag) {
    //var rowId = this.xRowId(rind);
    //this.xRowData(rowId).insFlag = flag;
    
    rId = (typeof (rId) == "number") ? this.getRowId(rId) : rId;
    
    this.setRowAttribute(rId, "INSFLAG", flag);
    
    //high light change
    switch (flag) {
        case "Q":
            this.setRowTextStyle(rId, this._xRowTextStyleQ);
            break;
        case "U":
            this.setRowTextStyle(rId, this._xRowTextStyleU);
            break;
        case "I":
            this.setRowTextStyle(rId, this._xRowTextStyleI);
            break;
        case "D":
            break;
    }
};

//Get insert flag of row
dGrid.prototype.xGetInsFlag = function(rId){
    //return this.xRowData(this.xRowId(rind)).insFlag;
    rId = (typeof (rId) == "number") ? this.getRowId(rId) : rId;
    return this.getRowAttribute(rId, "INSFLAG");
}
;

//Get AllCaps of column or grid
dGrid.prototype.xIsAllCaps = function(col) {
if (!(col == null || col == undefined || isNaN(col))) { 
        var colInd;
        if (typeof (col) == "string") { colInd = this.getColIndexById(col); } else { colInd = col; }
        if (this.xColData(colInd)['AC'] == 'yes') { return true };
        if (this.xColData(colInd)['AC'] == 'no') { return false };
        return this.xIsAllCaps();
    } else {
        if (this.xAllCaps == 'yes') { return true; }
        if (this.xAllCaps == 'no') { return false; }
        //inherit from doc
        if (yjit.config.doc.AllCaps == true) { return true; }
        return false;
    }
}
/* --------------------------------------- Data Export --------------------------------*/


dGrid.prototype.exportData = function(fnm, format) {
    var data = this.serializeToArray();
    var fileName = (fnm) ? fnm : 'GridExport';

    // currently only excel format supported
    var expType = (format) ? format : 'EXCEL';
    var colNames = [];
    
    dataExport(data, fileName, expType);
    
};


dGrid.prototype.serializeToArray = function() {

    var data = [];
    var cols = this.getColumnsNum();
    var rows = this.getRowsNum();

    // insert column IDs
    data[0] = [];
    for (var j=0; j < cols; j++) {
        data[0][j] = this.getColumnId(j);
    }

    // insert column titles
    rowOffset = 1;
    for (var i=0; i < rows; i++) {
        data[i+rowOffset] = [];
        for (var j=0; j < cols; j++ ) {
            data[i+rowOffset][j] = this.getColumnLabel(j);
        }
    }
    
    // insert data
    rowOffset = 2;
    for (var i=0; i < rows; i++) {
        data[i+rowOffset] = [];
        for (var j=0; j < cols; j++ ) {
            data[i+rowOffset][j] = this.matrix(i,j).getValue();
        }
    }
    
    return data;
};



/*********************************************************************************************/
/*********************************************************************************************/
// CUSTOM NAVIGATION
/*********************************************************************************************/
/*********************************************************************************************/
dhtmlXGridObject.prototype.SetTempNextCell=function(col) {
    this._tabOrder=[];
};

dGrid.prototype._getTempNextCell=function(acell, dir, i){

	acell=acell||this.cell;

	var arow = acell.parentNode;

	if (this._tabOrder){
		i=this._tabOrder[acell._cellIndex];

		if (typeof i != "undefined")
			if (i < 0)
				acell=this._nextRowCell(arow, dir, Math.abs(i)-1);
			else
				acell=arow.childNodes[i];
	} else {
		var i = acell._cellIndex+dir;

		if (i >= 0&&i < this._cCount){
			if (arow._childIndexes)
				i=arow._childIndexes[acell._cellIndex]+dir;
			acell=arow.childNodes[i];
		} else {

			acell=this._nextRowCell(arow, dir, (dir == 1 ? 0 : (this._cCount-1)));
		}
	}

	if (!acell){
		if ((dir == 1)&&this.tabEnd){
			this.tabEnd.focus();
			this.tabEnd.focus();
			this.setActive(false);
		}

		if ((dir == -1)&&this.tabStart){
			this.tabStart.focus();
			this.tabStart.focus();
			this.setActive(false);
		}
		return null;
	}

	//tab out

	// tab readonly
	if (acell.style.display != "none"
		&&(!this.smartTabOrder||!this.cells(acell.parentNode.idd, acell._cellIndex).isDisabled()))
		return acell;
	return this._getNextCell(acell, dir);
// tab readonly

};



