/**
 * @fileoverview Plugin for southprojects Grid to input grid data from XML source.
 *
 * <pre>
 * Copyright (c) 2006 by SouthProjects
 * http://www.southprojects.com
 * Santiago, Chile,
 * Version 1.2 Dec 2006.
 * All rights reserved.
 * </pre>
 */

/* $Id: spgrid-xml.js 5116 2006-11-14 18:59:54Z alex $ */

/**
 * Loads data from XML source.
 *
 * @private
 * @param {object} objDocument Input XMLDocument object.
 */
southprojects.Grid.prototype.loadDataXml = function(objDocument) {
  // Check arguments
  if (!objDocument || !objDocument.documentElement) {
    return;
  }
  var objTable =
   southprojects.Utils.getFirstChild(objDocument.documentElement, 'table');
  if (!objTable) {
    return;
  }
  var objFields = southprojects.Utils.getFirstChild(objTable, 'fields');
  if (!objFields) {
    return;
  }
  // Remove old data
  this.data = this.newDataXml(objTable);
  this.fields = this.data.fields;
  this.rows = this.data.rows;
  this.rowsIndex = [];
  // Set page
  if (typeof this.data.currentPage != 'undefined') {
    this.currentPage = this.data.currentPage;
  } else {
    this.currentPage = 0;
  }
  // Get fields
  var objCell = southprojects.Utils.getFirstChild(objFields, 'field');
  while (objCell) {
    // Add field
    this.fields.push(this.newFieldXml(objCell));
    // Next field
    objCell = southprojects.Utils.getNextSibling(objCell, 'field');
  }
  // Get rows
  var objRows = southprojects.Utils.getFirstChild(objTable, 'rows');
  if (objRows) {
    // Append rows
    objRows.setAttribute('noRefresh', 'noRefresh');
    this.spliceXml(objDocument);
  }
  // Show grid
  this.show();
};

/**
 * Creates new data object from XML source.
 *
 * @private
 * @param {object} objTable Source object
 * @return Data object
 * @type object
 */
southprojects.Grid.prototype.newDataXml = function(objTable) {
  // Create data object
  var objData = {
    fields: [],
    rows: []
  };
  // Get attributes
  var strStyle = objTable.getAttribute('style');
  if (strStyle) {
    objData.style = strStyle;
  }
  var strHeaderStyle = objTable.getAttribute('headerStyle');
  if (strHeaderStyle) {
    objData.headerStyle = strHeaderStyle;
  }
  var strTotalRows = objTable.getAttribute('totalRows');
  if (strTotalRows) {
    // Convert to number
    objData.totalRows = strTotalRows * 1;
  }
  var strDisplayedRows = objTable.getAttribute('displayedRows');
  if (strDisplayedRows) {
    // Convert to number
    objData.displayedRows = strDisplayedRows * 1;
  }
  var strCurrentPage = objTable.getAttribute('currentPage');
  if (strCurrentPage) {
    // Convert to number
    objData.currentPage = strCurrentPage * 1;
  }
  return objData;
};

/**
 * Creates new field object from XML source.
 *
 * @private
 * @param {object} objCell Source object
 * @return Field object
 * @type object
 */
southprojects.Grid.prototype.newFieldXml = function(objCell) {
  // Get title
  var objTitle = southprojects.Utils.getFirstChild(objCell, 'title');
  // Create field object
  var objField = {
    i: this.fields.length,
    title: southprojects.Utils.getChildText(objTitle)
  };
  // Set data type
  var objDataType = southprojects.Utils.getFirstChild(objCell, 'datatype');
  if (objDataType) {
    var strDataType = southprojects.Utils.getChildText(objDataType);
    if (strDataType) {
      objField.dataType = strDataType;
    }
  }
  // Set width
  var strWidth = objCell.getAttribute('width');
  if (strWidth) {
    strWidth += ''; // Convert to string
    if (strWidth.length) {
      objField.columnWidth = strWidth;
    }
  }
  // Set style
  var strStyle = objCell.getAttribute('style');
  if (strStyle) {
    objField.style = strStyle;
  }
  // Set span
  var strSpan = objCell.getAttribute('span');
  if (strSpan) {
    objField.span = strSpan * 1;
  }
  var strSpanTitle = objCell.getAttribute('spanTitle');
  if (strSpanTitle) {
    objField.spanTitle = strSpanTitle;
  }
  var strSpanStyle = objCell.getAttribute('spanStyle');
  if (strSpanStyle) {
    objField.spanStyle = strSpanStyle;
  }
  // Set hidden
  var boolHidden = (objCell.getAttribute('hidden') == 'true');
  if (boolHidden) {
    objField.hidden = boolHidden;
  }
  // Set nosort
  var boolNosort = (objCell.getAttribute('nosort') == 'true');
  if (boolNosort) {
    objField.nosort = boolNosort;
  }
  var strSortBy = objCell.getAttribute('sortbycolumn') + '';
  if (strSortBy.length && strSortBy != 'null' && strSortBy != 'undefined') {
    objField.sortByColumn = strSortBy * 1;
  }
  return objField;
};

/**
 * Changes content of the grid, adding new rows while removing old rows.
 *
 * <xmp>
 * Input XML format:
 *
 * <?xml version="1.0"?>
 * <grid>
 *   <table>
 *     <rows atRow="0" afterRow="0" howMany="0" noRefresh="noRefresh">
 *       <row style="background: #eee">
 *         <cell style="color: #f00">Value</cell>
 *         ...
 *       </row>
 *       ...
 *     </rows>
 *   </table>
 * </grid>
 *
 * Where:
 * "atRow" attribute [number, optional] id of row at which to start changing
 *  the grid (default: end of the grid);
 * "afterRow" attribute [number, optional] id of row after which to start
 *  changing the grid (ignored if atRow is defined);
 * "noRefresh" attribute [string, optional] indicates that grid should not be
 *  refreshed after changing (useful when several changes go one by one).
 * </xmp>
 *
 * XMLDocument object can be obtained from XML fragment using
 * southprojects.Transport.parseXml function.
 *
 * @param {object} objDocument XMLDocument object that describes one or several
 * rows to add.
 * @return Array with removed row objects. Number of removed rows can be
 * accessed through the length property of this array. If error occured, returns
 * undefined
 * @type object
 */
southprojects.Grid.prototype.spliceXml = function(objDocument) {
  // Check arguments
  if (!objDocument || !objDocument.documentElement) {
    return;
  }
  // Get table element
  var objTable =
   southprojects.Utils.getFirstChild(objDocument.documentElement, 'table');
  if (!objTable) {
    return;
  }
  // Get rows
  var objRows = southprojects.Utils.getFirstChild(objTable, 'rows');
  if (!objRows) {
    return;
  }
  // Will hold removed rows
  var arrRemoved = [];
  // Get insert position
  var iInsertPos = null;
  var strAtRow = objRows.getAttribute('atRow');
  if (strAtRow != null && strAtRow.length) {
    var iRowNum = strAtRow * 1;
    if (typeof this.rows[iRowNum] != 'undefined') {
      // Before specified row
      iInsertPos = iRowNum;
    }
  }
  if (iInsertPos == null) {
    var strAfterRow = objRows.getAttribute('afterRow');
    if (strAfterRow != null && strAfterRow.length) {
      var iRowNum = strAfterRow * 1;
      if (typeof this.rows[iRowNum] != 'undefined') {
        // After specified row
        iInsertPos = iRowNum + 1;
      }
    }
  }
  if (iInsertPos == null) {
    // End of the grid by default
    iInsertPos = this.rows.length;
  } else {
    // Delete rows
    var iHowManyToRemove = objRows.getAttribute('howMany') * 1;
    for (var iRemoved = 0; iRemoved < iHowManyToRemove; iRemoved++) {
      if (typeof this.rows[iInsertPos] == 'undefined') {
        // Tring to remove more rows than there are in the grid
        break;
      }
      var objRow = this.removeRow(iInsertPos);
      if (objRow) {
        arrRemoved.push(objRow);
      }
    }
  }
  // Insert new rows
  var objCurrRow = southprojects.Utils.getFirstChild(objRows, 'row');
  while (objCurrRow != null) {
    // Create row
    var objRow = this.newRowXml(objCurrRow);
    // Insert row
    this.rows.splice(iInsertPos++, 0, objRow);
    this.rowsIndex.push(objRow);
    // Next row
    objCurrRow = southprojects.Utils.getNextSibling(objCurrRow, 'row');
  }
  // Show grid
  if (!objRows.getAttribute('noRefresh')) {
    this.modify();
  }
  // Return removed rows
  return arrRemoved;
};

/**
 * Creates new row object from XML source.
 *
 * @private
 * @param {object} objCurrRow Source object
 * @return Row object
 * @type object
 */
southprojects.Grid.prototype.newRowXml = function(objCurrRow) {
  // Create new row object
  var objRow = {
    i: this.rowsIndex.length,
    cells: []
  };
  // Set style
  var strStyle = objCurrRow.getAttribute('style');
  if (strStyle) {
    objRow.style = strStyle;
  }
  // Get cells
  var objCurrCell = southprojects.Utils.getFirstChild(objCurrRow, 'cell');
  for (var iCol = 0; iCol < this.fields.length; iCol++) {
    // Add cell
    objRow.cells.push(this.newCellXml(objCurrCell, objRow.i, iCol));
    // Next cell
    if (objCurrCell) {
      objCurrCell = southprojects.Utils.getNextSibling(objCurrCell, 'cell');
    }
  }
  return objRow;
};

/**
 * Creates new cell object from XML source.
 *
 * @private
 * @param {object} objCurrCell Source object
 * @param {number} iRow Row id
 * @param {number} iCol Column id
 * @return Cell object
 * @type object
 */
southprojects.Grid.prototype.newCellXml = function(objCurrCell, iRow, iCol) {
  // Create cell object
  var objCell = {
    i: iCol,
    r: iRow,
    v: ''
  };
  if (objCurrCell) {
    // Set value
    var arrValue = [];
    for (var iChild = 0; iChild < objCurrCell.childNodes.length; iChild++) {
      arrValue.push(southprojects.Transport.serializeXmlDoc(
       objCurrCell.childNodes[iChild]));
    }
    objCell.v = arrValue.join('');
    // Set style
    var strCellStyle = objCurrCell.getAttribute('style');
    if (strCellStyle) {
      objCell.style = strCellStyle;
    }
  }
  // Convert cell value
  objCell = this.convertCell(objCell);
  return objCell;
};
