"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CfRuleXform = void 0;
const base_xform_1 = require("../../base-xform.js");
const composite_xform_1 = require("../../composite-xform.js");
const range_1 = require("../../../../range.js");
const databar_xform_1 = require("./databar-xform.js");
const ext_lst_ref_xform_1 = require("./ext-lst-ref-xform.js");
const formula_xform_1 = require("./formula-xform.js");
const color_scale_xform_1 = require("./color-scale-xform.js");
const icon_set_xform_1 = require("./icon-set-xform.js");
const extIcons = {
    "3Triangles": true,
    "3Stars": true,
    "5Boxes": true
};
const getTextFormula = model => {
    if (model.formulae && model.formulae[0]) {
        return model.formulae[0];
    }
    const range = new range_1.Range(model.ref);
    const { tl } = range;
    switch (model.operator) {
        case "containsText":
            return `NOT(ISERROR(SEARCH("${model.text}",${tl})))`;
        case "containsBlanks":
            return `LEN(TRIM(${tl}))=0`;
        case "notContainsBlanks":
            return `LEN(TRIM(${tl}))>0`;
        case "containsErrors":
            return `ISERROR(${tl})`;
        case "notContainsErrors":
            return `NOT(ISERROR(${tl}))`;
        default:
            return undefined;
    }
};
const getTimePeriodFormula = model => {
    if (model.formulae && model.formulae[0]) {
        return model.formulae[0];
    }
    const range = new range_1.Range(model.ref);
    const { tl } = range;
    switch (model.timePeriod) {
        case "thisWeek":
            return `AND(TODAY()-ROUNDDOWN(${tl},0)<=WEEKDAY(TODAY())-1,ROUNDDOWN(${tl},0)-TODAY()<=7-WEEKDAY(TODAY()))`;
        case "lastWeek":
            return `AND(TODAY()-ROUNDDOWN(${tl},0)>=(WEEKDAY(TODAY())),TODAY()-ROUNDDOWN(${tl},0)<(WEEKDAY(TODAY())+7))`;
        case "nextWeek":
            return `AND(ROUNDDOWN(${tl},0)-TODAY()>(7-WEEKDAY(TODAY())),ROUNDDOWN(${tl},0)-TODAY()<(15-WEEKDAY(TODAY())))`;
        case "yesterday":
            return `FLOOR(${tl},1)=TODAY()-1`;
        case "today":
            return `FLOOR(${tl},1)=TODAY()`;
        case "tomorrow":
            return `FLOOR(${tl},1)=TODAY()+1`;
        case "last7Days":
            return `AND(TODAY()-FLOOR(${tl},1)<=6,FLOOR(${tl},1)<=TODAY())`;
        case "lastMonth":
            return `AND(MONTH(${tl})=MONTH(EDATE(TODAY(),0-1)),YEAR(${tl})=YEAR(EDATE(TODAY(),0-1)))`;
        case "thisMonth":
            return `AND(MONTH(${tl})=MONTH(TODAY()),YEAR(${tl})=YEAR(TODAY()))`;
        case "nextMonth":
            return `AND(MONTH(${tl})=MONTH(EDATE(TODAY(),0+1)),YEAR(${tl})=YEAR(EDATE(TODAY(),0+1)))`;
        default:
            return undefined;
    }
};
const opType = attributes => {
    const { type, operator } = attributes;
    switch (type) {
        case "containsText":
        case "containsBlanks":
        case "notContainsBlanks":
        case "containsErrors":
        case "notContainsErrors":
            return {
                type: "containsText",
                operator: type
            };
        default:
            return { type, operator };
    }
};
class CfRuleXform extends composite_xform_1.CompositeXform {
    constructor() {
        super();
        this.map = {
            dataBar: (this.databarXform = new databar_xform_1.DatabarXform()),
            extLst: (this.extLstRefXform = new ext_lst_ref_xform_1.ExtLstRefXform()),
            formula: (this.formulaXform = new formula_xform_1.FormulaXform()),
            colorScale: (this.colorScaleXform = new color_scale_xform_1.ColorScaleXform()),
            iconSet: (this.iconSetXform = new icon_set_xform_1.IconSetXform())
        };
    }
    get tag() {
        return "cfRule";
    }
    static isPrimitive(rule) {
        // is this rule primitive?
        if (rule.type === "iconSet") {
            if (rule.custom || extIcons[rule.iconSet]) {
                return false;
            }
        }
        return true;
    }
    render(xmlStream, model) {
        switch (model.type) {
            case "expression":
                this.renderExpression(xmlStream, model);
                break;
            case "cellIs":
                this.renderCellIs(xmlStream, model);
                break;
            case "top10":
                this.renderTop10(xmlStream, model);
                break;
            case "aboveAverage":
                this.renderAboveAverage(xmlStream, model);
                break;
            case "dataBar":
                this.renderDataBar(xmlStream, model);
                break;
            case "colorScale":
                this.renderColorScale(xmlStream, model);
                break;
            case "iconSet":
                this.renderIconSet(xmlStream, model);
                break;
            case "containsText":
                this.renderText(xmlStream, model);
                break;
            case "timePeriod":
                this.renderTimePeriod(xmlStream, model);
                break;
        }
    }
    renderExpression(xmlStream, model) {
        xmlStream.openNode(this.tag, {
            type: "expression",
            dxfId: model.dxfId,
            priority: model.priority
        });
        this.formulaXform.render(xmlStream, model.formulae[0]);
        xmlStream.closeNode();
    }
    renderCellIs(xmlStream, model) {
        xmlStream.openNode(this.tag, {
            type: "cellIs",
            dxfId: model.dxfId,
            priority: model.priority,
            operator: model.operator
        });
        model.formulae.forEach(formula => {
            this.formulaXform.render(xmlStream, formula);
        });
        xmlStream.closeNode();
    }
    renderTop10(xmlStream, model) {
        xmlStream.leafNode(this.tag, {
            type: "top10",
            dxfId: model.dxfId,
            priority: model.priority,
            percent: base_xform_1.BaseXform.toBoolAttribute(model.percent, false),
            bottom: base_xform_1.BaseXform.toBoolAttribute(model.bottom, false),
            rank: base_xform_1.BaseXform.toIntValue(model.rank, 10)
        });
    }
    renderAboveAverage(xmlStream, model) {
        xmlStream.leafNode(this.tag, {
            type: "aboveAverage",
            dxfId: model.dxfId,
            priority: model.priority,
            aboveAverage: base_xform_1.BaseXform.toBoolAttribute(model.aboveAverage, true)
        });
    }
    renderDataBar(xmlStream, model) {
        xmlStream.openNode(this.tag, {
            type: "dataBar",
            priority: model.priority
        });
        this.databarXform.render(xmlStream, model);
        this.extLstRefXform.render(xmlStream, model);
        xmlStream.closeNode();
    }
    renderColorScale(xmlStream, model) {
        xmlStream.openNode(this.tag, {
            type: "colorScale",
            priority: model.priority
        });
        this.colorScaleXform.render(xmlStream, model);
        xmlStream.closeNode();
    }
    renderIconSet(xmlStream, model) {
        // iconset is all primitive or all extLst
        if (!CfRuleXform.isPrimitive(model)) {
            return;
        }
        xmlStream.openNode(this.tag, {
            type: "iconSet",
            priority: model.priority
        });
        this.iconSetXform.render(xmlStream, model);
        xmlStream.closeNode();
    }
    renderText(xmlStream, model) {
        xmlStream.openNode(this.tag, {
            type: model.operator,
            dxfId: model.dxfId,
            priority: model.priority,
            operator: base_xform_1.BaseXform.toStringAttribute(model.operator, "containsText")
        });
        const formula = getTextFormula(model);
        if (formula) {
            this.formulaXform.render(xmlStream, formula);
        }
        xmlStream.closeNode();
    }
    renderTimePeriod(xmlStream, model) {
        xmlStream.openNode(this.tag, {
            type: "timePeriod",
            dxfId: model.dxfId,
            priority: model.priority,
            timePeriod: model.timePeriod
        });
        const formula = getTimePeriodFormula(model);
        if (formula) {
            this.formulaXform.render(xmlStream, formula);
        }
        xmlStream.closeNode();
    }
    createNewModel({ attributes }) {
        return {
            ...opType(attributes),
            dxfId: base_xform_1.BaseXform.toIntValue(attributes.dxfId),
            priority: base_xform_1.BaseXform.toIntValue(attributes.priority),
            timePeriod: attributes.timePeriod,
            percent: base_xform_1.BaseXform.toBoolValue(attributes.percent),
            bottom: base_xform_1.BaseXform.toBoolValue(attributes.bottom),
            rank: base_xform_1.BaseXform.toIntValue(attributes.rank),
            aboveAverage: base_xform_1.BaseXform.toBoolValue(attributes.aboveAverage)
        };
    }
    onParserClose(name, parser) {
        switch (name) {
            case "dataBar":
            case "extLst":
            case "colorScale":
            case "iconSet":
                // merge parser model with ours
                Object.assign(this.model, parser.model);
                break;
            case "formula":
                // except - formula is a string and appends to formulae
                this.model.formulae = this.model.formulae ?? [];
                this.model.formulae.push(parser.model);
                break;
        }
    }
}
exports.CfRuleXform = CfRuleXform;
