dojo.provide("parus.sheet");

dojo.require("dojo.window");

dojo.declare("parus.sheet", [dijit._Widget, dijit._TemplatedMixin], {

  unique: null,

  styleSheetNode: null,

  styleSheet: null,

  _rowHeaderWidth: 40,
  //pixels
  _colHeaderHeight: 20,
  //pixels
  _aspectX: 7.829181494661921,

  _aspectY: 1.466666666666667,

  _fontSizeAspect: 1.1111111111111,

  _defaultColWidth: 8.43,

  _defaultRowHeight: 15,

  _defaultFontName: "Calibri",

  _defaultFontSize: 11,

  _rows: [],

  _cols: [],

  _cells: [],

  _styles: {},

  _formulasNode: null,

  _defaultCol: function() {
    return dojo.clone({
      size: this._defaultColWidth,
      pageBreak: false,
      hidden: false
    });
  },

  _defaultRow: function() {
    return dojo.clone({
      size: this._defaultRowHeight,
      pageBreak: false,
      hidden: false
    });
  },

  _defaultCell: function() {
    return dojo.clone({
      accessible: true,

      text: "",
      formulaNode: "",
      formulaText: "",

      hyperLink: "",
      comment: "",

      numberFormat: "General",

      fontName: this._defaultFontName,
      fontSize: this._defaultFontSize,

      bold: false,
      italic: false,
      underline: false,

      fontColor: "#000000",
      backgroundColor: "#FFFFFF",

      wrapText: false,

      horizontalAlignment: parus.sheet.XlHAlign.xlHAlignGeneral,
      verticalAlignment: parus.sheet.XlVAlign.xlVAlignBottom,
      indentLevel: 0,
      locked: true,

      pattern: parus.sheet.XlPattern.xlPatternNone,

      orientation: parus.sheet.XlOrientation.xlHorizontal,

      rightBorder: {
        style: parus.sheet.XlLineStyle.xlLineStyleNone,
        width: parus.sheet.XlBorderWeight.xlThin,
        color: "#000000"
      },
      bottomBorder: {
        style: parus.sheet.XlLineStyle.xlLineStyleNone,
        width: parus.sheet.XlBorderWeight.xlThin,
        color: "#000000"
      },
      diagonalBorder: {
        style: parus.sheet.XlLineStyle.xlLineStyleNone,
        width: parus.sheet.XlBorderWeight.xlThin,
        color: "#000000"
      },

      diagonalBorderUp: false,
      diagonalBorderDown: false,

      merged: false,
      rows: 1,
      cols: 1

    });

  },

  postMixInProperties: function() {
    this.inherited(arguments);

    this._styles = {};

    if (!this._rows.length && !this._cols.length && !this._cells.length) {

      this._rows = [];
      this._cols = [];
      this._cells = [];

      for (var i = 0; i < 3; i++) {
        this._rows.push(this._defaultRow());
        this._cols.push(this._defaultCol());
      };

      for (var i = 0; i < this._cols.length * this._rows.length; i++)
      this._cells.push(this._defaultCell());

    };

    this.unique = this.unique || ("U" + Math.trunc(Math.random() * (new Date().valueOf())));
    this.templateString = "<div class=\"" + this.unique + " templateDesignSheet\">" + "<style type=\"text/css\" dojoAttachPoint=\"styleSheetNode\"></style>" + "<div dojoAttachPoint=\"containerNode\"></div>" + "</div>";

    this._cornerNode = {};

    this._formulasNode = document.createElement("xml");

  },

  buildRendering: function() {
    this.inherited(arguments);

    this._styles["templateDesignRowHeader"] = {
      style: "left:0px;width:" + this._rowHeaderWidth + "px"
    };
    this._styles["templateDesignColHeader"] = {
      style: "top:0px;height:" + this._colHeaderHeight + "px"
    };

    if (!this._cornerNode.domNode) dojo.mixin(this._cornerNode, this._nodeWithContent("<div class=\"templateDesignHeader templateDesignCorner templateDesignRowHeader templateDesignColHeader\">" + "<div class=\"templateDesignCellBorder\">" + "<div class=\"templateDesignCellContent\"></div>" + "</div>" + "</div>"));

    var offset = this._colHeaderHeight;
    dojo.forEach(this._rows, dojo.hitch(this, function(row, idx) {
      this._rows[idx]._offset = offset;
      var styles = [];
      styles.push("top:" + offset + "px");
      styles.push("height:" + Math.round(row.size * this._aspectY) + "px");
      if (row.hidden) styles.push("display:none");
      else {
        this._rows[idx]._height = Math.round(row.size * this._aspectY);
        offset = offset + Math.round(row.size * this._aspectY);
      }
      this._styles["R" + (idx + 1)] = {
        style: styles.join(";")
      };
      if (this._rows[idx].contentNode) this._rows[idx].contentNode.innerHTML = (idx + 1);
      else dojo.mixin(this._rows[idx], this._nodeWithContent("<div class=\"templateDesignHeader templateDesignRowHeader R" + (idx + 1) + "\">" + "<div class=\"templateDesignCellBorder\">" + "<div class=\"templateDesignCellContent\">" + (idx + 1) + "</div>" + "</div>" + "</div>"));
    }));

    var offset = this._rowHeaderWidth;
    dojo.forEach(this._cols, dojo.hitch(this, function(col, idx) {
      this._cols[idx]._offset = offset;
      var styles = [];
      styles.push("left:" + offset + "px");
      styles.push("width:" + Math.round(col.size * this._aspectX) + "px");
      if (col.hidden) styles.push("display:none");
      else {
        this._cols[idx]._width = Math.round(col.size * this._aspectX);
        offset = offset + Math.round(col.size * this._aspectX);
      }
      this._styles["C" + (idx + 1)] = {
        style: styles.join(";")
      };


      if (this._cols[idx].contentNode) this._cols[idx].contentNode.innerHTML = this.numberToLetters(idx + 1);
      else dojo.mixin(this._cols[idx], this._nodeWithContent("<div class=\"templateDesignHeader templateDesignColHeader C" + (idx + 1) + "\">" + "<div class=\"templateDesignCellBorder\">" + "<div class=\"templateDesignCellContent\">" + this.numberToLetters(idx + 1) + "</div>" + "</div>" + "</div>"));
    }));

    dojo.forEach(this._cells, dojo.hitch(this, function(cell, idx) {
      this._renderCell(cell, Math.trunc(idx / this._cols.length) + 1, (idx % this._cols.length) + 1);
    }));

    dojo.forEach(this._images, dojo.hitch(this, function(image, idx) {
      this._renderImage(image);
    }));

    dojo.connect(this.domNode, "onscroll", this, this._doScroll);

    setTimeout(dojo.hitch(this, this._renderStylesheet), 10);

    console.log("sheet", this);

  },


  _borderToStyle: function(border) {

    if ((border.style != parus.sheet.XlLineStyle.xlLineStyleNone)
    /*&&
     ((border.width != parus.sheet.XlBorderWeight.xlThin) || (border.color != "#000000"))*/
    ) {

      var s;

      if (border.width == parus.sheet.XlBorderWeight.xlMedium) s = "3";
      else if (border.width == parus.sheet.XlBorderWeight.xlThick) s = "2";
      else s = "1";

      s = s + "px ";

      if (border.style == parus.sheet.XlLineStyle.xlContinuous) s = s + "solid";
      else if (border.style == parus.sheet.XlLineStyle.xlDash) s = s + "dashed";
      else if (border.style == parus.sheet.XlLineStyle.xlDot) s = s + "dotted";
      else if (border.style == parus.sheet.XlLineStyle.xlDashDot) s = s + "dashed";
      else if (border.style == parus.sheet.XlLineStyle.xlDashDotDot) s = s + "dotted";
      else if (border.style == parus.sheet.XlLineStyle.xlDouble) s = "3px double";
      else s = s + "solid";

      s = s + " " + border.color;

      return s;

    }
    else return "";

  },

  _makeSelector: function(prefix, str) {
    return prefix + dojo.map(str.split(""), function(c) {
      if (c.match(/\w/)) return c;
      else return "_" + c.charCodeAt(0);
    }).join("");
  },

  _renderCell: function(cell, row, col) {

    if (cell.formulaXml && !cell.formulaNode) {
      cell.formulaNode = dojo.place(cell.formulaXml, this._formulasNode, "last");
    };

    if (cell.formulaNode && !cell.formulaText) {
      cell.formulaText = cell.formulaNode.innerText;
    };

    var text = cell.text || "";
    var classes = [];
    var styles = [];

    classes.push("templateDesignCell");
    classes.push("R" + row);
    classes.push("C" + col);


    var b = this._borderToStyle(cell.rightBorder);
    if (b) {
      var sel = this._makeSelector("br", b);
      this._styles[sel + " .templateDesignCellBorder"] = {
        style: "border-right:" + b
      };
      classes.push(sel);
    }

    var b = this._borderToStyle(cell.bottomBorder);
    if (b) {
      var sel = this._makeSelector("bb", b);
      this._styles[sel + " .templateDesignCellBorder"] = {
        style: "border-bottom:" + b
      };
      classes.push(sel);
    }


    var alignStyles = [];
    if (cell.horizontalAlignment != parus.sheet.XlHAlign.xlHAlignGeneral) {
      if ((cell.horizontalAlignment == parus.sheet.XlHAlign.xlHAlignCenter) || (cell.horizontalAlignment == parus.sheet.XlHAlign.xlHAlignCenterAcrossSelection) || (cell.horizontalAlignment == parus.sheet.XlHAlign.xlHAlignDistributed) || (cell.horizontalAlignment == parus.sheet.XlHAlign.xlHAlignFill) || (cell.horizontalAlignment == parus.sheet.XlHAlign.xlHAlignJustify)) {
        alignStyles.push("justify-content:center");
        alignStyles.push("text-align:center");
      }

      else if ((cell.horizontalAlignment == parus.sheet.XlHAlign.xlHAlignRight)) {
        alignStyles.push("justify-content:right");
        alignStyles.push("text-align:right");
      }
    }

    if (cell.verticalAlignment != parus.sheet.XlVAlign.xlVAlignBottom) {

      if ((cell.verticalAlignment == parus.sheet.XlVAlign.xlVAlignCenter) || (cell.verticalAlignment == parus.sheet.XlVAlign.xlVAlignDistributed) || (cell.verticalAlignment == parus.sheet.XlVAlign.xlVAlignJustify)) {
        alignStyles.push("align-items:center");
      }

      else if ((cell.verticalAlignment == parus.sheet.XlVAlign.xlVAlignTop)) {
        alignStyles.push("align-items:start");
      }
    }

    if (alignStyles.length) {
      var sel = this._makeSelector("a", alignStyles.join(";"));
      this._styles[sel + " .templateDesignCellBorder"] = {
        style: alignStyles.join(";")
      };
      classes.push(sel);
    }

    var textStyles = [];
    if (cell.wrapText) textStyles.push("text-wrap:wrap");
    if (cell.indent) textStyles.push("margin-left:" + (cell.indent * 10) + "px");

    if (cell.orientation != parus.sheet.XlOrientation.xlHorizontal) {
      textStyles.push("writing-mode: tb-rl");
      textStyles.push("transform:rotate(180deg)");
      textStyles.push("filter:flipv() fliph()");
    }

    if (textStyles.length) {
      var sel = this._makeSelector("t", textStyles.join(";"));
      this._styles[sel + " .templateDesignCellContent"] = {
        style: textStyles.join(";")
      };
      classes.push(sel);
    }

    var fontStyles = [];
    if (cell.bold) fontStyles.push("font-weight:800");
    if (cell.italic) fontStyles.push("font-style:italic");
    if (cell.underline) fontStyles.push("text-decoration:underline");
    if (cell.fontColor != "#000000") fontStyles.push("color:" + cell.color);
    if (cell.backgroundColor != "#FFFFFF") fontStyles.push("background-color:" + cell.backgroundColor);
    if (cell.fontSize != this._defaultFontSize) fontStyles.push("font-size:" + (cell.fontSize * this._fontSizeAspect) + "pt");


    if (fontStyles.length) {
      var sel = this._makeSelector("f", fontStyles.join(";"));
      this._styles[sel] = {
        style: fontStyles.join(";")
      };
      classes.push(sel);
    }

    if (cell.cols > 1) {
      size = 0;
      for (var i = 0; i < cell.cols; i++)
      size = size + (this._cols[col + i - 1].hidden ? 0 : Math.round(this._cols[col + i - 1].size * this._aspectX));
      styles.push("width:" + size + "px");
    }

    if (cell.rows > 1) {
      size = 0;
      for (var i = 0; i < cell.rows; i++)
      size = size + (this._rows[row + i - 1].hidden ? 0 : Math.round(this._rows[row + i - 1].size * this._aspectY));
      styles.push("height:" + size + "px");
    }

    if (!cell.accessible) styles.push("display:none");

    if (cell.fontName != this._defaultFontName) styles.push("font-family:&quot;" + cell.fontName + "&quot;,&quot;" + this._defaultFontName + "&quot;");


    if (!cell.domNode) dojo.mixin(cell, this._nodeWithContent("<div style=\"" + styles.join(";") + "\"  class=\"" + classes.join(" ") + "\">" + "<div class=\"templateDesignCellBorder\">" + "<div class=\"templateDesignCellContent\"></div>" + "</div>" + "</div>"));

    cell.contentNode.innerText = text;
  },

  _renderImage: function(image) {
    if (!image.domNode) {
      var nodeStr = "<img class=\"" + "R" + image.row + " " + "C" + image.col + "\" style=\"position:absolute;z-index:5\" src=\"data:image/png;base64," + image.data + "\"></img>";
      image.domNode = dojo.place(nodeStr, this.containerNode, "last");
      dojo.style(image.domNode, {
        left: (this._cols[image.col - 1]._offset + image.left) + "px",
        top: (this._rows[image.row - 1]._offset + image.top) + "px",
        width: (image.width) + "px",
        height: (image.height) + "px"
      })



    }
  },

  _nodeWithContent: function(nodeStr) {
    var node = dojo.place(nodeStr, this.containerNode, "last");
    return {
      domNode: node,
      borderNode: dojo.query(".templateDesignCellBorder", node)[0],
      contentNode: dojo.query(".templateDesignCellContent", node)[0]
    };
  },

  _renderStylesheet: function() {
    if (!this.styleSheet) for (var i = 0; i < document.styleSheets.length; i++) {
      if (this.styleSheetNode == document.styleSheets[i].ownerNode) this.styleSheet = document.styleSheets[i];
    }

    var len = this.styleSheet.rules.length;
    for (var rule in this._styles) {
      if (!this._styles[rule].rule) {
        this.styleSheet.addRule("." + this.unique + " ." + rule, this._styles[rule].style, len);
        this._styles[rule].rule = this.styleSheet.rules[len];
        len = len + 1;
      }
    }

  },

  _doScroll: function(event) {
    dojo.query(".templateDesignColHeader", this.containerNode).style({
      top: event.target.scrollTop + "px"
    });
    dojo.query(".templateDesignRowHeader", this.containerNode).style({
      left: event.target.scrollLeft + "px"
    });
  },

  numberToLetters: function(num) {
    var r = "";
    do {
      var i = (num - 1) % 26;
      r = String.fromCharCode(65 + i) + r;
      num = Math.trunc((num - i) / 26);
    } while (num > 0);
    return r;
  },

  getCell: function(row, col) {
    var oldcols = this._cols.length;
    var oldrows = this._rows.length;

    if (col > oldcols) {
      while (col > this._cols.length)
      this._cols.push(this._defaultCol());
      for (var i = this._rows.length - 1; i >= 0; i--)
      for (var j = 0; j < col - oldcols; j++)
      this._cells.splice((i + 1) * (oldcols), 0, this._defaultCell());
    };

    if (row > oldrows) {
      while (row > this._rows.length) {
        this._rows.push(this._defaultRow());
        for (i = 0; i < this._cols.length; i++)
        this._cells.push(this._defaultCell());
      }
    };

    return this._cells[(row - 1) * this._cols.length + col - 1];
  },

  placeIndex: function(row, col, rn, text) {
    var cell = this.getCell(row, col);
    dojo.mixin(cell, {
      indexInfo: text,
      index: rn
    });
    this._renderCell(cell, row, col);
  },

  placeTable: function(row, col, width, height, rn, text) {
    for (var i = 0; i < width; i++)
    for (var j = 0; j < height; j++) {
      var cell = this.getCell(row + j, col + i);
      dojo.mixin(cell, {
        indexInfo: text,
        table: rn
      });
      this._renderCell(cell, row + j, col + i);
    }
  },

  placeTotal: function(row, col, width, height, rn, text) {
    for (var i = 0; i < width; i++)
    for (var j = 0; j < height; j++) {
      var cell = this.getCell(row + j, col + i);
      dojo.mixin(cell, {
        indexInfo: cell.indexInfo ? cell.indexInfo + " (" + text + ")" : text,
        total: rn
      });
      this._renderCell(cell, row + j, col + i);
    }
  },

  placeTableIndex: function(row, col, rn, text) {
    var cell = this.getCell(row, col);
    dojo.mixin(cell, {
      indexInfo: cell.indexInfo ? cell.indexInfo + " (" + text + ")" : text,
      tableIndex: rn
    });
    this._renderCell(cell, row, col);
  }

});


dojo.mixin(parus.sheet, {

  XlLineStyle: {
    xlContinuous: 1,
    xlDash: -4115,
    xlDashDot: 4,
    xlDashDotDot: 5,
    xlDot: -4118,
    xlDouble: -4119,
    xlSlantDashDot: 13,
    xlLineStyleNone: -4142
  },

  XlBorderWeight: {
    xlHairline: 1,
    xlMedium: -4138,
    xlThick: 4,
    xlThin: 2
  },

  XlVAlign: {
    xlVAlignBottom: -4107,
    xlVAlignCenter: -4108,
    xlVAlignDistributed: -4117,
    xlVAlignJustify: -4130,
    xlVAlignTop: -4160
  },

  XlHAlign: {
    xlHAlignCenter: -4108,
    xlHAlignCenterAcrossSelection: 7,
    xlHAlignDistributed: -4117,
    xlHAlignFill: 5,
    xlHAlignGeneral: 1,
    xlHAlignJustify: -4130,
    xlHAlignLeft: -4131,
    xlHAlignRight: -4152
  },

  XlPattern: {
    xlPatternAutomatic: -4105,
    xlPatternChecker: 9,
    xlPatternCrissCross: 16,
    xlPatternDown: -4121,
    xlPatternGray16: 17,
    xlPatternGray25: -4124,
    xlPatternGray50: -4125,
    xlPatternGray75: -4126,
    xlPatternGray8: 18,
    xlPatternGrid: 15,
    xlPatternHorizontal: -4128,
    xlPatternLightDown: 13,
    xlPatternLightHorizontal: 11,
    xlPatternLightUp: 14,
    xlPatternLightVertical: 12,
    xlPatternNone: -4142,
    xlPatternSemiGray75: 10,
    xlPatternSolid: 1,
    xlPatternUp: -4162,
    xlPatternVertical: -4166
  },

  XlOrientation: {
    xlDownward: -4170,
    xlHorizontal: -4128,
    xlUpward: -4171,
    xlVertical: -4166
  },

  XlFormatConditionType: {
    xlCellValue: 1,
    xlExpression: 2
  },

  XlFormatConditionOperator: {
    xlBetween: 1,
    xlNotBetween: 2,
    xlEqual: 3,
    xlNotEqual: 4,
    xlGreater: 5,
    xlLess: 6,
    xlGreaterEqual: 7,
    xlLessEqual: 8
  },

  XlSheetVisibility: {
    xlSheetVisible: -1,
    xlSheetHidden: 0,
    xlSheetVeryHidden: 2
  },

  XlPageOrientation: {
    xlLandscape: 2,
    xlPortrait: 1
  },

  XlPaperSize: {
    xlPaper10x14: 16,
    xlPaper11x17: 17,
    xlPaperA3: 8,
    xlPaperA4: 9,
    xlPaperA4Small: 10,
    xlPaperA5: 11,
    xlPaperB4: 12,
    xlPaperB5: 13,
    xlPaperCsheet: 24,
    xlPaperDsheet: 25,
    xlPaperEnvelope10: 20,
    xlPaperEnvelope11: 21,
    xlPaperEnvelope12: 22,
    xlPaperEnvelope14: 23,
    xlPaperEnvelope9: 19,
    xlPaperEnvelopeB4: 33,
    xlPaperEnvelopeB5: 34,
    xlPaperEnvelopeB6: 35,
    xlPaperEnvelopeC3: 29,
    xlPaperEnvelopeC4: 30,
    xlPaperEnvelopeC5: 28,
    xlPaperEnvelopeC6: 31,
    xlPaperEnvelopeC65: 32,
    xlPaperEnvelopeDL: 27,
    xlPaperEnvelopeItaly: 36,
    xlPaperEnvelopeMonarch: 37,
    xlPaperEnvelopePersonal: 38,
    xlPaperEsheet: 26,
    xlPaperExecutive: 7,
    xlPaperFanfoldLegalGerman: 41,
    xlPaperFanfoldStdGerman: 40,
    xlPaperFanfoldUS: 39,
    xlPaperFolio: 14,
    xlPaperLedger: 4,
    xlPaperLegal: 5,
    xlPaperLetter: 1,
    xlPaperLetterSmall: 2,
    xlPaperNote: 18,
    xlPaperQuarto: 15,
    xlPaperStatement: 6,
    xlPaperTabloid: 3,
    xlPaperUser: 256
  }

});