/* global OpenDocument, Node */

OpenDocument.Elements = {};

/***********************************************************
 * 
 * @constructor
 * @param {HTMLTableCellElement} cellElement
 * @param {Array} textArray
 * @param {Array} annotationArray
 * @param {String} styleName
 * @param {Number} rowSpan
 * @param {Number} colSpan
 * @param {Number} emptyNext
 * @param {Number} emptyPrevious
 * @returns {OpenDocument.TableColumn}
 */
OpenDocument.Elements.Cell = function (cellElement, textArray, annotationArray, styleName, rowSpan, colSpan, emptyNext, emptyPrevious) {
    this.cellElement = cellElement;
    this.textArray = textArray;
    this.annotationArray = annotationArray;
    this.styleName = styleName;
    this.rowSpan = rowSpan;
    this.colSpan = colSpan;
    this.emptyNext = emptyNext;
    this.emptyPrevious = emptyPrevious;
    this.jump = 0;
    this.columnIndex = -1;
};

OpenDocument.Elements.Cell.EMPTY = new OpenDocument.Elements.Cell(null, [], [], "", 1, 1, 0, 0);

/**
 * 
 * @returns {Boolean}
 */
OpenDocument.Elements.Cell.prototype.isEmpty = function () {
    return (this.textArray.length === 0);
};

/**
 * 
 * @returns {Boolean}
 */
OpenDocument.Elements.Cell.prototype.hasAnnotation = function () {
    return (this.annotationArray.length > 0);
};

/**
 * 
 * @returns {Boolean}
 */
OpenDocument.Elements.Cell.prototype.getValue = function () {
    return (this.textArray.join(" "));
};

/**
 * 
 * @returns {String}
 */
OpenDocument.Elements.Cell.prototype.getType = function () {
    return this.cellElement.dataset.odType;
};


/**
 * 
 * @param {String} defaultDatePattern
 * @returns {String}
 */
OpenDocument.Elements.Cell.prototype.getDatePattern = function (defaultDatePattern) {
    var datePattern =  this.cellElement.dataset.odDatePattern;
    if (!datePattern) {
        datePattern = defaultDatePattern;
    }
    return datePattern;
};

/**
 * 
 * @param {String} defaultCurrencyCode
 * @returns {String}
 */
OpenDocument.Elements.Cell.prototype.getCurrencyCode = function (defaultCurrencyCode) {
    var currencyCode = this.cellElement.dataset.odCurrency;
    if (!currencyCode) {
        currencyCode = defaultCurrencyCode;
    }
    return currencyCode;
};
 
/**
 * 
 * @param {HTMLTableCellElement} cellElement
 * @param {OpenDocument.StyleManager} styleManager
 * @param {Object} options
 * @returns {OpenDocument.Elements.Cell}
 */
OpenDocument.Elements.Cell.build = function (cellElement, styleManager, options) {
    var checkHidden = _initCheckHiddenFunction();
    var textDataAttribute = _initTextDataAttribute();
    var rowSpan = cellElement.dataset.odRowspan;
    if (!rowSpan) {
        rowSpan = cellElement.rowSpan;
    }
    var colSpan = cellElement.dataset.odColspan;
    var htmlColSpan = cellElement.colSpan;
    if (!colSpan) {
        colSpan = htmlColSpan;
    }
    var textArray = [];
    var annotationArray = [];
    var styleName = _getCellStyleName();
    _readContent();
    var emptyNext = _checkEmptyValue(cellElement.dataset.odEmptyNext);
    var emptyPrevious = _checkEmptyValue(cellElement.dataset.odEmptyPrevious);
    return new OpenDocument.Elements.Cell(cellElement, textArray, annotationArray, styleName, rowSpan, colSpan, emptyNext, emptyPrevious);
    
    function _checkEmptyValue(value) {
        if (!value) {
            return 0;
        } else if (value === "fill") {
            let diff = 0;
            if ((colSpan) && (htmlColSpan)) {
                diff = htmlColSpan - colSpan;
            }
            if (diff > 0) {
                return diff;
            } else {
                return 0;
            }
        } else if (value > 0) {
            return value;
        } else {
            return 0;
        }
    }
    
    function _initTextDataAttribute() {
        if (options) {
            if (options.textDataAttribute) {
                return options.textDataAttribute;
            }
        }
        return "";
    }
    
    function _initCheckHiddenFunction() {
        if (options) {
            if (options.hiddenFunction) {
                let hiddenFunction = options.hiddenFunction;
                return function (element) {
                    let hidden = hiddenFunction(element);
                    if ((!hidden) && (hidden !== 0)) {
                        hidden = OpenDocument.checkOdHidden(element);
                    }
                    return hidden;
                };
            }
        }
        return OpenDocument.checkOdHidden;
    }
    
    function _getCellStyleName() {
        if (!styleManager) {
            return "";
        }
        if ((options) && (options.styleNameFunction)) {
            let customStyleName = options.styleNameFunction(cellElement, styleManager);
            if (customStyleName) {
                return customStyleName;
            }
        }
        let styleName = cellElement.dataset.odStyle;
        if (styleName) {
            return styleName;
        }
        styleName = styleManager.getMatchingStyleName("cell", cellElement);
        if (styleName) {
            return styleName;
        }
        if (cellElement.tagName.toLowerCase() === "th") {
            return "Header";
        } else {
            return "";
        }
    }
    
    function _readContent() {
        var textBuffer = new OpenDocument.Elements.Cell.Buffer(textArray);
        var annotationBuffer = new OpenDocument.Elements.Cell.Buffer(annotationArray);
        let cellData =  __fromData(cellElement);
        if (cellData !== false) {
            textBuffer.addFromData(cellData);
            textBuffer.active = false;
        }
        __fromNodes(cellElement, textBuffer);
        textBuffer.flush();
        annotationBuffer.flush();
        
        function __fromData(element) {
            let dataText = element.dataset.odText;
            if ((dataText) || (dataText === "")) {
                return dataText;
            }
            if (textDataAttribute) {
                dataText = element.dataset[textDataAttribute];
                if ((dataText) || (dataText === "")) {
                    return dataText;
                }
            }
            return false;
        }
    
        function __fromNodes(element, currentBuffer) {
            for(let node of element.childNodes) {
                switch(node.nodeType) {
                    case Node.ELEMENT_NODE: {
                        let display = window.getComputedStyle(node).display;
                        let hidden = checkHidden(node);
                        let fromData = __fromData(node);
                        let buffer = currentBuffer;
                        if (node.dataset.odDestination === "annotation") {
                            buffer = annotationBuffer;
                        }
                        switch(display) {
                            case "none":
                                if (hidden === -1) {
                                    if (fromData !== false) {
                                        buffer.append(fromData);
                                    } else {
                                        buffer.append(node.textContent);
                                    }
                                  }
                                break;
                            case "block":
                                if (hidden !== 1) {
                                    buffer.flush();
                                    if (fromData !== false) {
                                        buffer.addFromData(fromData);
                                    } else {
                                        __fromNodes(node, buffer);
                                    }
                                }
                                break;
                            default:
                                if (hidden !== 1) {
                                    if (node.tagName.toUpperCase() === "BR") {
                                        buffer.flush();
                                    } else {
                                        if (fromData !== false) {
                                            buffer.append(fromData);
                                        } else {
                                            __fromNodes(node, buffer);
                                        }
                                    }
                                }
                        }
                        break;
                    }
                    case Node.TEXT_NODE:
                    case Node.CDATA_SECTION_NODE:
                        currentBuffer.append(node.textContent);

                }
            }
        }
    }
};


OpenDocument.Elements.Cell.Buffer = function (array) {
    this.array = array;
    this.buffer = "";
    this.active = true;
};

OpenDocument.Elements.Cell.Buffer.prototype.addFromData = function (dataContent) {
    let tokens = dataContent.split('\n');
    for (let token of tokens) {
        if (token.trim().length > 0) {
            this.array.push(token);
        }
    }
};

OpenDocument.Elements.Cell.Buffer.prototype.append = function (content) {
    content = content.replace(/[\s\uFEFF\xA0]/g, ' ');
    this.buffer += content;
};

OpenDocument.Elements.Cell.Buffer.prototype.flush = function () {
    if (!this.active) {
        return;
    }
    let text = this.buffer.trim().replace(/ +/g, ' ');
    if (text) {
        this.array.push(text);
    }
    this.buffer = "";
};


/***********************************************************
 * 
 * @constructor
 * @param {String} styleName
 * @param {Number} columnsRepeated
 * @param {String} defaultCellStyleName
 * @returns {OpenDocument.TableColumn}
 */
OpenDocument.Elements.TableColumn = function (styleName, columnsRepeated, defaultCellStyleName) {
    this.styleName = styleName;
    this.columnsRepeated = columnsRepeated;
    this.defaultCellStyleName = defaultCellStyleName;
};

OpenDocument.Elements.TableColumn.prototype.populateCellStyleArray = function (array) {
    let defaultCellStyleName = this.defaultCellStyleName;
    for(let i = 0; i < this.columnsRepeated; i++) {
        array.push(defaultCellStyleName);
    }
};

