/**
 * Creates an empty matrix with given rows and columns
 * @param rows - integer, the amount of rows the matrix should have
 * @param columns - integer, the amount of columns the matrix should have
 * @returns an empty matrix with given rows and columns
 */
export function createEmpty(rows, columns) {
    const matrix = Array(rows);
    for (let i = 0; i < rows; i++) {
        matrix[i] = Array(columns);
    }
    return matrix;
}
/** Gets the value at row and column of matrix. */
export function get(point, matrix) {
    const columns = matrix[point.row];
    if (columns === undefined) {
        return undefined;
    }
    return columns[point.column];
}
/** Creates a slice of matrix from startPoint up to, but not including, endPoint. */
export function slice(startPoint, endPoint, matrix) {
    const sliced = [];
    const columns = endPoint.column - startPoint.column;
    for (let row = startPoint.row; row <= endPoint.row; row++) {
        const slicedRow = row - startPoint.row;
        sliced[slicedRow] = sliced[slicedRow] || Array(columns);
        for (let column = startPoint.column; column <= endPoint.column; column++) {
            sliced[slicedRow][column - startPoint.column] = get({ row, column }, matrix);
        }
    }
    return sliced;
}
/** Sets the value at row and column of matrix. If a row doesn't exist, it's created. */
export function set(point, value, matrix) {
    // Create a shallow copy of the matrix
    const nextMatrix = [...matrix];
    // Ensure the first row exists (initialize if undefined)
    const firstRow = matrix[0] ?? [];
    const nextFirstRow = [...firstRow];
    // Ensure the first row has enough columns to accommodate the specified column
    if (nextFirstRow.length <= point.column) {
        nextFirstRow.length = point.column + 1; // Extend the first row if needed
    }
    // Set the modified first row back into the matrix
    nextMatrix[0] = nextFirstRow;
    // Ensure the specified row exists (initialize if undefined)
    const nextRow = matrix[point.row] ?? [];
    const nextRowCopy = [...nextRow];
    // Set the value at the specified point
    nextRowCopy[point.column] = value;
    // Set the modified row back into the matrix
    nextMatrix[point.row] = nextRowCopy;
    return nextMatrix;
}
/** Like Matrix.set() but mutates the matrix */
export function mutableSet(point, value, matrix) {
    // Ensure that the first row exists, if not, create it
    let firstRow = matrix[0];
    if (!firstRow) {
        firstRow = [];
        matrix[0] = firstRow;
    }
    // Ensure the row at point.row exists, if not, create it
    let row = matrix[point.row];
    if (!row) {
        row = [];
        matrix[point.row] = row;
    }
    // Ensure that the first row has enough columns
    if (firstRow.length <= point.column) {
        firstRow.length = point.column + 1; // Extend the first row if needed
    }
    // Set the value at the specified point
    row[point.column] = value;
}
/** Removes the coordinate of matrix */
// export function unset<T>(point: Point.Point, matrix: Matrix<T>): Matrix<T> {
//   if (!has(point, matrix)) {
//     return matrix;
//   }
//   const nextMatrix = [...matrix];
//   const nextRow = [...matrix[point.row]];
//   // Avoid deleting to preserve first row length
//   nextRow[point.column] = undefined;
//   nextMatrix[point.row] = nextRow;
//   return nextMatrix;
// }
export const convertPtToPx = (pt) => {
    const px = pt * 1.33;
    return `${px}px`;
};
const EmptyCell = {
    value: '',
    inputType: { type: 'text' },
    readOnly: false,
    style: {
        color: '#000000', // Needed hexacode for backend
        backgroundColor: '#ffffff', // Needed hexacode for backend
        borderColor: '#c9c9c9', // Needed hexacode for backend
        textDecoration: 'normal',
        borderRight: `1px solid var(--excel-header-border)`,
        borderLeft: `1px solid var(--excel-header-border)`,
        borderTop: `1px solid var(--excel-header-border)`,
        borderBottom: `1px solid var(--excel-header-border)`,
        fontSize: `${convertPtToPx(9)}`,
        fontWeight: 'normal',
        fontStyle: 'normal',
        fontFamily: 'Poppins',
        textAlign: 'left',
    },
};
export function unset(point, matrix) {
    // Check if the point exists in the matrix
    if (!has(point, matrix)) {
        return matrix;
    }
    // Create a shallow copy of the matrix
    const nextMatrix = [...matrix];
    // Check if the row exists before trying to copy it
    const currentRow = matrix[point.row];
    if (currentRow) {
        // Create a shallow copy of the row
        const nextRow = [...currentRow];
        // Avoid deleting to preserve first row length
        nextRow[point.column] = EmptyCell;
        // Update the matrix with the modified row
        nextMatrix[point.row] = nextRow;
    }
    return nextMatrix;
}
/** Creates an array of values by running each element in collection thru iteratee. */
export function map(func, matrix) {
    const newMatrix = [];
    for (const [point, value] of entries(matrix)) {
        mutableSet(point, func(value, point), newMatrix);
    }
    return newMatrix;
}
/** Create an iterator over the cells in the matrix */
export function* entries(matrix) {
    for (const [row, values] of matrix.entries()) {
        for (const [column, value] of values.entries()) {
            const point = { row, column };
            yield [point, value];
        }
    }
}
/**
 * Converts all elements in row into a string separated by horizontalSeparator and each row string
 * to string separated by verticalSeparator
 */
export function join(matrix, horizontalSeparator = '\t', verticalSeparator = '\n') {
    let joined = '';
    const { rows, columns } = getSize(matrix);
    for (let row = 0; row < rows; row++) {
        if (row) {
            joined += verticalSeparator;
        }
        for (let column = 0; column < columns; column++) {
            if (column) {
                joined += horizontalSeparator;
            }
            // Ensure matrix[row] exists and matrix[row][column] is not undefined
            const cellValue = matrix[row]?.[column];
            // If cellValue is undefined, you can use a fallback value like an empty string
            joined += cellValue !== undefined ? String(cellValue) : '';
        }
    }
    return joined;
}
/**
 * Parses a CSV separated by a horizontalSeparator and verticalSeparator into a
 * Matrix using a transform function
 */
export function split(csv, transform, horizontalSeparator = '\t', verticalSeparator = /\r\n|\n|\r/) {
    // Temporarily replace line breaks inside quotes
    const replaced = csv.replace(/"([^"]*?)"/g, (_, p1) => {
        return p1.replace(/\n/g, '\\n');
    });
    return replaced.split(verticalSeparator).map((row) => row
        .split(horizontalSeparator)
        .map((line) => {
        // Restore original line breaks in each line
        return line.replace(/\\n/g, '\n');
    })
        .map(transform));
}
/** Returns whether the point exists in the matrix or not. */
export function has(point, matrix) {
    const firstRow = matrix[0];
    if (!firstRow) {
        return false; // If first row is undefined, return false
    }
    // Perform validation checks
    return (point.row >= 0 &&
        point.column >= 0 &&
        Number.isInteger(point.row) &&
        Number.isInteger(point.column) &&
        point.column < firstRow.length &&
        point.row < matrix.length);
}
/** Gets the count of rows and columns of given matrix */
export function getSize(matrix) {
    return {
        columns: getColumnsCount(matrix),
        rows: getRowsCount(matrix),
    };
}
/** Gets the count of rows of given matrix */
export function getRowsCount(matrix) {
    return matrix.length;
}
/** Gets the count of columns of given matrix */
export function getColumnsCount(matrix) {
    const firstRow = matrix[0];
    return firstRow ? firstRow.length : 0;
}
/**
 * Pads matrix with empty rows to match given total rows
 * @param matrix - matrix to pad
 * @param totalRows - number of rows the matrix should have
 * @returns the updated matrix
 */
export function padRows(matrix, totalRows) {
    const { rows, columns } = getSize(matrix);
    if (rows >= totalRows) {
        return matrix;
    }
    const missingRows = totalRows - rows;
    const emptyRow = Array(columns).fill(undefined);
    const emptyRows = Array(missingRows).fill(emptyRow);
    return [...matrix, ...emptyRows];
}
/**
 * Pads matrix with empty columns to match given total columns
 * @param matrix - matrix to pad
 * @param size - minimum size of the matrix after padding.
 * @returns the updated matrix
 */
export function pad(matrix, size) {
    const { rows, columns } = getSize(matrix);
    if (rows >= size.rows && columns >= size.columns) {
        // Optimization, no padding required.
        return matrix;
    }
    const resultSize = {
        rows: size.rows > rows ? size.rows : rows,
        columns: size.columns > columns ? size.columns : columns,
    };
    let padded = [...matrix];
    if (resultSize.columns > columns) {
        const padColumns = resultSize.columns - columns;
        padded = padded.map((row) => [
            ...row,
            ...Array(padColumns).fill(EmptyCell),
        ]);
    }
    if (resultSize.rows > rows) {
        const padRows = resultSize.rows - rows;
        const emptyRow = Array(resultSize.columns).fill(EmptyCell);
        padded = [...padded, ...Array(padRows).fill(emptyRow)];
    }
    return padded;
}
/**
 * Flattens a matrix values to an array
 * @param matrix - the matrix to flatten values from
 * @param transform - optional transform function to apply to each value in the
 * matrix
 * @returns an array of the values from matrix, transformed if a transform
 * function is passed
 */
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function toArray(matrix, transform) {
    const array = [];
    for (let row = 0; row < matrix.length; row++) {
        const currentRow = matrix[row];
        // Ensure the row is not undefined
        if (currentRow !== undefined) {
            for (let column = 0; column < currentRow.length; column++) {
                const value = currentRow[column];
                // If transform is provided, apply it; otherwise, use the value as is
                array.push(transform ? transform(value, { row, column }) : value);
            }
        }
    }
    return array;
}
/** Returns the maximum point in the matrix */
export function maxPoint(matrix) {
    const size = getSize(matrix);
    return { row: size.rows - 1, column: size.columns - 1 };
}
//# sourceMappingURL=matrix.js.map