#include "_.h"

int count = 1;
int len = 0;
int lens = 0;

void set(int ***already, char **inputs, int y, int x) {
    (*already)[y][x] = inputs[y][x];
    
    if (inputs[y + 1] != NULL && inputs[y][x] == inputs[y + 1][x]
        && (*already)[y + 1][x] == 0) {
            set(already, inputs, y + 1, x);
            count++;
    }
    if (y > 0 && inputs[y][x] == inputs[y - 1][x]
         && (*already)[y - 1][x] == 0) {
            set(already, inputs, y - 1, x);
            count++;
    }
    if (x < strlen(inputs[y]) - 1 && inputs[y][x] == inputs[y][x + 1]
        && (*already)[y][x + 1] == 0) {
            set(already, inputs, y, x + 1);
            count++;
    }
    if (x > 0 && inputs[y][x] == inputs[y][x - 1]
        && (*already)[y][x - 1] == 0) {
            set(already, inputs, y, x - 1);
            count++;
    }
}

int test(int ***already, int ***sides_lines, int check, int *sides, int y, int x, int h, int w, int add_y, int add_x) {
    int i = 0;
    int abs_y = ABS(add_y), abs_x = ABS(add_x);
    for (i = 0; y >= -1 && x >= -1 && y + (i * abs_x) <= h && x + (i * abs_y) <= w && (*already)[y + (i * abs_x)][x + (i * abs_y)] != check && (*already)[y + (i * abs_x) + add_y][x + (i * abs_y) + add_x] == check && (*sides_lines)[y + (i * abs_x)][x + (i * abs_y)] == 0; i++) {
        if ((i == 0 && (*sides_lines)[y + (-1 * abs_x)][x + (-1 * abs_y)] != 0) ||
            (*sides_lines)[y + 1 + (i * abs_x)][x + (i * abs_y)] != 0 ||
            (*sides_lines)[y + (i * abs_x)][x + 1 + (i * abs_y)] != 0 ||
            (abs_x != 0 && (*sides_lines)[y + i][x - 1] != 0) ||
            (abs_y != 0 && (*sides_lines)[y - 1][x + i] != 0)) {

            (*sides_lines)[y][x] = 0;
            for (; i >= 0; i--)
                (*sides_lines)[y + (i * abs_x)][x + (i * abs_y)] = 0;
            i = 0;
            break;
        }
        (*sides_lines)[y + (i * abs_x)][x + (i * abs_y)] = *sides + 1;
    }
    if (i > 0) {
        int top = 0, bottom = 0, left = 0, right = 0;
        for (int j = 0; j < i; j++) {
            top = top ? 1 : (*already)[y - 1 + (j * abs_x)][x + (j * abs_y)] == check;
            if (top && add_y != 0) {
                for (int w = 0; ((*already)[y + w][x + 1] == check
                               ||(*already)[y + w][x - 1] == check)
                               && y + w < h 
                               && (*already)[y + w][x] != check
                               ; w++)
                    (*sides_lines)[y + w][x] = *sides + 1;
            }
            bottom = bottom ? 1 : (*already)[y + 1 + (j * abs_x)][x + (j * abs_y)] == check;
            if (bottom && add_y != 0) {
                for (int w = 0; ((*already)[y + 1][x - w] == check
                               ||(*already)[y - 1][x - w] == check)
                               && y + w < h
                               && (*already)[y][x - w] != check
                               ; w++)
                    (*sides_lines)[y - w][x] = *sides + 1;
            }
            right = right ? 1 : (*already)[y + (j * abs_x)][x + 1 + (j * abs_y)] == check;
            if (right && add_x != 1) {
            }
            left = left ? 1 : (*already)[y + (j * abs_x)][x - 1 + (j * abs_y)] == check;
            if (left && add_x != -1) {
            }
        }
        *sides += (top + bottom + left + right); 
        return 1;
    }
    return 0;
}


int get_side(int ***already, int check, int h, int w) {
    int **sides_lines = calloc(lens + 2, sizeof(int*));
    for (int i = -2; i < len + 2; i++) {
        sides_lines[i] = calloc(len + 2, sizeof(int));
        for (int j = -2; j < len + 2; j++)
            sides_lines[i][j] = 0;
    }

    int **new_already = calloc(lens + 2, sizeof(int*));
    for (int i = -2; i < len + 2; i++) {
        new_already[i] = calloc(len + 2, sizeof(int));
        for (int j = -2; j < len + 2; j++) {
            new_already[i][j] = (*already)[i][j];
        }
    }

    int sides = 0;
    for (int y = -1; y < h + 1; y++) {
        for (int x = -1; x < w + 1; x++) {
            if (x >= 0 && y >= 0 && x < w && y < h) {
                if ((*already)[y][x] == check) {
                    new_already[y][x] = -1;
                    continue;
                }
            }

            if (test(already, &sides_lines, check, &sides, y, x, h, w, 1, 0))
                continue;
            if (test(already, &sides_lines, check, &sides, y, x, h, w, -1, 0))
                continue;
            if (test(already, &sides_lines, check, &sides, y, x, h, w, 0, 1))
                continue;
            if (test(already, &sides_lines, check, &sides, y, x, h, w, 0, -1))
                continue;
        }
    }

    (*already) = new_already;
    return sides;
}

int main(int argc, char **argv) {
	
	if (argc != 2)
		return 1;

	char *input = argv[1];
	char **inputs = str_split(strdup(input), '\n');
    len = strlen(inputs[0]);
    lens = strslen(inputs);

    int **already = calloc(lens + 2, sizeof(int*));
    for (int i = -2; i < len + 2; i++)
        already[i] = calloc(len + 2, sizeof(int));

    long result = 0;
	for (int i = 0; inputs[i] != NULL; i++) {
        for (int j = 0; inputs[i][j] != '\0'; j++) {
            if (already[i][j] == 0) {
                set(&already, inputs, i, j);
                long side = get_side(&already, already[i][j], lens, len); 
                result += (count * side);
                printf("side: %ld\n", side);
                printf("count: %d\n\n", count);
                //printf("result: %ld\n", result);
                count = 1;
            }
        }
	}

    printf("result: %ld\n", result);

	return 0;
}
