#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include "debugmalloc.h"

#include<locale.h>
#include<ctype.h>
#include<time.h>

#include "structs.h"
#include "multiplatformLib.h"

//debugmalloc from infoc

#define green "\e[0;32m"
#define blue "\e[0;34m"

//There are lots of hints on https://infoc.eet.bme.hu/

//#define windows 1 with #ifndef __linux__ solved...

//-----------methods--------------

/**
 * @param   set set the unicode encoding
 * @return  is the program in unicode mode
 */
int isUnicodeEncoding(int set){
    static int bl = 0;
    if(set){
        bl = 1;
    }
    return bl;
}

/**
 * Only the first byte is required
 * @param   c   first byte of the unicode char
 * @return  How long is this utf-8 character (in bytes)
 */
int checkUnicharLen(char c){
    int i = 0;
    if(!isUnicodeEncoding(0)){
        return 1; //int windows-xyzw every char has 1 len;
    }
    if(!(c & 0x80)){
        return 1;
    }
    while(c & 0x80){
        i++;
        c = c << 1;
        if(i > 8){
            return EOF;
        }
    }
    return i;
}

/**
 * @deprecated only used for debugging
 */
void printChar(unichar c){
    int len;
    len = checkUnicharLen(c.bytes.c[0]);
    for(int i = 0; i < len; i++){
        printf("%c", c.bytes.c[i]);
    }
}

//fueoetoeoecsoeoe *next //what to NOT do

/**
 * read file into the map matrix
 * @param   file    the map file "object"
 * @param   matrix  the pointer of the matrix to return
 * @return  was the read successful
 */
int readFile(FILE *file, Matrix *matrix){
    int c, len, maxLineLen = 0, lineCount = 1, lineLen = 0; //lineCount = (3,1) ??? why?... i was just bored
    struct Vec2i pos;
    pos.x = 0;
    pos.y = 0;
    linkedString *linkedStr = 0, *current = 0, *next;
    //linkedStr = malloc(sizeof(linkedString));
    while(c = fgetc(file), c != EOF){
        next = malloc(sizeof(linkedString));
        if(next == NULL){
            return EOF;
        }
        #ifdef DEBUG
        memset(next, 0, sizeof(linkedString)); //fill it with zeros. only in debug mode
        #endif
        next->next = 0;
        while (c == '\r')
        {
            c = fgetc(file);
            if(c == -1){
                break;
            }
        }
        next->value.bytes.c[0] = c;
        len = checkUnicharLen(c);
        if(isUnicodeEncoding(0) && len -1){
            for (int i = 1; i < len; i++){
                c = fgetc(file);
                if(c == -1){
                    return EOF;
                }
                next->value.bytes.c[i] = c;
            }
        }
        else if(c == '\n'){       //checking newline (unichar can't be a newline char (\n))
            lineCount++;
            if(lineLen > maxLineLen){
                maxLineLen = lineLen;
            }
            lineLen = -1;
        }
        lineLen++;
        //next.value = chars;
        if(current != 0){
            current->next = next;
        }
        else
        {
            linkedStr = next;
            //current = next;
        }
        current = next;
    }
    maxLineLen = maxLineLen / 2 + maxLineLen % 2;
    matrix->height = lineCount;
    matrix->width = maxLineLen;
    matrix->matrix = calloc(maxLineLen, sizeof(chunk*));
    if(matrix->matrix == NULL){
        printf("failed to allocate memory for the matrix");
        return EOF-1;
    }
    for (int i = 0; i < maxLineLen; i++){
        matrix->matrix[i] = calloc(lineCount, sizeof(chunk));
        if(matrix->matrix[i] == NULL){
            printf("failed to allocate memory for the matrix");
            return EOF-1;
        }
        for(int n = 0; n < lineCount; n++){
            matrix->matrix[i][n].isFood = 0; //That is NOT food
            for(int a = 0; a < 2; a++){
                matrix->matrix[i][n].data.chars[a].bytes.c[0] = ' ';
            }
        }
    }

    current = linkedStr;
    while(current != 0){
        //tmp = current;
        //current = current->next;
        //free(tmp);
        if(current->value.bytes.c[0] == '\n'){
            pos.x = 0;
            pos.y++;
            //break;
        }
        else{
            for(int charPos = 0; charPos < 4; charPos++){
                matrix->matrix[pos.x/2][pos.y].data.chars[pos.x%2].bytes.c[charPos] = current->value.bytes.c[charPos];
            }
            pos.x++; 
        }
        next = current;
        current = current->next;
        free(next);
    }
    return 0;
}

/** free up matrix
 * @param map matrix to free up
 */
void rmMatrix(Matrix *map){
    for(int i = 0; i < map->width; i++){
        free(map->matrix[i]);
    }
    free(map->matrix);
}

//Use what chunk,
//witch screen coordinates?
//just the screen data
/**
 * prints a chunk into the screen, if the input position is relative
 * @param ch chunk to print
 * @param pos position relative to the screen
 * @param scrDat standard screen infos
 */
void printChunk(chunk ch, Pos pos, screenData *scrDat){
    //pos.x -= scrDat->pos.x;
    //pos.y -= scrDat->pos.y;
    if(pos.x < 0 || pos.y < 0 || pos.x >= scrDat->size.x || pos.y >= scrDat->size.y){
        return; //if pos is not on the screen, just do nothing.
    }
    if(ch.isFood){
        chunk ch = scrDat->foodTexture.text[ch.data.FRand%scrDat->foodTexture.len];
    }
    printf("\e[%d;%dH", pos.y+1, pos.x *2+1);
    for(int i = 0; i < 2; i++){
        printChar(ch.data.chars[i]); 
    }
    #ifdef DEBUG
    printf("\e[0;0H\n"); //to update terminal after EVERY print but drasticlally slowing it down
    #endif
}

/** Print characters to the screen with an absolute position input
 * It will check if the character is on the screen
 * 
 * @param ch chunk to print
 * @param pos absolute position
 * @param scrDat standard screen data
 * @param width map width
 * @param height map height
 */
void print(chunk ch, Pos pos, screenData *scrDat, int width, int height){
    pos.x = pos.x - scrDat->pos.x;
    if(pos.x < 0){
        if(scrDat->isXRepeat){
            pos.x += width;
        }
        else{
            return;
        }
    }
    pos.y = pos.y - scrDat->pos.y;
    if(pos.y < 0){
        if(scrDat->isYRepeat){
            pos.y += height;
        }
        else{
            return;
        }
    }
    printChunk(ch, pos, scrDat);
}


/** prints snake chain onto the map, listening to directions
 */
//TODO
void printSnakeChunk(snakeChain *snake, Direction prevDir, screenData *scrDat){
    //TODO
}


/**
 * update the windows size if resized
 * @param map map for width and height
 * @param scrDat standard screen data. changes will apply
 * @return did the screen size changed
 */
int updateScreenSize(Matrix *map, screenData *scrDat){
    struct Vec2i size = getWindowSize();
    size.x = size.x / 2;
    size.y = size.y;// / 2;//Why half?
    if(size.x == scrDat->size.x && size.y == scrDat->size.y){
        return 0; //no change happened
    }
    scrDat->size.x = size.x;
    scrDat->size.y = size.y;
    if(scrDat->repeatMap){
        scrDat->isXRepeat = size.x < map->width;
        scrDat->isYRepeat = size.y < map->height;
    }
    return 1;
}

/**
 * Update the screen if it changed size of snek is near to the screen border
 * The game doesn't update every character in every round to be more efficient
 * 
 * @param map map
 * @param scrDat screenData
 * @param head the head of the snake
 * @param d snek's current moving direction
 */
void updateScreen(Matrix *map, screenData *scrDat, snakeChain *head, Direction d){
    int do_update;
    do_update = updateScreenSize(map, scrDat);

    if(do_update){
        if(scrDat->size.x < map->width){
            scrDat->pos.x = mod(head->pos.x - scrDat->size.x / 2 ,map->width, scrDat->repeatMap);
        }else{
            scrDat->pos.x = 0;
        }
        if(scrDat->size.y < map->height){
            scrDat->pos.y = mod(head->pos.y - scrDat->size.y / 2 ,map->height, scrDat->repeatMap);
        }else{
            scrDat->pos.y = 0;
        }
    }
    else{
        int min_x = scrDat->pos.x;
        int max_x = scrDat->pos.x + scrDat->size.x;
        int min_y = scrDat->pos.y;
        int max_y = scrDat->pos.y + scrDat->size.y;
        switch (d)
        {
        case LEFT:
            if(scrDat->size.x < map->width && mod(head->pos.x - min_x, map->width, 1) < 6){
                scrDat->pos.x = mod(min_x - 1, map->width, scrDat->isXRepeat);
                do_update = 1;
            }
            break;
        case RIGHT:
            if(scrDat->size.x < map->width && mod(max_x - head->pos.x, map->width, 1) < 6){
                scrDat->pos.x = mod(mod(max_x + 1, map->width, scrDat->isXRepeat) - scrDat->size.x, map->width, true);
                do_update = 1; //1 equal true :D
            }
            break;
        case UP:
            if(scrDat->size.y < map->height && mod(head->pos.y - min_y, map->height, 1) < 6){
                scrDat->pos.y = mod(min_y - 1, map->height, scrDat->isYRepeat);
                do_update = 1;
            }
            break;
        case DOWN:
            if(scrDat->size.y < map->height && mod(max_y - head->pos.y, map->height, 1) < 6){
                scrDat->pos.y = mod(mod(max_y + 1, map->height, scrDat->isYRepeat) - scrDat->size.y, map->height, true);
                do_update = 1; //1 equal true :D
            }
            break;
        default:
            //printf("Something went wrong. Direction value is %d.\n", d);
            break;
        }
    }

    if(do_update){
        Pos pos;
        for (pos.y = scrDat->pos.y; pos.y < scrDat->pos.y + scrDat->size.y; pos.y++){
            printf("\e[%d;0H\e[K", pos.y - scrDat->pos.y + 1); //Clear the screen line
            if(pos.y >= map->height && !scrDat->isYRepeat){
                break;
            }
            for (pos.x = scrDat->pos.x; pos.x < scrDat->pos.x + scrDat->size.x; pos.x++){
                if(pos.x < map->width || scrDat->isXRepeat){
                    print(map->matrix[pos.x%map->width][pos.y%map->height], pos, scrDat, map->width, map->height);
                }
            }
        }
    }
}

/**
 * reads the stdin for new control commands (wasd), apply them to the scrDat commands standardDat
 * and dooesn't start to wait for user input if not available.
 * 
 * @param scrDat standard game data
 * @param direction current direction
 */
void getControl(screenData *scrDat, Direction *direction){
    int i;
    while(i = getNextChar(), i != EOF){
        Direction next = NONE;
        switch (i)
        {
        case 'a':
            next = LEFT;
            break;
        
        case 's':
            next = DOWN;
            break;
        
        case 'w':
            next = UP;
            break;
        
        case 'd':
            next = RIGHT;
            break;
        
        default:
            next = NONE;
            continue; //we don't have to registrate a non command...
        }

        if(*direction == NONE){
            *direction = next;
            continue;
        }

        if(next == *direction){
            scrDat->commands[0] = NONE;
            scrDat->commands[1] = NONE;
            continue;
        }

        // [a && b || c]  =  [c || a && b]  =  [(a && b) || c]
        if(((*direction == UP || *direction == DOWN) && (next == RIGHT || next == LEFT))
        || ((*direction == RIGHT || *direction == LEFT) && (next == UP || next == DOWN))){
            scrDat->commands[0] = next;
        }
        else
        {
            if(scrDat->commands[0] != NONE){
                scrDat->commands[1] = next;
            }
        }
    }
}

/**
 * @param c input chunk
 * @return false if the input chunk is a wall
 */
int isNotWall(chunk c){
    return c.isFood || (c.data.chars[0].bytes.c[0] == ' ' && c.data.chars[1].bytes.c[0] == ' ');
}

/**
 * @param c input chunk
 * @return is the chunk air (not wall and not food)
 */
int isAir(chunk c){
    return !c.isFood && isNotWall(c);
}

/**
 * after some round it will place a new food onto the map randomly.
 * 
 * @param map map
 * @param foodTick how long ago was the last food placed (pointer)
 * @param feedAmount how often (in ticks) sould be a new food placed
 * @param firstSnake snake, to avoid placing food into snake
 * @param scrDat food will be printed, screed data is needed for this
 */
void updateFood(Matrix *map, int *foodTick, int feedAmount, snakeChain *firstSnake, screenData *scrDat){
    if((*foodTick)++ > feedAmount){
        for(int i = 0; i < 128; i++){
            Pos pos;
            int isFree = 1;
            snakeChain *snake = firstSnake;
            pos.x = rand()%map->width;
            pos.y = rand()%map->height;

            if(isAir(map->matrix[pos.x][pos.y])){
                while(snake != NULL){
                    if(snake->pos.x == pos.x && snake->pos.y == pos.y){
                        isFree = false;
                        break;
                    }
                    snake = snake->next;
                }
                if(!isFree){
                    continue;
                }
                //pos is available
                {
                    *foodTick = 0;
                    chunk c;
                    map->matrix[pos.x][pos.y].isFood = 1;
                    map->matrix[pos.x][pos.y].data.FRand = rand();
                    c.data.chars[0].bytes.c[0] = 'X';
                    c.data.chars[1].bytes.c[0] = 'X';
                    printf(green);
                    print(c, pos, scrDat, map->width, map->height);
                    printf("\e[0m");
                    break;
                }
            }
        }
    }
}

//EOF fatal error, 1 game over

/**
 * step and check snake
 * 
 * 
 * @param map map
 * @param scrDat screenData
 * @param d current direction
 * @param head head of snek
 * @param canBite can sneak bite itself (boolean)
 * @return EOF if fatal error happened, 1 if the game is over, 0 instead.
 */
int updateSnake(Matrix *map, screenData *scrDat, Direction d, snakeChain *head, int canBite){
    Pos pos = head->pos;
    switch (d)
    {
    case UP:
        pos.y--;
        break;
    case DOWN:
        pos.y++;
        break;
    case LEFT:
        pos.x--;
        break;
    case RIGHT:
        pos.x++;
        break;
    default:
        return EOF;
        break;
    }
    if(pos.x < 0 || pos.x >= map->width){
        if(scrDat->repeatMap){
            pos.x = mod(pos.x, map->width, true);
        }
        else
        {
            return 1; //GAME OVER reached map end;
        }
    }
    if(pos.y < 0 || pos.y >= map->height){
        if(scrDat->repeatMap){
            pos.y = mod(pos.y, map->height, true);
        }
        else
        {
            return 1; //GAME OVER reached map end;
        }
    }
    
    if(isNotWall(map->matrix[pos.x][pos.y])){
        int isFood = map->matrix[pos.x][pos.y].isFood;
        if(isFood){
            map->matrix[pos.x][pos.y].isFood = false;
            map->matrix[pos.x][pos.y].data.chars[0].bytes.c[0] = ' ';
            map->matrix[pos.x][pos.y].data.chars[1].bytes.c[0] = ' ';
        }
        snakeChain *snake = head;
        Pos tmp_pos1 = head->pos, tmp_pos2;
        Direction dir_tmp = head->dir, dir_tmp2;
        head->dir = d;
        head->pos = pos;
        while (snake->next != 0)
        {
            snake = snake->next;
            chunk c;

            //if snek hit itself
            if(snake != head && snake->pos.x == head->pos.x && snake->pos.y == head->pos.y){
                if(snake->next != NULL){
                    if(canBite){
                        //if snek can bite its own tail, free that space and fill these places with   .
                        snakeChain *current = snake, *tmp_snek = snake->next;
                        current->next = NULL;
                        while (tmp_snek != NULL)
                        {
                            current = tmp_snek;
                            tmp_snek = tmp_snek->next;
                            c.data.chars[0].bytes.c[0] = ' ';
                            c.data.chars[1].bytes.c[0] = ' ';
                            print(c, current->pos, scrDat, map->width, map->height);
                            free(current);
                        }
                    }
                    else
                    {
                        return 1; //GAME OVER snake hit itself;
                    }
                }else
                {
                    isFood = false;
                }
                
                
            }
            //step position
            tmp_pos2 = snake->pos;
            snake->pos = tmp_pos1;
            tmp_pos1 = tmp_pos2;

            //step direction
            dir_tmp2 = snake->dir;
            snake->dir = dir_tmp;

            //render snek
            
            /*
            c.data.chars[0].bytes.c[0] = '>';
            c.data.chars[1].bytes.c[0] = '<';            
            */
            if(snake->pos.x != -1){
                //TODO call render
            }

            //create a new segment
            if(snake->next == NULL && isFood){
                isFood = false;
                snake->next = malloc(sizeof(snakeChain));
                if(snake->next == NULL){
                    return EOF;
                }
                snake->next->next = NULL;
                snake->next->pos = tmp_pos1;
                snake->next->num = snake->num + 1;
            }
            //printf(blue);
            //print(c, snake->pos, scrDat, map->width, map->height); //TODO direction snake

            #ifdef DEBUG
            printf("\e[0m"); //if debug active, update display after every segments
            #endif

        }

        //clear last segment form the screen
        if(tmp_pos2.x != -1){
            chunk c; 
            c.data.chars[0].bytes.c[0] = ' ';
            c.data.chars[1].bytes.c[0] = ' ';
            print(c, tmp_pos2, scrDat, map->width, map->height); //set this to air.
        }
        chunk c;
        c.data.chars[0].bytes.c[0] = '(';
        c.data.chars[1].bytes.c[0] = ')';
        printf(blue);
        print(c, head->pos, scrDat, map->width, map->height); //TODO direction snake

        #ifdef DEBUG
        printf("\e[0m");
        #endif
    }
    else
    {
        return 1; //GAME OVER hit the wall;
    }
    return 0;
}

//------------config loader------------

/**
 * Loads game config file
 * 
 * @param tickSpeed game tickSpeed in miliseconds
 * @param repeatMap is the map repeated
 * @param feedAmount food spawn rate
 * @param canBite can snek bite itself
 * 
 * @return EOF if error 0 instead
 */
int loadConfig(int *tickSpeed, int *repeatMap, int *feedAmount, int *canBite){
    FILE *config;
    config = fopen("config.cfg", "r");
    //int stillFile = 1; //boolean to show file is ended...
    if(config == NULL){
        return -1;
    }
    while(1){
        char name[32] = {0}, c; //it have to be enough;
        while(c = fgetc(config), c != -1 && isspace(c));
        if(c == -1){
            break;
        }
        //name[0] = c;
        for(int i = 0; i < 32 && !isspace(c) && c != '='; i++, c = fgetc(config)){
            name[i] = c;
        }
        //c = fgetc(config);
        while(c != '='){
            c = fgetc(config);
            if(c == -1){
                printf("I can't  understand the config file: %s", name);
                return EOF;
            }
        }
        if(strncmp(name, "use_utf8", 9) == 0){
            int bl;
            fscanf(config, " %d", &bl);
            isUnicodeEncoding(bl);
        }
        else if(strncmp(name, "tickspeed", 10) == 0){
            fscanf(config, " %d", tickSpeed);
        }
        else if(strncmp(name, "repeat_map", 10) == 0){
            fscanf(config, " %d", repeatMap);
        }
        else if(strncmp(name, "feed_amount", 12) == 0){
            fscanf(config, " %d", feedAmount);
        }
        else if(strncmp(name, "can_bite", 9) == 0){
            fscanf(config, " %d", canBite);
        }
        else{
            printf("Unknown keyword: %s", name);
        }
    }
    return 0;
}



//------------LOOP METHODs--------------

//Tick the game, step the snake, collect and place food.
//check new direction
//update display
//update food state
//step snake
/**
 * ticks the game including everything
 * updates the control
 * updates the screen
 * updates the foods
 * steps snek
 * 
 * @param map map
 * @param scrDat screenData
 * @param snake snake's head
 * @param d direction
 * @param feedAmount food spawn rate
 * @param canBite can snake bite its own tail
 * @return 1 if game over
 */
int tick(Matrix *map, screenData *scrDat, snakeChain *snake, Direction *d, int feedAmount, int canBite){
    static int foodTick = 0;
    getControl(scrDat, d);
    if(scrDat->commands[0] != NONE){
        *d = scrDat->commands[0];
    }
    scrDat->commands[0] = scrDat->commands[1];
    scrDat->commands[1] = NONE;
    updateScreen(map, scrDat, snake, *d);
    if(*d == NONE){
        chunk c;
        c.data.chars[0].bytes.c[0] = '(';
        c.data.chars[1].bytes.c[0] = ')';
        printf(blue);
        print(c, snake->pos, scrDat, map->width, map->height);
        printf("\e[0m");
        return 0; // waiting for user input.
    }
    updateFood(map, &foodTick, feedAmount, snake, scrDat);
    if(updateSnake(map, scrDat, *d, snake, canBite)){
        *d = NONE;
        //TODO Game over or remove 1 hp or ...
    }
    //printf("\e[0;0H\n"); //Update the terminal (mostly on Unix based systems)
    fflush(stdout);
    return 0;
}

/**
 * prepares the game for loop and then starts the infinite loop
 * 
 * @param matrix map
 * @param tickspeed game tickspeed in milis
 * @param repeatMap does the map repeat itself
 * @param feedAmount food spawn rate
 * @param canBite can snake bite itself
 * @return 0
 */
int loop(Matrix *matrix, int tickspeed, int repeatMap, int feedAmount, int canBite){

    Direction d = NONE; //Init with none
    screenData scrDat;
    snakeChain snake, *chain;

    while(true){
        Pos p;
        p.x = rand()%matrix->width;
        p.y = rand()&matrix->height;
        if(isNotWall(matrix->matrix[p.x][p.y])){
            snake.pos = p;
            break;
        }
    }
    chain = &snake;
    for(int i = 1; i < 3; i++){
        Pos p;
        p.x = -1;
        p.y = -1;
        chain->next = malloc(sizeof(snakeChain));
        if(chain->next == NULL){
            return -1;
        }
        chain = chain->next;
        chain->pos = p;
        chain->next = NULL;
        chain->num = i-1;
    }

    scrDat.size.x = 0;
    scrDat.size.y = 0;
    scrDat.repeatMap = repeatMap;
    scrDat.commands[0] = NONE;
    scrDat.commands[1] = NONE;
    while(42){
        if(tick(matrix, &scrDat, &snake, &d, feedAmount, canBite)){
            break;
        }
        unisleep(tickspeed); //Special sleep to work both in windows and unix environment
    }
    return 0;
}

//------------TESTING METHODS-------------

/**
 * ONLY FOR DEBUG
 * print the map for debug
 * 
 * @param map map
 */
void _testprint(Matrix *map){
    for (int y = 0; y < map->height; y++){
        for(int x = 0; x < map->width; x++){
            for(int i = 0; i < 2; i++){
                //printf("%c", map->matrix[x][y].chars->bytes.c[i * 4]); //WTF... I didn't indexed correctly, but accidentaly I've got the right value...
                printChar(map->matrix[x][y].data.chars[i]);
                //unisleep(1000);
            }
            //printf("|");
        }
        printf("\n");
    }
}

/**
 * ONLY FOR DEBUG
 * reads coordinates from stdin and print this pos to the stdout
 * 
 * @param map map
 */
void _print1char(Matrix *map){
    int x, y;
    while(scanf(" %d%d", &x, &y) == 2){
        if(x >= 0 && y >= 0 && x < map->width && y < map->height){
            for(int i = 0;i < 2; i++){
                printf("\nvalue: %hx, %hx, %hx, %hx\n",
                (unsigned)map->matrix[x][y].data.chars[i].bytes.c[0],
                (unsigned)map->matrix[x][y].data.chars[i].bytes.c[1],
                (unsigned)map->matrix[x][y].data.chars[i].bytes.c[2],
                (unsigned)map->matrix[x][y].data.chars[i].bytes.c[3]);
                printf("as character: \"");
                printChar(map->matrix[x][y].data.chars[i]);
                printf("\"\n");
            }
        }
    }
}


//-------------CORE METHOD----------------

/**
 * The main method is respinsible for the debug or release mode start, technically the main is redirected here
 * initialize the game then start tle game
 * 
 * @param argc redirected argc
 * @param argv redirected argv
 */
int core(int argc, char const *argv[])
{
    FILE *f;
    Matrix map;

    initMultiplatform(); // init stuff.

    srand(time(0)); // bee a bit more random

    int tickspeed = 100, repeatMap = 0, feedAmount = 20, canBite = true; // if no config, default value

    //----load config----

    if(loadConfig(&tickspeed, &repeatMap, &feedAmount, &canBite)){
        printf("Error while loading config...");
    }

    //----init tasks----

    if(isUnicodeEncoding(0)){
        #ifndef __linux__
        setlocale(LC_ALL, ".utf-8");
        #endif
    }

    //----import map----

    if(argc == 1){
        printf("Usage: snake \<map name\> \[\<snake skin\>\]");
        return 0;
    }
    else{
        f = fopen(argv[1], "rb");
        if(f == NULL){
            printf("Map file not found: %s", argv[1]);
            return EOF;
        }
        readFile(f, &map);
    }

    //----start game----


    #ifdef DEBUG
    _testprint(&map);
    #endif

    loop(&map, tickspeed, repeatMap, feedAmount, canBite);

    //test code
    //printf("map:\n");
    //_print1char(&map);
    /* code */
    //free stuff



    rmMatrix(&map);
 
    return 0;
}


/*
int main(int argc, char const *argv[])
{
    return core(argc, argv);
}
*/

/**
 * debugger main function
 * in debug mode, starts the core with correct params
 * in release mode, it will use user input files.
 * @param argc argc
 * @param argv *argv[]
 */
int main(int argc, char const *argv[])
{
    int walltest; //warning: unused variable ‘walltest’ [-Wunused-variable]

    //2 + 3;  //... this does nothing...
    #ifdef DEBUG
    int ret;
    char const *array[] = {argv[0], "snake.c"}; // set the debug input
    ret = core(2, array);
    printf("\npress any key to continue");
    getchar();
    //return 0, ret; //Miért van ez a függvény tele szeméttel??? pl 0, smt...

    return ret; // így szép.
    #else
    return core(argc, argv);
    debugmalloc_dump();
    #endif
}