import { chineseToNumber, fillChnNumber, fillChnWeek, fillCopy, fillExtendNumber, fillLoopSeries, fillSeries, getLoopSeriesInfo, isChnNumber, isChnWeek2, isChnWeek3, isEqualDiff, isLoopSeries, matchExtendNumber } from "./utils/fill";

import { APPLY_TYPE, DATA_TYPE, Direction } from "./types";

import { converterManager, DateConverter } from "./series-converters";

import { CellValueType } from "./types";

export const dateRule = {
    type: DATA_TYPE.DATE,
    priority: 1100,
    match: (cellData, accessor) => "string" == typeof (null == cellData ? void 0 : cellData.v) && converterManager.getConverter(cellData.v) instanceof DateConverter,
    isContinue: (prev, cur) => prev.type === DATA_TYPE.DATE,
    applyFunctions: {
        [APPLY_TYPE.SERIES]: (dataWithIndex, len, direction) => {
            var _a;
            const {data: data} = dataWithIndex, converter = converterManager.getConverter(null === (_a = data[0]) || void 0 === _a ? void 0 : _a.v);
            return direction === Direction.LEFT || direction === Direction.UP ? (data.reverse(), 
            fillSeries(data, len, direction, converter).reverse()) : fillSeries(data, len, direction, converter);
        }
    }
};

export const numberRule = {
    type: DATA_TYPE.NUMBER,
    priority: 1e3,
    match: cellData => "number" == typeof (null == cellData ? void 0 : cellData.v) || (null == cellData ? void 0 : cellData.t) === CellValueType.NUMBER,
    isContinue: (prev, cur) => prev.type === DATA_TYPE.NUMBER,
    applyFunctions: {
        [APPLY_TYPE.SERIES]: (dataWithIndex, len, direction) => {
            const {data: data} = dataWithIndex;
            return direction === Direction.LEFT || direction === Direction.UP ? (data.reverse(), 
            fillSeries(data, len, direction).reverse()) : fillSeries(data, len, direction);
        }
    }
};

export const otherRule = {
    type: DATA_TYPE.OTHER,
    priority: 0,
    match: () => !0,
    isContinue: (prev, cur) => prev.type === DATA_TYPE.OTHER
};

export const extendNumberRule = {
    type: DATA_TYPE.EXTEND_NUMBER,
    priority: 900,
    match: cellData => {
        var _a;
        return matchExtendNumber(`${null !== (_a = null == cellData ? void 0 : cellData.v) && void 0 !== _a ? _a : ""}` || "").isExtendNumber;
    },
    isContinue: (prev, cur) => {
        var _a, _b, _c;
        if (prev.type === DATA_TYPE.EXTEND_NUMBER) {
            const {beforeTxt: beforeTxt, afterTxt: afterTxt} = matchExtendNumber(`${null !== (_b = null === (_a = prev.cellData) || void 0 === _a ? void 0 : _a.v) && void 0 !== _b ? _b : ""}` || ""), {beforeTxt: curBeforeTxt, afterTxt: curAfterTxt} = matchExtendNumber(`${null !== (_c = null == cur ? void 0 : cur.v) && void 0 !== _c ? _c : ""}` || "");
            if (beforeTxt === curBeforeTxt && afterTxt === curAfterTxt) return !0;
        }
        return !1;
    },
    applyFunctions: {
        [APPLY_TYPE.SERIES]: (dataWithIndex, len, direction) => {
            var _a;
            const {data: data} = dataWithIndex, isReverse = direction === Direction.UP || direction === Direction.LEFT;
            let step;
            if (1 === data.length) return step = isReverse ? -1 : 1, reverseIfNeed(fillExtendNumber(data, len, step), isReverse);
            const dataNumArr = [];
            for (let i = 0; i < data.length; i++) {
                const txt = `${null === (_a = data[i]) || void 0 === _a ? void 0 : _a.v}`;
                txt && dataNumArr.push(Number(matchExtendNumber(txt).matchTxt));
            }
            return isReverse && (data.reverse(), dataNumArr.reverse()), isEqualDiff(dataNumArr) ? (step = dataNumArr[1] - dataNumArr[0], 
            reverseIfNeed(fillExtendNumber(data, len, step), isReverse)) : fillCopy(data, len);
        }
    }
};

export const chnNumberRule = {
    type: DATA_TYPE.CHN_NUMBER,
    priority: 830,
    match: cellData => {
        var _a;
        return !!isChnNumber(`${null !== (_a = null == cellData ? void 0 : cellData.v) && void 0 !== _a ? _a : ""}` || "");
    },
    isContinue: (prev, cur) => prev.type === DATA_TYPE.CHN_NUMBER,
    applyFunctions: {
        [APPLY_TYPE.SERIES]: (dataWithIndex, len, direction) => {
            var _a, _b;
            const {data: data} = dataWithIndex, isReverse = direction === Direction.LEFT || direction === Direction.UP;
            if (1 === data.length) {
                let step;
                return step = isReverse ? -1 : 1, reverseIfNeed(fillChnNumber(data, len, step), isReverse);
            }
            let hasWeek = !1;
            for (let i = 0; i < data.length; i++) {
                if ("日" === (null === (_a = data[i]) || void 0 === _a ? void 0 : _a.v)) {
                    hasWeek = !0;
                    break;
                }
            }
            const dataNumArr = [];
            let weekIndex = 0;
            for (let i = 0; i < data.length; i++) {
                const formattedValue = `${null === (_b = data[i]) || void 0 === _b ? void 0 : _b.v}`;
                "日" === formattedValue ? 0 === i ? dataNumArr.push(0) : (weekIndex++, dataNumArr.push(7 * weekIndex)) : hasWeek && chineseToNumber(formattedValue) > 0 && chineseToNumber(formattedValue) < 7 ? dataNumArr.push(chineseToNumber(formattedValue) + 7 * weekIndex) : dataNumArr.push(chineseToNumber(formattedValue));
            }
            if (isReverse && (data.reverse(), dataNumArr.reverse()), isEqualDiff(dataNumArr)) {
                const step = dataNumArr[1] - dataNumArr[0];
                return reverseIfNeed(fillChnNumber(data, len, step), isReverse);
            }
            return fillCopy(data, len);
        }
    }
};

export const chnWeek2Rule = {
    type: DATA_TYPE.CHN_WEEK2,
    priority: 820,
    match: cellData => {
        var _a;
        return !!isChnWeek2(`${null !== (_a = null == cellData ? void 0 : cellData.v) && void 0 !== _a ? _a : ""}` || "");
    },
    isContinue: (prev, cur) => prev.type === DATA_TYPE.CHN_WEEK2,
    applyFunctions: {
        [APPLY_TYPE.SERIES]: (dataWithIndex, len, direction) => {
            var _a;
            const {data: data} = dataWithIndex, isReverse = direction === Direction.LEFT || direction === Direction.UP;
            if (1 === data.length) {
                let step;
                return step = isReverse ? -1 : 1, reverseIfNeed(fillChnWeek(data, len, step, 1), isReverse);
            }
            const dataNumArr = [];
            let weekIndex = 0;
            for (let i = 0; i < data.length; i++) {
                const formattedValue = `${null === (_a = data[i]) || void 0 === _a ? void 0 : _a.v}`, lastTxt = null == formattedValue ? void 0 : formattedValue.substr(formattedValue.length - 1, 1);
                "周日" === formattedValue ? 0 === i ? dataNumArr.push(0) : (weekIndex++, dataNumArr.push(7 * weekIndex)) : dataNumArr.push(chineseToNumber(lastTxt) + 7 * weekIndex);
            }
            if (isReverse && (data.reverse(), dataNumArr.reverse()), isEqualDiff(dataNumArr)) {
                const step = dataNumArr[1] - dataNumArr[0];
                return reverseIfNeed(fillChnWeek(data, len, step, 1), isReverse);
            }
            return fillCopy(data, len);
        }
    }
};

export const chnWeek3Rule = {
    type: DATA_TYPE.CHN_WEEK3,
    priority: 810,
    match: cellData => {
        var _a;
        return isChnWeek3(`${null !== (_a = null == cellData ? void 0 : cellData.v) && void 0 !== _a ? _a : ""}` || "");
    },
    isContinue: (prev, cur) => prev.type === DATA_TYPE.CHN_WEEK3,
    applyFunctions: {
        [APPLY_TYPE.SERIES]: (dataWithIndex, len, direction) => {
            var _a;
            const {data: data} = dataWithIndex, isReverse = direction === Direction.LEFT || direction === Direction.UP;
            if (1 === data.length) {
                let step;
                return step = isReverse ? -1 : 1, reverseIfNeed(fillChnWeek(data, len, step, 2), isReverse);
            }
            const dataNumArr = [];
            let weekIndex = 0;
            for (let i = 0; i < data.length; i++) {
                const formattedValue = `${null === (_a = data[i]) || void 0 === _a ? void 0 : _a.v}`;
                if (formattedValue) {
                    const lastTxt = formattedValue.substr(formattedValue.length - 1, 1);
                    "星期日" === formattedValue ? 0 === i ? dataNumArr.push(0) : (weekIndex++, dataNumArr.push(7 * weekIndex)) : dataNumArr.push(chineseToNumber(lastTxt) + 7 * weekIndex);
                }
            }
            if (isReverse && (data.reverse(), dataNumArr.reverse()), isEqualDiff(dataNumArr)) {
                const step = dataNumArr[1] - dataNumArr[0];
                return reverseIfNeed(fillChnWeek(data, len, step, 2), isReverse);
            }
            return fillCopy(data, len);
        }
    }
};

export const loopSeriesRule = {
    type: DATA_TYPE.LOOP_SERIES,
    priority: 800,
    match: cellData => {
        var _a;
        return isLoopSeries(`${null !== (_a = null == cellData ? void 0 : cellData.v) && void 0 !== _a ? _a : ""}` || "");
    },
    isContinue: (prev, cur) => {
        var _a, _b, _c;
        return prev.type === DATA_TYPE.LOOP_SERIES && getLoopSeriesInfo(`${null !== (_b = null === (_a = prev.cellData) || void 0 === _a ? void 0 : _a.v) && void 0 !== _b ? _b : ""}` || "").name === getLoopSeriesInfo(`${null !== (_c = null == cur ? void 0 : cur.v) && void 0 !== _c ? _c : ""}` || "").name;
    },
    applyFunctions: {
        [APPLY_TYPE.SERIES]: (dataWithIndex, len, direction) => {
            var _a, _b;
            const {data: data} = dataWithIndex, isReverse = direction === Direction.LEFT || direction === Direction.UP, {series: series} = getLoopSeriesInfo(`${null === (_a = data[0]) || void 0 === _a ? void 0 : _a.v}` || "");
            if (1 === data.length) {
                let step;
                return step = isReverse ? -1 : 1, reverseIfNeed(fillLoopSeries(data, len, step, series), isReverse);
            }
            const dataNumArr = [];
            let cycleIndex = 0;
            for (let i = 0; i < data.length; i++) {
                const formattedValue = `${null === (_b = data[i]) || void 0 === _b ? void 0 : _b.v}`;
                formattedValue && (formattedValue === series[0] ? 0 === i ? dataNumArr.push(0) : (cycleIndex++, 
                dataNumArr.push(cycleIndex * series.length)) : dataNumArr.push(series.indexOf(formattedValue) + 7 * cycleIndex));
            }
            if (isReverse && (data.reverse(), dataNumArr.reverse()), isEqualDiff(dataNumArr)) {
                const step = dataNumArr[1] - dataNumArr[0];
                return reverseIfNeed(fillLoopSeries(data, len, step, series), isReverse);
            }
            return fillCopy(data, len);
        }
    }
};

export function reverseIfNeed(data, reverse) {
    return reverse ? data.reverse() : data;
}

export const formulaRule = {
    type: DATA_TYPE.FORMULA,
    priority: 1200,
    match: (cellData, accessor) => "string" == typeof (null == cellData ? void 0 : cellData.v) && cellData.v.startsWith("="),
    isContinue: (prev, cur) => {
        var _a;
        return !(prev.type !== DATA_TYPE.FORMULA || !(null === (_a = null == cur ? void 0 : cur.v) || void 0 === _a ? void 0 : _a.startsWith("=")));
    },
    applyFunctions: {
        [APPLY_TYPE.COPY]: (dataWithIndex, len, direction, copyDataPiece, location) => {
            const {data: data} = dataWithIndex;
            return fillCopy(data, len);
        },
        [APPLY_TYPE.SERIES]: (dataWithIndex, len, direction, copyDataPiece, location) => {
            const {data: data} = dataWithIndex;
            if (1 === data.length) return adjustFormulaReferences(data, len, direction, location);
            const adjustedFormulas = adjustFormulaReferencesInSeries(data, len, direction, location);
            return adjustedFormulas || fillCopy(data, len);
        }
    }
};

function adjustFormulaReferences(formulas, len, direction, location) {
    var _a, _b;
    const result = [], baseFormula = (null === (_a = formulas[0]) || void 0 === _a ? void 0 : _a.v) || "";
    for (let i = 0; i < len; i++) {
        let newFormula = baseFormula, rowOffset = 0, colOffset = 0;
        switch (direction) {
          case Direction.DOWN:
            rowOffset = i + 1;
            break;

          case Direction.UP:
            rowOffset = -(i + 1);
            break;

          case Direction.RIGHT:
            colOffset = i + 1;
            break;

          case Direction.LEFT:
            colOffset = -(i + 1);
        }
        newFormula = adjustCellReferencesInFormula(baseFormula, rowOffset, colOffset), result.push({
            v: newFormula,
            t: null === (_b = formulas[0]) || void 0 === _b ? void 0 : _b.t
        });
    }
    return result;
}

function adjustFormulaReferencesInSeries(formulas, len, direction, location) {
    var _a, _b, _c;
    if (formulas.length < 2) return null;
    const baseFormula1 = (null === (_a = formulas[0]) || void 0 === _a ? void 0 : _a.v) || "", pattern = detectFormulaPattern(baseFormula1, (null === (_b = formulas[1]) || void 0 === _b ? void 0 : _b.v) || "");
    if (!pattern) return null;
    const result = [];
    for (let i = 0; i < len; i++) {
        let newFormula = baseFormula1;
        newFormula = applyFormulaPattern(newFormula, pattern, i + 1, direction), result.push({
            v: newFormula,
            t: null === (_c = formulas[0]) || void 0 === _c ? void 0 : _c.t
        });
    }
    return result;
}

function detectFormulaPattern(formula1, formula2) {
    const cellRefRegex = /\$?([A-Z]+)\$?(\d+)/g, matches1 = [ ...formula1.matchAll(cellRefRegex) ], matches2 = [ ...formula2.matchAll(cellRefRegex) ];
    if (matches1.length !== matches2.length || 0 === matches1.length) return null;
    let totalRowOffset = 0, totalColOffset = 0, validMatches = 0;
    for (let i = 0; i < matches1.length; i++) {
        const col1 = matches1[i][1], row1 = parseInt(matches1[i][2], 10), col2 = matches2[i][1], row2 = parseInt(matches2[i][2], 10), colOffset = columnToNumber(col2) - columnToNumber(col1), rowOffset = row2 - row1;
        Math.abs(colOffset) < 100 && Math.abs(rowOffset) < 1e4 && (totalColOffset += colOffset, 
        totalRowOffset += rowOffset, validMatches++);
    }
    return 0 === validMatches ? null : {
        rowOffset: totalRowOffset / validMatches,
        colOffset: totalColOffset / validMatches
    };
}

function applyFormulaPattern(formula, pattern, multiplier, direction) {
    return formula.replace(/\$?([A-Z]+)\$?(\d+)/g, ((match, colStr, rowStr) => {
        const isColAbsolute = match.startsWith("$") && match.indexOf(colStr) > 0, isRowAbsolute = match.includes("$" + rowStr);
        let newCol = colStr, newRow = rowStr;
        if (!isColAbsolute && 0 !== pattern.colOffset) {
            newCol = numberToColumn(columnToNumber(colStr) + pattern.colOffset * multiplier);
        }
        if (!isRowAbsolute && 0 !== pattern.rowOffset) {
            newRow = (parseInt(rowStr, 10) + pattern.rowOffset * multiplier).toString();
        }
        let result = "";
        return isColAbsolute && (result += "$"), result += newCol, isRowAbsolute && (result += "$"), 
        result += newRow, result;
    }));
}

function adjustCellReferencesInFormula(formula, rowOffset, colOffset) {
    return formula.replace(/\$?([A-Z]+)\$?(\d+)/g, ((match, colStr, rowStr) => {
        const isColAbsolute = match.startsWith("$") && match.indexOf(colStr) > 0, isRowAbsolute = match.includes("$" + rowStr);
        let newCol = colStr, newRow = rowStr;
        if (!isColAbsolute && 0 !== colOffset) {
            newCol = numberToColumn(columnToNumber(colStr) + colOffset);
        }
        if (!isRowAbsolute && 0 !== rowOffset) {
            newRow = (parseInt(rowStr, 10) + rowOffset).toString();
        }
        let result = "";
        return isColAbsolute && (result += "$"), result += newCol, isRowAbsolute && (result += "$"), 
        result += newRow, result;
    }));
}

function columnToNumber(col) {
    let result = 0;
    for (let i = 0; i < col.length; i++) result = 26 * result + (col.charCodeAt(i) - "A".charCodeAt(0) + 1);
    return result;
}

function numberToColumn(num) {
    let result = "";
    for (;num > 0; ) num--, result = String.fromCharCode("A".charCodeAt(0) + num % 26) + result, 
    num = Math.floor(num / 26);
    return result;
}
//# sourceMappingURL=rules.js.map