/**
 * Created with JetBrains WebStorm.
 * User: taoqili
 * Date: 13-1-18
 * Time: 上午11:09
 * To change this template use File | Settings | File Templates.
 */
/**
 * UE表格操作类
 * @param table
 * @constructor
 */
;(function() {
  var UETable = (UE.UETable = function(table) {
    this.table = table;
    this.indexTable = [];
    this.selectedTds = [];
    this.cellsRange = {};
    this.update(table);
  });

  //===以下为静态工具方法===
  UETable.removeSelectedClass = function(cells) {
    utils.each(cells, function(cell) {
      domUtils.removeClasses(cell, "selectTdClass");
    });
  };
  UETable.addSelectedClass = function(cells) {
    utils.each(cells, function(cell) {
      domUtils.addClass(cell, "selectTdClass");
    });
  };
  UETable.isEmptyBlock = function(node) {
    var reg = new RegExp(domUtils.fillChar, "g");
    if (
      node[browser.ie ? "innerText" : "textContent"]
        .replace(/^\s*$/, "")
        .replace(reg, "").length > 0
    ) {
      return 0;
    }
    for (var i in dtd.$isNotEmpty)
      if (dtd.$isNotEmpty.hasOwnProperty(i)) {
        if (node.getElementsByTagName(i).length) {
          return 0;
        }
      }
    return 1;
  };
  UETable.getWidth = function(cell) {
    if (!cell) return 0;
    return parseInt(domUtils.getComputedStyle(cell, "width"), 10);
  };

  /**
     * 获取单元格或者单元格组的“对齐”状态。 如果当前的检测对象是一个单元格组， 只有在满足所有单元格的 水平和竖直 对齐属性都相同的
     * 条件时才会返回其状态值，否则将返回null； 如果当前只检测了一个单元格， 则直接返回当前单元格的对齐状态；
     * @param table cell or table cells , 支持单个单元格dom对象 或者 单元格dom对象数组
     * @return { align: 'left' || 'right' || 'center', valign: 'top' || 'middle' || 'bottom' } 或者 null
     */
  UETable.getTableCellAlignState = function(cells) {
    !utils.isArray(cells) && (cells = [cells]);

    var result = {},
      status = ["align", "valign"],
      tempStatus = null,
      isSame = true; //状态是否相同

    utils.each(cells, function(cellNode) {
      utils.each(status, function(currentState) {
        tempStatus = cellNode.getAttribute(currentState);

        if (!result[currentState] && tempStatus) {
          result[currentState] = tempStatus;
        } else if (
          !result[currentState] ||
          tempStatus !== result[currentState]
        ) {
          isSame = false;
          return false;
        }
      });

      return isSame;
    });

    return isSame ? result : null;
  };

  /**
     * 根据当前选区获取相关的table信息
     * @return {Object}
     */
  UETable.getTableItemsByRange = function(editor) {
    var start = editor.selection.getStart();

    //ff下会选中bookmark
    if (
      start &&
      start.id &&
      start.id.indexOf("_baidu_bookmark_start_") === 0 &&
      start.nextSibling
    ) {
      start = start.nextSibling;
    }

    //在table或者td边缘有可能存在选中tr的情况
    var cell = start && domUtils.findParentByTagName(start, ["td", "th"], true),
      tr = cell && cell.parentNode,
      table = tr && domUtils.findParentByTagName(tr, ["table"]),
      caption = table && table.getElementsByTagName("caption")[0];

    return {
      cell: cell,
      tr: tr,
      table: table,
      caption: caption
    };
  };
  UETable.getUETableBySelected = function(editor) {
    var table = UETable.getTableItemsByRange(editor).table;
    if (table && table.ueTable && table.ueTable.selectedTds.length) {
      return table.ueTable;
    }
    return null;
  };

  UETable.getDefaultValue = function(editor, table) {
    var borderMap = {
      thin: "0px",
      medium: "1px",
      thick: "2px"
    },
      tableBorder,
      tdPadding,
      tdBorder,
      tmpValue;
    if (!table) {
      table = editor.document.createElement("table");
      table.insertRow(0).insertCell(0).innerHTML = "xxx";
      editor.body.appendChild(table);
      var td = table.getElementsByTagName("td")[0];
      tmpValue = domUtils.getComputedStyle(table, "border-left-width");
      tableBorder = parseInt(borderMap[tmpValue] || tmpValue, 10);
      tmpValue = domUtils.getComputedStyle(td, "padding-left");
      tdPadding = parseInt(borderMap[tmpValue] || tmpValue, 10);
      tmpValue = domUtils.getComputedStyle(td, "border-left-width");
      tdBorder = parseInt(borderMap[tmpValue] || tmpValue, 10);
      domUtils.remove(table);
      return {
        tableBorder: tableBorder,
        tdPadding: tdPadding,
        tdBorder: tdBorder
      };
    } else {
      td = table.getElementsByTagName("td")[0];
      tmpValue = domUtils.getComputedStyle(table, "border-left-width");
      tableBorder = parseInt(borderMap[tmpValue] || tmpValue, 10);
      tmpValue = domUtils.getComputedStyle(td, "padding-left");
      tdPadding = parseInt(borderMap[tmpValue] || tmpValue, 10);
      tmpValue = domUtils.getComputedStyle(td, "border-left-width");
      tdBorder = parseInt(borderMap[tmpValue] || tmpValue, 10);
      return {
        tableBorder: tableBorder,
        tdPadding: tdPadding,
        tdBorder: tdBorder
      };
    }
  };
  /**
     * 根据当前点击的td或者table获取索引对象
     * @param tdOrTable
     */
  UETable.getUETable = function(tdOrTable) {
    var tag = tdOrTable.tagName.toLowerCase();
    tdOrTable = tag == "td" || tag == "th" || tag == "caption"
      ? domUtils.findParentByTagName(tdOrTable, "table", true)
      : tdOrTable;
    if (!tdOrTable.ueTable) {
      tdOrTable.ueTable = new UETable(tdOrTable);
    }
    return tdOrTable.ueTable;
  };

  UETable.cloneCell = function(cell, ignoreMerge, keepPro) {
    if (!cell || utils.isString(cell)) {
      return this.table.ownerDocument.createElement(cell || "td");
    }
    var flag = domUtils.hasClass(cell, "selectTdClass");
    flag && domUtils.removeClasses(cell, "selectTdClass");
    var tmpCell = cell.cloneNode(true);
    if (ignoreMerge) {
      tmpCell.rowSpan = tmpCell.colSpan = 1;
    }
    //去掉宽高
    !keepPro && domUtils.removeAttributes(tmpCell, "width height");
    !keepPro && domUtils.removeAttributes(tmpCell, "style");

    tmpCell.style.borderLeftStyle = "";
    tmpCell.style.borderTopStyle = "";
    tmpCell.style.borderLeftColor = cell.style.borderRightColor;
    tmpCell.style.borderLeftWidth = cell.style.borderRightWidth;
    tmpCell.style.borderTopColor = cell.style.borderBottomColor;
    tmpCell.style.borderTopWidth = cell.style.borderBottomWidth;
    flag && domUtils.addClass(cell, "selectTdClass");
    return tmpCell;
  };

  UETable.prototype = {
    getMaxRows: function() {
      var rows = this.table.rows,
        maxLen = 1;
      for (var i = 0, row; (row = rows[i]); i++) {
        var currentMax = 1;
        for (var j = 0, cj; (cj = row.cells[j++]); ) {
          currentMax = Math.max(cj.rowSpan || 1, currentMax);
        }
        maxLen = Math.max(currentMax + i, maxLen);
      }
      return maxLen;
    },
    /**
         * 获取当前表格的最大列数
         */
    getMaxCols: function() {
      var rows = this.table.rows,
        maxLen = 0,
        cellRows = {};
      for (var i = 0, row; (row = rows[i]); i++) {
        var cellsNum = 0;
        for (var j = 0, cj; (cj = row.cells[j++]); ) {
          cellsNum += cj.colSpan || 1;
          if (cj.rowSpan && cj.rowSpan > 1) {
            for (var k = 1; k < cj.rowSpan; k++) {
              if (!cellRows["row_" + (i + k)]) {
                cellRows["row_" + (i + k)] = cj.colSpan || 1;
              } else {
                cellRows["row_" + (i + k)]++;
              }
            }
          }
        }
        cellsNum += cellRows["row_" + i] || 0;
        maxLen = Math.max(cellsNum, maxLen);
      }
      return maxLen;
    },
    getCellColIndex: function(cell) {},
    /**
         * 获取当前cell旁边的单元格，
         * @param cell
         * @param right
         */
    getHSideCell: function(cell, right) {
      try {
        var cellInfo = this.getCellInfo(cell),
          previewRowIndex,
          previewColIndex;
        var len = this.selectedTds.length,
          range = this.cellsRange;
        //首行或者首列没有前置单元格
        if (
          (!right && (!len ? !cellInfo.colIndex : !range.beginColIndex)) ||
          (right &&
            (!len
              ? cellInfo.colIndex == this.colsNum - 1
              : range.endColIndex == this.colsNum - 1))
        )
          return null;

        previewRowIndex = !len ? cellInfo.rowIndex : range.beginRowIndex;
        previewColIndex = !right
          ? !len
            ? cellInfo.colIndex < 1 ? 0 : cellInfo.colIndex - 1
            : range.beginColIndex - 1
          : !len ? cellInfo.colIndex + 1 : range.endColIndex + 1;
        return this.getCell(
          this.indexTable[previewRowIndex][previewColIndex].rowIndex,
          this.indexTable[previewRowIndex][previewColIndex].cellIndex
        );
      } catch (e) {
        showError(e);
      }
    },
    getTabNextCell: function(cell, preRowIndex) {
      var cellInfo = this.getCellInfo(cell),
        rowIndex = preRowIndex || cellInfo.rowIndex,
        colIndex = cellInfo.colIndex + 1 + (cellInfo.colSpan - 1),
        nextCell;
      try {
        nextCell = this.getCell(
          this.indexTable[rowIndex][colIndex].rowIndex,
          this.indexTable[rowIndex][colIndex].cellIndex
        );
      } catch (e) {
        try {
          rowIndex = rowIndex * 1 + 1;
          colIndex = 0;
          nextCell = this.getCell(
            this.indexTable[rowIndex][colIndex].rowIndex,
            this.indexTable[rowIndex][colIndex].cellIndex
          );
        } catch (e) {}
      }
      return nextCell;
    },
    /**
         * 获取视觉上的后置单元格
         * @param cell
         * @param bottom
         */
    getVSideCell: function(cell, bottom, ignoreRange) {
      try {
        var cellInfo = this.getCellInfo(cell),
          nextRowIndex,
          nextColIndex;
        var len = this.selectedTds.length && !ignoreRange,
          range = this.cellsRange;
        //末行或者末列没有后置单元格
        if (
          (!bottom && cellInfo.rowIndex == 0) ||
          (bottom &&
            (!len
              ? cellInfo.rowIndex + cellInfo.rowSpan > this.rowsNum - 1
              : range.endRowIndex == this.rowsNum - 1))
        )
          return null;

        nextRowIndex = !bottom
          ? !len ? cellInfo.rowIndex - 1 : range.beginRowIndex - 1
          : !len ? cellInfo.rowIndex + cellInfo.rowSpan : range.endRowIndex + 1;
        nextColIndex = !len ? cellInfo.colIndex : range.beginColIndex;
        return this.getCell(
          this.indexTable[nextRowIndex][nextColIndex].rowIndex,
          this.indexTable[nextRowIndex][nextColIndex].cellIndex
        );
      } catch (e) {
        showError(e);
      }
    },
    /**
         * 获取相同结束位置的单元格，xOrY指代了是获取x轴相同还是y轴相同
         */
    getSameEndPosCells: function(cell, xOrY) {
      try {
        var flag = xOrY.toLowerCase() === "x",
          end =
            domUtils.getXY(cell)[flag ? "x" : "y"] +
            cell["offset" + (flag ? "Width" : "Height")],
          rows = this.table.rows,
          cells = null,
          returns = [];
        for (var i = 0; i < this.rowsNum; i++) {
          cells = rows[i].cells;
          for (var j = 0, tmpCell; (tmpCell = cells[j++]); ) {
            var tmpEnd =
              domUtils.getXY(tmpCell)[flag ? "x" : "y"] +
              tmpCell["offset" + (flag ? "Width" : "Height")];
            //对应行的td已经被上面行rowSpan了
            if (tmpEnd > end && flag) break;
            if (cell == tmpCell || end == tmpEnd) {
              //只获取单一的单元格
              //todo 仅获取单一单元格在特定情况下会造成returns为空，从而影响后续的拖拽实现，修正这个。需考虑性能
              if (tmpCell[flag ? "colSpan" : "rowSpan"] == 1) {
                returns.push(tmpCell);
              }
              if (flag) break;
            }
          }
        }
        return returns;
      } catch (e) {
        showError(e);
      }
    },
    setCellContent: function(cell, content) {
      cell.innerHTML = content || (browser.ie ? domUtils.fillChar : "<br />");
    },
    cloneCell: UETable.cloneCell,
    /**
         * 获取跟当前单元格的右边竖线为左边的所有未合并单元格
         */
    getSameStartPosXCells: function(cell) {
      try {
        var start = domUtils.getXY(cell).x + cell.offsetWidth,
          rows = this.table.rows,
          cells,
          returns = [];
        for (var i = 0; i < this.rowsNum; i++) {
          cells = rows[i].cells;
          for (var j = 0, tmpCell; (tmpCell = cells[j++]); ) {
            var tmpStart = domUtils.getXY(tmpCell).x;
            if (tmpStart > start) break;
            if (tmpStart == start && tmpCell.colSpan == 1) {
              returns.push(tmpCell);
              break;
            }
          }
        }
        return returns;
      } catch (e) {
        showError(e);
      }
    },
    /**
         * 更新table对应的索引表
         */
    update: function(table) {
      this.table = table || this.table;
      this.selectedTds = [];
      this.cellsRange = {};
      this.indexTable = [];
      var rows = this.table.rows,
        rowsNum = this.getMaxRows(),
        dNum = rowsNum - rows.length,
        colsNum = this.getMaxCols();
      while (dNum--) {
        this.table.insertRow(rows.length);
      }
      this.rowsNum = rowsNum;
      this.colsNum = colsNum;
      for (var i = 0, len = rows.length; i < len; i++) {
        this.indexTable[i] = new Array(colsNum);
      }
      //填充索引表
      for (var rowIndex = 0, row; (row = rows[rowIndex]); rowIndex++) {
        for (
          var cellIndex = 0, cell, cells = row.cells;
          (cell = cells[cellIndex]);
          cellIndex++
        ) {
          //修正整行被rowSpan时导致的行数计算错误
          if (cell.rowSpan > rowsNum) {
            cell.rowSpan = rowsNum;
          }
          var colIndex = cellIndex,
            rowSpan = cell.rowSpan || 1,
            colSpan = cell.colSpan || 1;
          //当已经被上一行rowSpan或者被前一列colSpan了，则跳到下一个单元格进行
          while (this.indexTable[rowIndex][colIndex]) colIndex++;
          for (var j = 0; j < rowSpan; j++) {
            for (var k = 0; k < colSpan; k++) {
              this.indexTable[rowIndex + j][colIndex + k] = {
                rowIndex: rowIndex,
                cellIndex: cellIndex,
                colIndex: colIndex,
                rowSpan: rowSpan,
                colSpan: colSpan
              };
            }
          }
        }
      }
      //修复残缺td
      for (j = 0; j < rowsNum; j++) {
        for (k = 0; k < colsNum; k++) {
          if (this.indexTable[j][k] === undefined) {
            row = rows[j];
            cell = row.cells[row.cells.length - 1];
            cell = cell
              ? cell.cloneNode(true)
              : this.table.ownerDocument.createElement("td");
            this.setCellContent(cell);
            if (cell.colSpan !== 1) cell.colSpan = 1;
            if (cell.rowSpan !== 1) cell.rowSpan = 1;
            row.appendChild(cell);
            this.indexTable[j][k] = {
              rowIndex: j,
              cellIndex: cell.cellIndex,
              colIndex: k,
              rowSpan: 1,
              colSpan: 1
            };
          }
        }
      }
      //当框选后删除行或者列后撤销，需要重建选区。
      var tds = domUtils.getElementsByTagName(this.table, "td"),
        selectTds = [];
      utils.each(tds, function(td) {
        if (domUtils.hasClass(td, "selectTdClass")) {
          selectTds.push(td);
        }
      });
      if (selectTds.length) {
        var start = selectTds[0],
          end = selectTds[selectTds.length - 1],
          startInfo = this.getCellInfo(start),
          endInfo = this.getCellInfo(end);
        this.selectedTds = selectTds;
        this.cellsRange = {
          beginRowIndex: startInfo.rowIndex,
          beginColIndex: startInfo.colIndex,
          endRowIndex: endInfo.rowIndex + endInfo.rowSpan - 1,
          endColIndex: endInfo.colIndex + endInfo.colSpan - 1
        };
      }
      //给第一行设置firstRow的样式名称,在排序图标的样式上使用到
      if (!domUtils.hasClass(this.table.rows[0], "firstRow")) {
        domUtils.addClass(this.table.rows[0], "firstRow");
        for (var i = 1; i < this.table.rows.length; i++) {
          domUtils.removeClasses(this.table.rows[i], "firstRow");
        }
      }
    },
    /**
         * 获取单元格的索引信息
         */
    getCellInfo: function(cell) {
      if (!cell) return;
      var cellIndex = cell.cellIndex,
        rowIndex = cell.parentNode.rowIndex,
        rowInfo = this.indexTable[rowIndex],
        numCols = this.colsNum;
      for (var colIndex = cellIndex; colIndex < numCols; colIndex++) {
        var cellInfo = rowInfo[colIndex];
        if (
          cellInfo.rowIndex === rowIndex &&
          cellInfo.cellIndex === cellIndex
        ) {
          return cellInfo;
        }
      }
    },
    /**
         * 根据行列号获取单元格
         */
    getCell: function(rowIndex, cellIndex) {
      return (
        (rowIndex < this.rowsNum &&
          this.table.rows[rowIndex].cells[cellIndex]) ||
        null
      );
    },
    /**
         * 删除单元格
         */
    deleteCell: function(cell, rowIndex) {
      rowIndex = typeof rowIndex == "number"
        ? rowIndex
        : cell.parentNode.rowIndex;
      var row = this.table.rows[rowIndex];
      row.deleteCell(cell.cellIndex);
    },
    /**
         * 根据始末两个单元格获取被框选的所有单元格范围
         */
    getCellsRange: function(cellA, cellB) {
      function checkRange(
        beginRowIndex,
        beginColIndex,
        endRowIndex,
        endColIndex
      ) {
        var tmpBeginRowIndex = beginRowIndex,
          tmpBeginColIndex = beginColIndex,
          tmpEndRowIndex = endRowIndex,
          tmpEndColIndex = endColIndex,
          cellInfo,
          colIndex,
          rowIndex;
        // 通过indexTable检查是否存在超出TableRange上边界的情况
        if (beginRowIndex > 0) {
          for (colIndex = beginColIndex; colIndex < endColIndex; colIndex++) {
            cellInfo = me.indexTable[beginRowIndex][colIndex];
            rowIndex = cellInfo.rowIndex;
            if (rowIndex < beginRowIndex) {
              tmpBeginRowIndex = Math.min(rowIndex, tmpBeginRowIndex);
            }
          }
        }
        // 通过indexTable检查是否存在超出TableRange右边界的情况
        if (endColIndex < me.colsNum) {
          for (rowIndex = beginRowIndex; rowIndex < endRowIndex; rowIndex++) {
            cellInfo = me.indexTable[rowIndex][endColIndex];
            colIndex = cellInfo.colIndex + cellInfo.colSpan - 1;
            if (colIndex > endColIndex) {
              tmpEndColIndex = Math.max(colIndex, tmpEndColIndex);
            }
          }
        }
        // 检查是否有超出TableRange下边界的情况
        if (endRowIndex < me.rowsNum) {
          for (colIndex = beginColIndex; colIndex < endColIndex; colIndex++) {
            cellInfo = me.indexTable[endRowIndex][colIndex];
            rowIndex = cellInfo.rowIndex + cellInfo.rowSpan - 1;
            if (rowIndex > endRowIndex) {
              tmpEndRowIndex = Math.max(rowIndex, tmpEndRowIndex);
            }
          }
        }
        // 检查是否有超出TableRange左边界的情况
        if (beginColIndex > 0) {
          for (rowIndex = beginRowIndex; rowIndex < endRowIndex; rowIndex++) {
            cellInfo = me.indexTable[rowIndex][beginColIndex];
            colIndex = cellInfo.colIndex;
            if (colIndex < beginColIndex) {
              tmpBeginColIndex = Math.min(cellInfo.colIndex, tmpBeginColIndex);
            }
          }
        }
        //递归调用直至所有完成所有框选单元格的扩展
        if (
          tmpBeginRowIndex != beginRowIndex ||
          tmpBeginColIndex != beginColIndex ||
          tmpEndRowIndex != endRowIndex ||
          tmpEndColIndex != endColIndex
        ) {
          return checkRange(
            tmpBeginRowIndex,
            tmpBeginColIndex,
            tmpEndRowIndex,
            tmpEndColIndex
          );
        } else {
          // 不需要扩展TableRange的情况
          return {
            beginRowIndex: beginRowIndex,
            beginColIndex: beginColIndex,
            endRowIndex: endRowIndex,
            endColIndex: endColIndex
          };
        }
      }

      try {
        var me = this,
          cellAInfo = me.getCellInfo(cellA);
        if (cellA === cellB) {
          return {
            beginRowIndex: cellAInfo.rowIndex,
            beginColIndex: cellAInfo.colIndex,
            endRowIndex: cellAInfo.rowIndex + cellAInfo.rowSpan - 1,
            endColIndex: cellAInfo.colIndex + cellAInfo.colSpan - 1
          };
        }
        var cellBInfo = me.getCellInfo(cellB);
        // 计算TableRange的四个边
        var beginRowIndex = Math.min(cellAInfo.rowIndex, cellBInfo.rowIndex),
          beginColIndex = Math.min(cellAInfo.colIndex, cellBInfo.colIndex),
          endRowIndex = Math.max(
            cellAInfo.rowIndex + cellAInfo.rowSpan - 1,
            cellBInfo.rowIndex + cellBInfo.rowSpan - 1
          ),
          endColIndex = Math.max(
            cellAInfo.colIndex + cellAInfo.colSpan - 1,
            cellBInfo.colIndex + cellBInfo.colSpan - 1
          );

        return checkRange(
          beginRowIndex,
          beginColIndex,
          endRowIndex,
          endColIndex
        );
      } catch (e) {
        //throw e;
      }
    },
    /**
         * 依据cellsRange获取对应的单元格集合
         */
    getCells: function(range) {
      //每次获取cells之前必须先清除上次的选择，否则会对后续获取操作造成影响
      this.clearSelected();
      var beginRowIndex = range.beginRowIndex,
        beginColIndex = range.beginColIndex,
        endRowIndex = range.endRowIndex,
        endColIndex = range.endColIndex,
        cellInfo,
        rowIndex,
        colIndex,
        tdHash = {},
        returnTds = [];
      for (var i = beginRowIndex; i <= endRowIndex; i++) {
        for (var j = beginColIndex; j <= endColIndex; j++) {
          cellInfo = this.indexTable[i][j];
          rowIndex = cellInfo.rowIndex;
          colIndex = cellInfo.colIndex;
          // 如果Cells里已经包含了此Cell则跳过
          var key = rowIndex + "|" + colIndex;
          if (tdHash[key]) continue;
          tdHash[key] = 1;
          if (
            rowIndex < i ||
            colIndex < j ||
            rowIndex + cellInfo.rowSpan - 1 > endRowIndex ||
            colIndex + cellInfo.colSpan - 1 > endColIndex
          ) {
            return null;
          }
          returnTds.push(this.getCell(rowIndex, cellInfo.cellIndex));
        }
      }
      return returnTds;
    },
    /**
         * 清理已经选中的单元格
         */
    clearSelected: function() {
      UETable.removeSelectedClass(this.selectedTds);
      this.selectedTds = [];
      this.cellsRange = {};
    },
    /**
         * 根据range设置已经选中的单元格
         */
    setSelected: function(range) {
      var cells = this.getCells(range);
      UETable.addSelectedClass(cells);
      this.selectedTds = cells;
      this.cellsRange = range;
    },
    isFullRow: function() {
      var range = this.cellsRange;
      return range.endColIndex - range.beginColIndex + 1 == this.colsNum;
    },
    isFullCol: function() {
      var range = this.cellsRange,
        table = this.table,
        ths = table.getElementsByTagName("th"),
        rows = range.endRowIndex - range.beginRowIndex + 1;
      return !ths.length
        ? rows == this.rowsNum
        : rows == this.rowsNum || rows == this.rowsNum - 1;
    },
    /**
         * 获取视觉上的前置单元格，默认是左边，top传入时
         * @param cell
         * @param top
         */
    getNextCell: function(cell, bottom, ignoreRange) {
      try {
        var cellInfo = this.getCellInfo(cell),
          nextRowIndex,
          nextColIndex;
        var len = this.selectedTds.length && !ignoreRange,
          range = this.cellsRange;
        //末行或者末列没有后置单元格
        if (
          (!bottom && cellInfo.rowIndex == 0) ||
          (bottom &&
            (!len
              ? cellInfo.rowIndex + cellInfo.rowSpan > this.rowsNum - 1
              : range.endRowIndex == this.rowsNum - 1))
        )
          return null;

        nextRowIndex = !bottom
          ? !len ? cellInfo.rowIndex - 1 : range.beginRowIndex - 1
          : !len ? cellInfo.rowIndex + cellInfo.rowSpan : range.endRowIndex + 1;
        nextColIndex = !len ? cellInfo.colIndex : range.beginColIndex;
        return this.getCell(
          this.indexTable[nextRowIndex][nextColIndex].rowIndex,
          this.indexTable[nextRowIndex][nextColIndex].cellIndex
        );
      } catch (e) {
        showError(e);
      }
    },
    getPreviewCell: function(cell, top) {
      try {
        var cellInfo = this.getCellInfo(cell),
          previewRowIndex,
          previewColIndex;
        var len = this.selectedTds.length,
          range = this.cellsRange;
        //首行或者首列没有前置单元格
        if (
          (!top && (!len ? !cellInfo.colIndex : !range.beginColIndex)) ||
          (top &&
            (!len
              ? cellInfo.rowIndex > this.colsNum - 1
              : range.endColIndex == this.colsNum - 1))
        )
          return null;

        previewRowIndex = !top
          ? !len ? cellInfo.rowIndex : range.beginRowIndex
          : !len
            ? cellInfo.rowIndex < 1 ? 0 : cellInfo.rowIndex - 1
            : range.beginRowIndex;
        previewColIndex = !top
          ? !len
            ? cellInfo.colIndex < 1 ? 0 : cellInfo.colIndex - 1
            : range.beginColIndex - 1
          : !len ? cellInfo.colIndex : range.endColIndex + 1;
        return this.getCell(
          this.indexTable[previewRowIndex][previewColIndex].rowIndex,
          this.indexTable[previewRowIndex][previewColIndex].cellIndex
        );
      } catch (e) {
        showError(e);
      }
    },
    /**
         * 移动单元格中的内容
         */
    moveContent: function(cellTo, cellFrom) {
      if (UETable.isEmptyBlock(cellFrom)) return;
      if (UETable.isEmptyBlock(cellTo)) {
        cellTo.innerHTML = cellFrom.innerHTML;
        return;
      }
      var child = cellTo.lastChild;
      if (child.nodeType == 3 || !dtd.$block[child.tagName]) {
        cellTo.appendChild(cellTo.ownerDocument.createElement("br"));
      }
      while ((child = cellFrom.firstChild)) {
        cellTo.appendChild(child);
      }
    },
    /**
         * 向右合并单元格
         */
    mergeRight: function(cell) {
      var cellInfo = this.getCellInfo(cell),
        rightColIndex = cellInfo.colIndex + cellInfo.colSpan,
        rightCellInfo = this.indexTable[cellInfo.rowIndex][rightColIndex],
        rightCell = this.getCell(
          rightCellInfo.rowIndex,
          rightCellInfo.cellIndex
        );
      //合并
      cell.colSpan = cellInfo.colSpan + rightCellInfo.colSpan;
      //被合并的单元格不应存在宽度属性
      cell.removeAttribute("width");
      //移动内容
      this.moveContent(cell, rightCell);
      //删掉被合并的Cell
      this.deleteCell(rightCell, rightCellInfo.rowIndex);
      this.update();
    },
    /**
         * 向下合并单元格
         */
    mergeDown: function(cell) {
      var cellInfo = this.getCellInfo(cell),
        downRowIndex = cellInfo.rowIndex + cellInfo.rowSpan,
        downCellInfo = this.indexTable[downRowIndex][cellInfo.colIndex],
        downCell = this.getCell(downCellInfo.rowIndex, downCellInfo.cellIndex);
      cell.rowSpan = cellInfo.rowSpan + downCellInfo.rowSpan;
      cell.removeAttribute("height");
      this.moveContent(cell, downCell);
      this.deleteCell(downCell, downCellInfo.rowIndex);
      this.update();
    },
    /**
         * 合并整个range中的内容
         */
    mergeRange: function() {
      //由于合并操作可以在任意时刻进行，所以无法通过鼠标位置等信息实时生成range，只能通过缓存实例中的cellsRange对象来访问
      var range = this.cellsRange,
        leftTopCell = this.getCell(
          range.beginRowIndex,
          this.indexTable[range.beginRowIndex][range.beginColIndex].cellIndex
        );

      // 这段关于行表头或者列表头的特殊处理会导致表头合并范围错误
      // 为什么有这段代码的原因未明，暂且注释掉，希望原作者看到后出面说明下
      // if (
      //   leftTopCell.tagName == "TH" &&
      //   range.endRowIndex !== range.beginRowIndex
      // ) {
      //   var index = this.indexTable,
      //     info = this.getCellInfo(leftTopCell);
      //   leftTopCell = this.getCell(1, index[1][info.colIndex].cellIndex);
      //   range = this.getCellsRange(
      //     leftTopCell,
      //     this.getCell(
      //       index[this.rowsNum - 1][info.colIndex].rowIndex,
      //       index[this.rowsNum - 1][info.colIndex].cellIndex
      //     )
      //   );
      // }

      // 删除剩余的Cells
      var cells = this.getCells(range);
      for (var i = 0, ci; (ci = cells[i++]); ) {
        if (ci !== leftTopCell) {
          this.moveContent(leftTopCell, ci);
          this.deleteCell(ci);
        }
      }
      // 修改左上角Cell的rowSpan和colSpan，并调整宽度属性设置
      leftTopCell.rowSpan = range.endRowIndex - range.beginRowIndex + 1;
      leftTopCell.rowSpan > 1 && leftTopCell.removeAttribute("height");
      leftTopCell.colSpan = range.endColIndex - range.beginColIndex + 1;
      leftTopCell.colSpan > 1 && leftTopCell.removeAttribute("width");
      if (leftTopCell.rowSpan == this.rowsNum && leftTopCell.colSpan != 1) {
        leftTopCell.colSpan = 1;
      }

      if (leftTopCell.colSpan == this.colsNum && leftTopCell.rowSpan != 1) {
        var rowIndex = leftTopCell.parentNode.rowIndex;
        //解决IE下的表格操作问题
        if (this.table.deleteRow) {
          for (
            var i = rowIndex + 1,
              curIndex = rowIndex + 1,
              len = leftTopCell.rowSpan;
            i < len;
            i++
          ) {
            this.table.deleteRow(curIndex);
          }
        } else {
          for (var i = 0, len = leftTopCell.rowSpan - 1; i < len; i++) {
            var row = this.table.rows[rowIndex + 1];
            row.parentNode.removeChild(row);
          }
        }
        leftTopCell.rowSpan = 1;
      }
      this.update();
    },
    /**
         * 插入一行单元格
         */
    insertRow: function(rowIndex, sourceCell) {
      var numCols = this.colsNum,
        table = this.table,
        row = table.insertRow(rowIndex),
        cell,
        thead = null,
        isInsertTitle =
          typeof sourceCell == "string" && sourceCell.toUpperCase() == "TH";

      function replaceTdToTh(colIndex, cell, tableRow) {
        if (colIndex == 0) {
          var tr = tableRow.nextSibling || tableRow.previousSibling,
            th = tr.cells[colIndex];
          if (th.tagName == "TH") {
            th = cell.ownerDocument.createElement("th");
            th.appendChild(cell.firstChild);
            tableRow.insertBefore(th, cell);
            domUtils.remove(cell);
          }
        } else {
          if (cell.tagName == "TH") {
            var td = cell.ownerDocument.createElement("td");
            td.appendChild(cell.firstChild);
            tableRow.insertBefore(td, cell);
            domUtils.remove(cell);
          }
        }
      }

      //首行直接插入,无需考虑部分单元格被rowspan的情况
      if (rowIndex == 0 || rowIndex == this.rowsNum) {
        for (var colIndex = 0; colIndex < numCols; colIndex++) {
          cell = this.cloneCell(sourceCell, true);
          this.setCellContent(cell);
          cell.getAttribute("vAlign") &&
            cell.setAttribute("vAlign", cell.getAttribute("vAlign"));
          row.appendChild(cell);
          if (!isInsertTitle) replaceTdToTh(colIndex, cell, row);
        }

        if (isInsertTitle) {
          thead = table.createTHead();
          thead.insertBefore(row, thead.firstChild);
        }
      } else {
        var infoRow = this.indexTable[rowIndex],
          cellIndex = 0;
        for (colIndex = 0; colIndex < numCols; colIndex++) {
          var cellInfo = infoRow[colIndex];
          //如果存在某个单元格的rowspan穿过待插入行的位置，则修改该单元格的rowspan即可，无需插入单元格
          if (cellInfo.rowIndex < rowIndex) {
            cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex);
            cell.rowSpan = cellInfo.rowSpan + 1;
          } else {
            cell = this.cloneCell(sourceCell, true);
            this.setCellContent(cell);
            row.appendChild(cell);
          }
          if (!isInsertTitle) replaceTdToTh(colIndex, cell, row);
        }
      }
      //框选时插入不触发contentchange，需要手动更新索引。
      this.update();
      return row;
    },
    /**
         * 删除一行单元格
         * @param rowIndex
         */
    deleteRow: function(rowIndex) {
      var row = this.table.rows[rowIndex],
        infoRow = this.indexTable[rowIndex],
        colsNum = this.colsNum,
        count = 0; //处理计数
      for (var colIndex = 0; colIndex < colsNum; ) {
        var cellInfo = infoRow[colIndex],
          cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex);
        if (cell.rowSpan > 1) {
          if (cellInfo.rowIndex == rowIndex) {
            var clone = cell.cloneNode(true);
            clone.rowSpan = cell.rowSpan - 1;
            clone.innerHTML = "";
            cell.rowSpan = 1;
            var nextRowIndex = rowIndex + 1,
              nextRow = this.table.rows[nextRowIndex],
              insertCellIndex,
              preMerged =
                this.getPreviewMergedCellsNum(nextRowIndex, colIndex) - count;
            if (preMerged < colIndex) {
              insertCellIndex = colIndex - preMerged - 1;
              //nextRow.insertCell(insertCellIndex);
              domUtils.insertAfter(nextRow.cells[insertCellIndex], clone);
            } else {
              if (nextRow.cells.length)
                nextRow.insertBefore(clone, nextRow.cells[0]);
            }
            count += 1;
            //cell.parentNode.removeChild(cell);
          }
        }
        colIndex += cell.colSpan || 1;
      }
      var deleteTds = [],
        cacheMap = {};
      for (colIndex = 0; colIndex < colsNum; colIndex++) {
        var tmpRowIndex = infoRow[colIndex].rowIndex,
          tmpCellIndex = infoRow[colIndex].cellIndex,
          key = tmpRowIndex + "_" + tmpCellIndex;
        if (cacheMap[key]) continue;
        cacheMap[key] = 1;
        cell = this.getCell(tmpRowIndex, tmpCellIndex);
        deleteTds.push(cell);
      }
      var mergeTds = [];
      utils.each(deleteTds, function(td) {
        if (td.rowSpan == 1) {
          td.parentNode.removeChild(td);
        } else {
          mergeTds.push(td);
        }
      });
      utils.each(mergeTds, function(td) {
        td.rowSpan--;
      });
      row.parentNode.removeChild(row);
      //浏览器方法本身存在bug,采用自定义方法删除
      //this.table.deleteRow(rowIndex);
      this.update();
    },
    insertCol: function(colIndex, sourceCell, defaultValue) {
      var rowsNum = this.rowsNum,
        rowIndex = 0,
        tableRow,
        cell,
        backWidth = parseInt(
          (this.table.offsetWidth -
            (this.colsNum + 1) * 20 -
            (this.colsNum + 1)) /
            (this.colsNum + 1),
          10
        ),
        isInsertTitleCol =
          typeof sourceCell == "string" && sourceCell.toUpperCase() == "TH";

      function replaceTdToTh(rowIndex, cell, tableRow) {
        if (rowIndex == 0) {
          var th = cell.nextSibling || cell.previousSibling;
          if (th.tagName == "TH") {
            th = cell.ownerDocument.createElement("th");
            th.appendChild(cell.firstChild);
            tableRow.insertBefore(th, cell);
            domUtils.remove(cell);
          }
        } else {
          if (cell.tagName == "TH") {
            var td = cell.ownerDocument.createElement("td");
            td.appendChild(cell.firstChild);
            tableRow.insertBefore(td, cell);
            domUtils.remove(cell);
          }
        }
      }

      var preCell;
      if (colIndex == 0 || colIndex == this.colsNum) {
        for (; rowIndex < rowsNum; rowIndex++) {
          tableRow = this.table.rows[rowIndex];
          preCell =
            tableRow.cells[colIndex == 0 ? colIndex : tableRow.cells.length];
          cell = this.cloneCell(sourceCell, true); //tableRow.insertCell(colIndex == 0 ? colIndex : tableRow.cells.length);
          this.setCellContent(cell);
          cell.setAttribute("vAlign", cell.getAttribute("vAlign"));
          preCell && cell.setAttribute("width", preCell.getAttribute("width"));
          if (!colIndex) {
            tableRow.insertBefore(cell, tableRow.cells[0]);
          } else {
            domUtils.insertAfter(
              tableRow.cells[tableRow.cells.length - 1],
              cell
            );
          }
          if (!isInsertTitleCol) replaceTdToTh(rowIndex, cell, tableRow);
        }
      } else {
        for (; rowIndex < rowsNum; rowIndex++) {
          var cellInfo = this.indexTable[rowIndex][colIndex];
          if (cellInfo.colIndex < colIndex) {
            cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex);
            cell.colSpan = cellInfo.colSpan + 1;
          } else {
            tableRow = this.table.rows[rowIndex];
            preCell = tableRow.cells[cellInfo.cellIndex];

            cell = this.cloneCell(sourceCell, true); //tableRow.insertCell(cellInfo.cellIndex);
            this.setCellContent(cell);
            cell.setAttribute("vAlign", cell.getAttribute("vAlign"));
            preCell &&
              cell.setAttribute("width", preCell.getAttribute("width"));
            //防止IE下报错
            preCell
              ? tableRow.insertBefore(cell, preCell)
              : tableRow.appendChild(cell);
          }
          if (!isInsertTitleCol) replaceTdToTh(rowIndex, cell, tableRow);
        }
      }
      //框选时插入不触发contentchange，需要手动更新索引
      this.update();
      this.updateWidth(
        backWidth,
        defaultValue || { tdPadding: 10, tdBorder: 1 }
      );
    },
    updateWidth: function(width, defaultValue) {
      var table = this.table,
        tmpWidth =
          UETable.getWidth(table) -
          defaultValue.tdPadding * 2 -
          defaultValue.tdBorder +
          width;
      if (tmpWidth < table.ownerDocument.body.offsetWidth) {
        table.setAttribute("width", tmpWidth);
        return;
      }
      var tds = domUtils.getElementsByTagName(this.table, "td th");
      utils.each(tds, function(td) {
        td.setAttribute("width", width);
      });
    },
    deleteCol: function(colIndex) {
      var indexTable = this.indexTable,
        tableRows = this.table.rows,
        backTableWidth = this.table.getAttribute("width"),
        backTdWidth = 0,
        rowsNum = this.rowsNum,
        cacheMap = {};
      for (var rowIndex = 0; rowIndex < rowsNum; ) {
        var infoRow = indexTable[rowIndex],
          cellInfo = infoRow[colIndex],
          key = cellInfo.rowIndex + "_" + cellInfo.colIndex;
        // 跳过已经处理过的Cell
        if (cacheMap[key]) continue;
        cacheMap[key] = 1;
        var cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex);
        if (!backTdWidth)
          backTdWidth =
            cell && parseInt(cell.offsetWidth / cell.colSpan, 10).toFixed(0);
        // 如果Cell的colSpan大于1, 就修改colSpan, 否则就删掉这个Cell
        if (cell.colSpan > 1) {
          cell.colSpan--;
        } else {
          tableRows[rowIndex].deleteCell(cellInfo.cellIndex);
        }
        rowIndex += cellInfo.rowSpan || 1;
      }
      this.table.setAttribute("width", backTableWidth - backTdWidth);
      this.update();
    },
    splitToCells: function(cell) {
      var me = this,
        cells = this.splitToRows(cell);
      utils.each(cells, function(cell) {
        me.splitToCols(cell);
      });
    },
    splitToRows: function(cell) {
      var cellInfo = this.getCellInfo(cell),
        rowIndex = cellInfo.rowIndex,
        colIndex = cellInfo.colIndex,
        results = [];
      // 修改Cell的rowSpan
      cell.rowSpan = 1;
      results.push(cell);
      // 补齐单元格
      for (
        var i = rowIndex, endRow = rowIndex + cellInfo.rowSpan;
        i < endRow;
        i++
      ) {
        if (i == rowIndex) continue;
        var tableRow = this.table.rows[i],
          tmpCell = tableRow.insertCell(
            colIndex - this.getPreviewMergedCellsNum(i, colIndex)
          );
        tmpCell.colSpan = cellInfo.colSpan;
        this.setCellContent(tmpCell);
        tmpCell.setAttribute("vAlign", cell.getAttribute("vAlign"));
        tmpCell.setAttribute("align", cell.getAttribute("align"));
        if (cell.style.cssText) {
          tmpCell.style.cssText = cell.style.cssText;
        }
        results.push(tmpCell);
      }
      this.update();
      return results;
    },
    getPreviewMergedCellsNum: function(rowIndex, colIndex) {
      var indexRow = this.indexTable[rowIndex],
        num = 0;
      for (var i = 0; i < colIndex; ) {
        var colSpan = indexRow[i].colSpan,
          tmpRowIndex = indexRow[i].rowIndex;
        num += colSpan - (tmpRowIndex == rowIndex ? 1 : 0);
        i += colSpan;
      }
      return num;
    },
    splitToCols: function(cell) {
      var backWidth = (cell.offsetWidth / cell.colSpan - 22).toFixed(0),
        cellInfo = this.getCellInfo(cell),
        rowIndex = cellInfo.rowIndex,
        colIndex = cellInfo.colIndex,
        results = [];
      // 修改Cell的rowSpan
      cell.colSpan = 1;
      cell.setAttribute("width", backWidth);
      results.push(cell);
      // 补齐单元格
      for (
        var j = colIndex, endCol = colIndex + cellInfo.colSpan;
        j < endCol;
        j++
      ) {
        if (j == colIndex) continue;
        var tableRow = this.table.rows[rowIndex],
          tmpCell = tableRow.insertCell(
            this.indexTable[rowIndex][j].cellIndex + 1
          );
        tmpCell.rowSpan = cellInfo.rowSpan;
        this.setCellContent(tmpCell);
        tmpCell.setAttribute("vAlign", cell.getAttribute("vAlign"));
        tmpCell.setAttribute("align", cell.getAttribute("align"));
        tmpCell.setAttribute("width", backWidth);
        if (cell.style.cssText) {
          tmpCell.style.cssText = cell.style.cssText;
        }
        //处理th的情况
        if (cell.tagName == "TH") {
          var th = cell.ownerDocument.createElement("th");
          th.appendChild(tmpCell.firstChild);
          th.setAttribute("vAlign", cell.getAttribute("vAlign"));
          th.rowSpan = tmpCell.rowSpan;
          tableRow.insertBefore(th, tmpCell);
          domUtils.remove(tmpCell);
        }
        results.push(tmpCell);
      }
      this.update();
      return results;
    },
    isLastCell: function(cell, rowsNum, colsNum) {
      rowsNum = rowsNum || this.rowsNum;
      colsNum = colsNum || this.colsNum;
      var cellInfo = this.getCellInfo(cell);
      return (
        cellInfo.rowIndex + cellInfo.rowSpan == rowsNum &&
        cellInfo.colIndex + cellInfo.colSpan == colsNum
      );
    },
    getLastCell: function(cells) {
      cells = cells || this.table.getElementsByTagName("td");
      var firstInfo = this.getCellInfo(cells[0]);
      var me = this,
        last = cells[0],
        tr = last.parentNode,
        cellsNum = 0,
        cols = 0,
        rows;
      utils.each(cells, function(cell) {
        if (cell.parentNode == tr) cols += cell.colSpan || 1;
        cellsNum += cell.rowSpan * cell.colSpan || 1;
      });
      rows = cellsNum / cols;
      utils.each(cells, function(cell) {
        if (me.isLastCell(cell, rows, cols)) {
          last = cell;
          return false;
        }
      });
      return last;
    },
    selectRow: function(rowIndex) {
      var indexRow = this.indexTable[rowIndex],
        start = this.getCell(indexRow[0].rowIndex, indexRow[0].cellIndex),
        end = this.getCell(
          indexRow[this.colsNum - 1].rowIndex,
          indexRow[this.colsNum - 1].cellIndex
        ),
        range = this.getCellsRange(start, end);
      this.setSelected(range);
    },
    selectTable: function() {
      var tds = this.table.getElementsByTagName("td"),
        range = this.getCellsRange(tds[0], tds[tds.length - 1]);
      this.setSelected(range);
    },
    setBackground: function(cells, value) {
      if (typeof value === "string") {
        utils.each(cells, function(cell) {
          cell.style.backgroundColor = value;
        });
      } else if (typeof value === "object") {
        value = utils.extend(
          {
            repeat: true,
            colorList: ["#ddd", "#fff"]
          },
          value
        );
        var rowIndex = this.getCellInfo(cells[0]).rowIndex,
          count = 0,
          colors = value.colorList,
          getColor = function(list, index, repeat) {
            return list[index]
              ? list[index]
              : repeat ? list[index % list.length] : "";
          };
        for (var i = 0, cell; (cell = cells[i++]); ) {
          var cellInfo = this.getCellInfo(cell);
          cell.style.backgroundColor = getColor(
            colors,
            rowIndex + count == cellInfo.rowIndex ? count : ++count,
            value.repeat
          );
        }
      }
    },
    removeBackground: function(cells) {
      utils.each(cells, function(cell) {
        cell.style.backgroundColor = "";
      });
    }
  };
  function showError(e) {}
})();
