export type Cell = "#"|"."
export type Data = Cell[][]

export function isCell(x: string): x is Cell {
    return x === "#" || x === ".";
}

export function normalizeCRLF(str: string) {
    return str.replace(/\r\n/g, "\n");
}

export function readData(content: string): Data[]{
    const normalized = normalizeCRLF(content);
    const maps = normalized.split("\n\n");
    return maps.map(x => x.split("\n").map(x => {
        const cells = x.split("");
        if (cells.every(isCell)) {
            return cells;
        }
        throw new Error("Invalid line: " + x);
    }));
}

export function transpose<T>(arr: T[][]): T[][] {
    return arr[0].map((_, i) => arr.map(x => x[i]));
}

export function getBitsNumbers(cells: Cell[]){
    if (cells.length > 30) {
        throw new Error("Too long line");
    }
    const numbers = cells.map(x => x === "#" ? 1 : 0);
    let ret = 0;
    for (let i = 0; i < numbers.length; i++) {
        ret = ret << 1;
        ret = ret | numbers[i];
    }
    return ret;
}

/**
 * Find the reflection index in the given array.
 *
 * @param {number[]} arr - the input array of numbers
 * @return {number} the reflection index if found, otherwise -1
 */
export function getReflectionIndex(arr: number[]): number {
    for (let i = 1; i < arr.length; i++) {
        let isEqual = true;
        for (let j = i; j < arr.length && (2*i - j-1 >= 0) ; j++) {
            if (arr[j] !== arr[2*i-j-1]) {
                isEqual = false;
                break;
            }
        }
        if (isEqual) {
            return i;
        }
    }
    return -1;
}

export function popcount(n: number): number{
    n = n - ((n >> 1) & 0x55555555);
    n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
    return (((n + (n >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24;
}

export function correctReflection(arr: number[]): number {
    let diff: number;
    for (let i = 1; i < arr.length; i++) {
        diff = 0;
        for (let j = i; j < arr.length && (2*i - j-1 >= 0) ; j++) {
            diff += popcount(arr[j] ^ arr[2*i-j-1])
            // console.log(arr[j], arr[2*i-j-1], diff)
            if (diff > 1) {
                break;
            }
        }
        if (diff === 1) {
            return i;
        }
    }
    return -1;
}