/*
 * Copyright (c) 1998-2006 TeamDev Ltd. All Rights Reserved.
 * Use is subject to license terms.
 */

// ================================== PUBLIC API METHODS

/**
 * Selects all rows in a table identified by the passed tableId. The table must have a multiple row selection mode.
 */
function q_selectAllRows(tableId) {
  if (!tableId)
    throw "q_selectAllRows: Table's clientId must be passed as a parameter";
  var table = document.getElementById(tableId);
  if (!table)
    throw "q_selectAllRows: Invalid clientId passed - no such component was found: " + tableId;
  if (!table._getBodyRows)
    throw "q_selectAllRows: The clientId passed refers to a component other than <q:dataTable> : " + tableId;

  table.__selectAllRows();
}

/**
 * Clears selection in a table identified by the passed tableId. This method works with any selection mode.
 */
function q_clearSelection(tableId) {
  if (!tableId)
    throw "q_clearSelection: table's clientId must be passed as a parameter";
  var table = document.getElementById(tableId);
  if (!table)
    throw "q_clearSelection: Invalid clientId passed - no such component was found: " + tableId;
  if (!table._getBodyRows)
    throw "q_clearSelection: The clientId passed refers to a component other than <q:dataTable> : " + tableId;
//  if (table._selectableItems != "rows")
//    throw "q_clearSelection: The specified table is not set up for row selection. Selectable items are: " + table._selectableItems + "; table's clientId is: " + tableId;

  table.__clearSelection();
}

/**
 * Returns true if the table has any row(s) selected. This method works with any selection mode.
 */
function q_isTableSelectionEmpty(tableId) {
  if (!tableId)
    throw "q_isTableSelectionEmpty: table's clientId must be passed as a parameter";
  var table = document.getElementById(tableId);
  if (!table)
    throw "q_isTableSelectionEmpty: Invalid clientId passed - no such component was found: " + tableId;
  if (!table._getSelectedItems)
    throw "q_isTableSelectionEmpty: The clientId passed refers to a component other than <q:dataTable> : " + tableId;
  return table.__isSelectionEmpty();
}

/**
 * Returns a zero-based index of the currently selected row, or -1 if no row is selected. The table must be in the single
 * row selection mode for this method to work.
 */
function q_getSelectedRowIndex(tableId) {
  if (!tableId)
    throw "q_getSelectedRowIndex: table's clientId must be passed as a parameter";
  var table = document.getElementById(tableId);
  if (!table)
    throw "q_getSelectedRowIndex: Invalid clientId passed - no such component was found: " + tableId;
  if (!table._getSelectedItems)
    throw "q_getSelectedRowIndex: The clientId passed refers to a component other than <q:dataTable> : " + tableId;

  return table.__getSelectedRowIndex();
}

/**
 * Selects a row with the specified index. The table must be in the single row selection mode for this method to work.
 */
function q_setSelectedRowIndex(tableId, rowIndex) {
  if (!tableId)
    throw "q_setSelectedRowIndex: table's clientId must be passed as a parameter";
  var table = document.getElementById(tableId);
  if (!table)
    throw "q_setSelectedRowIndex: Invalid clientId passed - no such component was found: " + tableId;
  if (!table._getSelectedItems)
    throw "q_setSelectedRowIndex: The clientId passed refers to a component other than <q:dataTable> : " + tableId;

  table.__setSelectedRowIndex(rowIndex);
}

/**
 * Returns an array of zero-based indexes of the currently selected rows. The table must be in the multiple row
 * selection mode for this method to work.
 */
function q_getSelectedRowIndexes(tableId) {
  if (!tableId)
    throw "q_getSelectedRowIndexes: table's clientId must be passed as a parameter";
  var table = document.getElementById(tableId);
  if (!table)
    throw "q_getSelectedRowIndexes: Invalid clientId passed - no such component was found: " + tableId;
  if (!table._getSelectedItems)
    throw "q_getSelectedRowIndexes: The clientId passed refers to a component other than <q:dataTable> : " + tableId;

  return table.__getSelectedRowIndexes();
}

/**
 * Selects rows whose indexes are passed in the rowIndeses array. The table must be in the multiple row selection mode
 * for this method to work.
 */
function q_setSelectedRowIndexes(tableId, rowIndexes) {
  if (!tableId)
    throw "q_setSelectedRowIndexes: table's clientId must be passed as a parameter";
  var table = document.getElementById(tableId);
  if (!table)
    throw "q_setSelectedRowIndexes: Invalid clientId passed - no such component was found: " + tableId;
  if (!table._getSelectedItems)
    throw "q_setSelectedRowIndexes: The clientId passed refers to a component other than <q:dataTable> : " + tableId;

  table.__setSelectedRowIndexes(rowIndexes);
}

function q_getRowCount(tableId) {
  if (!tableId)
    throw "q_getRowCount: table's clientId must be passed as a parameter";
  var table = document.getElementById(tableId);
  if (!table)
    throw "q_getRowCount: Invalid clientId passed - no such component was found: " + tableId;
  if (!table._getSelectedItems)
    throw "q_getRowCount: The clientId passed refers to a component other than <q:dataTable> : " + tableId;
  return table.__getRowCount();

}

// ================================== END OF PUBLIC API METHODS


// -------------------------- COMMON UTILITIES

function q__getRowsInSection(table, tableSection) {
  var section = q__getChildNodesWithNames(table, [tableSection])[0];
  var result = (section != null) ? q__getChildNodesWithNames(section, ["tr"]) : [];
  return result;
}

function q__getRowCells(row) {
  var safari = false;
  var cells = !safari ? row.cells : q__getChildNodesWithNames(row, ["td", "th"])
  return cells
}

function q__getCellColSpan(cell) {
  var safari = false;// todo: check under safari when collspans are implemented
  var colSpan = !safari ? cell.colSpan : cell.getAttribute('colSpan');
  if (!colSpan || colSpan == -1)
    colSpan = 1;
  return colSpan;
}

function q__stringEmpty(str) {
  return (!str || str == "");
}

// -------------------------- COMMON TABLE FUNCTIONS

function q__initDataTableAPI(table) {
  table.selectAllRows = function() { this.__selectAllRows(); }
  table.clearSelection = function() { this.__clearSelection(); }
  table.isSelectionEmpty = function() { return this.__isSelectionEmpty(); }
  table.getSelectedRowIndex = function() { return this.__getSelectedRowIndex(); }
  table.setSelectedRowIndex = function(rowIndex) { this.__setSelectedRowIndex(rowIndex); }
  table.getSelectedRowIndexes = function() { return this.__getSelectedRowIndexes(); }
  table.setSelectedRowIndexes = function(rowIndexes) { this.__setSelectedRowIndexes(); }
  table.getRowCount = function() { return this.__getRowCount(); }
}

function q__initTable(tableId, columns, headerFacetUsed, filterRowUsed, footerFacetUsed, noDataRows,
        gridLines, bodyRowClass, bodyOddRowClass, commonHeaderRowClass, headerRowClass, filterRowClass,
        commonFooterRowClass, footerRowClass, useAjax, rowStylesMap, cellStylesMap, rolloverClass, rolloverRowClass,
        apiInitializationFunctionName) {
  var table = document.getElementById(tableId);

  if (table._commonTableFunctionsInitialized)
    return;
  table._commonTableFunctionsInitialized = true;
  table._tableComponentMarker = true;

  table._filterRowUsed = filterRowUsed;
  table._headerFacetUsed = headerFacetUsed;
  table._commonHeaderRowClass = commonHeaderRowClass;
  table._headerRowClass = headerRowClass;
  table._filterRowClass = filterRowClass;
  table._commonFooterRowClass = commonFooterRowClass;
  table._bodyRowClass = bodyRowClass;
  table._bodyOddRowClass = bodyOddRowClass;
  table._footerRowClass = footerRowClass;
  table._rowStylesMap = rowStylesMap;
  table._cellStylesMap = cellStylesMap;
  table._rolloverClass = rolloverClass;
  table._rolloverRowClass = rolloverRowClass;
  table._headerFacetUsed = headerFacetUsed;
  table._footerFacetUsed = footerFacetUsed;
  table._useAjax = useAjax;
  table._noDataRows = noDataRows;

  // initialize grid lines
  var tempIdx = 0;
  table._horizontalGridLines   = gridLines[tempIdx++];
  table._verticalGridLines     = gridLines[tempIdx++];
  table._commonHeaderSeparator = gridLines[tempIdx++];
  table._commonFooterSeparator = gridLines[tempIdx++];
  table._headerHorizSeparator  = gridLines[tempIdx++];
  table._headerVertSeparator   = gridLines[tempIdx++];
  table._filterRowSeparator    = gridLines[tempIdx++];
  table._footerHorizSeparator  = gridLines[tempIdx++];
  table._footerVertSeparator   = gridLines[tempIdx++];

  table.style.emptyCells = "show";
  if (q__isExplorer()) {
    var bordersNeeded =
        !q__stringEmpty(table._horizontalGridLines)   ||
        !q__stringEmpty(table._verticalGridLines)     ||
        !q__stringEmpty(table._commonHeaderSeparator) ||
        !q__stringEmpty(table._commonFooterSeparator) ||
        !q__stringEmpty(table._headerHorizSeparator)  ||
        !q__stringEmpty(table._headerVertSeparator)   ||
        !q__stringEmpty(table._filterRowSeparator)    ||
        !q__stringEmpty(table._footerHorizSeparator)  ||
        !q__stringEmpty(table._footerVertSeparator);
    if (bordersNeeded)
      table.style.borderCollapse = "collapse";
  }

  try {
    q__initTableRows(table);
    q__initTableColumns(table, columns);
    q__initApiFunctions(table);
    q__initTableMouseOvers(table);
  } finally {
    var originalClassName = table.className;
    var classNames = q__getArrayFromString(originalClassName, " ");
    var initiallyInvisibleClassName = classNames[0];
    q__excludeClassNames(table, [initiallyInvisibleClassName]);
  }

  table._originalClassName = table.className;
  table._updayStyle = function() {
    var newClassName = q__combineClassNames([
            this._originalClassName,
            this._mouseIsOver ? this._rolloverClass : null,
            this._focused ? this._focusedClassName : null]);
    if (this.className != newClassName)
      this.className = newClassName;
  }

  table._insertRowsAfter = q__table_insertRowsAfter;
  table._rowInsertionCallbacks = new Array();
  table._addRowInsertionCallback = function(callback) {
    table._rowInsertionCallbacks.push(callback);
  }
  table.onComponentUnload = function() {
    q__deinitializeTableKeyboardNavigation(this);
    var filtersToHide = this._filtersToHide;
    if (!q__isExplorer() || !filtersToHide)
      return false;

    for (var i = 0, count = filtersToHide.length; i < count; i++) {
      var filter = filtersToHide[i];
      filter.style.visibility = "hidden";
    }
    return true;
  }
  if (apiInitializationFunctionName) {
    var initFunction = eval(apiInitializationFunctionName);
    if (initFunction)
      initFunction(table);
  }
}


function q__table_insertRowsAfter(afterIndex, rowsToInsert, newRowsToStylesMap, newRowCellsToStylesMap) {
  var bodyRows = this._getBodyRows();
  var columns = this._columns;
  var afterRow = bodyRows[afterIndex];

  var addedRowCount = rowsToInsert.length;
  this._bodyRowCount += addedRowCount;
  for (var originalRowIndex = bodyRows.length - 1; originalRowIndex >= afterIndex; originalRowIndex--) {
    var newRowIndex = originalRowIndex + addedRowCount;
    var moveRow = originalRowIndex != afterIndex;
    var movedRow = bodyRows[originalRowIndex];

    if (moveRow) {
      bodyRows[newRowIndex] = movedRow;
      bodyRows[originalRowIndex] = null;
      movedRow._index = newRowIndex;
    }

    q__calculateInitialRowClass(movedRow, this, moveRow ? newRowIndex : originalRowIndex);

    if (moveRow){
      this._rowStylesMap[newRowIndex] = this._rowStylesMap[originalRowIndex];
      this._rowStylesMap[originalRowIndex] = null;
    }

    for (var colIndex = 0, colCount = columns.length; colIndex < colCount; colIndex++) {
      var column = columns[colIndex];
      var bodyCells = column._bodyCells;
      var movedCell = bodyCells[originalRowIndex];

      if (moveRow) {
        bodyCells[newRowIndex] = movedCell;
        bodyCells[originalRowIndex] = null;
        var originalCellKey = originalRowIndex + "x" + colIndex;
        var newCellKey = newRowIndex + "x" + colIndex;
        this._cellStylesMap[newCellKey] = this._cellStylesMap[originalCellKey];
        this._cellStylesMap[originalCellKey] = null;
      }

      q__initColumnBodyCellStyles(movedCell);
    }

  }

  var nextNode = afterRow.nextSibling;
  var rowContainer = afterRow.parentNode;
  for (var i = 0, count = rowsToInsert.length; i < count; i++) {
    var newRow = rowsToInsert[i];
    if (nextNode != null)
      rowContainer.insertBefore(newRow, nextNode);
    else
      rowContainer.appendChild(newRow);

    var newRowIndex = afterIndex + 1 + i;
    bodyRows[newRowIndex] = newRow;
    this._rowStylesMap[newRowIndex] = newRowsToStylesMap[i];
    q__initTableRow(newRow, this, newRowIndex);

    for (var colIndex = 0, colCount = columns.length; colIndex < colCount; colIndex++) {
      var column = columns[colIndex];
      var cellStyleKey = newRowIndex + "x" + colIndex;
      this._cellStylesMap[cellStyleKey] = newRowCellsToStylesMap[i + "x" + colIndex];
      var cell = q__initTableColumnCell(newRow, column);
      var bodyCells = column._bodyCells;
      bodyCells[newRowIndex] = cell;
      if (cell)
        q__initColumnBodyCell(cell);
    }

  }

  for (var i = 0, count = this._rowInsertionCallbacks.length; i < count; i++) {
    this._rowInsertionCallbacks[i](this, afterIndex, rowsToInsert);
  }


}

function q__initTableRow(row, table, rowIndex) {
  row._table = table;
  row._index = rowIndex;
  row._selected = false;
  row._visible = true;
  row._setVisible = function (visible) {
    if (this._visible == visible)
      return;
    this.style.display = visible ? "" : "none";
    this._visible = visible;
  }

  q__initRowCells(row);

  row._mouseOverHandler = function() {
    this._mouseIsOver = true;
    this._updayStyle();
  }

  row._mouseOutHandler = function() {
    this._mouseIsOver = false;
    this._updayStyle();
  }

  row._updayStyle = function() {
    var cells = this._cells;
    var rowTable = this._table;
    var addedClassName = q__combineClassNames([
              this._selected ? rowTable._selectionClass : null,
              this._mouseIsOver ? rowTable._rolloverRowClass : null]);
    if (row._addedClassName == addedClassName)
      return;
    row._addedClassName = addedClassName;
    var opera = q__isOpera();
    for (var i = 0, count = cells.length; i < count; i++) {
      var cell = cells[i];
      var cls = q__combineClassNames([cell._originalClassName, addedClassName]);
      if (cell.className != cls)
        cell.className = cls;
      q__updateCellWrapperStyle(cell);
      if (opera) {
        var oldBackground = cell.style.background;
        cell.style.background = "white";
        cell.style.background = oldBackground;
      }
    }

  }

  row._originalClassName = row.className;
  row._mouseIsOver = false;
  if (!table._noDataRows && table._rolloverRowClass) {
    q__addEventHandlerSimple(row, "mouseover", "_mouseOverHandler");
    q__addEventHandlerSimple(row, "mouseout", "_mouseOutHandler");
  }
  q__calculateInitialRowClass(row, table, rowIndex);
}

function q__initTableRows(table) {
  table._getHeaderRows = function() {
    if (!this._headerRows)
      this._headerRows = q__getRowsInSection(this, "thead");
    return this._headerRows;
  }
  table._getBodyRows = function() {
    if (!this._bodyRows) {
      this._bodyRows = q__getRowsInSection(this, "tbody");
      this._bodyRowCount = this._bodyRows.length;
    }
    return this._bodyRows;
  }
  table._getFooterRows = function() {
    if (!this._footerRows)
      this._footerRows = q__getRowsInSection(this, "tfoot");
    return this._footerRows;
  }


  var headRows = table._getHeaderRows();
  for (var rowIndex = 0, rowCount = headRows.length; rowIndex < rowCount; rowIndex++) {
    var row = headRows[rowIndex];
    q__initRowCells(row);
  }
  var commonHeaderRowIndex = table._headerFacetUsed ? 0 : -1;
  var columnHeadersRowIndex = table._headerFacetUsed ? 1 : 0;
  var filterRowIndex = table._filterRowUsed ? headRows.length - 1 : -1;
  table._filterRowIndex = filterRowIndex;
  table._columnHeadersRowIndex = columnHeadersRowIndex;
  table._commonHeaderRowIndex = commonHeaderRowIndex;
  if (filterRowIndex != -1 && columnHeadersRowIndex == filterRowIndex)
    columnHeadersRowIndex = -1;
  if (columnHeadersRowIndex >= headRows.length) {
    columnHeadersRowIndex = -1;
  }

  if (commonHeaderRowIndex != -1)
    q__appendRowCellClassNames(headRows[commonHeaderRowIndex], [table._commonHeaderRowClass]);
  if (filterRowIndex != -1)
    q__appendRowCellClassNames(headRows[filterRowIndex], [table._filterRowClass]);
  if (columnHeadersRowIndex != -1)
    q__appendRowCellClassNames(headRows[columnHeadersRowIndex], [table._headerRowClass]);

  var bodyRows = table._getBodyRows();
  for (var rowIndex = 0, rowCount = bodyRows.length; rowIndex < rowCount; rowIndex++) {
    var row = bodyRows[rowIndex];
    q__initTableRow(row, table, rowIndex);
  }
  var footRows = table._getFooterRows();
  for (var rowIndex = 0, rowCount = footRows.length; rowIndex < rowCount; rowIndex++) {
    var row = footRows[rowIndex];
    q__initRowCells(row);
  }
  var footerRowIndex = footRows.length - 1;
  if (table._footerFacetUsed)
    q__appendRowCellClassNames(footRows[footerRowIndex--], [table._commonFooterRowClass]);
  if (footerRowIndex >= 0)
    q__appendRowCellClassNames(footRows[footerRowIndex], [table._footerRowClass]);
}

function q__calculateInitialRowClass(row, table, rowIndex) {
  var rowClass;
  if (!table._noDataRows)
    rowClass = (rowIndex % 2 == 0) ? table._bodyRowClass : (table._bodyOddRowClass ? table._bodyOddRowClass : table._bodyRowClass);
  else
    rowClass = null;

  row._initialClass = rowClass;
  row._addedClassName = undefined;
}

function q__updateCellWrapperStyle(cell) {
  if (cell._noCellWrapperFound)
    return;
  var cellWrapper = cell._cellWrapper;
  if (!cellWrapper) {
    var nodes = q__findChildNodesByClass(cell, "tc_cellWrapper", true);
    if (nodes.length == 0) {
      cell._noCellWrapperFound = true;
      return;
    }
    q__assert (nodes.length == 1, "q__updateCellWrapperStyle: no more than one cellwrapper expected, but found: " + nodes.length);
    cellWrapper = nodes[0];
    q__assert(cellWrapper, "q__updateCellWrapperStyle: non-null cellWrapper expected");
    cell._cellWrapper = cellWrapper;
  }
  if (cellWrapper.className != cell.ClassName)
    cellWrapper.className = cell.className;
  cellWrapper.style.width = "100%";
}

function q__initTableMouseOvers(table) {
  table._mouseIsOver = false;
  if (table._rolloverClass) {
    q__addEventHandlerSimple(table, "mouseover", "_mouseOverHandler");
    q__addEventHandlerSimple(table, "mouseout", "_mouseOutHandler");
  }

  table._mouseOverHandler = function() {
    this._mouseIsOver = true;
    this._updayStyle();
  }

  table._mouseOutHandler = function() {
    this._mouseIsOver = false;
    this._updayStyle();
  }
}

function q__setCellStyleProperty(cell, propertyName, propertyValue) {
  if (!cell || !propertyValue || propertyValue == "")
    return;
  if (!cell._subCells) {
    try {
      cell.style[propertyName] = propertyValue;
    } catch (e) {
      q__logError("q__setCellStyleProperty: couldn't set style property \"" + propertyName + "\" to \"" + propertyValue + "\" ; original error: " + e.message);
      throw e;
    }
    return;
  }

  for (var i = 0, count = cell._subCells.length; i < count; i++) {
    var subCell = cell._subCells[i];
    if (subCell)
      subCell.style[propertyName] = propertyValue;
  }

}

function q__setCellProperty(cell, propertyName, propertyValue) {
  if (!cell)
    return;
  if (!cell._subCells) {
    try {
      cell[propertyName] = propertyValue;
    } catch (e) {
      q__logError("q__setCellProperty: couldn't set cell property \"" + propertyName + "\" to \"" + propertyValue + "\" ; original error: " + e.message);
      throw e;
    }
    return;
  }
  for (var i = 0, count = cell._subCells.length; i < count; i++) {
    var subCell = cell._subCells[i];
    if (subCell)
      subCell[propertyName] = propertyValue;
  }
}


function q__setCellRightBorder(cell, borderValue) {
  if (!cell)
    return;
  if (!cell._subCells) {
    try {
      cell.style.borderRight = borderValue;
    } catch (e) {
      q__logError("q__setCellRightBorder: invalid borderValue: \"" + borderValue + "\" ; it must be a valid CSS declaration of form \"1px solid gray\" ; original error: " + e.message);
      throw e;
    }
    return;
  }
  var lastSubCell = null;
  for (var i = 0, count = cell._subCells.length; i < count; i++) {
    var subCell = cell._subCells[i];
    if (subCell)
      lastSubCell = subCell;
  }
  try {
    lastSubCell.style.borderRight = borderValue;
  } catch (e) {
    q__logError("q__setCellRightBorder: invalid borderValue: " + borderValue + " ; it must be a valid CSS declaration of form '1px solid gray' ; original error: " + e.message);
    throw e;
  }
}

function q__appendRowCellClassNames(row, classNames) {
  var cells = row._cells;
  for (var i = 0, count = cells.length; i < count; i++) {
    var cell = cells[i];
    q__appendCellClassNames(cell, classNames);
  }
}

function q__appendCellClassNames(cell, classNames) {
  if (!cell._subCells) {
    q__appendClassNames(cell, classNames);
    q__updateCellWrapperStyle(cell);
    cell._originalClassName = cell.className;
    return;
  }
  var subCells = cell._subCells
  for (var i = 0, count = subCells.length; i < count; i++) {
    var subCell = subCells[i];
    if (!subCell)
      continue;
    subCell._originalClassName = subCell.className;
    q__appendClassNames(subCell, classNames);
    q__updateCellWrapperStyle(cell);
  }
}

function q__initColumnCell(cell, events1, events2) {

  if (!cell._subCells) {
    q__assignEvents(cell, events1);
    q__assignEvents(cell, events2);
  } else {
    var subCells = cell._subCells;
    for (var i = 0, count = subCells.length; i < count; i++) {
      var subCell = subCells[i];
      if (!subCell)
        continue;
      q__assignEvents(subCell, events1);
      q__assignEvents(subCell, events2);
    }
  }
}

function q__initTableColumns(table, columns) {
  table._columns = new Array();
  var physicalColIndex = 0;
  var colCount = columns.length;
  table._columnCount = colCount;
  for (var logicalColIndex = 0; logicalColIndex < colCount; logicalColIndex++) {
    var colDataArray = columns[logicalColIndex];
    var i = 0;
    var generalStyleClass  = colDataArray[i++];
    var headerStyleClass   = colDataArray[i++];
    var bodyStyleClass     = colDataArray[i++];
    var footerStyleClass   = colDataArray[i++];
    var generalEventsArray = colDataArray[i++];
    var headerEventsArray  = colDataArray[i++];
    var bodyEventsArray    = colDataArray[i++];
    var footerEventsArray  = colDataArray[i++];
    var subColCount        = colDataArray[i++];


    var column = new q__tableColumn(table, logicalColIndex, physicalColIndex, subColCount);

    column._generalStyleClass = generalStyleClass;
    column._bodyStyleClass = bodyStyleClass;
    column._generalEventsArray = generalEventsArray;
    column._bodyEventsArray = bodyEventsArray;

    table._columns[logicalColIndex] = column;
    column._subColCount = subColCount;

    var headerCells = column._headerCells;
    if (table._headerFacetUsed) {
      var cell = headerCells[0];
      q__setCellStyleProperty(cell, "borderBottom", q__nullToEmptyStr(table._commonHeaderSeparator));
    }
    for (var cellIndex = table._headerFacetUsed ? 1 : 0, cellCount = headerCells.length; cellIndex < cellCount; cellIndex++) {
      var cell = headerCells[cellIndex];
      if (cell) {
        if (cellIndex == cellCount - 1)
          q__setCellStyleProperty(cell, "borderBottom", q__nullToEmptyStr(table._headerHorizSeparator != null ? table._headerHorizSeparator : table._horizontalGridLines));
        if (cellIndex == table._filterRowIndex - 1 && table._columnHeadersRowIndex != -1)
          q__setCellStyleProperty(cell, "borderBottom", q__nullToEmptyStr(table._filterRowSeparator));
        if (logicalColIndex != colCount - 1)
          q__setCellRightBorder(cell, q__nullToEmptyStr(table._headerVertSeparator != null ? table._headerVertSeparator : table._verticalGridLines));
        q__appendCellClassNames(cell, [generalStyleClass, headerStyleClass]);
        q__initColumnCell(cell, generalEventsArray, headerEventsArray);
      }
    }

    var bodyCells = column._bodyCells;
    for (var bodyCellIndex = 0, cellCount = bodyCells.length; bodyCellIndex < cellCount; bodyCellIndex++) {
      var cell = bodyCells[bodyCellIndex];
      if (!cell)
        continue;

      q__initColumnBodyCell(cell);
    }

    var footerCells = column._footerCells;
    if (table._footerFacetUsed) {
      var cell = footerCells[footerCells.length - 1];
      if (cell)
        q__setCellStyleProperty(cell, "borderTop", q__nullToEmptyStr(table._commonFooterSeparator));
    }
    for (var cellIndex = 0, cellCount = table._footerFacetUsed ? footerCells.length - 1 : footerCells.length; cellIndex < cellCount; cellIndex++) {
      var cell = footerCells[cellIndex];
      if (cell) {
        if (cellIndex == 0)
          q__setCellStyleProperty(cell, "borderTop", q__nullToEmptyStr(table._footerHorizSeparator != null ? table._footerHorizSeparator : table._horizontalGridLines));
        if (logicalColIndex != colCount - 1)
          q__setCellRightBorder(cell, q__nullToEmptyStr(table._footerVertSeparator != null ? table._footerVertSeparator : table._verticalGridLines));
        q__appendCellClassNames(cell, [generalStyleClass, footerStyleClass]);
        q__initColumnCell(cell, column._generalEventsArray, footerEventsArray);
      }
    }
    if (subColCount == 0)
      physicalColIndex++;
    else
      physicalColIndex += subColCount;
  }
}

function q__initColumnBodyCellStyles(cell) {
  cell.className = cell._classNameBeforeInitialization;
  var column = cell._column;
  var row = cell._row;
  var table = row._table;
  var rowIndex = row._index;
  var colIndex = column._logicalColIndex;
  var rowCount = table._bodyRowCount;
  var colCount = table._columnCount;


  var cellKey = rowIndex + "x" + colIndex;
  var individualCellStyle = table._cellStylesMap[cellKey];
  var individualRowClass = table._rowStylesMap[row._index];
  q__appendCellClassNames(cell, [row._initialClass, individualRowClass, individualCellStyle]);

  if (rowIndex != rowCount - 1)
    q__setCellStyleProperty(cell, "borderBottom", q__nullToEmptyStr(table._horizontalGridLines));
  if (colIndex != colCount - 1)
    q__setCellRightBorder(cell, q__nullToEmptyStr(table._verticalGridLines));
  q__appendCellClassNames(cell, [column._generalStyleClass, column._bodyStyleClass]);
}

function q__initColumnBodyCell(cell) {
  cell._classNameBeforeInitialization = cell.className;
  q__initColumnBodyCellStyles(cell);

  var column = cell._column;
  q__initColumnCell(cell, column._generalEventsArray, column._bodyEventsArray);

}

function q__initApiFunctions(table) {
  table.__selectAllRows = function() {
    if (this._selectableItems != "rows")
      throw "selectAllRows: The table is not set up for row selection. Selectable items are: " + this._selectableItems + "; table's clientId is: " + this.id;
    if (!this._multipleSelectionAllowed)
      throw "selectAllRows: The table is not set up for multiple selection. Table's clientId is: " + this.id;
    this._selectAllItems();
  }
  table.__clearSelection = function() {
    this._unselectAllItems();
  }
  table.__isSelectionEmpty = function() {
    var selectedItems = this._getSelectedItems();
    if (!selectedItems || selectedItems.length == 0)
      return true;
    if (selectedItems[0] == -1)
      return true;
    return false;
  }
  table.__getSelectedRowIndex = function() {
    if (this._selectableItems != "rows")
      throw "getSelectedRowIndex: The specified table is not set up for row selection. Selectable items are: " + this._selectableItems + "; table's clientId is: " + this.id;
    if (this._multipleSelectionAllowed)
      throw "getSelectedRowIndex can only used on a table with single selection mode; table's clientId is: " + this.id;

    var selectedItems = this._getSelectedItems();
    if (selectedItems.length == 0)
      return -1;
    return selectedItems[0];
  }
  table.__setSelectedRowIndex = function(rowIndex) {
    if (this._selectableItems != "rows")
      throw "setSelectedRowIndex: The specified table is not set up for row selection. Selectable items are: " + this._selectableItems + "; table's clientId is: " + this.id;
    if (this._multipleSelectionAllowed)
      throw "setSelectedRowIndex can only used on a table with single selection mode; table's clientId is: " + this.id;
    var bodyRows = table._getBodyRows();
    if ((rowIndex != -1) && (rowIndex < 0 || rowIndex >= bodyRows.length))
      throw "setSelectedRowIndex parameter is out of range (" + rowIndex + "); table's clientId is: " + this.id + "; number of rows is: " + bodyRows.length;
    this._setSelectedItems(rowIndex != -1 ? [rowIndex] : []);
  }
  table.__getSelectedRowIndexes = function() {
    if (this._selectableItems != "rows")
      throw "getSelectedRowIndexes: The specified table is not set up for row selection. Selectable items are: " + this._selectableItems + "; table's clientId is: " + this.id;
    if (!this._multipleSelectionAllowed)
      throw "getSelectedRowIndexes can only used on a table with multiple selection mode; table's clientId is: " + this.id;

    var selectedItems = this._getSelectedItems();
    if (!selectedItems || (selectedItems.length == 1 && selectedItems[0] == -1))
      selectedItems = [];
    return selectedItems;
  }
  table.__setSelectedRowIndexes = function(rowIndexes) {
    if (this._selectableItems != "rows")
      throw "setSelectedRowIndexes: The specified table is not set up for row selection. Selectable items are: " + this._selectableItems + "; table's clientId is: " + this.id;
    if (!this._multipleSelectionAllowed)
      throw "setSelectedRowIndexes can only used on a table with multiple selection mode; table's clientId is: " + this.id;
    if (!rowIndexes)
      rowIndexes = [];

    var bodyRows = table.__getRowCount();
    for (var i = 0, count = rowIndexes.length; i < count; i++) {
      var rowIndex = rowIndexes[i];
      if (rowIndex < 0 || rowIndex >= bodyRows.length)
        throw "setSelectedRowIndexes parameter is out of range (" + rowIndex + "); table's clientId is: " + this.id + "; number of rows is: " + bodyRows.length;
    }
    this._setSelectedItems(rowIndexes);
  }
  table.__getRowCount = function() {
    if (this._noDataRows)
      return 0;
    var bodyRows = this._getBodyRows();
    var rowCount = bodyRows.length;
    return rowCount;
  }
}

function q__assignEvents(element, eventsArray) {
  if (!eventsArray || eventsArray.length == 0)
    return;
  for (var i = 0, count = eventsArray.length; i < count; i++) {
    var eventEntry = eventsArray[i];
    var eventName = eventEntry[0];
    var eventScript = eventEntry[1];

    var handlerFunction;
    eval('handlerFunction = function(event) {return eval(arguments.callee.prototype._handlerScript); }');
    handlerFunction.prototype._handlerScript = eventScript;
    q__addEventHandler(element, eventName, handlerFunction);
  }
}


function q__initRowCells(row) {
  var cells = q__getRowCells(row);
  row._cells = cells;
  row._cellsByColumns = new Array();
  var physicalColIndex = 0;
  for (var cellIndex = 0, cellCount = cells.length; cellIndex < cellCount; cellIndex++) {
    var cell = cells[cellIndex];
    cell._row = row;
    var cellColSpan = q__getCellColSpan(cell);
    cell._colSpan = cellColSpan;
    cell._physicalColIndex = physicalColIndex;
    row._cellsByColumns[physicalColIndex] = cell;
    physicalColIndex += cellColSpan;
    if (cell.innerHTML == "")
      cell.innerHTML = "&nbsp;";
  }
  row._getCellByPhysicalColIndex = function(index) {
    var cell = this._cellsByColumns[index];
    return cell ? cell : null;
  }
}

function q__getSubCellsArray(cell, physicalColIndex, subColCount) {
  var row = cell._row;
  if (subColCount == 0)
    return null;
  var cells = new Array();
  for (var i = 0; i < subColCount; i++) {
    var subCell = row._getCellByPhysicalColIndex(physicalColIndex + i);
    cells.push(subCell);
  }
  return cells;
}

/*
  There are "logical" and "physical" columns. This separation is needed for TreeTable which simulates TreeColumn
  with several columns. Logical columns are columns from the user's point of view, i.e. TreeColumns is a single logical
  column, though it consists of several physical columns. Physical columns are actual columns in the resulting DOM.
 */
function q__tableColumn(table, logicalColIndex, physicalColIndex, subColCount) {
  this._table = table;
  this._logicalColIndex = logicalColIndex;
  this._physicalColIndex = physicalColIndex;
  this._subColCount = subColCount;

  this._headerCells = new Array();
  var headRows = table._getHeaderRows();
  for (var i = 0, count = headRows.length; i < count; i++) {
    var row = headRows[i];
    var cell = row._getCellByPhysicalColIndex(physicalColIndex);
    if (cell) {
      cell._column = this;
      cell._logicalColIndex = logicalColIndex;
      cell._subCells = q__getSubCellsArray(cell, physicalColIndex, subColCount);
    }
    this._headerCells[i] = cell;
  }

  this._bodyCells = new Array();
  var bodyRows = table._getBodyRows();
  for (var i = 0, count = bodyRows.length; i < count; i++) {
    var row = bodyRows[i];
    var cell = q__initTableColumnCell(row, this);
    this._bodyCells[i] = cell;
  }

  this._footerCells = new Array();
  var footRows = table._getFooterRows();
  for (var i = 0, count = footRows.length; i < count; i++) {
    var row = footRows[i];
    var cell = row._getCellByPhysicalColIndex(physicalColIndex);
    if (cell) {
      cell._column = this;
      cell._logicalColIndex = logicalColIndex;
      cell._subCells = q__getSubCellsArray(cell, physicalColIndex, subColCount);
    }
    this._footerCells[i] = cell;
  }
}

function q__initTableColumnCell(row, column) {
  var colIndex = column._physicalColIndex;
  var cell = row._getCellByPhysicalColIndex(colIndex);
  if (cell) {
    cell._column = column;
    cell._logicalColIndex = column._logicalColIndex;
    cell._subCells = q__getSubCellsArray(cell, column._physicalColIndex, column._subColCount);
  }
  return cell;

}

// -------------------------- KEYBOARD NAVIGATION SUPPORT

function q__deinitializeTableKeyboardNavigation(table) {
  table.onfocus = null;
  table.onblur = null;
  if (table._focusControl) {
//    if (table._focused)
//      table.blur();
    table._focusControl.parentNode.removeChild(table._focusControl);
  }
}

function q__initTableKeyboardNavigation(tableId, controlPaging, focusedClassName, canPageBack, canPageForth, canSelectLastPage) {
  var table = document.getElementById(tableId);
  table._controlPagingWithKeyboard = controlPaging;
  table._focusedClassName = focusedClassName;
  table._canPageBack = canPageBack;
  table._canPageForth = canPageForth;
  table._canSelectLastPage = canSelectLastPage;

  q__setupArtificialFocus(table.id, table._focusedClassName);

  var pagingFld = document.getElementById(table.id + "::paging");
  if (pagingFld)
    pagingFld.value = "";
  table._performPagingAction = function(actionStr) {
    q__addHiddenField(this, this.id + "::paging", actionStr);
    q__submitTableInternal(this, null);
  }

  table._nextPage = function() {if (this._canPageForth) this._performPagingAction("selectNextPage");}
  table._previousPage = function() {if (this._canPageBack) this._performPagingAction("selectPrevPage");}
  table._firstPage = function() {if (this._canPageBack) this._performPagingAction("selectFirstPage");}
  table._lastPage = function() {if (this._canSelectLastPage) this._performPagingAction("selectLastPage");}
  table._selectPageNo = function(pageNo) {this._performPagingAction("selectPageNo:" + pageNo);}

  table._prevKeydown_kn = table.onkeydown;
  table.onkeydown = function (evt) {
    var e = evt ? evt : event;

    if (this._prevKeydown_kn)
      this._prevKeydown_kn(evt);

    var ctrlPressed = e.ctrlKey;
    var altPressed = e.altKey;
    var shiftPressed = e.shiftKey;
    var noModifiersPressed = !ctrlPressed && !altPressed && !shiftPressed;

    e.upPressed = false;
    e.downPressed = false;
    e.homePressed = false;
    e.endPressed = false;
    e.pageUpPressed = false;
    e.pageDownPressed = false;
    e.leftPressed = false;
    e.rightPressed = false;
    e.plusPressed = false;
    e.minusPressed = false;
    switch (e.keyCode) {
      case 33: // page up
        e.pageUpPressed = true;
        break;
      case 34: // page down
        e.pageDownPressed = true;
        break;
      case 35: // end
        e.endPressed = true;
        break;
      case 36: // home
        e.homePressed = true;
        break;
      case 37: // left
        e.leftPressed = true;
        break;
      case 38: // up
        e.upPressed = true;
        break;
      case 39: // right
        e.rightPressed = true;
        break;
      case 40: // down
        e.downPressed = true;
        break;
      case 107:
      case 43:
        e.plusPressed = true;
        break;
      case 109:
      case 45:
        e.minusPressed = true;
        break;
    }

    var passEvent = true;

    if (this._controlPagingWithKeyboard && !altPressed && !shiftPressed) {
      if (e.pageUpPressed) {
        passEvent = false;
        this._previousPage();
      }
      if (e.pageDownPressed) {
        passEvent = false;
        this._nextPage();
      }
      if (ctrlPressed && e.homePressed) {
        passEvent = false;
        this._firstPage();
      }
      if (ctrlPressed && e.endPressed) {
        passEvent = false;
        this._lastPage();
      }
    }

    if (this._selectionKeyboardSupport && this._selectionEnabled) {
      var rowCount = this.__getRowCount();
      if (this._multipleSelectionAllowed && !altPressed && !ctrlPressed) {      // ------ multiple selection
        var selectedRowIndexes = this.__getSelectedRowIndexes();
        var idx;
        if (selectedRowIndexes.length == 0)
          idx = -1;
        else if (selectedRowIndexes.length == 1)
          idx = selectedRowIndexes[0];
        else {
          idx = this._rangeEndRowIndex;
          if (!idx)
            idx = selectedRowIndexes[0];
        }

        if (!shiftPressed) {
          var newIdx = q__checkTableNavigation(this, idx, rowCount, e);
          if (newIdx != null) {
            passEvent = false;
            this.__setSelectedRowIndexes([newIdx]);
            q__scrollToRowIndexes(this, [newIdx]);
            this._baseRowIndex = null;
            this._baseSelectedRowIndexes = null;
            this._rangeEndRowIndex = null;
          }
        } else {
          var baseRowIndex = this._baseRowIndex;
          if (baseRowIndex == null) {
            baseRowIndex = idx != -1 ? idx : 0;
            this._baseRowIndex = baseRowIndex;
            this._baseSelectedRowIndexes = selectedRowIndexes;
          }
          var rangeEndRowIndex = this._rangeEndRowIndex;
          if (rangeEndRowIndex == null)
            rangeEndRowIndex = baseRowIndex;
          var newRangeEndRowIndex = q__checkTableNavigation(this, rangeEndRowIndex, rowCount, e);
          if (newRangeEndRowIndex != null) {
            passEvent = false;
            var newSelectedRowIndexes = q__combineSelectedRowsWithRange(this, this._baseSelectedRowIndexes, baseRowIndex, newRangeEndRowIndex);
            this._rangeEndRowIndex = newRangeEndRowIndex;
            this.__setSelectedRowIndexes(newSelectedRowIndexes);
            q__scrollToRowIndexes(this, newSelectedRowIndexes);
          }
        }

      }
      if (!this._multipleSelectionAllowed && noModifiersPressed) {              // ------ single selection
        var idx = this.__getSelectedRowIndex();
        var newIdx = q__checkTableNavigation(this, idx, rowCount, e);
        if (newIdx != null) {
          passEvent = false;
          this.__setSelectedRowIndex(newIdx);
          q__scrollToRowIndexes(this, [newIdx]);
        }


      }
    }
    if (passEvent) {
      if (this._onKeyboardNavigation)
        passEvent = this._onKeyboardNavigation(e);
    }
    if (!passEvent) {
      e.cancelBubble = true;
//      if (q__isOpera()) {
//        window._scrollPos = q__getPageScrollPos();
//        window._restoreScrollPos = function() {
//          q__setScrollPos(window._scrollPos);
//        }
//        setTimeout("window._restoreScrollPos()", 1);
//      }
    }
    return passEvent;
  }

  table._prevOnfocus_kn = table.onfocus;
  table.onfocus = function(e) {
    if (this._submitting)
      return;
    if (this._prevOnfocus_kn)
      this._prevOnfocus_kn(e);
    var focusFld = document.getElementById(this.id + "::focused");
    focusFld.value = "true";
  }

  table._prevOnblur_kn = table.onblur;
  table.onblur = function(e) {
    if (this._submitting)
      return;
    if (this._prevOnblur_kn)
      this._prevOnblur_kn(e);
    var focusFld = document.getElementById(this.id + "::focused");
    focusFld.value = "false";
  }

  var focusFld = document.getElementById(table.id + "::focused");
  if (focusFld.value == "true") {
    window._tableToFocus = table;
    setTimeout("window._tableToFocus.focus()", 1);
  }
}

function q__scrollToRowIndexes(table, rowIndexes) {
  var bodyRows = table._getBodyRows();

  var boundingRect = null;
  for (var i = 0, count = rowIndexes.length; i < count; i++) {
    var rowIndex = rowIndexes[i];
    var row = bodyRows[rowIndex];
    var x = q__getElementLeft(row);
    var y = q__getElementTop(row);
    var rect = new q__Rectangle(x, y, row.offsetWidth, row.offsetHeight);
    if (!boundingRect)
      boundingRect = rect;
    else
      boundingRect.addRectangle(rect);
  }

  if (boundingRect)
    q__scrollRectIntoView(boundingRect);
}


function q__combineSelectedRowsWithRange(table, baseSelectedRowIndexes, baseRowIndex, rangeEndRowIndex) {
  q__assert(baseRowIndex, "q__combineSelectedRowsWithRange: baseRowIndex should be specified");
  q__assert(rangeEndRowIndex, "q__combineSelectedRowsWithRange: rangeEndRowIndex should be specified");

  var result = new Array();
  var alreadyIncludedIndexes = new Array();
  var rangeStart, rangeEnd;
  if (baseRowIndex < rangeEndRowIndex) {
    rangeStart = baseRowIndex;
    rangeEnd = rangeEndRowIndex;
  } else {
    rangeStart = rangeEndRowIndex;
    rangeEnd = baseRowIndex;
  }

  if (baseSelectedRowIndexes)
    for (var i = 0, count = baseSelectedRowIndexes.length; i < count; i++) {
      var idx = baseSelectedRowIndexes[i];
      result.push(idx);
      if (idx >= rangeStart && idx <= rangeEnd)
        alreadyIncludedIndexes.push(idx);
    }

  var bodyRows = table._getBodyRows();
  for (var i = rangeStart; i <= rangeEnd; i++) {
    if (q__findValueInArray(i, alreadyIncludedIndexes) == -1) {
      var row = bodyRows[i];
      if (row._visible)
        result.push(i);
    }
  }
  return result;
}

function q__checkTableNavigation(table, idx, rowCount, e){
  var newIndex = null;
  if (e.upPressed) {
    if (idx == -1)
      newIndex = q__getNeighboringVisibleRowIndex(table, -1, +1);
    else
      newIndex = q__getNeighboringVisibleRowIndex(table, idx, -1);
  }
  if (e.downPressed) {
    if (idx == -1)
      newIndex = q__getNeighboringVisibleRowIndex(table, -1, +1);
    else
      newIndex = q__getNeighboringVisibleRowIndex(table, idx, +1);
  }
  if (e.homePressed) {
    newIndex = q__getNeighboringVisibleRowIndex(table, idx, -rowCount);
  }
  if (e.endPressed) {
    newIndex = q__getNeighboringVisibleRowIndex(table, idx, rowCount);
  }
  /*
  if (e.pageUpPressed) {
    if (idx == -1)
      newIndex = q__getNeighboringVisibleRowIndex(table, -1, +1);
    else
      newIndex = q__getNeighboringVisibleRowIndex(table, idx, -5);
  }
  if (e.pageDownPressed) {
    if (idx == -1)
      newIndex = q__getNeighboringVisibleRowIndex(table, -1, +1);
    else
      newIndex = q__getNeighboringVisibleRowIndex(table, idx, +5);
  }
  */

  return newIndex;
}

function q__showControlOutline(control, outlineStyleClass) {
  if (!outlineStyleClass)
    return;
  if (!control._outline) {
    var outline = document.createElement("div");
    outline._control = control;
    outline._updatePosition = function() {
      var outlineToControlSpacingPx = 2;
      var x = q__getElementLeft(control);
      var y = q__getElementTop(control);
      var width = this._control.offsetWidth;
      var height = this._control.offsetHeight;

      this.style.position = "absolute";
      this.style.left   = (x - outlineToControlSpacingPx) + "px";
      this.style.top    = (y - outlineToControlSpacingPx) + "px";
      this.style.width  = (width + outlineToControlSpacingPx * 2) + "px";
      this.style.height = (height + outlineToControlSpacingPx * 2) + "px";
      this.style.zIndex = -1000;
    }
    control._outline = outline;
    document.body.appendChild(outline);
  } else {
    control._outline.style.visibility = "visible";
  }
  control._outline._updatePosition();
}

function q__hideControlOutline(control) {
  if (!control._outline)
    return;
  control._outline.style.visibility = "hidden";
}

var q__tableBlurCounter = 0;

function q__setupArtificialFocus(tableId, focusedClassName) {
  var table = document.getElementById(tableId);

  table._focusedClassName = focusedClassName;

  table._focused = false;
  table._updateOutline = function() {
    if (this._outlineUpdateBlocked)
      return;
    this._updayStyle();
    if (this._focused)
      q__showControlOutline(this, null);
    else
      q__hideControlOutline(this);
  }

  table._blockOutlineUpdate = function() {
    this._outlineUpdateBlocked = true;
    this._focusedBeforeBlocking = this._focused;
  }

  table._unblockOutlineUpdate = function () {
    if (!q__tableBlurCounter)
      q__tableBlurCounter = 0;
    var varName = "tc_unblockedControl" + q__tableBlurCounter++;
    window[varName] = this;
    setTimeout("window." + varName + "._doUnblockOutlineUpdate()", 1);
  }
  table._doUnblockOutlineUpdate = function() {
    this._outlineUpdateBlocked = false;
    if (this._focusedBeforeBlocking != null && this._focusedBeforeBlocking != this._focused) {
      this._focusedBeforeBlocking = null;
      if (this._focused) {
        if (this._prevOnfocusHandler_af)
          this._prevOnfocusHandler_af(null);
      } else {
        if (this._prevOnblurHandler_af)
          this._prevOnblurHandler_af(null);
      }
    }
    this._updateOutline();
  }

  table._prevOnfocusHandler_af = table.onfocus;
  table._prevOnblurHandler_af = table.onblur;

  table.onfocus = function(evt) {
    if (this._submitting)
      return;
    this._focused = true;
    if (this._prevOnfocusHandler_af && !this._outlineUpdateBlocked)
      this._prevOnfocusHandler_af(evt);

    table._updateOutline();
  }
  table.onblur = function(evt) {
    if (this._submitting)
      return;
    this._focused = false;
    if (this._prevOnblurHandler_af && !this._outlineUpdateBlocked)
      this._prevOnblurHandler_af(evt);
    var varName = "tc_blurredControl" + q__tableBlurCounter++;
    window[varName] = this;
    setTimeout("window." + varName + "._updateOutline()", 1);
  }

  var focusControl = q__createHiddenFocusElement();

  focusControl._table = table;
  focusControl.onfocus = function(evt) {
    this._prevStatusText = window.status;
    window.status = "";
    return q__fireEvent(this._table, "onfocus", evt);
  }
  focusControl.onblur = function(evt) {
    window.status = this._prevStatusText;
    return q__fireEvent(this._table, "onblur", evt);
  }
  focusControl.onkeydown = function(evt) {
    return q__fireEvent(this._table, "onkeydown", evt);
  }
  focusControl.onkeyup = function(evt) {
    return q__fireEvent(this._table, "onkeyup", evt);
  }
  focusControl.onkeypress = function(evt) {
    return q__fireEvent(this._table, "onkeypress", evt);
  }

  table._focusControl = focusControl;

  table._focusOnClick = function(evt) {
    if (window.getSelection) {
      if (window.getSelection() != "")
        return; // don't switch focus to make text selection possible under FF (JSFC-1134)
    }
    var e = evt ? evt : event;
    if (this._focused)
      return;

    var target = (e != null)
        ? (e.target ? e.target : e.srcElement)
        : null;
    if (target.id && target.id == this.id)
      return;
    if (q__isControlFocusable(target))
      return;
    this.focus();
  }

  table.focus = function() {
    this._focusControl.focus();
  }

  table.blur = function() {
    this._focusControl.blur();
  }

  q__addEventHandlerSimple(table, "click", "_focusOnClick");
  q__addEventHandlerSimple(table, "mousedown", "_blockOutlineUpdate");
  q__addEventHandlerSimple(table, "mouseup", "_unblockOutlineUpdate");
  q__addEventHandlerSimple(table, "mouseout", "_unblockOutlineUpdate");

  table.parentNode.insertBefore(focusControl, table);
}

function q__fireEvent(object, eventName, param) {
  var handler = object[eventName];
  if (!handler)
    return;
  if (q__isExplorer())
    return object[eventName]();
  else
    return object[eventName](param);
}

function q__isControlFocusable(control) {
  if (!control)
    return false;

  if (control._focusable)
    return true;
  var tagName = control.tagName;
  if (!tagName)
    return false;
  tagName = tagName.toLowerCase();
  if (tagName == "input" ||
      tagName == "select" ||
      tagName == "textarea" ||
      tagName == "button" ||
      tagName == "a")
    return true;
  else
    return false;
}

function q__getNeighboringVisibleRowIndex(table, startRowIndex, stepCount) {
  var bodyRows = table._getBodyRows();
  if (stepCount == 0)
    return bodyRows[startRowIndex];
  var dir = (stepCount > 0) ? +1 : -1;
  var rowIndex = startRowIndex;
  var destRowIndex = startRowIndex;
  var stepsRemaining = (stepCount > 0) ? stepCount : -stepCount;
  while (stepsRemaining > 0) {
    rowIndex += dir;
    if (rowIndex < 0 || rowIndex >= bodyRows.length)
      break;
    var row = bodyRows[rowIndex];
    if (row._visible) {
      destRowIndex = rowIndex;
      stepsRemaining--;
    }
  }
  return destRowIndex;
}


// -------------------------- TABLE SELECTION SUPPORT

function q__initTableSelection(tableId, enabled, selectableItems, multipleSelectionAllowed, selectedItems, selectionClass,
        selectionChangeHandler, postEventOnSelectionChange, selectionColumnIndexes, mouseSupport,
        keyboardSupport) {
  var table = document.getElementById(tableId);
  q__assert(table, "Couldn't find table by id: " + tableId);

  q__assert(!table._selectionInitialized, "q__initTableSelection shouldn't be called twice on the same table");
  table._selectionInitialized = true;

  // initialize fields
  table._selectionEnabled = !table._noDataRows && enabled;
  table._selectableItems = selectableItems;
  table._multipleSelectionAllowed = multipleSelectionAllowed;
  table._selectionClass = selectionClass;
  table._selectionColumnIndexes = selectionColumnIndexes;
  table._selectionMouseSupport = mouseSupport;
  table._selectionKeyboardSupport = keyboardSupport;

  // initialize function references
  table._selectItem = q__table_selectItem;
  table._unselectItem = q__table_unselectItem;
  table._getSelectedItems = function(items) {
    if (!this._selectedItems)
      this._selectedItems = [];
    return this._selectedItems;
  }
  table._setSelectionFieldValue = function (value) {
    var selectionFieldId = this.id + "::selection";
    var selectionField = document.getElementById(selectionFieldId);
    q__assert(selectionField, "Couldn't find selectionField by id: " + selectionFieldId);
    selectionField.value = value;
  }
  table._setSelectedItems = function(items, forceUpdate) {
    var changesArray = new Array();
    var changesArrayIndexes = new Array();
    var oldSelectedItemsStr = "";
    if (this._selectedItems)
      for (var i = 0; i < this._selectedItems.length; i++) {
        var item = this._selectedItems[i];
        if (i > 0)
          oldSelectedItemsStr += ",";
        oldSelectedItemsStr += item;
        changesArray[item] = "unselect";
        changesArrayIndexes.push(item);
      }
    if (!this._multipleSelectionAllowed && items && items.length > 1)
      items = [items[0]];
    if (items.length == 1 && items[0] == -1)
      items = [];
    this._selectedItems = items;
    var newSelectedItemsStr = "";
    if (this._selectedItems) {
      for (var i = 0; i < this._selectedItems.length; i++) {
        if (i > 0)
          newSelectedItemsStr += ",";
        var itemToSelect = this._selectedItems[i];
        q__assert(itemToSelect, "table._setSelectedItems: itemToSelect is undefined for index " + i);
        newSelectedItemsStr += itemToSelect;
        if (changesArray[itemToSelect] == "unselect" && !forceUpdate)
          changesArray[itemToSelect] = null;
        else
          changesArray[itemToSelect] = "select";
        changesArrayIndexes.push(itemToSelect);
      }
    }

    for (var i = 0, count = changesArrayIndexes.length; i < count; i++) {
      var changesArrayIndex = changesArrayIndexes[i];
      var change = changesArray[changesArrayIndex];
      if (change) {
        if (change == "select")
          this._selectItem(changesArrayIndex);
        if (change == "unselect")
          this._unselectItem(changesArrayIndex);
        changesArray[changesArrayIndex] = null;
      }
    }

    var selectionFieldValue = q__formatSelectedItems(this._selectableItems, this._selectedItems);
    this._setSelectionFieldValue(selectionFieldValue);
    if (!this._blockSelectionChangeNotifications && oldSelectedItemsStr != newSelectedItemsStr) {
      if (this._selectionChangeHandlers) {
        for (var handlerIdx = 0, handlerCount = this._selectionChangeHandlers.length; handlerIdx < handlerCount; handlerIdx++)
          this._selectionChangeHandlers[handlerIdx]();
      }
      if (this._postEventOnSelectionChange) {
        var eventFieldId = this.id + "::selectionEvent";
        var eventField = document.getElementById(eventFieldId);
        eventField.value = this._postEventOnSelectionChange;
        window._submittingTable = this;
        setTimeout("q__submitEnclosingForm(window._submittingTable);", 1);
      }
    }
  }

  table._selectAllItems = function() {
    q__assert(this._multipleSelectionAllowed, "table._selectAllItems: multiple selection is not allowed for table: " + this.id);

    if (this._noDataRows)
      return;
    if (this._selectableItems == "rows") {
      var rows = this._getBodyRows();
      var allItems = new Array();
      for (var i = 0, count = rows.length; i < count; i++)
        allItems[i] = i;
      this._setSelectedItems(allItems);
    }
  }

  table._unselectAllItems = function() {
    this._setSelectedItems([]);
  }

  table._isItemSelected = function(item) {
    var result = q__findValueInArray(item, selectedItems) != -1;
    return result;
  }

  table._toggleItemSelected = function(itemIndex) {
    if (itemIndex == -1) {
      q__logError("_toggleItemSelected: itemIndex == -1");
      return;
    }
    var selectedIndexes = this._selectedItems;
    var newArray = new Array();
    for (var i = 0, count = selectedIndexes.length; i < count; i++) {
      var idx = selectedIndexes[i];
      if (idx != itemIndex)
        newArray[newArray.length] = idx;
    }
    if (newArray.length == selectedIndexes.length)
      newArray[newArray.length] = itemIndex;
    this._setSelectedItems(newArray);
  }

  // run initialization code
  if (selectableItems == "rows") {
    var rows = table._getBodyRows();
    for (var i = 0, count = rows.length; i < count; i++) {
      var row = rows[i];
      q__initRowForSelection(row);
    }
  }

  table._setSelectedItems(selectedItems);
  table._setSelectionFieldValue("");

  table._selectionChangeHandler = selectionChangeHandler;
  table._invokeUserSelectionStateHandler = function() {
    if (this._selectionChangeHandler)
      eval(this._selectionChangeHandler);
  }
  if (selectionChangeHandler != null)
    q__addTableSelectionChangeHandler(table, q__getEventHandlerFunction("_invokeUserSelectionStateHandler", "", table));
  table._postEventOnSelectionChange = postEventOnSelectionChange;

  table._addRowInsertionCallback(function(table, insertedAfterIndex, insertedRows){
    var insertedRowCount = insertedRows.length;
    for (var i = 0; i < insertedRowCount; i++) {
      var insertedRow = insertedRows[i];
      q__initRowForSelection(insertedRow);
    }
    var selectedItems = table._getSelectedItems();
    if (table._selectableItems != "rows")
      throw "Not supported selectable item type: " + table._selectableItems;

    var selectedItemCount = selectedItems.length;
    if (selectedItemCount > 0) {
      var newSelectedItems = new Array();
      var selectionChanged = false;
      for (var i = 0; i < selectedItemCount; i++) {
        var rowIndex = selectedItems[i];
        if (rowIndex > insertedAfterIndex) {
          rowIndex += insertedRowCount;
          selectionChanged = true;
        }
        newSelectedItems.push(rowIndex);
      }
      /*if (selectionChanged) */{
        table._blockSelectionChangeNotifications = true;
        table._setSelectedItems(newSelectedItems, true);
        table._blockSelectionChangeNotifications = false;
      }
    }
  });
}

function q__initRowForSelection(row) {
  var table = row._table;
  if (table._selectionEnabled) {
    if (row._originalClickHandler)
      q__logError("q__initTableSelection: row click handler already initialized");
    row._originalClickHandler = row.onclick;
    row.onclick = q__tableRow_handleSelectionOnClick;
  }
  var cells = row._cells;
  var colIndex = 0;
  for (var cellIndex = 0, cellCount = cells.length; cellIndex < cellCount; cellIndex++) {
    var cell = cells[cellIndex];
    var cellSpan = q__getCellColSpan(cell);
    var logicalColIndex = cell._logicalColIndex;
    if ((logicalColIndex != undefined) && (q__findValueInArray(logicalColIndex, table._selectionColumnIndexes) != -1))
      q__initSelectionCell(cell);
    colIndex += cellSpan;
  }
}

function q__addTableSelectionChangeHandler(table, handler) {
  q__assert(handler, "q__addTableSelectionChangeHandler: handler must be specified. table.id = " + table.id);
  var handlers = table._selectionChangeHandlers;
  if (!handlers) {
    handlers = new Array();
    table._selectionChangeHandlers = handlers;
  }
  handlers[handlers.length] = handler;
}

function q__initSelectionCell(cell) {
  var checkBoxAsArray = q__getChildNodesWithNames(cell, ["input"]);
  q__assert(checkBoxAsArray.length == 1);
  if (!checkBoxAsArray || checkBoxAsArray.length == 0)
    return;
  var checkBox = checkBoxAsArray[0];
  if (!checkBox)
    return;
  checkBox._cell = cell;
  var row = cell._row;
  var table = row._table;
  checkBox.checked = false; // fix for Mozilla's issue: reloading a page retains previous values for inputs regardless of their values received from server
  checkBox.disabled = !table._selectionEnabled;
  cell._selectionCheckBox = checkBox;
  cell.onclick = function(evt) {
    cell._handlingClick = true;
    try {
      var cellRow = this._row;
      var cellTable = cellRow._table;
      if (!cellTable._selectionEnabled)
        return;
      if (cellTable._multipleSelectionAllowed) {
        this._selectionCheckBox.checked = !this._selectionCheckBox.checked;
        this._selectionCheckBox.onclick(evt);
      } else {
        if (!this._selectionCheckBox.checked) {
          this._selectionCheckBox.checked = true;
          this._selectionCheckBox.onclick(evt);
        }
      }
    } finally {
      cell._handlingClick = false;
    }
  }
  checkBox.onclick = function(evt) {
    if (evt)
      event = evt;
    var checkBoxCell = this._cell;
    if (!checkBoxCell._handlingClick)
      return;
    var checkBoxRow = checkBoxCell._row;
    var checkBoxTable = checkBoxRow._table;
    if (!checkBoxTable._selectionEnabled)
      return;
    if (checkBoxTable._selectableItems != "rows")
      return;
    if (!checkBoxTable._multipleSelectionAllowed) {
      if (this.checked)
        checkBoxTable._setSelectedItems([checkBoxRow._index]);
       else
        checkBoxTable._setSelectedItems([]);
      event.cancelBubble = true;
    } else {
      var selectedItems = checkBoxTable._getSelectedItems();
      var itemSelected = checkBoxTable._isItemSelected(row._index)
      if (itemSelected != this.checked);
        checkBoxTable._toggleItemSelected(row._index);
      event.cancelBubble = true;
    }
  }
  var cellRow = cell._row;
  if (!cellRow._selectionCheckBoxes)
    cellRow._selectionCheckBoxes = new Array();
  cellRow._selectionCheckBoxes[cellRow._selectionCheckBoxes.length] = checkBox;
}

function q__tableRow_handleSelectionOnClick(evt) {
  if (this._originalClickHandler)
    this._originalClickHandler(evt);

  if (evt)
    event = evt;

  var table = this._table;
  if (!table._selectionMouseSupport)
    return;
  if (table._selectableItems == "rows") {
    table._baseRowIndex = null;
    table._baseSelectedRowIndexes = null;
    table._rangeEndRowIndex = null;
    if (!table._multipleSelectionAllowed) {
      table._setSelectedItems([this._index]);
    } else {
      if (event.ctrlKey || event.metaKey) {
        table._toggleItemSelected(this._index);
        var newSelectedRowIndexes = table.__getSelectedRowIndexes();
        table._baseRowIndex = (q__findValueInArray(this._index, newSelectedRowIndexes) != -1) ? this._index : null;
        table._baseSelectedRowIndexes = newSelectedRowIndexes;
        table._rangeEndRowIndex = null;
      } else
        table._setSelectedItems([this._index]);
    }
  }
}

function q__formatSelectedItems(selectableItems, selectedItemIndexes) {
  if (selectableItems == "rows" || selectableItems == "columns") {
    var result = "[";
    for (var i = 0; i < selectedItemIndexes.length; i++) {
      var itemIndex = selectedItemIndexes[i];
      if (result.length > 1)
        result += ",";
      result += itemIndex;
    }
    result += "]";
    return result;
  }
  q__logError("q__formatSelectedItems: unknown selectableItems: " + selectableItems);
}

function q__table_selectItem(itemIndex) {
  q__assert(itemIndex, "q__table_selectItem: itemIndex should be specified");
  if (this._selectableItems == "rows") {
    if (itemIndex == -1)
      return;
    var rows = this._getBodyRows();
    if (itemIndex < 0 || itemIndex >= rows.length)
      throw "Row index out of range: " + itemIndex;
    var row = rows[itemIndex];
    row._selected = true;
    row._updayStyle();
    q__setSelectionCheckboxesSelected(row, true);
  }
}

function q__table_unselectItem(itemIndex) {
  q__assert(itemIndex, "q__table_unselectItem: itemIndex should be specified");
  if (this._selectableItems == "rows") {
    if (itemIndex == -1)
      return;
    var rows = this._getBodyRows();
    var row = rows[itemIndex];

    row._selected = false;
    row._updayStyle();
    q__setSelectionCheckboxesSelected(row, false);
  }
}

function q__setSelectionCheckboxesSelected(row, selected) {
  if (row._selectionCheckBoxes) {
    for (var i = 0, count = row._selectionCheckBoxes.length; i < count; i++) {
      var checkbox = row._selectionCheckBoxes[i];
      checkbox.checked = selected;
    }
  }
}

function q__initCheckboxColHeader(headerId, colId) {
  var header = document.getElementById(headerId);
  var table = q__findParentNode(header, "TABLE");
  if (!table)
    throw "SelectAllCheckbox must be placed in a header of <q:dataTable> component. clientId = " + headerId;
  header._table = table;
  header._columnObjectId = colId;

  if (!table._checkBoxColumnHeaders)
    table._checkBoxColumnHeaders = new Array();
  if (!table._checkBoxColumnHeaders[colId])
    table._checkBoxColumnHeaders[colId] = new Array();
  var colHeadersArray = table._checkBoxColumnHeaders[colId];
  colHeadersArray[colHeadersArray.length] = header;

  header._updateFromCheckboxes = function(tableColumn) {
    var cells = tableColumn._bodyCells;
    var allChecked = true;
    for (var i = 0, count = cells.length; i < count; i++) {
      var cell = cells[i];
      if (!cell)
        continue;
      var checkBox = cell._checkBox;
      if (checkBox && !checkBox.checked) {
        allChecked = false;
        break;
      }
    }
    this.checked = allChecked;
  };

  header.onclick = function() {
    var cell = q__findAnyParentNode(this, ["td", "th"]);
    var col = cell._column;
    q__setAllCheckboxes(col, this.checked);
    var columnObj = document.getElementById(this._columnObjectId);
    columnObj._updateHeaderCheckBoxes();
    col._updateSubmissionField();
  }
}

function q__setAllCheckboxes(col, checked) {
  var cells = col._bodyCells;
  for (var i = 0, count = cells.length; i < count; i++) {
    var cell = cells[i];
    cell._checkBox.checked = checked;
  }
}

function q__initSelectionHeader(headerId) {
  var header = document.getElementById(headerId);
  var table = q__findParentNode(header, "TABLE");
  if (!table)
    throw "SelectAllCheckbox must be placed in a header of <q:dataTable> component. clientId = " + headerId;
  header._table = table;
  header._updateStateFromTable = function(table) {
    var headerTable = this._table;
    var selectedItems = headerTable._getSelectedItems();
    var bodyRows = headerTable._getBodyRows();
    if (selectedItems.length == 0) {
      this.checked = false;
    } else if (selectedItems.length == bodyRows.length) {
      this.checked = true;
    } else {
      this.checked = false;
    }
  };
  q__addTableSelectionChangeHandler(table,
          q__getEventHandlerFunction("_updateStateFromTable", "'" + table.id + "'", header)
          );
  header.onclick = function() {
    if (this.disabled) {
      this.disabled = false;
      this.checked = true;
      this._table._selectAllItems();
    } else {
      if (this.checked)
        this._table._selectAllItems();
      else
        this._table._unselectAllItems();
    }
  }
}

// -------------------------- CHECKBOX COLUMN SUPPORT
function q__initCheckboxCol(tableId, colIndex, colId, checkedRowIndexes) {
  var table = document.getElementById(tableId);
  var tableColumn = table._columns[colIndex];
  var columnObj = document.getElementById(colId);
  tableColumn._submissionField = columnObj;
  columnObj._tableColumn = tableColumn;
  var bodyCells = tableColumn._bodyCells;
  for (var i = 0, count = bodyCells.length; i < count; i++) {
    var cell = bodyCells[i];
    if (!cell)
      continue;
    cell._column = tableColumn;
    if (!q__initCheckboxCell(cell, columnObj))
      continue;
    var shouldBeChecked = q__findValueInArray(i, checkedRowIndexes) != -1;
    cell._checkBox.checked = shouldBeChecked;
  }

  tableColumn._updateSubmissionField = function() {
    var field = this._submissionField;
    var selectedRows = "";
    for (var i = 0, count = bodyCells.length; i < count; i++) {
      var cell = bodyCells[i];
      if (!cell)
        continue;
      if (cell._checkBox && cell._checkBox.checked) {
        if (selectedRows.length > 0)
          selectedRows += ",";
        selectedRows += i;
      }
    }
    this._submissionField.value = selectedRows;
  }
  tableColumn._updateSubmissionField();

  if (table._checkBoxColumnHeaders) {
    var columnHeadersArray = table._checkBoxColumnHeaders[colId];
    columnObj._headers = columnHeadersArray;
  }

  columnObj._updateHeaderCheckBoxes = function() {
    var tableCol = this._tableColumn;
    for (var i = 0, count = this._headers.length; i < count; i++) {
      var header = this._headers[i];
      header._updateFromCheckboxes(tableCol);
    }
  }

  columnObj._updateHeaderCheckBoxes();
}

function q__initCheckboxCell(cell, colField) {
  var checkBoxAsArray = q__getChildNodesWithNames(cell, ["input"]);
  q__assert(checkBoxAsArray.length == 1);
  var checkBox = checkBoxAsArray[0];
  if (!checkBox)
    return false;
  checkBox._cell = cell;
  cell._checkBox = checkBox;
  cell._columnObj = colField;
  cell.onclick = function(evt) {
    if (evt)
      event = evt;
    if (event._checkBoxClickProcessed) {
      event.cancelBubble = true;
      return;
    }
    var row = this._row;
    var table = row._table;
    this._checkBox.checked = !this._checkBox.checked;
    this._processCheckboxChange();
    event.cancelBubble = true;
    return false;
  }

  checkBox.onclick = function(evt) {
    if (evt)
      event = evt;
    var checkBoxCell = this._cell;
    checkBoxCell._processCheckboxChange();
    event._checkBoxClickProcessed = true;
    event.cancelBubble = true;
  }

  cell._processCheckboxChange = function() {
    var columnObj = this._columnObj;
    columnObj._updateHeaderCheckBoxes();
    cell._column._updateSubmissionField();
  }
  return true;
}

// -------------------------- TABLE SORTING SUPPORT

function q__initTableSorting(tableId, autoSortingRowIndex,
        columnSortableFlags, sortableColHeaderCursor, notSortableColHeaderCursor, sortedColIndex,
        sortedColStyleClass, sortedColHeaderStyleClass, sortedColBodyStyleClass, sortedColFooterStyleClass) {
  if (autoSortingRowIndex == -1)
    return;
  var table = document.getElementById(tableId);
  table._sortedColIndex = sortedColIndex;
  table._sortedColStyleClass = sortedColStyleClass;
  table._sortedColBodyStyleClass = sortedColBodyStyleClass;
  q__assert(table, "Couldn't find table by id: " + tableId);

  var headerRows = q__getRowsInSection(table, "thead");
  var autoSortingRow = headerRows[autoSortingRowIndex];

  for (var i = 0, count = table._columns.length; i < count; i++) {
    var column = table._columns[i]
    var colHeader = column._headerCells[autoSortingRowIndex];
    q__assert(colHeader, "Couldn't retrieve column header at rowIndex: " + autoSortingRowIndex);
    var columnSortable = columnSortableFlags[i];
    var newCursor = columnSortable ? sortableColHeaderCursor : notSortableColHeaderCursor;
    if (newCursor)
      q__setCellStyleProperty(colHeader, "cursor", newCursor);
    if (columnSortable) {
      q__setCellProperty(colHeader, "_table", table);
      q__setCellProperty(colHeader, "_index", i);
      var clickHandler = function() {
        if (this._prevOnclick)
          this._prevOnclick();
        var focusField = document.getElementById(table.id +"::focused")
        if (focusField)
          focusField.value = true; // set true explicitly before it gets auto-set when the click bubbles up (JSFC-801)
        q__toggleColumnSorting(this._table, this._index);
      };
      if (!colHeader._subCells) {
        colHeader._prevOnclick = colHeader.onclick;
        colHeader.onclick = clickHandler;
      } else {
        var subCells = colHeader._subCells;
        for (var subCellIndex = 0, subCellCount = subCells.length; subCellIndex < subCellCount; subCellIndex++) {
          var subCell = subCells[subCellIndex];
          if (!subCell)
            continue;
          subCell._prevOnclick = subCell.onclick;
          subCell.onclick = clickHandler;
        }
      }
    }
  }

  if (sortedColIndex != -1) {
    var column = table._columns[table._sortedColIndex];
    var headerCells = column._headerCells;
    var startIdx = table._headerFacetUsed ? 1 : 0;
    for (var cellIndex = startIdx, cellCount = headerCells.length; cellIndex < cellCount; cellIndex++) {
      var cell = headerCells[cellIndex];
      if (!cell)
        continue;
      if (cellIndex == startIdx)
        q__appendCellClassNames(cell, [sortedColStyleClass, sortedColHeaderStyleClass]);
      else
        ;//q__appendClassNames(cell, [sortedColStyleClass]);
    }

    q__appendSortedColBodyStyles(table, 0);

    var footerCells = column._footerCells;
    for (var cellIndex = 0, cellCount = table._footerFacetUsed ? footerCells.length - 1 : footerCells.length; cellIndex < cellCount; cellIndex++) {
      var cell = footerCells[cellIndex];
      if (cell)
        q__appendCellClassNames(cell, [sortedColStyleClass, sortedColFooterStyleClass]);
    }
  }

  table._addRowInsertionCallback(function(table, afterRowIndex, insertedRows) {
    q__appendSortedColBodyStyles(table, afterRowIndex);
  });

}

function q__appendSortedColBodyStyles(table, startingRowIndex) {
  var colIndex = table._sortedColIndex;
  if (colIndex == -1)
    return;
  var column = table._columns[colIndex];
  var bodyCells = column._bodyCells;
  for (var cellIndex = startingRowIndex, cellCount = bodyCells.length; cellIndex < cellCount; cellIndex++) {
    var cell = bodyCells[cellIndex];
    if (cell)
      q__appendCellClassNames(cell, [table._sortedColStyleClass, table._sortedColBodyStyleClass]);
  }
}


function q__toggleColumnSorting(table, columnIndex) {
  var sortingFieldId = table.id + "::sorting";
  var sortingField = document.getElementById(sortingFieldId);
  sortingField.value = "" + columnIndex;
  q__submitTableInternal(table);
}

function q__submitTableWithField(tableId, focusedField) {
  var focusedFieldId = focusedField ? focusedField.id : null;
  var table = document.getElementById(tableId);
  document._filterFieldIdToFocus = focusedFieldId;
  document._focusFilterField = function() {
    var fieldId = document._filterFieldIdToFocus;
    if (!fieldId)
      return;
    var field = document.getElementById(fieldId);
    if (!field)
      return;
    if (field.focus)
      field.focus();
  }
  q__submitTableInternal(table, function() {
    setTimeout("document._focusFilterField();", 1);
  });
}

function q__performPagerAction(tableId, field, paramName, paramValue) {
  var table = document.getElementById(tableId);
  var hf = q__addHiddenField(table, paramName, paramValue);
  q__submitTableWithField(tableId, field);
  hf.parentNode.removeChild(hf);
}

function q__submitTableInternal(table, completionCallback) {
  var useAjax = table._useAjax;
  if (!useAjax)
    q__submitEnclosingForm(table);
  else {
    q__reloadComponent(table.id, completionCallback);
  }
}

function q__submitDropDownFilter(tableId, filter) {
  var table = document.getElementById(tableId);
  if (table._useAjax)
    q__submitTableWithField(tableId, filter);
  else
    q__submitEnclosingForm(table);
}


function q__showTableFilter(tableId, filterId) {
  var table = document.getElementById(tableId);
  var f = document.getElementById(filterId);

  if (!table._filtersToHide)
    table._filtersToHide = new Array();
  table._filtersToHide.push(f);
}


//AUTO GENERATED CODE

window['tc_loadedLibrary:/teamdev/internalResource/teamdev/jsf/renderkit/datatable/table.js'] = true;