// ---------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------
//                                   Common helper functions
// ---------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------

// Images
var deleteAction            = "delete";
var newOReditAction         = "newORedit";
var untouchAction           = "untouched";
var nondeleteAction         = "nondeleted";
var editAction              = "edit";
var newAction               = "new";
var constraint              = "constraint";

var menuIcon                = "dropdown.gif";
var deletedIcon             = "deleted_table.gif";
var editedIcon              = "edited.gif";
var newIcon                 = "inserted.gif";
var constraintIcon          = "constraint.gif";

var deletedIconAltTxt       = "";
var editedIconAltTxt        = "";
var newIconAltTxt           = "";
var constraintIconAltTxt    = "";

var img_node          = document.createElement("IMG");

// Other global constants
var TABLE_ROW         = "tableRow";
var UPDATE_BUTTON_ID  = "buttonID";
var KEYS              = "Keys";
var DELETE_ID         = "DeleteID";
var statusEditable    = "Editable";
var statusReadOnly    = "ReadOnly";

// Arrays
var iconActionArray   = new Array(deleteAction, editAction, newAction, constraint);
var activeIconArray   = new Array("srch_actv.gif", "rfrsh_actv.gif", "cstmz_actv.gif");
var inactiveIconArray = new Array("srch_inactv.gif", "rfrsh_inactv.gif", "cstmz_inactv.gif");


function getIconSrc(iconType)
{
    var src = i2uiImageDirectory + "/";
    if (iconType == deleteAction)
        src = src + deletedIcon;
    else if (iconType == editAction)
        src = src + editedIcon;
    else if (iconType == newAction)
        src = src + newIcon;
    else if (iconType == constraint)
        src = src + constraintIcon;
    else
        src = "";
    return src;
}

function verifyIconType(iconType)
{
    var result = false;
    for (var i = 0, iaLen = iconActionArray.length; i < iaLen; i++)
    {
        if (iconActionArray[i] == iconType)
            result = true;
    }
    return result;
}

function setIcon(iconType, icon)
{
    if (iconType == deleteAction)
        deletedIcon = icon;
    else if (iconType == editAction)
        editedIcon = icon;
    else if (iconType == newAction)
        newIcon = icon;
    else if (iconType == constraint)
        constraintIcon = icon;
}

function getIcon(iconType)
{
    var iconNode = null;
    if (verifyIconType(iconType))
    {
        iconNode = img_node.cloneNode(true);
        iconNode.src = getIconSrc(iconType);
        iconNode.alt = getIconAltTxt(iconType);
    }
    return iconNode;
}

function setIconAltTxt(iconType, altTxt)
{
    if (iconType == deleteAction)
        deletedIconAltTxt = altTxt;
    else if (iconType == editAction)
        editedIconAltTxt = altTxt;
    else if (iconType == newAction)
        newIconAltTxt = altTxt;
    else if (iconType == constraint)
        constraintIconAltTxt = altTxt;
}

function getIconAltTxt(iconType)
{
    var altTxt = "";
    if (iconType == deleteAction)
        altTxt = deletedIconAltTxt;
    else if (iconType == editAction)
        altTxt = editedIconAltTxt;
    else if (iconType == newAction)
        altTxt = newIconAltTxt;
    else if (iconType == constraint)
        altTxt = constraintIconAltTxt;
    return altTxt;
}

// Return element or it's closest parent with tag name tagName.
function getTag(tag, tagName) {
    var parentTag = tag;
    while (parentTag != null && parentTag.tagName != tagName) {
        parentTag = parentTag.parentElement;
    }
    return parentTag;
}

// Return closest TR element
function getTR(tag) {
    return getTag(tag, "TR");
}

// Return closest TD element
function getTD(tag) {
    return getTag(tag, "TD");
}

function fixTabIndex(tabnode, idx)
{
    if (tabnode.tabIndex != null && tabnode.tabIndex != 0)
        tabnode.tabIndex = idx++;
    return idx;
}

function fixButtonsIndex(idx)
{
    var nbr = 0;
    var buttonNode = document.getElementById(UPDATE_BUTTON_ID + nbr);
    while (buttonNode != null)
    {
        var btbody = buttonNode.tBodies[0];
        if (btbody.hasChildNodes())
        {
            var anchorNode = btbody.rows[0].cells[0].childNodes[0];
            idx = fixTabIndex(anchorNode, idx);
        }

        nbr++;
        buttonNode = document.getElementById(UPDATE_BUTTON_ID + nbr);
    }
}

function focusOnRow(aNode)
{
    var cells = aNode.cells;
loopFOR1:
    for (var i = 0, cellsLen = cells.length; i < cellsLen; i++)
    {
        var tdnode = cells[i];
        var childNodes = tdnode.childNodes;
        for (var j = 0, cnLen = childNodes.length; j < cnLen; j++)
        {
            var wrkChild = childNodes[j];
            if ((wrkChild.nodeName == "INPUT" && wrkChild.type.toUpperCase() != "HIDDEN") || wrkChild.nodeName == "SELECT")
            {
                wrkChild.focus();
                break loopFOR1;
            }
        }
    }
}

// You know the field name and you have the row node in which the field is located.
// aNode = the row node.
// fldName = the field name.
function focusOnCellWithRowNodeAndFieldName(aNode, fldName)
{
    var cells = aNode.cells;
loopFOCWRNAFN1:
    for (var i = 0, cellsLen = cells.length; i < cellsLen; i++)
    {
        var tdnode = cells[i];
        var childNodes = tdnode.childNodes;
        for (var j = 0, cnLen = childNodes.length; j < cnLen; j++)
        {
            var wrkChild = childNodes[j];
            if (((wrkChild.nodeName == "INPUT" && wrkChild.type.toUpperCase() != "HIDDEN") ||
                 wrkChild.nodeName == "SELECT") && wrkChild.name == fldName)
            {
                wrkChild.focus();
                break loopFOCWRNAFN1;
            }
        }
    }
}

// Returns true if value is in array of values.
function isInList(arrayOfValues, value) {
    var result = false;
    if (arrayOfValues != null) {
        for (var i = 0, arLen = arrayOfValues.length; i < arLen; i++) {
            if (arrayOfValues[i] == value) {
                result = true;
                break;
            }
        }
    }
    return result;
}

function updateFieldFromMassRow(field, value)
{
    if(field != null) {
    	if(field.type == "select-one") {
            for(var j = 0, foLen = field.options.length; j < foLen; j++)
                if(field.options[j].value == value)
                    field.selectedIndex = j;
        }
        else if(field.length != null) {
            for(var j = 0, fldLen = field.length; j < fldLen; j++) {
                if(field != undefined && field[j] != undefined && field[j].value != undefined)
        			field[j].value = value;
                else if(field != undefined && field[j] != undefined && field[j].checked != undefined)
        			field[j].checked = value;
            }
        }
        else
            field.value = value;
    }
}

// ---------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------
//                                  Base Table support
// ---------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------

function BaseTable()
{
}

BaseTable.prototype.initBaseTable = function(prefix, maintableid, isFixedHeader, displayHeight, tablewidth) {
    this.prefix          = prefix;
    this.maintableid     = maintableid;
    this.isFixedHeader   = isFixedHeader;
    this.main_table_node = document.getElementById(maintableid);
    this.main_tbody_node = (this.main_table_node != null) ? this.main_table_node.tBodies[0] : null;
    this.form            = getTag(this.main_table_node, "FORM");
    this.displayHeight   = displayHeight;
    this.tablewidth      = tablewidth;
}

BaseTable.prototype.getSelectAllName = function() {
    return this.prefix+"SelectAll";
}

BaseTable.prototype.getSelectedRowName = function() {
    return this.prefix+"SelectedRow";
}

BaseTable.prototype.getSelectedColumnName = function() {
    return this.prefix+"SelectedColumn";
}

BaseTable.prototype.getKeyName = function() {
    return this.prefix+"Key";
}

BaseTable.prototype.getKeysName = function() {
    return this.prefix+"Keys";
}

BaseTable.prototype.getSelectedIndexName = function() {
    return this.prefix+"SelectedIndex";
}

BaseTable.prototype.getRowKeyName = function() {
    return this.prefix+"RowKey";
}

BaseTable.prototype.getFormObject = function(name) {
    return eval("this.form."+name);
}

BaseTable.prototype.getSelectAllObject = function() {
    return this.getFormObject(this.getSelectAllName());
}

BaseTable.prototype.getSelectedRowObject = function() {
    return this.getFormObject(this.getSelectedRowName());
}

BaseTable.prototype.getSelectedRowValue = function() {
    return this.getSelectedRowObject().value;
}

BaseTable.prototype.getSelectedColumnObject = function() {
    return this.getFormObject(this.getSelectedColumnName());
}

BaseTable.prototype.getKeyObject = function() {
    return this.getFormObject(this.getKeyName());
}

BaseTable.prototype.getKeyValue = function() {
    return this.getKeyObject().value;
}

BaseTable.prototype.getSelectedIndexObject = function() {
    return this.getFormObject(this.getSelectedIndexName());
}

BaseTable.prototype.getRowKeyObject = function() {
    return this.getFormObject(this.getRowKeyName());
}

/** To update hidden field "SelectedIndex" when a row is selected in a Table or UpdateableTable */
BaseTable.prototype.updateSelectedIndex = function(index)
{
    var selectedIndex = this.getSelectedIndexObject();
    var rowKey = this.getRowKeyObject();
    if (selectedIndex.length > 1)
    {
        if (rowKey[index].checked)
            selectedIndex[index].value = index;
        else
            selectedIndex[index].value = '';
    }
    else if (rowKey.checked)
        selectedIndex.value = index;
    else
        selectedIndex.value = '';
}

/**
 * To select or deselect all checkboxes in a Table or UpdateableTable
 */
BaseTable.prototype.toggleCheckAll = function() {
    var checked = false;
    var selectAll = this.getSelectAllObject();
    if (selectAll.length == undefined)
        checked = (selectAll.checked) ? true : false;
    else
        checked = (selectAll[0].checked) ? true : false;

    var selectedRow = this.getSelectedRowObject();
    if(checked)
        selectedRow.value='0';
    else
        selectedRow.value='';

    var rowKey = this.getRowKeyObject();
    if (rowKey != undefined)
    {
        var selectedIndex = this.getSelectedIndexObject();
        var rkLen = rowKey.length;
        if(rkLen > 1)
        {
            for (j = 0; j < rkLen; j++)
            {
                rowKey[j].checked = checked;
                if(checked)
                    selectedIndex[j].value = j;
                else
                    selectedIndex[j].value = '';
            }
        }
        else
        {
            rowKey.checked = checked;
            if(checked)
                selectedIndex.value = 0;
            else
                selectedIndex.value = '';
        }
    }
}

// Check if there are selected rows. Reports error if none.
BaseTable.prototype.checkHasSelectedRow_ = function(testedCheckBoxes, errormsg) {
    if (!errormsg)  errormsg = "SELECT_CHECKBOX";
    if (testedCheckBoxes.length > 1) {
        for (var i = 0, tcbLen = testedCheckBoxes.length; i < tcbLen; i++) {
            if (testedCheckBoxes[i].checked)
                return true;
        }
        messageAlert(errormsg);
        return false;
    } else if (testedCheckBoxes.checked) {
        return true;
    } else {
        messageAlert(errormsg);
        return false;
    }
}

// ---------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------
//                                  Read-only Table support
// ---------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------

function ROTable(prefix, roName, maintableid, tableSelectable, isFixedHeader, fixedColumns, narrowTable,
                 tableHeight, tablewidth, dataRowFirstTabIndex, displayHeight,
                 imagepath, unsortimage, ascendingimage, descendingimage,
                 headerDescs, secondarytableid, onclickrowcode)
{
    this.initBaseTable(prefix, maintableid, isFixedHeader, displayHeight, tablewidth);
    this.roName = roName;
    this.tableSelectable = tableSelectable;
    this.fixedColumns = fixedColumns;
    this.narrowTable = narrowTable;
    this.tableHeight = tableHeight;
    this.dataRowFirstTabIndex = dataRowFirstTabIndex;
    this.imagepath = imagepath;
    this.unsortimage = unsortimage;
    this.ascendingimage = ascendingimage;
    this.descendingimage = descendingimage;
    this.main_data_node = (this.isFixedHeader) ? document.getElementById(maintableid+'_data') : null;
    this.main_data_tbody_node = (this.main_data_node != null) ? this.main_data_node.tBodies[0] : null;

    this.headerDescs = headerDescs;
    this.secondarytableid = (secondarytableid != undefined) ? secondarytableid : null;
    this.secondary_table_node = (this.secondarytableid != null) ? document.getElementById(secondarytableid) : null;
    this.secondary_tbody_node = (this.secondary_table_node != null) ? this.secondary_table_node.tBodies[0] : null;
    this.secondary_data_node = (this.secondarytableid != null) ? document.getElementById(secondarytableid+'_data') : null;
    this.secondary_data_tbody_node = (this.secondary_data_node != null) ? this.secondary_data_node.tBodies[0] : null;

    this.sortByColumnIdx = -1;
    this.sortDirection = null;
    this.lastTag = null;
    this.mainheader = null;
    this.secondaryheader = null;

    // More efficient support for onClick for tables rows
    this.onclickrowcode = onclickrowcode;
    var rowkeys_ = this.form[this.getRowKeyName()];
    if (rowkeys_ != null) {
        if (rowkeys_.length != null) {
            for (var i = 0, rk_Len = rowkeys_.length; i < rk_Len; i++) {
                rowkeys_[i].onclick = onClickRowGlobal;
            }
        } else {
            rowkeys_.onclick = onClickRowGlobal;
        }
    }
    var table = this.main_data_node != null ? this.main_data_node : this.main_table_node;
    table.roName = this.roName;
}

ROTable.prototype = new BaseTable();
ROTable.prototype.constructor = ROTable;

// This function is invoked when clicked on a row in read-only tables.
// This function finds ROTable object, corresponding to a row and invokes table
// specific method. This is more efficient then defining specific onclick script for each row in the page.
function onClickRowGlobal() {
    var table = getTag(this, "TABLE");
    window[table.roName].onClickRow(this);
}

ROTable.prototype.onClickRow = function(button)
{
    if (this.onclickrowcode != null && this.onclickrowcode != "") {
        eval(this.onclickrowcode);
    }
    var rowIndex = this.getRowIndex(button);
    this.getSelectedRowObject().value=rowIndex;
    this.getKeyObject().value=button.value;
    this.updateSelectedIndex(rowIndex);
}

// Duplicate ReadOnly table row.
ROTable.prototype.dupRORow = function(rowIdx)
{
    var tbody = this.isFixedHeader ? this.main_data_tbody_node : this.main_tbody_node;
    var newRow = tbody.rows[rowIdx].cloneNode(true);
    var oldFirstTD = tbody.rows[rowIdx].cells[0];
    var newFirstTD = null;
    var trchildren = newRow.childNodes;
    var trchildlen = trchildren.length;
    for (var i = 0; i < trchildlen; i++)
    {
        newFirstTD = trchildren[i];
        if (newFirstTD.nodeName == "TD")
            break;
    }
    // Make sure functions' content are also copied.
    // Current functions catered for are as follow,
    //  onmouseover within "A",
    //  onclick within "INPUT" where type is not "Hidden"
    var oldtdchildren = oldFirstTD.childNodes;
    var oldtdlen = oldtdchildren.length;
    var newtdchildren = newFirstTD.childNodes;
    for (var i = 0; i < oldtdlen; i++)
    {
        var oldtdchild = oldtdchildren[i];
        var newtdchild = newtdchildren[i];
        if (oldtdchild.nodeName == "A")
        {
            if (oldtdchild.onmouseover != null)
            {
                var newfcnbody = extractOnMouseOverFcnBdy(oldtdchild);
                if (newfcnbody != null && newfcnbody.length > 0)
                    newtdchild.onmouseover = new Function(newfcnbody);
            }
        }
        else if (oldtdchild.nodeName == "INPUT" && oldtdchild.type.toUpperCase() != "HIDDEN")
        {
            if (oldtdchild.onclick != null)
            {
                var newfcnbody = extractOnclickFcnBdy(oldtdchild);
                if (newfcnbody != null && newfcnbody.length > 0)
                    newtdchild.onclick = new Function(newfcnbody);
            }
        }
    }
    return newRow;
}

// Get the row object.
ROTable.prototype.getRow = function (fromtableid, rowIdx)
{
    var rIdx = parseInt(rowIdx+'');
    if (fromtableid == null || fromtableid.length == 0)
        return null;
    else if (fromtableid.indexOf('master') > 0)
        return this.secondary_data_tbody_node.rows[rIdx].cloneNode(true);
    else 
        return this.dupRORow(rIdx);
}

// Replace the target row with the incoming row object (fromNode).
ROTable.prototype.setRow = function (fromtableid, targetRow, fromNode)
{
    var rIdx = parseInt(targetRow+'');
    var tbodynode = null;
    if (fromtableid.indexOf('master') > 0)
        tbodynode = this.secondary_data_tbody_node;
    else if (this.isFixedHeader)
        tbodynode = this.main_data_tbody_node;
    else
        tbodynode = this.main_tbody_node;
    
    if (tbodynode != null)
    {
        var oldNode = tbodynode.rows[rIdx];
        tbodynode.replaceChild(fromNode, oldNode);
    }
}

// Get the column value.
// If nothing is found, return an empty string.
// row = 0,1,2...   col = 0,1,2...
ROTable.prototype.getValue = function (fromtableid, row, col)
{
    var textValue = '';
    var rIdx = parseInt(row+'');
    var cIdx = parseInt(col+'');
    var isTableSelectable = this.tableSelectable;
    var tbodynode = null;

    if (fromtableid.indexOf('master') > 0)
    {
        isTableSelectable = false;
        cIdx = cIdx - this.fixedColumns;
        tbodynode = this.secondary_data_tbody_node;
    }
    else
    {
        if (this.isFixedHeader)
            tbodynode = this.main_data_tbody_node;
        else
            tbodynode = this.main_tbody_node;
    }
    
    if (tbodynode != null)
    {
        if (isTableSelectable)
            cIdx++;

        var trnode = tbodynode.rows[rIdx];
        if (trnode != null)
        {
            var tdnode = trnode.cells[cIdx];
            for (var i = 0, tcLen = tdnode.childNodes.length; i < tcLen; i++)
            {
                // Get the first text value only.
                var wrkChild = tdnode.childNodes[i];
                if (wrkChild.nodeName == "#text")
                {
                    textValue = wrkChild.nodeValue;
                    break;
                }
                else if (wrkChild.nodeName == "A") // For table where the key column is a link
                {
                    textValue = wrkChild.childNodes[0].nodeValue;
                    break;
                }
            }
        }
    }
    return textValue;
}

// Data for sorting of RO table
function RowData(row) {
    this.rowMaster = row;
    this.rowSlave  = null;
    this.value = null;
}

var ro_isSortAscending   = true;
function compareRowData(a,b) {
    var aValue = a.value;
    var bValue = b.value;
    if (aValue == bValue) return 0;
    if (aValue < bValue) return ro_isSortAscending ? -1 : 1;
    return ro_isSortAscending ? 1 : -1;
}

ROTable.prototype.doSorting = function (tableID, colIndex)
{
    var sortIcon = document.getElementById(tableID + colIndex);

    this.sortByColumnIdx = colIndex;
    if((sortIcon.src.indexOf(this.unsortimage) > 0) ||
       (sortIcon.src.indexOf(this.ascendingimage) > 0))
    {
        ro_isSortAscending = true;
        sortIcon.src = this.imagepath + this.descendingimage;
        this.sortDirection = "asc";
    }
    else if(sortIcon.src.indexOf(this.descendingimage) > 0)
    {
        ro_isSortAscending = false;
        sortIcon.src = this.imagepath + this.ascendingimage;
        this.sortDirection = "dsc";
    }

    var headertable1 = tableID;
    var headertable1start = 0;
    var headertable1end = 0;
    var headertable2 = '';
    var headertable2start = 0;
    var headertable2end = 0;

    //plain HTML table does not have data header/data tables
    var immediatetable = tableID + (this.isFixedHeader ? '_data' : '');
    
    //need to skip header row of plain HTML table
    var adjust = this.isFixedHeader ? 0 : 1;
    
    var othertable = '';
    if (tableID.indexOf('master') > 0)
    {
        othertable = tableID.substring(0, tableID.indexOf('master')) + 'slave_data';
        headertable2 = tableID.substring(0, tableID.indexOf('master'))+'slave';
        headertable1start = this.fixedColumns;
        headertable1end = this.tablewidth-1;
        headertable2start = 0;
        headertable2end = this.fixedColumns-1;
    }
    else if (tableID.indexOf('slave') > 0)
    {
        othertable = tableID.substring(0, tableID.indexOf('slave')) + 'master_data';
        headertable2 = tableID.substring(0, tableID.indexOf('slave'))+'master';
        headertable1start = 0;
        headertable1end = this.fixedColumns-1;
        headertable2start = this.fixedColumns;
        headertable2end = this.tablewidth-1;
    }

    var mastertbodynode = this.isFixedHeader ? this.main_data_tbody_node : this.main_tbody_node;
    var slavetbodynode = null;
    var isFixedColumns = othertable != '';
    if (isFixedColumns) {
        slavetbodynode = mastertbodynode;
        mastertbodynode = this.secondary_data_tbody_node;
    }

    var cellValues = new Array();
    var newRows = new Array();
    
    for(var rowIndex = 0; rowIndex < this.tableHeight; rowIndex++)
    {
        cellValues[rowIndex] = this.getValue(immediatetable, rowIndex+adjust, colIndex);
        var rowData = new RowData(mastertbodynode.rows[rowIndex+adjust]);
        newRows[rowIndex] = rowData;
        if (isFixedColumns)
            rowData.rowSlave = slavetbodynode.rows[rowIndex];
    }

    var colType = determineColumnType(cellValues);

    // Get sorted values converted from string to the right internal representation
    for (var rowIndex = 0, cvLen = cellValues.length; rowIndex < cvLen; rowIndex++)
    {
        if (colType == 1)
        {
            var fvalue = parseFloat(cellValues[rowIndex]);
            if (!isNaN(fvalue))
                newRows[rowIndex].value = fvalue;
        }
        else if (colType == 2)
        {
            newRows[rowIndex].value = parseDate(cellValues[rowIndex]);
        }
        else if (colType == 3)
        {
            newRows[rowIndex].value = parseDateTime(cellValues[rowIndex]);
        }
        else
        {
            newRows[rowIndex].value = cellValues[rowIndex];
        }
    }

    // Now sort.
    newRows.sort(compareRowData);

    // Remove the last row(s) which is added by resizeTable.
    var mtbLen = mastertbodynode.rows.length;
    while (isFixedColumns && slavetbodynode.rows.length > mtbLen) {
        slavetbodynode.removeChild(slavetbodynode.rows[slavetbodynode.rows.length-1]);
    }

    // Rearrange table rows in accordance with sorting results.
    var nrLen = newRows.length;
    for(var rowIndex = 0; rowIndex < nrLen; rowIndex++)
    {
        var rowData = newRows[rowIndex];
        mastertbodynode.appendChild(rowData.rowMaster);
        if (isFixedColumns) {
            slavetbodynode.appendChild(rowData.rowSlave);
        }
    }

    // Adjust classname.
    for(var rowIndex = 0; rowIndex < nrLen; rowIndex++)
    {
        var className = "tableRow"+((rowIndex+1)%2);
        var oldClassName = mastertbodynode.rows[rowIndex+adjust].className;
        if (oldClassName != className) {
            mastertbodynode.rows[rowIndex+adjust].className = className;
            if (isFixedColumns) {
                slavetbodynode.rows[rowIndex].className = className;
            }
        }
    }

    if (this.fixedColumns == 0)
        resetSortIcon(tableID, colIndex, 0, this.tablewidth-1, this.imagepath + this.unsortimage);
    else
    {
        resetSortIcon(headertable1, colIndex, headertable1start, headertable1end, this.imagepath + this.unsortimage);
        resetSortIcon(headertable2, colIndex, headertable2start, headertable2end, this.imagepath + this.unsortimage);
    }
    
    // Re-organize RowKey index if applicable.
    var tabidx = this.dataRowFirstTabIndex;
    var tblrows = this.isFixedHeader ? this.main_data_tbody_node.rows : this.main_tbody_node.rows;
    for (var i = 0; i < this.tableHeight; i++)
    {
        tabidx = this.fixRowIndexes(tblrows[i+adjust], tabidx, i);
    }
}

ROTable.prototype.fixRowIndexes = function(trnode, tabidx, idx)
{
    var cells = trnode.cells;
    for (var i = 0, cellsLen = cells.length; i < cellsLen; i++)
    {
        var wrktdnode = cells[i];
        var childNodes = wrktdnode.childNodes;
        for (var j = 0, cnLen = childNodes.length; j < cnLen; j++)
        {
            var chldnode = childNodes[j];
            if (chldnode.nodeName == "INPUT" || chldnode.nodeName == "SELECT" || chldnode.nodeName == "A")
            {
                tabidx = fixTabIndex(chldnode, tabidx);
            }
        }
    }
    return tabidx;
}

ROTable.prototype.fixTableRows = function(fromtboName, totboName)
{
    if (this.tableHeight > 0)
    {
        var maintbody = null;
        var secondarytbody = null;
        if (!this.isFixedHeader)
            maintbody = this.main_tbody_node;
        else
        {
            maintbody = this.main_data_tbody_node;
            if (this.fixedColumns > 0)
                secondarytbody = this.secondary_data_tbody_node;
        }
        var adjust = (this.isFixedHeader) ? 0 : 1;
        var tabidx = this.dataRowFirstTabIndex;
        for (var i = 0; i < this.tableHeight; i++)
        {
            var classname = "tableRow" + ((i+1)%2);
            maintbody.rows[i+adjust].className = classname;
            if (secondarytbody != null)
                secondarytbody.rows[i+adjust].className = classname;

            // Fix indices.
            tabidx = this.fixRowIndexes(maintbody.rows[i+adjust], tabidx, i);
        }
    }
}

ROTable.prototype.saveHeaderRows = function(tableObj2)
{
    if (this.isFixedHeader || tableObj2.isFixedHeader)
    {
        if (this.tableHeight > 0 || tableObj2.tableHeight > 0)
        {
            if (this.tableHeight > 0 && tableObj2.tableHeight > 0)
            {
                this.saveHeader(null);
                tableObj2.saveHeader(null);
            }
            else if (this.tableHeight > 0)
                this.saveHeader(tableObj2);
            else
                tableObj2.saveHeader(this);
        }
    }
}

ROTable.prototype.saveHeader = function(noHeaderObj)
{
    var mainheaderobj = document.getElementById(this.maintableid+'_header');
    this.mainheader = mainheaderobj.cloneNode(true);
    if (this.fixedColumns > 0)
    {
        var secondaryheaderobj = document.getElementById(this.secondarytableid+'_header');
        this.secondaryheader = secondaryheaderobj.cloneNode(true);
    }

    if (noHeaderObj != null)
    {
        noHeaderObj.mainheader = this.copyHeader(noHeaderObj, true);
        if (this.fixedColumns > 0)
            noHeaderObj.secondaryheader = this.copyHeader(noHeaderObj, false);
    }
}

ROTable.prototype.copyHeader = function(noHeaderObj, isMain)
{
    var fromFormName = this.form.name;
    var fromROName = this.roName;
    var toFormName = noHeaderObj.form.name;
    var toROName = noHeaderObj.roName;

    var fixedColumns = this.fixedColumns;
    var tablewidth = this.tablewidth;
    var origtbody = null;
    var tbody = null;

    if (isMain)
    {
        var origheaderobj = this.mainheader;
        origtbody = origheaderobj.tBodies[0];
        var mainheaderobj = origheaderobj.cloneNode(true);
        tbody = mainheaderobj.tBodies[0];

        // Convert toggleCheckAll(document.formname)
        var origtdnode = origtbody.rows[0].cells[0];
        var origtdchildren = origtdnode.childNodes;
        var tdnode = tbody.rows[0].cells[0];
        var tdchildren = tdnode.childNodes;
        for (var i = 0, tcLen = tdchildren.length; i < tcLen; i++)
        {
            var origchldnode = origtdchildren[i];
            var chldnode = tdchildren[i];
            if (chldnode.nodeName == "INPUT" && chldnode.name == "SelectAll")
            {
                chldnode.tabIndex = noHeaderObj.dataRowFirstTabIndex - 1;
                var fcnbody = extractOnclickFcnBdy(origchldnode);
                if (fcnbody != null && fcnbody.length > 0)
                {
                    var idx0 = fcnbody.indexOf(fromFormName);
                    if (idx0 > -1)
                    {
                        var newfcnbody = fcnbody.substring(0, idx0) + toFormName + fcnbody.substring(idx0 + fromFormName.length);
                        chldnode.onclick = new Function(newfcnbody);
                    }
                }
                break;
            }
        }
        // Convert sort() and <img id="">
        if (fixedColumns > 0)
            tablewidth = fixedColumns;
        for (var i = 0; i < tablewidth; i++)
        {
            origtdnode = origtbody.rows[0].cells[i+1];
            tdnode = tbody.rows[0].cells[i+1];
            // Change sort()
            var fcnbody = extractOnclickFcnBdy(origtdnode);
            if (fcnbody != null && fcnbody.length > 0)
            {
                var idx0 = fcnbody.indexOf(fromROName);
                var idx1 = fcnbody.indexOf(fromFormName);
                var newfcnbody = fcnbody.substring(0, idx0) + toROName + fcnbody.substring(idx0 + fromROName.length, idx1) +
                                    toFormName + fcnbody.substring(idx1 + fromFormName.length);
                tdnode.onclick = new Function(newfcnbody);
            }
            // Change <img id>
            origtdchildren = origtdnode.childNodes;
            tdchildren = tdnode.childNodes;
            for (var j = 0, tcLen = tdchildren.length; j < tcLen; j++)
            {
                var origchldnode = origtdchildren[j];
                var chldnode = tdchildren[j];
                if (chldnode.nodeName == "IMG")
                {
                    var idstr = origchldnode.id;
                    var idx0 = idstr.indexOf(fromFormName);
                    chldnode.id = idstr.substring(0, idx0) + toFormName + idstr.substring(idx0 + fromFormName.length);
                    break;
                }
            }
        }
        return mainheaderobj;
    }
    else
    {
        var origheaderobj = this.secondaryheader;
        origtbody = origheaderobj.tBodies[0];
        var secondaryheaderobj = origheaderobj.cloneNode(true);
        tbody = secondaryheaderobj.tBodies[0];
        tablewidth -= fixedColumns;
        for (var i = 0; i < tablewidth; i++)
        {
            var origtdnode = origtbody.rows[0].cells[i];
            var tdnode = tbody.rows[0].cells[i];
            // Change sort()
            var fcnbody = extractOnclickFcnBdy(origtdnode);
            if (fcnbody != null && fcnbody.length > 0)
            {
                var idx0 = fcnbody.indexOf(fromROName);
                var idx1 = fcnbody.indexOf(fromFormName);
                var newfcnbody = fcnbody.substring(0, idx0) + toROName + fcnbody.substring(idx0 + fromROName.length, idx1) +
                                    toFormName + fcnbody.substring(idx1 + fromFormName.length);
                tdnode.onclick = new Function(newfcnbody);
            }
            // Change <img id>
            var origtdchildren = origtdnode.childNodes;
            var tdchildren = tdnode.childNodes;
            for (var j = 0, tcLen = tdchildren.length; j < tcLen; j++)
            {
                var origchldnode = origtdchildren[j];
                var chldnode = tdchildren[j];
                if (chldnode.nodeName == "IMG")
                {
                    var idstr = origchldnode.id;
                    var idx0 = idstr.indexOf(fromFormName);
                    chldnode.id = idstr.substring(0, idx0) + toFormName + idstr.substring(idx0 + fromFormName.length);
                    break;
                }
            }
        }
        return secondaryheaderobj;
    }
}

ROTable.prototype.dupHeader = function(isMain)
{
    var toFormName = this.form.name;
    var toROName = this.roName;
    var fixedColumns = this.fixedColumns;
    var tablewidth = this.tablewidth;
    var origtbody = null;
    var tbody = null;

    if (isMain)
    {
        var origheaderobj = this.mainheader;
        origtbody = origheaderobj.tBodies[0];
        var mainheaderobj = origheaderobj.cloneNode(true);
        tbody = mainheaderobj.tBodies[0];

        // Convert toggleCheckAll(document.formname)
        var origtdnode = origtbody.rows[0].cells[0];
        var origtdchildren = origtdnode.childNodes;
        var tdnode = tbody.rows[0].cells[0];
        var tdchildren = tdnode.childNodes;
        for (var i = 0, tcLen = tdchildren.length; i < tcLen; i++)
        {
            var origchldnode = origtdchildren[i];
            var chldnode = tdchildren[i];
            if (chldnode.nodeName == "INPUT" && chldnode.name == "SelectAll")
            {
                chldnode.tabIndex = this.dataRowFirstTabIndex - 1;
                var newfcnbody = extractOnclickFcnBdy(origchldnode);
                if (newfcnbody != null && newfcnbody.length > 0)
                {
                    chldnode.onclick = new Function(newfcnbody);
                }
                break;
            }
        }
        // Convert sort() and <img id="">
        if (fixedColumns > 0)
            tablewidth = fixedColumns;
        for (var i = 0; i < tablewidth; i++)
        {
            origtdnode = origtbody.rows[0].cells[i+1];
            tdnode = tbody.rows[0].cells[i+1];
            // Change sort()
            var newfcnbody = extractOnclickFcnBdy(origtdnode);
            if (newfcnbody != null && newfcnbody.length > 0)
            {
                tdnode.onclick = new Function(newfcnbody);
            }
            // Change <img id>
            origtdchildren = origtdnode.childNodes;
            tdchildren = tdnode.childNodes;
            for (var j = 0, tcLen = tdchildren.length; j < tcLen; j++)
            {
                var origchldnode = origtdchildren[j];
                var chldnode = tdchildren[j];
                if (chldnode.nodeName == "IMG")
                {
                    var idstr = origchldnode.id;
                    chldnode.id = idstr;
                    break;
                }
            }
        }
        return mainheaderobj;
    }
    else
    {
        var origheaderobj = this.secondaryheader;
        origtbody = origheaderobj.tBodies[0];
        var secondaryheaderobj = origheaderobj.cloneNode(true);
        tbody = secondaryheaderobj.tBodies[0];
        tablewidth -= fixedColumns;
        for (var i = 0; i < tablewidth; i++)
        {
            var origtdnode = origtbody.rows[0].cells[i];
            var tdnode = tbody.rows[0].cells[i];
            // Change sort()
            var newfcnbody = extractOnclickFcnBdy(origtdnode);
            if (newfcnbody != null && newfcnbody.length > 0)
            {
                tdnode.onclick = new Function(newfcnbody);
            }
            // Change <img id>
            var origtdchildren = origtdnode.childNodes;
            var tdchildren = tdnode.childNodes;
            for (var j = 0, tcLen = tdchildren.length; j < tcLen; j++)
            {
                var origchldnode = origtdchildren[j];
                var chldnode = tdchildren[j];
                if (chldnode.nodeName == "IMG")
                {
                    var idstr = origchldnode.id;
                    chldnode.id = idstr;
                    break;
                }
            }
        }
        return secondaryheaderobj;
    }
}

ROTable.prototype.addHeaderRow = function()
{
    if (this.isFixedHeader && this.tableHeight == 0)
    {
        var oldheaderobj = document.getElementById(this.maintableid+'_header');
        var oldtbody = oldheaderobj.tBodies[0];
        var oldheaderrow = oldtbody.rows[0];
        var newheaderobj = this.dupHeader(true);
        var newtbody = newheaderobj.tBodies[0];
        var newheaderrow = newtbody.rows[0];
        oldtbody.replaceChild(newheaderrow, oldheaderrow);

        if (this.fixedColumns > 0)
        {
            oldheaderobj = document.getElementById(this.secondarytableid+'_header');
            oldtbody = oldheaderobj.tBodies[0];
            oldheaderrow = oldtbody.rows[0];
            newheaderobj = this.dupHeader(false);
            newtbody = newheaderobj.tBodies[0];
            newheaderrow = newtbody.rows[0];
            oldtbody.replaceChild(newheaderrow, oldheaderrow);
        }
    }
}

ROTable.prototype.removeHeaderRow = function()
{
    if (this.isFixedHeader && this.tableHeight == 0)
    {
        var mainheaderobj = document.getElementById(this.maintableid+'_header');
        var oldtbody = mainheaderobj.tBodies[0];
        var trnode = oldtbody.rows[0];
        var tdnodes = trnode.childNodes;
        for (var i = 0, tdnodelen = tdnodes.length; i < tdnodelen; i++)
        {
            var chldnode = tdnodes[tdnodes.length - 1];
            trnode.removeChild(chldnode);
        }

        if (this.fixedColumns > 0)
        {
            var secondaryheaderobj = document.getElementById(this.secondarytableid+'_header');
            oldtbody = secondaryheaderobj.tBodies[0];
            trnode = oldtbody.rows[0];
            tdnodes = trnode.childNodes;
            for (var i = 0, tdnodelen = tdnodes.length; i < tdnodelen; i++)
            {
                var chldnode = tdnodes[tdnodes.length - 1];
                trnode.removeChild(chldnode);
            }
        }
    }
}

ROTable.prototype.removeHiddenDataRow = function()
{
    if (this.isFixedHeader && this.fixedColumns > 0 && this.tableHeight == 0)
    {
        var maindataobj = document.getElementById(this.maintableid+'_data');
        var tbody = maindataobj.tBodies[0];
        for (var i = 0, nbrOfRows = tbody.rows.length; i < nbrOfRows; i++)
        {
            var trnode = tbody.rows[i];
            var tds = tbody.rows[i].cells.length;
            for (var j = 0; j < tds; j++)
            {
                var tdnode = tbody.rows[i].cells[tbody.rows[i].cells.length - 1];
                trnode.removeChild(tdnode);
            }
        }

    }
}

ROTable.prototype.moveRow = function(fromRowIdx, toTableObj, toRowIdx)
{
    var fromMainTbody = null;
    var fromSecondaryTbody = null;
    var toMainTbody = null;
    var toSecondaryTbody = null;
    var maintrnode = null;
    var secondarytrnode = null;
    var fromTableIdxDelta = (this.isFixedHeader) ? 0 : 1;
    var toTableIdxDelta = (toTableObj.isFixedHeader) ? 0 : 1;

    // Remove row from original table.
    if (this.isFixedHeader)
    {
        fromMainTbody = this.main_data_tbody_node;
        if (this.fixedColumns > 0)
            fromSecondaryTbody = this.secondary_data_tbody_node;
    }
    else
        fromMainTbody = this.main_tbody_node;

    var maintrnodewrk = fromMainTbody.rows[fromRowIdx];
    maintrnode = fromMainTbody.removeChild(maintrnodewrk);
    if (this.isFixedHeader && this.fixedColumns > 0)
    {
        var secondarytrnodewrk = fromSecondaryTbody.rows[fromRowIdx];
        secondarytrnode = fromSecondaryTbody.removeChild(secondarytrnodewrk);
    }
    this.tableHeight--;

    // Substitute form name, table object name, etc..., if necessary.
    substitution(this, toTableObj, maintrnode);

    // Add/Insert row to target table.
    if (toTableObj.isFixedHeader)
    {
        toMainTbody = toTableObj.main_data_tbody_node;
        if (toTableObj.fixedColumns > 0)
            toSecondaryTbody = toTableObj.secondary_data_tbody_node;
    }
    else
        toMainTbody = toTableObj.main_tbody_node;

    var tmpNode = null;
    if (toRowIdx >= toMainTbody.rows.length - toTableIdxDelta)
        toMainTbody.appendChild(maintrnode);
    else
    {
        tmpNode = toMainTbody.rows[toRowIdx + toTableIdxDelta];
        if (toTableObj.isFixedHeader && toTableObj.tableHeight == 0 && toMainTbody.rows.length == 1)
            toMainTbody.replaceChild(maintrnode, tmpNode);
        else
            toMainTbody.insertBefore(maintrnode, tmpNode);
    }
    if (toTableObj.isFixedHeader && toTableObj.fixedColumns > 0)
    {
        if (toRowIdx >= toSecondaryTbody.rows.length - toTableIdxDelta)
            toSecondaryTbody.appendChild(secondarytrnode);
        else
        {
            tmpNode = toSecondaryTbody.rows[toRowIdx + toTableIdxDelta];
            if (toTableObj.tableHeight == 0 && toSecondaryTbody.rows.length == 1)
                toSecondaryTbody.replaceChild(secondarytrnode, tmpNode);
            else
                toSecondaryTbody.insertBefore(secondarytrnode, tmpNode);
        }
    }
    toTableObj.tableHeight++;
}

ROTable.prototype.movingRows = function(fromRowIndices, toTableObj)
{
    var toRowIdx = -1;
    var fromRowIndex = -1;
    var nbrOfRowMoved = 0;
    var nbrOfRows = fromRowIndices.length;

    if (nbrOfRows > 0)
    {
        // For table with Fixed Header
        //  if the "To" table header row is empty, get it from its table object.
        toTableObj.addHeaderRow();

        for (var i = 0; i < nbrOfRows; i++)
        {
            fromRowIndex = fromRowIndices[i] - nbrOfRowMoved;
            if (toTableObj.sortDirection == null)
                toRowIdx = toTableObj.tableHeight;
            else
                toRowIdx = findInsertIndex(this, fromRowIndex, toTableObj);

            this.moveRow(fromRowIndex, toTableObj, toRowIdx);
            nbrOfRowMoved++;
        }

        // For table with Fixed Header
        //  if the "From" table has no more data row, replace header row with empty row.
        this.removeHeaderRow();
        //  clean up hidden data row (which are generated by resize functions when table has fixed header).
        this.removeHiddenDataRow();
    }

    this.fixTableRows(toTableObj.roName, this.roName);
    toTableObj.fixTableRows(this.roName, toTableObj.roName);

    var form = this.form;
    if (form.SelectAll != undefined)
        if (form.SelectAll.length == undefined)
            form.SelectAll.checked = false;
        else
            form.SelectAll[0].checked = false;

    resizeTables();
}

ROTable.prototype.fixRowIndex = function(trnode, tabidx, idx) {
    var cells = trnode.cells;
    for (var i = 0, cellsLen = cells.length; i < cellsLen; i++)
    {
        var wrktdnode = cells[i];
        var childNodes = wrktdnode.childNodes;
        for (var j = 0, cnLen = childNodes.length; j < cnLen; j++)
        {
            var chldnode = childNodes[j];
            if (chldnode.nodeName == "INPUT" || chldnode.nodeName == "SELECT" || chldnode.nodeName == "A")
            {
                tabidx = fixTabIndex(chldnode, tabidx);
            }
        }
    }
    return tabidx;
}

ROTable.prototype.getRowIndex = function (tag)
{
    var result = getTR(tag).rowIndex;
    if (!this.isFixedHeader)
        result--;
    return result;
}

ROTable.prototype.getColumnValues = function (colIdx)
{
    var tBody = null;
    var tgtColIdx = colIdx; 
    if (this.tableSelectable)
        tgtColIdx++;    // cater for the selection column (checkbox/radio button)
    if (!this.isFixedHeader)
        tBody = this.main_tbody_node;
    else
    {
        if (this.fixedColumns == 0)
            tBody = this.main_data_tbody_node;
        else
        {
            if (colIdx < this.fixedColumns)
                tBody = this.main_data_tbody_node;
            else
            {
                tBody = this.secondary_data_tbody_node;
                tgtColIdx = colIdx - this.fixedColumns; // no selection column on secondary table
            }
        }
    }
    
    var adjust = (this.isFixedHeader) ? 0 : 1;
    var result = new Array();
    for (var i = adjust; i < (this.tableHeight + adjust); i++)
    {
        var tdnode = tBody.rows[i].cells[tgtColIdx];
        result[result.length] = tdnode.childNodes[0].nodeValue;
    }
    return result;
}

ROTable.prototype.getSelectedRowIndices = function (fieldname)
{
    var result = new Array();
    if (this.tableSelectable)
    {
        var tBody = null;
        if (!this.isFixedHeader)
            tBody = this.main_tbody_node;
        else
            tBody = this.main_data_tbody_node;

        var adjust = (this.isFixedHeader) ? 0 : 1;

        for (var i = adjust; i < (this.tableHeight + adjust); i++)
        {
            var tdnode = tBody.rows[i].cells[0];
            var wrknodes = tdnode.childNodes;
            for (var j = 0, wnLen = wrknodes.length; j < wnLen; j++)
            {
                var anode = wrknodes[j];
                if (anode.nodeName == "INPUT" && anode.name == fieldname && anode.checked)
                {
                    result[result.length] = i;
                    break;
                }
            }
        }
    }
    return result;
}

ROTable.prototype.getRowsState = function ()
{
    var result = new Array();
    if (this.tableSelectable)
    {
        var tBody = null;
        if (!this.isFixedHeader)
            tBody = this.main_tbody_node;
        else
            tBody = this.main_data_tbody_node;

        var adjust = (this.isFixedHeader) ? 0 : 1;

        for (var i = adjust; i < (this.tableHeight + adjust); i++)
        {
            var tdnode = tBody.rows[i].cells[0];
            var wrknodes = tdnode.childNodes;
            for (var j = 0, wnLen = wrknodes.length; j < wnLen; j++)
            {
                var anode = wrknodes[j];
                if (anode.nodeName == "INPUT" && anode.name == "state")
                {
                    result[result.length] = anode.value;
                    break;
                }
            }
        }
    }
    return result;
}

ROTable.prototype.getCellValue = function (rowIdx, colIdx)
{
    var tBody = null;
    var tgtColIdx = colIdx + 1; // cater for the selection column (checkbox/radio button)
    if (!this.isFixedHeader)
        tBody = this.main_tbody_node;
    else
    {
        if (this.fixedColumns == 0)
            tBody = this.main_data_tbody_node;
        else
        {
            if (colIdx < this.fixedColumns)
                tBody = this.main_data_tbody_node;
            else
            {
                tBody = this.secondary_data_tbody_node;
                tgtColIdx = colIdx - this.fixedColumns; // no selection column on secondary table
            }
        }
    }

    var result = '';
    var tdnode = tBody.rows[rowIdx].cells[tgtColIdx];
    if (tdnode.childNodes.length > 0)
        result = tdnode.childNodes[0].nodeValue;
    return result;
}

ROTable.prototype.getRowKeys = function (keyName)
{
    var result = new Array(3);
    var allKeys = new Array(2);
    var allKeyValues = new Array();
    var allKeyStates = new Array();
    var activeKeys = new Array();
    var inactiveKeys = new Array();

    if (this.tableSelectable)
    {
        var tBody = null;
        if (!this.isFixedHeader)
            tBody = this.main_tbody_node;
        else
            tBody = this.main_data_tbody_node;

        var adjust = (this.isFixedHeader) ? 0 : 1;

        var rowsstate = this.getRowsState();
        for (var i = adjust; i < (this.tableHeight + adjust); i++)
        {
            var tdnode = tBody.rows[i].cells[0];
            var wrknodes = tdnode.childNodes;
            for (var j = 0, wnLen = wrknodes.length; j < wnLen; j++)
            {
                var anode = wrknodes[j];
                if (anode.nodeName == "INPUT" && anode.name == keyName)
                {
                    allKeyValues[allKeyValues.length] = anode.value;
                    if (rowsstate[i-adjust] == "inactive")
                    {
                        inactiveKeys[inactiveKeys.length] = anode.value;
                        allKeyStates[allKeyStates.length] = false;
                    }
                    else
                    {
                        activeKeys[activeKeys.length] = anode.value;
                        allKeyStates[allKeyStates.length] = true;
                    }
                    break;
                }
            }
        }
    }
    allKeys[0] = allKeyValues;
    allKeys[1] = allKeyStates;
    result[0] = allKeys;
    result[1] = activeKeys;
    result[2] = inactiveKeys;
    return result;
}

// rowMenuOver
function roMenuOver(tblobj)
{
    var event = window.event;
    var tag = event.srcElement;
    tblobj.lastTag = tag;
    i2uiSetMenuCoords(tag,event);
}

// rowMenuHref
function roMenuHref(menuid)
{
    i2uiShowMenu(menuid);
}

function roMenuAction(tblobj, fieldName, action)
{
    var okay = true;
    if((typeof(this['beforeRowMenuAction']) != 'undefined') && (typeof(this['beforeRowMenuAction']) == 'function'))
        okay = beforeRowMenuAction();

    if (!okay)
        return;

    var form = tblobj.form;
    var formObj = eval("form." + fieldName);
    var rowIndex = tblobj.getRowIndex(tblobj.lastTag);

    if (formObj != undefined)
    {
        if (action == 'activate')
        {
            if (formObj.length > 1)
            {
                formObj[rowIndex].value = "active";
                form.RowKey[rowIndex].disabled = false;
            }
            else
            {
                formObj.value = "active";
                form.RowKey.disabled = false;
            }
        }
        else
        {
            if (formObj.length > 1)
            {
                formObj[rowIndex].value = "inactive";
                form.RowKey[rowIndex].checked = false;
                form.RowKey[rowIndex].disabled = true;
            }
            else
            {
                formObj.value = "inactive";
                form.RowKey.checked = false;
                form.RowKey.disabled = true;
            }
        }
    }

    if((typeof(this['afterRowMenuAction']) != 'undefined') && (typeof(this['afterRowMenuAction']) == 'function'))
        afterRowMenuAction();
}

function findInsertIndex(fromTableObj, fromRowIndex, toTableObj)
{
    var sortDirection = toTableObj.sortDirection;
    var sortedColumnValues = toTableObj.getColumnValues(toTableObj.sortByColumnIdx);
    var scvLen = sortedColumnValues.length;
    var insertIdx = sortedColumnValues.length;
    var colType = determineColumnType(sortedColumnValues);
    var fromTableValue;
    if (colType > 0)
    {
        if (colType == 1)
            fromTableValue = parseFloat(fromTableObj.getCellValue(fromRowIndex, toTableObj.sortByColumnIdx));
        else if (colType == 2)
            fromTableValue = parseDate(fromTableObj.getCellValue(fromRowIndex, toTableObj.sortByColumnIdx));
        else if (colType == 3)
            fromTableValue = parseDateTime(fromTableObj.getCellValue(fromRowIndex, toTableObj.sortByColumnIdx));

        for (var rowIndex = 0; rowIndex < scvLen; rowIndex++)
        {
            if (colType == 1)
            {
                var fvalue = parseFloat(sortedColumnValues[rowIndex]);
                if (!isNaN(fvalue))
                    sortedColumnValues[rowIndex] = fvalue;
            }
            else if (colType == 2)
                sortedColumnValues[rowIndex] = parseDate(sortedColumnValues[rowIndex]);
            else if (colType == 3)
                sortedColumnValues[rowIndex] = parseDateTime(sortedColumnValues[rowIndex]);
        }
    }
    else
        fromTableValue = fromTableObj.getCellValue(fromRowIndex, toTableObj.sortByColumnIdx);

    if (sortDirection == 'dsc')
    {
        for (var i = 0; i < scvLen; i++)
            if (sortedColumnValues[i] < fromTableValue)
            {
                insertIdx = i;
                break;
            }
    }
    else
    {
        for (var i = 0; i < scvLen; i++)
            if (sortedColumnValues[i] > fromTableValue)
            {
                insertIdx = i;
                break;
            }
    }
    return insertIdx;
}

function substitution(fromTableObj, toTableObj, maintrnode)
{
    var fromROName = fromTableObj.roName;
    var toROName = toTableObj.roName;
    var rowChildren = maintrnode.childNodes;
loopSubst1:
    for (var i = 0, rcLen = rowChildren.length; i < rcLen; i++)
    {
        var rowChild = rowChildren[i];
        if (rowChild.nodeName == "TD")
        {
            var menuChildren = rowChild.childNodes;
            for (var j = 0, mcLen = menuChildren.length; j < mcLen; j++)
            {
                var menuChild = menuChildren[j];
                if (menuChild.nodeName == "A")
                {
                    // Change onmouseover function.
                    var fcnbody = extractOnMouseOverFcnBdy(menuChild);
                    if (fcnbody != null && fcnbody.length > 0)
                    {
                        var idx0 = fcnbody.indexOf(fromROName);
                        if (idx0 > -1)
                        {
                            var newfcnbody = fcnbody.substring(0, idx0) + toROName + fcnbody.substring(idx0 + fromROName.length);
                            menuChild.onmouseover = new Function(newfcnbody);
                        }
                    }
                    // Change roMenuHref parameter value.
                    var nodehref = menuChild.href;
                    if (nodehref != null && nodehref.length > 0)
                    {
                        var idx0 = nodehref.indexOf(fromROName);
                        if (idx0 > -1)
                        {
                            var idx1 = nodehref.lastIndexOf(fromROName);
                            if (idx0 == idx1)
                                menuChild.href = nodehref.substring(0, idx0) + toROName + nodehref.substring(idx0 + fromROName.length);
                            else
                                menuChild.href = nodehref.substring(0, idx0) + toROName + nodehref.substring(idx0 + fromROName.length, idx1) +
                                                    toROName + nodehref.substring(idx1 + fromROName.length);
                        }
                    }

                    break loopSubst1;
                }
            }
        }
    }
}

function extractOnMouseOverFcnBdy(aNode)
{
    var fcnString = null;
    if (aNode.onmouseover != null)
    {
        fcnString = aNode.onmouseover.toString();
        if (fcnString != null && fcnString != "")
        {
            var idx0 = fcnString.indexOf("{");
            var idx1 = fcnString.lastIndexOf("}");
            fcnString = trimBeginEnd(fcnString.substring(idx0+1, idx1));
        }
    }
    return fcnString;
}

function extractOnclickFcnBdy(aNode)
{
    var fcnString = null;
    if (aNode.onclick != null)
    {
        fcnString = aNode.onclick.toString();
        if (fcnString != null && fcnString != "")
        {
            var idx0 = fcnString.indexOf("{");
            var idx1 = fcnString.lastIndexOf("}");
            fcnString = trimBeginEnd(fcnString.substring(idx0+1, idx1));
        }
    }
    return fcnString;
}

function addInputTextHiddenField(placeHolder, fieldname, fieldvalue)
{
    var plchdr = document.getElementById(placeHolder);
    var fld = document.createElement("INPUT");
    fld.setAttribute("type", "HIDDEN");
    fld.setAttribute("name", fieldname);
    fld.setAttribute("value", fieldvalue);
    plchdr.appendChild(fld);
}

// Check if there are selected rows. Reports error if none.
ROTable.prototype.checkHasSelectedRow = function(errormsg) {
    return this.checkHasSelectedRow_(this.getRowKeyObject(), errormsg);
}

// ---------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------
//                                  Updateable Table support
// ---------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------

function UpdateableTable(prefix,
                         maintableid, 
                         isMassEntryRow, 
                         startTabIndex, 
                         isFixedHeader, 
                         fieldNames, 
                         matrixOriginalValues,
                         displayHeight, 
                         tablewidth, 
                         headerDescs)
{
    this.initBaseTable(prefix, maintableid, isFixedHeader, displayHeight, tablewidth);
    this.hasMassEntryRow      = isMassEntryRow;
    this.firstTabIndex        = startTabIndex;
    this.indexDelta           = 0;
    this.matrixOriginalValues = matrixOriginalValues;
    this.fieldNames           = fieldNames;
    this.columns              = fieldNames.length;
    this.isTableModified      = false;
    this.headerDescs          = headerDescs;
    //i2uitrace(0, 'UpdateableTable('+"maintableid="+maintableid+", isMassEntryRow="+isMassEntryRow+", startTabIndex="+startTabIndex+", isFixedHeader="+isFixedHeader+')');

    if (this.main_tbody_node.hasChildNodes())
    {
        // Find out the first tab index value.
        var first_row = null;

        if (!this.isFixedHeader)
            this.indexDelta++;

        if (this.hasMassEntryRow)
            this.indexDelta++;

        this.first_row = this.main_tbody_node.rows[this.indexDelta];
        this.firstTabIndex = this.getRowFirstTabIndex(this.first_row);

        this.comboBoxIndex = new Array();

        // Make a copy of an existing row for add/insert action.
        var rows = this.main_tbody_node.rows;
        var last_row = rows[rows.length - 1];
        if (last_row != null && last_row.nodeName == "TR")
        {
            // Keep track of ComboBox pre-selected index.
            // This is necessary because Microsoft IE does not retain the pre-selected index
            // on duplication.  Pre-selected index is set to zero by IE automatically.
            // Netscape has no such problem.
            var cells = last_row.cells;
            for (var j = 0, cellsLen = cells.length; j < cellsLen; j++)
            {
                var tdnode = cells[j];
                var childNodes = tdnode.childNodes;
                for (var k = 0, cnLen = childNodes.length; k < cnLen; k++)
                {
                    var wrkChild = childNodes[k];
                    if (wrkChild.nodeName == 'SELECT')
                        this.comboBoxIndex[this.comboBoxIndex.length] = wrkChild.selectedIndex;
                }
            }
            this.sample_node = last_row.cloneNode(true);
            this.main_tbody_node.removeChild(last_row);
        }
    }
    //i2uitrace(0, 'UpdateableTable.indexDelta='+this.indexDelta);
}

UpdateableTable.prototype = new BaseTable();
UpdateableTable.prototype.constructor = UpdateableTable;

UpdateableTable.prototype.isModified = function(tag)
{
   return this.isTableModified;
}

// Return row index of updateable table (without special rows)
UpdateableTable.prototype.getRowIndex = function(tag)
{
   var result = getTR(tag).rowIndex - this.indexDelta;
   //i2uitrace(0, 'getRowIndex('+tag.tagName+', indexDelta='+this.indexDelta+')->'+result);
   return result;
}

// Return column index of updateable table
UpdateableTable.prototype.getColumnIndex = function(tag)
{
   return getTD(tag).cellIndex - 1;
}

// Check if action icon exists in the first column of a particular row.
// rowIdx = the row number in which action occurs (0,1, ...).
// iconType = the type of action icon to be checked (deleteAction, editAction, newAction).
// wantToAdd = if the above icon type not found, do you want to add it. (true = want to add, false = do not want to add)
// replaceByIconType = the type of action icon to replace the checked icon (deleteAction, editAction, newAction).
// Note: When wantToAdd = true, replaceByIconType must be null.
UpdateableTable.prototype.checkAndManageIcon = function (rowIdx, iconType, wantToAdd, replaceByIconType)
{
    var iconsrc = getIconSrc(iconType);
    var iconExisted = false;
    var aNode = null;
    var tdnode = this.main_tbody_node.rows[parseInt(rowIdx)+this.indexDelta].cells[0];
    var childNodes = tdnode.childNodes;

    for (var i = 0, cnLen = childNodes.length; i < cnLen; i++)
    {
        aNode = childNodes[i];
        if (aNode.nodeName == "IMG" && aNode.src.indexOf(iconsrc) > -1)
        {
            iconExisted = true;
            break;
        }
    }
    if (!iconExisted)
    {   // Add the checked icon if wantToAdd is true and replaceByIconType = null.
        if (wantToAdd && (replaceByIconType == null || replaceByIconType.length == 0))
        {
            var iconNode = getIcon(iconType);
            if (iconNode != null)
            {
                var endNode = null;
                aNode = null;
                childNodes = tdnode.childNodes;
                for (var i = 0, cnLen = childNodes.length; i < cnLen; i++)
                {
                    endNode = childNodes[i];
                    if (endNode.nodeName == "A")
                    {
                        var wrkNodes = endNode.childNodes;
                        for (var j = 0, wnLen = wrkNodes.length; j < wnLen; j++)
                        {
                            if (wrkNodes[j].nodeName == "IMG" && wrkNodes[j].src.indexOf(menuIcon) > -1)
                                aNode = endNode;
                        }
                    }
                    else if (endNode.nodeName == "INPUT" && endNode.type.toUpperCase() != "HIDDEN")
                        aNode = endNode;
                }
                if (aNode != null)
                {
                    endNode = aNode.nextSibling;
                    if (endNode != null)
                        tdnode.insertBefore(iconNode, endNode);
                    else
                        tdnode.appendChild(iconNode);
                }
                else
                    tdnode.appendChild(iconNode);
            }
        }
    }
    else
    {
        if (replaceByIconType != null)
        {   // If replaceByIconType has an actionType, replace the checked icon with the appropriate action icon.
            if (replaceByIconType.length > 0)
            {
                var iconNode = getIcon(replaceByIconType);
                if (iconNode != null)
                    tdnode.replaceChild(iconNode, aNode);
            }
            else    // If replaceByIconType is an empty string, means remove the checked icon.
                tdnode.removeChild(aNode);
        }
    }
    return iconExisted;
}

UpdateableTable.prototype.rowModified = function(rowIdx)
{
    if (!this.isNewRow(rowIdx))
    {
        this.checkAndManageIcon(rowIdx, editAction, true, null);
    }
    this.isTableModified = true;
    this.setSelectedRowIdx(rowIdx);
}


UpdateableTable.prototype.insertRow = function(rowIdx)
{
    var idx = parseInt(rowIdx);
    var new_node = this.dupData();
    if (new_node != null)
    {
        var curr_row = this.main_tbody_node.rows[idx + this.indexDelta];
        this.main_tbody_node.insertBefore(new_node, curr_row);

        for (var i = 0; i < this.columns; i++)
            this.matrixOriginalValues[this.matrixOriginalValues.length] = '';

        // shift rows in matrix of initial values
        for (var i = this.matrixOriginalValues.length - 1; i >= (idx * this.columns) + this.columns; i--)
            this.matrixOriginalValues[i] = this.matrixOriginalValues[i - this.columns];

        for (var i = 0; i < this.columns; i++)
            this.matrixOriginalValues[i + (idx * this.columns)] = this.matrixOriginalValues[this.matrixOriginalValues.length - this.columns + i];

        this.fixIndexes2(idx);
        focusOnRow(new_node);
    }
}

UpdateableTable.prototype.deleteRow = function(rowIdx)
{
    // If this is a new record, physically remove it from table.
    var idx = parseInt(rowIdx);
    var newIconExisted = this.checkAndManageIcon(idx, newAction, false, null);
    if (newIconExisted)
    {
        this.removeRow(idx);
        this.fixIndexes2(idx);
        // shift values up row by row.
        var matrixIdx = idx * this.columns;
        var limit = (this.main_tbody_node.rows.length - this.indexDelta + 1) * this.columns;
        for (var i = matrixIdx; i < limit; i++)
            this.matrixOriginalValues[i] = this.matrixOriginalValues[i + this.columns];

        // Make "matrixOriginalValues" to have new values.
        var wrkArray = new Array(this.matrixOriginalValues.length - this.columns);
        for (var i = 0, waLen = wrkArray.length; i < waLen; i++)
            wrkArray[i] = this.matrixOriginalValues[i];

        this.matrixOriginalValues = wrkArray;
    }
    else
    {
        // If edited icon already existed, replace it by the delete icon and mark the record as deleted.
        var editedIconExisted = this.checkAndManageIcon(idx, editAction, false, deleteAction);
        if (editedIconExisted)
            this.markRowAsDeleted(idx);
        else
        {   // If record already marked as deleted, do nothing.
            // If record is live, mark the record as deleted.
            var deletedIconExisted = this.checkAndManageIcon(idx, deleteAction, true, null);
            if (!deletedIconExisted)
                this.markRowAsDeleted(idx);
        }
    }
}

UpdateableTable.prototype.addRows = function(nbrOfRows)
{
    for (var i = 0; i < nbrOfRows; i++)
        this.addRow();
	focusOnRow(this.main_tbody_node.rows[this.main_tbody_node.rows.length - nbrOfRows]);
}

UpdateableTable.prototype.addRow = function()
{
    this.appendRow();
    // create elements for additional row
    for (var i = 0; i < this.columns; i++)
        this.matrixOriginalValues[this.matrixOriginalValues.length] = '';

    // copy initial values into new row
    var idx = this.matrixOriginalValues.length - 1;
    for (var i = idx; i > (idx - this.columns); i--)
        this.matrixOriginalValues[i] = this.matrixOriginalValues[i - this.columns];
}

UpdateableTable.prototype.fixRowIndexes = function(trnode, tabidx, idx)
{
    var cells = trnode.cells;
    for (var i = 0, cellsLen = cells.length; i < cellsLen; i++)
    {
        var wrktdnode = cells[i];
        var childNodes = wrktdnode.childNodes;
        for (var j = 0, cnLen = childNodes.length; j < cnLen; j++)
        {
            var chldnode = childNodes[j];
            if (chldnode.nodeName == "INPUT" || chldnode.nodeName == "SELECT" || chldnode.nodeName == "A")
            {
                tabidx = fixTabIndex(chldnode, tabidx);

                // FIXME: This code was "inherited" from tables. The code may need some cleaning..
                // Fix "this.form.SelectedRow.value=0", "updateSelectedIndex (0, form)"
                if (i == 0) // Only for the selection column
                {
                    if (chldnode.nodeName == "INPUT" && chldnode.name == "RowKey")
                    {
                        var fcnbody = extractOnclickFcnBdy(chldnode);
                        if (fcnbody != null && fcnbody.length > 0)
                        {
                            var newfcnbody = null;
                            var idx0 = fcnbody.indexOf("SelectedRow");
                            var idx1 = -1;
                            if (idx0 > -1)
                            {
                                idx0 = fcnbody.indexOf("=", idx0);
                                idx1 = fcnbody.indexOf(";", idx0);
                            }
                            var idx2 = fcnbody.indexOf("updateSelectedIndex");
                            var idx3 = -1;
                            if (idx2 > -1)
                            {
                                idx2 = fcnbody.indexOf("(", idx2);
                                idx3 = fcnbody.indexOf(")", idx2);
                            }
                            if (idx0 > -1 && idx2 > -1)
                                newfcnbody = fcnbody.substring(0, idx0+1) + idx + fcnbody.substring(idx1, idx2+1) + idx + fcnbody.substring(idx3);
                            else if (idx0 > -1)
                                newfcnbody = fcnbody.substring(0, idx0+1) + idx + fcnbody.substring(idx1);
                            else if (idx2 > -1)
                                newfcnbody = fcnbody.substring(0, idx2+1) + idx + fcnbody.substring(idx3);

                            if (newfcnbody != null)
                            {
                                chldnode.onclick = new Function(newfcnbody);
                            }
                        }
                    }
                }
            }
        }
    }
    return tabidx;
}

UpdateableTable.prototype.appendRow = function()
{
    var tabidx = this.firstTabIndex;
    var new_node = this.dupData();

    if (new_node != null)
    {
        this.main_tbody_node.appendChild(new_node);
        var rowIdx = this.main_tbody_node.rows.length - 1;
        if (rowIdx > this.indexDelta)
            tabidx = this.getRowLastTabIndex(this.main_tbody_node.rows[rowIdx-1]);

        rowIdx = rowIdx - this.indexDelta;
   		var rown = (Math.abs(rowIdx-1))%2;
      	new_node.className = TABLE_ROW + rown;
        tabidx = this.fixRowIndexes(new_node, tabidx, rowIdx);

        // Fix footer buttons index
        fixButtonsIndex(tabidx);
    }
}

UpdateableTable.prototype.removeUntouchedNewRows = function(keepOneRow)
{
    var rtnVal = false;
    var newRows = this.getActionedRows(newAction);
    var newRowsLen = newRows.length;
    // If new rows exist.
    if (newRowsLen > 0)
    {
        var defaultValues = new Array(this.columns);
        var idx = this.matrixOriginalValues.length;
        for (var j = 0; j < this.columns; j++)
            defaultValues[j] = this.matrixOriginalValues[idx - this.columns + j];

        var startIndex = 0;
        if (!isEmptyListAllowed)
        {
            if (this.getNumberOfTouchedNewRows() == 0 || keepOneRow)
            {
                var totalRows = this.getNumberOfRows();
                if (totalRows == this.getNumberOfDeletedRows() + newRowsLen)
                    startIndex = 1;
            }
        }
        var rowsDeleted = 0;
        for (var i = startIndex; i < newRowsLen; i++)
        {
            var actualRowIdx = newRows[i] - rowsDeleted + this.indexDelta;
            var virtualRowIdx = newRows[i] - rowsDeleted;
            var cells = this.main_tbody_node.rows[actualRowIdx].cells;
            var maxColumns = cells.length;
            var elem = 0;

            // Start comparing from column 1 because column 0 is the menu column.
loopDUNR1:
            for (var j = 1; j < maxColumns; j++)
            {
                var tdnode = cells[j];
                var childNodes = tdnode.childNodes;
loopDUNR2:
                for (var k = 0, cnLen = childNodes.length; k < cnLen; k++)
                {
                    var chldnode = childNodes[k];
                    if (chldnode.nodeName == "INPUT")
                    {   // Input field
                        var nodeType = chldnode.type.toUpperCase();
                        if (nodeType != "HIDDEN")
                        {
                            if (nodeType == "TEXT")
                            {   // Text input field
                                if (chldnode.value != defaultValues[elem])
                                    break loopDUNR1;
                            }
                            else if (nodeType == "CHECKBOX" || nodeType == "RADIO")
                            {   // Check Box or Radio button
                                if (!(chldnode.checked && (defaultValues[elem] == "checked") ||
                                     !chldnode.checked && !(defaultValues[elem] == "checked")))
                                    break loopDUNR1;
                            }
                        }
                        elem++;
                        break loopDUNR2;
                    }
                    else if (chldnode.nodeName == "SELECT")
                    {   // Combo Box
                        if (defaultValues[elem][0] != chldnode.options[chldnode.selectedIndex].value)
                            break loopDUNR1;
                        
                        elem++;
                        break loopDUNR2;
                    }
                    else if (chldnode.nodeName == "#text")
                    {   // Read only field
                        elem++;
                        break loopDUNR2;
                    }
                }
                // In case the cell <TD> has no child, increment index for default value array is necessary.
                if (childNodes.length == 0)
                    elem++;
                
                // If this is the last column, this means the new row has not been changed.
                // Delete the current row.
                if (j == (maxColumns - 1))
                {
                    this.deleteRow(virtualRowIdx);
                    rowsDeleted++;
                }
            }
        }
        if (rowsDeleted > 0)
            rtnVal = true;
    }
    return rtnVal;
}

// Assumed only one value to be restored per column.
UpdateableTable.prototype.resetRowValues = function(rowIdx)
{
    var idx = parseInt(rowIdx);
    var trnode = this.main_tbody_node.rows[idx + this.indexDelta];
    var matrixIndex = idx * this.columns;
    var cells = trnode.cells;
    for (var i = 1, cellsLen = cells.length; i < cellsLen; i++)
    {
        var tdnode = cells[i];

        var childLength = tdnode.childNodes.length;
        var displayValue = null;
        var keyValue = null;
        if(this.matrixOriginalValues[matrixIndex] instanceof Array)
        {
            keyValue = reverseSpecialChars((this.matrixOriginalValues[matrixIndex])[0]);
            displayValue = (this.matrixOriginalValues[matrixIndex])[1];
        }
        else
        {
            keyValue = this.matrixOriginalValues[matrixIndex];
            displayValue = keyValue;
        }
        displayValue = reverseSpecialChars(displayValue);

        //i2uitrace(0, "length="+childLength+", original value:"+this.matrixOriginalValues[matrixIndex]);
        if (childLength == 0)
        {
            var new_node = document.createTextNode(displayValue);
            tdnode.appendChild(new_node);
        }
        else
        {
            var inputRestored = false;
            var inputHiddenRestored = false;
            var selectRestored = false;
            var textRestored = false;
            for (var j = 0; j < childLength; j++)
            {
                var chldnode = tdnode.childNodes[j];
                //i2uitrace(0, "chldnode.nodeName="+chldnode.nodeName);
                if (chldnode.nodeName == "INPUT")
                {
                    var chldnodeType = chldnode.type.toUpperCase();
                    if (chldnodeType != "HIDDEN")
                    {
                        if (chldnodeType == "TEXT")
                        {
                            if (!inputRestored)
                            {
                                chldnode.value = displayValue;
                                inputRestored = true;
                            }
                        }
                        else if (chldnodeType == "CHECKBOX" || chldnodeType == "RADIO")
                        {
                            if (!inputRestored)
                            {
                                chldnode.checked = (this.matrixOriginalValues[matrixIndex] == "checked");
                                inputRestored = true;
                            }
                        }
                    }
                    else
                    {
                        if (!inputHiddenRestored)
                        {
                            chldnode.value = keyValue;
                            inputHiddenRestored = true;
                        }
                    }
                }
                else if (chldnode.nodeName == "SELECT")
                {
                    if (!selectRestored)
                    {
                        chldnode.value = keyValue;
                        selectRestored = true;
                    }
                }
                else if (chldnode.nodeName == "#text")
                {
                    if (!textRestored && !selectRestored && !inputRestored)
                    {
                        chldnode.nodeValue = displayValue;
                        textRestored = true;
                    }
                }
            }
        }
        matrixIndex++;
    }
}

UpdateableTable.prototype.getKey = function(rowIdx)
{
    var trnode = this.main_tbody_node.rows[parseInt(rowIdx)+this.indexDelta];
    // First column processing.
    var tdnode = trnode.cells[0];
    var childNodes = tdnode.childNodes;
	var key = null;
    for (var i = 0, cnLen = childNodes.length; i < cnLen; i++)
    {
        var chldnode = childNodes[i];
        if (chldnode.nodeName == "INPUT")
        {
            var nodeType = chldnode.type.toUpperCase();

            if (nodeType == "HIDDEN" && chldnode.name == KEYS)
			{
                key = chldnode.value;
				break;
			}
		}
    }

	return key;
}


UpdateableTable.prototype.markRowAsDeleted = function(rowIdx)
{
    var trnode = this.main_tbody_node.rows[parseInt(rowIdx)+this.indexDelta];
    // First column processing.
    var tdnode = trnode.cells[0];
    var childNodes = tdnode.childNodes;
    var selectedIndexName = this.getSelectedIndexName();
    var KEYS = this.getKeysName();
    for (var i = 0, cnLen = childNodes.length; i < cnLen; i++)
    {
        var chldnode = childNodes[i];
        if (chldnode.nodeName == "INPUT")
        {
            var nodeType = chldnode.type.toUpperCase();

            // Set Key value to "DeleteID" concatenate with the original key value.
            if (nodeType == "HIDDEN" && chldnode.name == KEYS)
                chldnode.value = DELETE_ID + chldnode.value;
            // Set SelectedIndex.value = '' (empty).
            else if (nodeType == "HIDDEN" && chldnode.name == selectedIndexName)
            {
                if (chldnode.nodeName == "INPUT" && chldnode.name == selectedIndexName && chldnode.value.length > 0)
                    chldnode.value = '';
            }
            // Disable Radio button if exists.
            else if (nodeType == "RADIO")
            {
                chldnode.checked = false; //For the first column, it doesn't make sense to keep this button being selected.
                chldnode.disabled = true;
            }
            // Disable Checkbox if exists.
            else if (nodeType == "CHECKBOX")
            {
                chldnode.checked = false;//For the first column, it doesn't make sense to keep this checkbox being checked.
                chldnode.disabled = true;
            }
        }
    }

	// Disable all input capable fields and icons from second column onwards.
    var aiLen = activeIconArray.length;
    for (var i = 1, tcLen = trnode.cells.length; i < tcLen; i++)
    {
        tdnode = trnode.cells[i];
        for (var j = 0, tdcnLen = tdnode.childNodes.length; j < tdcnLen; j++)
        {
            var chldnode = tdnode.childNodes[j];
            if (chldnode.nodeName == "INPUT")
                chldnode.disabled = true;
            else if (chldnode.nodeName == "SELECT")
                chldnode.disabled = true;
            else if (chldnode.nodeName == "A")
            {
                // If Anchor node has associated image node, replace active icon by inactive icon.
                if (chldnode.hasChildNodes())
                {
                    var imgnode = chldnode.childNodes[0];
                    if (imgnode.nodeName == "IMG")
                    {
                        var imgsrc = imgnode.src;
                        // If active icon exists, change it to inactive icon.
                        for (var k = 0; k < aiLen; k++)
                        {
                            var idx0 = imgsrc.indexOf(activeIconArray[k]);
                            if (idx0 > -1)
                            {
                                imgsrc = imgsrc.substring(0, idx0) + inactiveIconArray[k];
                                break;
                            }
                        }
                        imgnode.src = imgsrc;
                    }
                }
            }
        }
    }
}

UpdateableTable.prototype.unmarkDeletedRow = function(rowIdx)
{
    var trnode = this.main_tbody_node.rows[parseInt(rowIdx)+this.indexDelta];
    var tdnode = null;
    var cells = trnode.cells;
    var iiLen = inactiveIconArray.length;
    // Enable all input capable fields and icons from second column onwards.
    for (var i = 1, cellsLen = cells.length; i < cellsLen; i++)
    {
        tdnode = cells[i];
        var childNodes = tdnode.childNodes;
        for (var j = 0, cnLen = childNodes.length; j < cnLen; j++)
        {
            var chldnode = childNodes[j];
            if (chldnode.nodeName == "INPUT")
                chldnode.disabled = false;
            else if (chldnode.nodeName == "SELECT")
                chldnode.disabled = false;
            else if (chldnode.nodeName == "A")
            {
                // If Anchor node has associated image node, replace inactive icon by active icon.
                if (chldnode.hasChildNodes())
                {
                    var imgnode = chldnode.childNodes[0];
                    if (imgnode.nodeName == "IMG")
                    {
                        var imgsrc = imgnode.src;
                        // If inactive icon exists, change it to active icon.
                        for (var k = 0; k < iiLen; k++)
                        {
                            idx0 = imgsrc.indexOf(inactiveIconArray[k]);
                            if (idx0 > -1)
                            {
                                imgsrc = imgsrc.substring(0, idx0) + activeIconArray[k];
                                break;
                            }
                        }
                        imgnode.src = imgsrc;
                    }
                }
            }
        }
    }
    // First column processing.
    tdnode = trnode.cells[0];
    for (var i = 0, tcnLen = tdnode.childNodes.length; i < tcnLen; i++)
    {
        var chldnode = tdnode.childNodes[i];
        if (chldnode.nodeName == "INPUT")
        {
            var nodeType = chldnode.type.toUpperCase();
            // Remove "DeleteID" from Key value.
            if (nodeType == "HIDDEN" && chldnode.name == KEYS)
                chldnode.value = chldnode.value.substring(DELETE_ID.length);
            // SelectedIndex.value remains empty.
            // ...
            // Enable Radio button if exists.
            else if (nodeType == "RADIO")
                chldnode.disabled = false;
            // Enable Checkbox if exists.
            else if (nodeType == "CHECKBOX")
                chldnode.disabled = false;
        }
    }
}

UpdateableTable.prototype.resetRowStatus = function(rowIdx)
{
    var idx = parseInt(rowIdx);
    var editedIconExisted = this.checkAndManageIcon(idx, editAction, false, "");
    if (!editedIconExisted)
    {
        var deletedIconExisted = this.checkAndManageIcon(idx, deleteAction, false, "");
        if (deletedIconExisted)
            this.unmarkDeletedRow(idx);
    }
}

// Internal function.
UpdateableTable.prototype.removeRow = function(rowIdx)
{
    var sel_node = this.main_tbody_node.rows[parseInt(rowIdx)+this.indexDelta];
    this.main_tbody_node.removeChild(sel_node);
}

function dumpCombos(text, row) {
    var oldCells = row.cells;
    for (var j = 0, ocLen = oldCells.length; j < ocLen; j++)
    {
        var old_tdnode = oldCells[j];
        var old_childNodes = old_tdnode.childNodes;
        for (var k = 0, ocnLen = old_childNodes.length; k < ocnLen; k++)
        {
            var wrkChild = old_childNodes[k];
            if (wrkChild.nodeName == "SELECT")
                alert(text+' selectedIndex='+wrkChild.selectedIndex);
        }
    }
}

// Internal function.
UpdateableTable.prototype.dupData = function()
{
    var newNode = this.sample_node.cloneNode(true);
    // Set ComboBox pre-selected index if applicable.
    if (this.comboBoxIndex.length > 0)
    {
        var k = 0;
        var newChildNodes = newNode.childNodes;
        for (var i = 0, ncnLen = newChildNodes.length; i < ncnLen; i++)
        {
            var tdnode = newChildNodes[i];
            if (tdnode.nodeName == 'TD')
            {
                var newChildNodes2 = tdnode.childNodes;
                for (var j = 0, ncn2Len = newChildNodes2.length; j < ncn2Len; j++)
                {
                    var wrkChild = newChildNodes2[j];
                    if (wrkChild.nodeName == 'SELECT')
                    {
                        if (wrkChild.options.length > 0 && this.comboBoxIndex[k] > 0)
                            wrkChild.options[this.comboBoxIndex[k]].selected = true;
                        k++;
                    }
                }
            }
        }
    }
    return newNode;
}

UpdateableTable.prototype.fixIndexes2 = function(rowIdx)
{
    var tabidx = this.firstTabIndex;
    var idx = parseInt(rowIdx) + this.indexDelta;
    if (idx > this.indexDelta)
        tabidx = this.getRowLastTabIndex(this.main_tbody_node.rows[idx-1]);

    if (this.main_tbody_node.rows.length > this.indexDelta)
    {
        var rows = this.main_tbody_node.rows;
        for (var i = idx, rowsLen = rows.length; i < rowsLen; i++)
        {
            var trnode = rows[i];
            var rown = (i+this.indexDelta+1)%2;
            trnode.className = TABLE_ROW + rown;
            tabidx = this.fixRowIndexes(trnode, tabidx, (i-this.indexDelta));
        }
    }

    // Fix footer buttons index
    fixButtonsIndex(tabidx);
}

UpdateableTable.prototype.getRowFirstTabIndex = function(aNode)
{
    var wrkTabIdx = this.firstTabIndex;
loopGRFTI01:
    for (var j = 0, acLen = aNode.cells.length; j < acLen; j++)
    {
        var tdnode = aNode.cells[j];
        for (var k = 0, tcnLen = tdnode.childNodes.length; k < tcnLen; k++)
        {
            var chldnode = tdnode.childNodes[k];
            if ((chldnode.nodeName == "INPUT" && chldnode.type.toUpperCase() != "HIDDEN") || chldnode.nodeName == "SELECT")
       	    {
                if (chldnode.tabIndex != null)
                {
                    wrkTabIdx = chldnode.tabIndex;
                    break loopGRFTI01;
                }
       	    }
        }
    }
    return wrkTabIdx;
}

UpdateableTable.prototype.getRowLastTabIndex = function(aNode)
{
    var wrkTabIdx = this.firstTabIndex;
    var cells = aNode.cells;
loopGRLTI01:
    for (var j = cells.length - 1; j > -1; j--)
    {
        var tdnode = cells[j];
        var childNodes = tdnode.childNodes;
        for (var k = childNodes.length - 1; k > -1; k--)
        {
            var chldnode = childNodes[k];
            if ((chldnode.nodeName == "INPUT" && chldnode.type.toUpperCase() != "HIDDEN") ||
                 chldnode.nodeName == "SELECT" || chldnode.nodeName == "A")
       	    {
                if (chldnode.tabIndex != null)
                {
                    wrkTabIdx = chldnode.tabIndex;
                    break loopGRLTI01;
                }
       	    }
        }
    }
    return wrkTabIdx;
}

UpdateableTable.prototype.focusOnRowByIdx = function(rowIdx)
{
    var idx = parseInt(rowIdx);
    var aNode = this.main_tbody_node.rows[idx+this.indexDelta];
    focusOnRow(aNode);
}

// You know the field name and you know the row index in which the field is located.
// rowIdx = the row index.
// fldName = the field name.
UpdateableTable.prototype.focusOnCellWithRowIndexAndFieldName = function(rowIdx, fldName)
{
    var idx = parseInt(rowIdx);
    var aNode = this.main_tbody_node.rows[idx+this.indexDelta];
    focusOnCellWithRowNodeAndFieldName(aNode, fldName);
}

// Returns true, if index corresponds to existing row
UpdateableTable.prototype.isExistingRow = function(rowIndex) {
    var result = isInList(this.getActionedRows(editAction), rowIndex) || 
                 isInList(this.getActionedRows(untouchAction), rowIndex);
    return result;
}

// Returns true, if index corresponds to existing edited row
UpdateableTable.prototype.isEditedRow = function(rowIndex) {
    return this.isRowWithIcon(parseInt(rowIndex)+this.indexDelta, editAction);
}

// Returns true, if index corresponds to existing deleted row
UpdateableTable.prototype.isDeletedRow = function(rowIndex) {
    return this.isRowWithIcon(parseInt(rowIndex)+this.indexDelta, deleteAction);
}

// Returns true, if index corresponds to existing untouched row
UpdateableTable.prototype.isUntouchedRow = function(rowIndex) {
    var delIconSrc  = getIconSrc(deleteAction);
    var editIconSrc = getIconSrc(editAction);
    var newIconSrc  = getIconSrc(newAction);

    var result      = true;
    var aNode       = null;
    var childNodes  = this.main_tbody_node.rows[rowIndex].cells[0].childNodes;
    for (var j = 0, cnLen = childNodes.length; j < cnLen; j++)
    {
        aNode = childNodes[j];
        if (aNode.nodeName == "IMG" && 
            (aNode.src.indexOf(delIconSrc) > -1 ||
             aNode.src.indexOf(editIconSrc) > -1 ||
             aNode.src.indexOf(newIconSrc) > -1))
        {
            result = false;
            break;
        }
    }
    return result;
}

// Returns true, if index corresponds to new row
UpdateableTable.prototype.isNewRow = function(rowIndex) {
    return this.isRowWithIcon(parseInt(rowIndex)+this.indexDelta, newAction);
}

// Returns true, if index corresponds to row with specified icon
UpdateableTable.prototype.isRowWithIcon = function(rowIndex, iconType) {
    var iconSrc     = getIconSrc(iconType);
    var result      = false;
    var aNode       = null;
    var childNodes  = this.main_tbody_node.rows[rowIndex].cells[0].childNodes;
    for (var j = 0, cnLen = childNodes.length; j < cnLen; j++)
    {
        aNode = childNodes[j];
        if (aNode.nodeName == "IMG" && aNode.src.indexOf(iconSrc) > -1)
        {
            result = true;
            break;
        }
    }
    return result;
}

UpdateableTable.prototype.getNumberOfNewRows = function()
{
    return this.getActionedRows(newAction).length;
}

UpdateableTable.prototype.getNumberOfDeletedRows = function()
{
    return this.getActionedRows(deleteAction).length;
}

// Get number of rows excluding the header row.
UpdateableTable.prototype.getNumberOfRows = function()
{
    return this.main_tbody_node.rows.length - this.indexDelta;
}

UpdateableTable.prototype.getNumberOfTouchedNewRows = function()
{
    var count = 0;
    var newRows = this.getActionedRows(newAction);
    // If new rows exist.
    if (newRows.length > 0)
    {
        for (var i = 0, nrLen = newRows.length; i < nrLen; i++)
        {
            var actualRowIdx = newRows[i] + this.indexDelta;
            var virtualRowIdx = newRows[i];
            var maxColumns = this.main_tbody_node.rows[actualRowIdx].cells.length;
            var elem = this.columns * virtualRowIdx;

            // Start comparing from column 1 because column 0 is the menu column.
loopNTNR1:
            for (var j = 1; j < maxColumns; j++)
            {
                var tdnode = this.main_tbody_node.rows[actualRowIdx].cells[j];
                var childNodes = tdnode.childNodes;
loopNTNR2:
                for (var k = 0, cnLen = childNodes.length; k < cnLen; k++)
                {
                    var chldnode = childNodes[k];
                    if (chldnode.nodeName == "INPUT")
                    {   // Input field
                        var nodeType = chldnode.type.toUpperCase();
                        if (nodeType != "HIDDEN")
                        {
                            if (nodeType == "TEXT")
                            {   // Text input field
                                if (chldnode.value != this.matrixOriginalValues[elem])
                                {
                                    count++;
                                    break loopNTNR1;
                                }
                            }
                            else if (nodeType == "CHECKBOX" || nodeType == "RADIO")
                            {   // Check Box or Radio button
                                if (!(chldnode.checked && (this.matrixOriginalValues[elem] == "checked") ||
                                     !chldnode.checked && !(this.matrixOriginalValues[elem] == "checked")))
                                {
                                    count++;
                                    break loopNTNR1;
                                }
                            }
                        }
                        elem++;
                        break loopNTNR2;
                    }
                    else if (chldnode.nodeName == "SELECT")
                    {   // Combo Box
                        if (this.matrixOriginalValues[elem] != chldnode.options[chldnode.selectedIndex].value)
                        {
                            count++;
                            break loopNTNR1;
                        }
                        
                        elem++;
                        break loopNTNR2;
                    }
                    else if (chldnode.nodeName == "#text")
                    {   // Read only field
                        elem++;
                        break loopNTNR2;
                    }
                }
            }
        }
    }
    return count;
}

UpdateableTable.prototype.getActionedRows = function(iconType)
{
    var delIconSrc  = getIconSrc(deleteAction);
    var editIconSrc = getIconSrc(editAction);
    var newIconSrc  = getIconSrc(newAction);

    var editResult      = new Array();
    var newResult       = new Array();
    var newOReditResult = new Array();
    var delResult       = new Array();
    var untouchResult   = new Array();
    var nondeleteResult = new Array();
    var result          = new Array();

    var startRow = this.indexDelta;
    var rows = this.main_tbody_node.rows;
    for (var i = startRow, rowsLen = rows.length; i < rowsLen; i++)
    {
        var tdnode      = rows[i].cells[0];
        var aNode       = null;
        var found       = false;
        var deleted     = false;
        var childNodes  = tdnode.childNodes;
        for (var j = 0, cnLen = childNodes.length; j < cnLen; j++)
        {
            aNode = childNodes[j];
            if (aNode.nodeName == "IMG")
            {
                if (aNode.src.indexOf(editIconSrc) > -1)
                {
                    editResult[editResult.length] = (i - this.indexDelta);
                    newOReditResult[newOReditResult.length] = (i - this.indexDelta);
                    found = true;
                    break;
                }
                else if (aNode.src.indexOf(newIconSrc) > -1)
                {
                    newResult[newResult.length] = (i - this.indexDelta);
                    newOReditResult[newOReditResult.length] = (i - this.indexDelta);
                    found = true;
                    break;
                }
                else if (aNode.src.indexOf(delIconSrc) > -1)
                {
                    delResult[delResult.length] = (i - this.indexDelta);
                    found = true;
                    deleted = true;
                    break;
                }
            }
        }
        if (!found)
            untouchResult[untouchResult.length] = (i - this.indexDelta);
        if(!deleted)
            nondeleteResult[nondeleteResult.length] = (i - this.indexDelta);
    }
    if (iconType == editAction)
        result = editResult;
    else if (iconType == newAction)
        result = newResult;
    else if (iconType == newOReditAction)
        result = newOReditResult;
    else if (iconType == deleteAction)
        result = delResult;
    else if (iconType == untouchAction)
        result = untouchResult;
    else if (iconType == nondeleteAction)
        result = nondeleteResult;
    return result;
}

// Gets an object for particular column, assuming only one input capable field within a column.
UpdateableTable.prototype.getColumnObject = function(form, clmName, rowIndex)
{
    var fields = eval("form."+clmName);
    var rIdx = this.hasMassEntryRow ? parseInt(rowIndex)+1 : rowIndex;
    var result = (fields.name == undefined) ? fields[rIdx] : fields;
    return result;
}

// Gets all *objects* of a particular column within a table, assuming only one input capable field within a column.
// Column 0 is reserved (menu icon).
// Returns an array of objects.
UpdateableTable.prototype.getColumnObjects = function(fldName)
{
    var result = new Array();

    var idx = -1;
    var startRow = this.indexDelta;
    var childNodes = this.sample_node.childNodes
loopGCV1:
    for (var j = 0, cnLen = childNodes.length; j < cnLen; j++)
    {
        var tdnode = childNodes[j];
        if (tdnode.nodeName == "TD")
        {
            idx++;
            for (var k = 0, tdcnLen = tdnode.childNodes.length; k < tdcnLen; k++)
            {
                var aNode = tdnode.childNodes[k];
                // if (aNode.nodeName == "INPUT" && aNode.type.toUpperCase() == "TEXT" && aNode.name == fldName)
                // Changed to check only the fldName to allow column with other types to be selected (e.g. combo box or hidden field)
                if (aNode.name == fldName)
                    break loopGCV1;
            }
        }
    }
    // if (idx > 0)
    // Changed to -1 to allow all columns to be considered (including key)
    if (idx > -1)
    {
        var rows = this.main_tbody_node.rows;
        for (var i = startRow, rowsLen = rows.length; i < rowsLen; i++)
        {
            var tdnode = rows[i].cells[idx];
            for (var j = 0, tdcnLen = tdnode.childNodes.length; j < tdcnLen; j++)
            {
/*  Reasons for changes:-
    Javascript error in sequence.jsp - case insensitive comparison required
    caused by new code for country/states in UpdateableTable.jsp, where it's possible for 
    field name to start with lower case letter.
*/ 
                if(tdnode.childNodes[j].name)
            	    if(tdnode.childNodes[j].name.toLowerCase() == fldName.toLowerCase()) {
                        result[result.length] = tdnode.childNodes[j];
                        break;
    	            }
    	    }
        }
    }
    return result;
}

// Gets all values of a particular column within a table, assuming only one input capable field within a column.
// Column 0 is reserved (menu icon).
// Returns an array of two elements.
//      First element is an array of String values.
//      Second element is an array of String indicates that particular row is ReadOnly or Editable.
// The function "trimBeginEnd" defined in file i2tm.js.
UpdateableTable.prototype.getColumnValues = function(fldName)
{
    var columnObjects = this.getColumnObjects(fldName);

    var result = new Array();
    var values = new Array();
    var status = new Array();

    for(var i = 0, valLen = 0, coLen = columnObjects.length; i < coLen; i++)
    {
        var aNode = columnObjects[i];
        if (aNode.nodeName == "#text")
        {
            values[valLen] = trimBeginEnd(aNode.nodeValue);
            status[valLen++] = statusReadOnly;
        }
        else if (aNode.type.toUpperCase() == "HIDDEN")
        {
            values[valLen] = trimBeginEnd(aNode.value);
            status[valLen++] = statusReadOnly;
        }
        else if (aNode.nodeName == "INPUT" || aNode.nodeName == "SELECT")
        {
            values[valLen] = trimBeginEnd(aNode.value);
            status[valLen++] = statusEditable;
        }
    }
    result[0] = values;
    result[1] = status;
    return result;
}

// Incoming parameters
//  fldNames    - is an array of field names which are to be affected.
//  maxLens     - is an array of new maxlength values.
UpdateableTable.prototype.setFieldMaxlength = function(fldNames, maxLens)
{
    var startRow = this.indexDelta;
    // Try to find out the column index of each field within the updateable table.
    // Also, update the sample_node maxLength value for each requested column.
    var nbrOfFieldsProcessed = 0;
    var colIdx = new Array();
    var idx = -1;
    var childNodes = this.sample_node.childNodes;
    for (var j = 0, cnLen = childNodes.length; j < cnLen; j++)
    {
        var tdnode = childNodes[j];
        if (tdnode.nodeName == "TD")
        {
            idx++;
loopSFM1:
            for (var k = 0, tdcnLen = tdnode.childNodes.length; k < tdcnLen; k++)
            {
                var aNode = tdnode.childNodes[k];
                if (aNode.nodeName == "INPUT" && aNode.type.toUpperCase() == "TEXT")
                {
                    for (var i = 0, fnLen = fldNames.length; i < fnLen; i++)
                    {
                        if (aNode.name == fldNames[i])
                        {
                            colIdx[colIdx.length] = idx;
                            aNode.maxLength = parseInt(maxLens[i]);
                            nbrOfFieldsProcessed++;
                            break loopSFM1;
                        }
                    }
                }
            }
        }
        if (nbrOfFieldsProcessed == fldNames.length)
            break;
    }
    // Update the field maxlength one by one within the Updateable table.
    if (this.main_tbody_node.rows.length > this.indexDelta)
    {
        for (var i = startRow, mtnrLen = this.main_tbody_node.rows.length; i < mtnrLen; i++)
        {
            for (var j = 0, ciLen = colIdx.length; j < ciLen; j++)
            {
                var tdnode = this.main_tbody_node.rows[i].cells[colIdx[j]];
                for (var k = 0, tdcnLen = tdnode.childNodes.length; k < tdcnLen; k++)
                {
                    var aNode = tdnode.childNodes[k];
                    if (aNode.nodeName == "INPUT" && aNode.type.toUpperCase() == "TEXT" && aNode.name == fldNames[j])
                    {
                        aNode.maxLength = parseInt(maxLens[j]);
                        break;
                    }
                }
            }
        }
    }
}

UpdateableTable.prototype.setReadOnlyColumn = function(rowIdx, colName, fldValue)
{
    for (var i = 0, fnLen = this.fieldNames.length; i < fnLen; i++)
    {
        if(this.fieldNames[i] == colName)
        {
            this.setReadOnlyColumnByIndex(rowIdx, i + 1, fldValue);
            break;
        }
    }
}

UpdateableTable.prototype.setReadOnlyColumnByIndex = function(rowIdx, colIdx, fldValue)
{
    var rIdx = parseInt(rowIdx);
    var cIdx = parseInt(colIdx);
    var tdnode = this.main_tbody_node.rows[rIdx+this.indexDelta].cells[cIdx];
    if (tdnode.hasChildNodes())
    {
        var childNodes = tdnode.childNodes;
        for (var i = 0, cnLen = childNodes.length; i < cnLen; i++)
        {
            var wrkChild = childNodes[i];

            if (wrkChild.nodeName == "#text")
            {
                wrkChild.nodeValue = fldValue;
                break;
            }
            else if (wrkChild.nodeName == "INPUT" && wrkChild.type.toUpperCase() == "TEXT")
            {
                wrkChild.value = fldValue;
                break;
            }
        }
    }
    else
    {
        var new_node = document.createTextNode(fldValue);
        tdnode.appendChild(new_node);
    }
}

UpdateableTable.prototype.isEnabled = function(tag)
{
    // return !isDeletedRow(this.getRowIndex(tag));
	var key = this.getKey(this.getRowIndex(tag));
	return ( key!=null && key.indexOf(DELETE_ID)==-1);
}

// Prepares form for request submit when button is pressed.
UpdateableTable.prototype.onButton = function(tag, action)
{
    var isEnabled = this.isEnabled(tag);
    //i2uitrace(0, 'onButton isEnabled='+isEnabled+' tag='+tag.tagName+' action='+action);
    if (isEnabled)
    {
        var row    = this.getRowIndex(tag);
        var column = this.getColumnIndex(tag);
        //i2uitrace(0, 'onButton row='+row+' column='+column);

        this.getSelectedRowObject().value = row;
        this.getSelectedColumnObject().value = column;
        this.form.ControllerAction.value = action;
    }
    return isEnabled;
}

UpdateableTable.prototype.onCalendarButton = function(tag, name, onChangeCallback)
{
    if (this.isEnabled(tag)) {
        var objs = eval('document.' + name);
        var fullName = name;
        if (objs.length && objs.length > 1) {
            var rIdx = this.getRowIndex(tag);
            if (this.hasMassiveRow) rIdx = rIdx + 1;
            fullName = name+'['+ rIdx +']';
        }
        showCalendar('/tm/component/i2uidatepickerdialog.jsp', fullName, onChangeCallback);
    }
}

// Radio button in the first column is pressed
UpdateableTable.prototype.onRadioButton = function(tag, value)
{
    this.getSelectedRowObject().value = this.getRowIndex(tag);
    this.getKeyObject().value = value;
}

// Checkbox button in the first column is pressed
UpdateableTable.prototype.onCheckboxButton = function(tag, value)
{
    this.getSelectedRowObject().value = this.getRowIndex(tag);
    this.getKeyObject().value = value;
    this.updateSelectedIndex(this.getSelectedRowObject().value);
}

// Return index of currently selected row
UpdateableTable.prototype.getSelectedRowIdx = function()
{
    return parseInt(this.getSelectedRowObject().value);
}

// Set index of currently selected row
UpdateableTable.prototype.setSelectedRowIdx = function(rowIndx)
{
    this.getSelectedRowObject().value = rowIndx;
}

// Check if there are selected rows. Reports error if none.
UpdateableTable.prototype.checkHasSelectedRow = function(errormsg) {
    return this.checkHasSelectedRow_(this.getRowKeyObject(), errormsg);
}

// ---------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------
//                                  Gant chart support
// ---------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------

function GanttChart(prefix, maintableid, tableWidth, displayHeight, minRowInfoWidth, chartWidth,
                    ganttChartID, attrgantt_scrollerID, chart_header_scrollerID,
                    chart_scrollerID, ganttchart_scrollerID, attrtable_collumns_scrollerID,
                    attributetablecolumnsID, attrtable_body_scrollerID, attrtable_bodyID) {
    this.initBaseTable(prefix, maintableid, true, displayHeight, tableWidth);
    this.elementSelected = null;
    this.elementBorderStyle = null;
    this.minRowInfoWidth = minRowInfoWidth;
    this.chartWidth = chartWidth;
    this.oGanttChart = document.getElementById(ganttChartID);
    this.oattrgantt_scroller = document.getElementById(attrgantt_scrollerID);
    this.ochart_header_scroller = document.getElementById(chart_header_scrollerID);
    this.ochart_scroller = document.getElementById(chart_scrollerID);
    this.oganttchart_scroller = document.getElementById(ganttchart_scrollerID);
    this.oattrtable_collumns_scroller = document.getElementById(attrtable_collumns_scrollerID);
    this.oattributetablecolumns = document.getElementById(attributetablecolumnsID);
    this.oattrtable_body_scroller = document.getElementById(attrtable_body_scrollerID);
    this.oattrtable_body = document.getElementById(attrtable_bodyID);
}

GanttChart.prototype = new BaseTable();
GanttChart.prototype.constructor = GanttChart;

GanttChart.prototype.selectElement = function (elem) {
    this.unselectElement();
    var oldwitdh = parseInt(elem.style.width);
    this.elementSelected = elem;
    this.form[this.getSelectedRowName()].value = elem.entindex;
    this.form[this.getKeyName()].value = elem.entkey;
    this.form[this.getRowKeyName()].value = elem.entkey;
    this.elementBorderStyle = elem.style.border;
    if (oldwitdh >= 4) {
        elem.style.width = (oldwitdh - 4) + "px";
    } else {
        elem.toonarrow = true;
    }
    elem.style.height = (parseInt(elem.style.height) + 2) + "px";
    elem.style.border = "3px solid black";
}

GanttChart.prototype.unselectElement = function () {
    if (this.elementSelected != null) {
        if (this.elementSelected.toonarrow == null) {
            this.elementSelected.style.width = (parseInt(this.elementSelected.style.width) + 4) + "px";
        }
        this.elementSelected.style.height = (parseInt(this.elementSelected.style.height) - 2) + "px";
        this.elementSelected.style.border = "1px solid #999999";
        this.elementSelected = null;
        this.form[this.getSelectedRowName()].value = -1;
        this.form[this.getKeyName()].value = null;
        this.form[this.getRowKeyName()].value = null;
    }
}

// onclick reaction for the chart area
GanttChart.prototype.onClick = function() {
    var elem = event.srcElement;
    if (elem.entkey != null && elem.selectable == "y") {
        this.selectElement(elem);
    } else if (elem.entkey == null) {
        this.unselectElement();
    }
}

// Jump action validation
GanttChart.prototype.jump = function(jumpAction, jumpFieldName, jumpFieldNamei18n) {
    var jumpField = eval("this.form."+jumpFieldName);
    if(!validateFieldType(jumpField.value, jumpFieldNamei18n, 'date')) {
        jumpField.focus();
        jumpField.select();
    }
    else {
        this.form.ControllerAction.value = jumpAction;
        this.form.submit();
    }
}

GanttChart.prototype.resizeTable = function (tableWidth) {
    tableWidth += 16;                             // + scrollbar
    if (tableWidth < 515) tableWidth = 515;       // do not make width less then minimal width

    var scrollMinRowInfoWidth = this.minRowInfoWidth;
    var scrollChartWidth = this.chartWidth;

    var chartwidth=(tableWidth*3)/4;
    if (scrollMinRowInfoWidth < tableWidth-chartwidth) {
        chartwidth = tableWidth-scrollMinRowInfoWidth
    }
    if (scrollChartWidth+2 < chartwidth) {
        chartwidth = scrollChartWidth+2;
    }
    var attrwidth=tableWidth-chartwidth;
    var scrollattrwidth = (attrwidth < scrollMinRowInfoWidth) ? scrollMinRowInfoWidth : attrwidth;

    this.oattrtable_collumns_scroller.style.width = scrollattrwidth;
    this.oattrtable_body_scroller.style.width = scrollattrwidth;
    _setAllTDWidth(this.oattributetablecolumns, scrollattrwidth);
    _setAllTDWidth(this.oattrtable_body, scrollattrwidth);
    this.oattrgantt_scroller.style.width=attrwidth+2;

    this.oganttchart_scroller.style.left=attrwidth+2;
    this.ochart_header_scroller.style.width=chartwidth;
    this.ochart_scroller.style.width=chartwidth;

    this.oGanttChart.style.width=tableWidth;
}

function _setAllTDWidth(table, newWidth) {
    var rows = table.rows;
    for (var i = 0, rowsLen = rows.length; i < rowsLen; i++) {
        var cell = rows[i].cells[0];
        cell.width = newWidth;
    }
}

function GanttChart2(prefix, maintableid, tableWidth, displayHeight, ganttChartID, leftTableHeader, leftTableData, leftPanelWidth,
                        leftHeaderPanel, leftDataPanel, rightHeaderPanel, rightDataPanel, pagenavsec) {
    this.initBaseTable(prefix, maintableid, false, displayHeight, tableWidth);
    this.elementSelected = null;
    this.elementBorderStyle = null;
    this.oGanttChart = document.getElementById(ganttChartID);
    this.leftTableHeader = leftTableHeader;
    this.leftTableData = leftTableData;
    this.leftPanelWidth = leftPanelWidth;
    this.leftHeaderPanel = leftHeaderPanel;
    this.leftDataPanel = leftDataPanel;
    this.rightHeaderPanel = rightHeaderPanel;
    this.rightDataPanel = rightDataPanel;
    this.pagenavsec = pagenavsec;
}

GanttChart2.prototype = new BaseTable();
GanttChart2.prototype.constructor = GanttChart2;

GanttChart2.prototype.selectElement = function(elem) {
    this.unselectElement();
    var oldwitdh = parseInt(elem.style.width);
    this.elementSelected = elem;
    this.form[this.getKeyName()].value = elem.entkey;
    this.form[this.getRowKeyName()].value = elem.entkey;
    this.elementBorderStyle = elem.style.border;
    if (oldwitdh >= 4) {
        elem.style.width = (oldwitdh - 4) + "px";
    } else {
        elem.toonarrow = true;
    }
    elem.style.height = (parseInt(elem.style.height) + 2) + "px";
    elem.style.border = "3px solid black";
    elem.style.zIndex = 35;
}

GanttChart2.prototype.unselectElement = function() {
    if (this.elementSelected != null) {
        var elemSltd = this.elementSelected;
        if (elemSltd.toonarrow == null) {
            elemSltd.style.width = (parseInt(elemSltd.style.width) + 4) + "px";
        }
        elemSltd.style.height = (parseInt(elemSltd.style.height) - 2) + "px";
        elemSltd.style.border = "1px solid #999999";
        if ((elemSltd.className == 'gnstyle21') ||
            (elemSltd.className == 'gnstyle31') || (elemSltd.className == 'gnstyle41'))
            elemSltd.style.zIndex = 30;
        else if (elemSltd.className != 'gnstyle4')
            elemSltd.style.zIndex = 25;
        else if (elemSltd.className != 'gnstyle2')
            elemSltd.style.zIndex = 20;
        else if (elemSltd.className != 'gnstyle5')
            elemSltd.style.zIndex = 15;
        this.elementSelected = null;
        this.form[this.getKeyName()].value = "";
        this.form[this.getRowKeyName()].value = "";
    }
}

// onclick reaction for the chart area
GanttChart2.prototype.onClick = function() {
    var elem = event.srcElement;
    if (elem.entkey != null) {
        if (elem.selectable == "y")
            this.selectElement(elem);
        else {
            this.unselectElement();
            messageAlert("ITEM_IS_NOT_ELIGIBLE_FOR_SELECTION");
        }
    } else if (elem.entkey == null) {
        this.unselectElement();
    }
}

GanttChart2.prototype.resizeGanttTable = function() {
    var chartTableWidth = this.leftPanelWidth;
    var delta = 165;
    var limit = 1087;
    if (!isNavPadOpen)
    {
        delta = (document.body.clientWidth > limit) ? (document.body.clientWidth - limit) : 0;
        chartTableWidth += delta;
    }
    var tryOnce = isNavPadOpen;

    var lefthdrPnl = document.getElementById(this.leftHeaderPanel);
    var lefthdrPnlscr = document.getElementById(this.leftHeaderPanel + '_scroller');
    var leftdtaPnlscr = document.getElementById(this.leftDataPanel + '_scroller');
    
    lefthdrPnl.style.width = chartTableWidth;
    lefthdrPnlscr.style.width = chartTableWidth;
    if (leftdtaPnlscr != undefined)
        leftdtaPnlscr.style.width = chartTableWidth;

    var righthdrPnlscr = document.getElementById(this.rightHeaderPanel + '_scroller');
    var rightdtaPnlscr = document.getElementById(this.rightDataPanel + '_scroller');

    righthdrPnlscr.style.left = chartTableWidth - 1;
    if (rightdtaPnlscr != undefined)
        rightdtaPnlscr.style.left = chartTableWidth - 1;

    var leftnav = document.getElementById(this.pagenavsec);
    var leftnavTD = leftnav.parentElement;
    leftnavTD.width = chartTableWidth + 8;

    var hdr = document.getElementById(this.leftTableHeader);
    var dta = document.getElementById(this.leftTableData);

    var loop = 2;
    while ((!this.isAligned() || tryOnce) && (loop > 0))
    {
        tryOnce = 0;
        if ((hdr != undefined) && (dta != undefined))
        {
            var hdr0 = hdr.rows[0];
            var tcols = hdr0.cells.length;
            var trows = dta.rows.length;
            var hdrscrwidth = new Array();
            for (var i = 0; i < tcols; i++)
            {
                hdrscrwidth[i] = hdr0.cells[i].scrollWidth;
            }
            var dtascrwidth = new Array();
            var dtarows = dta.rows;
            for (var i = 0; i < tcols; i++)
            {
                var scrwidth = 0;
                for (var j = 0; j < trows; j++)
                {
                    var scrw = dtarows[j].cells[i].scrollWidth;
                    if (scrw > scrwidth)
                        scrwidth = scrw;
                }
                dtascrwidth[i] = scrwidth;
            }
            var tcw = new Array();
            var tcwv = 0;
            for (var i = 0; i < tcols; i ++)
            {
                if (hdrscrwidth[i] < dtascrwidth[i])
                    tcw[i] = dtascrwidth[i];
                else
                    tcw[i] = hdrscrwidth[i];
                tcwv += tcw[i];
            }
            var wdelta = chartTableWidth - tcwv;
            var spread = Math.ceil(Math.abs(wdelta)/tcols);
            if ((wdelta > 0) && (spread > 0))
            {
                for (var i = 0; i < tcols; i ++)
                {
                    tcw[i] += spread;
                    if (i == 0)
                        tcw[i]++;
                }
            }
            for (var i = 0; i < tcols; i ++)
            {
                if (wdelta < 0)
                    hdr0.cells[i].width = tcw[i]+1;
                else
                    hdr0.cells[i].width = tcw[i];
                for (var j = 0; j < trows; j++)
                {
                    dtarows[j].cells[i].width = tcw[i];
                    dtarows[j].cells[i].style.width = tcw[i];
                }
            }
        }
        loop--;
    }
}

GanttChart2.prototype.isAligned = function() {
    var result = true;
    var hdr = document.getElementById(this.leftTableHeader);
    var dta = document.getElementById(this.leftTableData);
    if (hdr != null && dta != null)
    {
        var hdr0 = hdr.rows[0];
        var tcols = hdr0.cells.length;
        var trows = dta.rows.length;
        if (trows > 0)
        {
            var dtarows = dta.rows;
            for (var i = 0; i < tcols; i++)
            {
                if (hdr0.cells[i].clientWidth != dtarows[0].cells[i].clientWidth)
                {
                    result = false;
                    break;
                }
            }
        }
    }
    return result;
}

// ---------------------------------------------------------------------------------------
//                                  Depricated functions
//

function getRowIndex(tag) 
{ 
  return utp.getRowIndex(tag);
}

function getColumnIndex(tag)
{
    return utp.getColumnIndex(tag);
}

function rowModified(rowIdx)
{
    utp.rowModified(rowIdx);
}

function focusOnRowByIdx(rowIdx)
{
    utp.focusOnRowByIdx(rowIdx);
}

function focusOnCellWithRowIndexAndFieldName(rowIdx, fldName)
{
    utp.focusOnCellWithRowIndexAndFieldName(rowIdx, fldName);
}

function isExistingRow(rowIndex) {
    return utp.isExistingRow(rowIndex);
}

function isDeletedRow(rowIndex)
{
    return utp.isDeletedRow(rowIndex);
}

function getNumberOfRows()
{
    return utp.getNumberOfRows();
}

function getNumberOfNewRows()
{
    return utp.getNumberOfNewRows();
}

function getNumberOfDeletedRows()
{
    return utp.getNumberOfDeletedRows();
}

function getColumnObject(form, clmName, rowIndex)
{
    return utp.getColumnObject(form, clmName, rowIndex);
}

function getColumnObjects(fldName)
{
    return utp.getColumnObjects(fldName);
}

function getColumnValues(fldName)
{
    return utp.getColumnValues(fldName);
}

function setFieldMaxlength(fldNames, maxLens)
{
    return utp.setFieldMaxlength(fldNames, maxLens);
}

function setReadOnlyColumn(rowIdx, colName, fldValue)
{
    utp.setReadOnlyColumn(rowIdx, colName, fldValue);
}

function isEnabled(tag)
{
    return utp.isEnabled(tag);
}

function isTableModified()
{
    return utp.isModified();
}

function removeUntouchedNewRows(keepOneRow)
{
    return utp.removeUntouchedNewRows(keepOneRow);
}

function getActionedRows(iconType)
{
    return utp.getActionedRows(iconType);
}

