/*
  Copyright Tom Lukeywood 2018
    This file is part of Forest2D

    Forest2D is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Forest2D is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Forest2D.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <ctype.h>

#include "Data.h"

#define GLOBAL /**/
#define World(w,z,y,x) (world [(w * x_size * y_size * z_size) + (z * x_size * y_size) + (y * x_size) + x])
#define world_size w_size * z_size * y_size * x_size * sizeof (Tile)

typedef struct Tile
{
    uint8_t tile_id;
    uint8_t animation_id;
    uint8_t animated;
    uint8_t impassable;
} Tile;

GLOBAL Tile *world;
GLOBAL uint64_t w_size = 0, z_size = 0, y_size = 0, x_size = 0;
GLOBAL uint8_t MAP_IS_INITIALIZED = 0;

static int set_tile(lua_State *L){

    uint64_t W = lua_tonumber(L, 1) - 1;
    uint64_t Z = lua_tonumber(L, 2) - 1;
    uint64_t Y = lua_tonumber(L, 3) - 1;
    uint64_t X = lua_tonumber(L, 4) - 1;
    uint8_t Value = lua_tonumber(L, 5);
    const char * Member = lua_tostring(L, 6);

    if (W >= w_size || Z >= z_size || Y >= y_size || X >= x_size){
        puts("set_tile: Warning invalid value given as parameter");
        puts("set_tile: no value set");
        return 0;
    }

    if (!strcmp(Member, "tile_id"))
    {
        World(W,Z,Y,X).tile_id = Value;
    }
    else if (!strcmp(Member, "animation_id"))
    {
        World(W,Z,Y,X).animation_id = Value;
    }
    else if (!strcmp(Member, "animated"))
    {
        Value = lua_toboolean(L, 5);
        World(W,Z,Y,X).animated = Value;
    }
    else if (!strcmp(Member, "impassable"))
    {
        Value = lua_toboolean(L, 5);
        World(W,Z,Y,X).impassable = Value;
    }
    else printf("set_tile: Warning member %s does not exist\n", Member);

    return 0;
}

static int get_tile(lua_State *L){

    uint64_t W = lua_tonumber(L, 1) - 1;
    uint64_t Z = lua_tonumber(L, 2) - 1;
    uint64_t Y = lua_tonumber(L, 3) - 1;
    uint64_t X = lua_tonumber(L, 4) - 1;
    const char * Member = lua_tostring(L, 5);

    if (W >= w_size || Z >= z_size || Y >= y_size || X >= x_size){
        puts("get_tile: Warning invalid value given as parameter");
        puts("get_tile: no value set");
        return 0;
    }

    if (!strcmp(Member, "tile_id"))
    {
        lua_pushnumber(L, World(W,Z,Y,X).tile_id);
    }
    else if (!strcmp(Member, "animation_id"))
    {
        lua_pushnumber(L, World(W,Z,Y,X).animation_id);
    }
    else if (!strcmp(Member, "animated"))
    {
        lua_pushboolean(L, World(W,Z,Y,X).animated);
    }
    else if (!strcmp(Member, "impassable"))
    {
        lua_pushboolean(L, World(W,Z,Y,X).impassable);
    }
    else{
        printf("get_tile: Warning member %s does not exist\n", Member);
        lua_pushnumber(L, 0);
    }

    return 1;
}

static int free_world(lua_State *L){
    if (MAP_IS_INITIALIZED){
        free(world);
        MAP_IS_INITIALIZED = 0;
    }
    else{
        puts("free_tilemap: Warning no map initialised");
        puts("free_tilemap: nothing to be done");
        }
    return 0;
    }

static int init_world(lua_State *L){
    if (MAP_IS_INITIALIZED){
        puts("init_tilemap: Warning map is already initialised");
        puts("init_tilemap: nothing to be done");
        return 0;
        }
    w_size = lua_tonumber(L, 1);
    z_size = lua_tonumber(L, 2);
    y_size = lua_tonumber(L, 3);
    x_size = lua_tonumber(L, 4);

    world = malloc(world_size);

    if (world == NULL){
        puts("init_tilemap: Failed to allocate memory\nNo map was initialized");
        return 0;
        }
    uint64_t w, z, y, x;
    for (w = 0; w <= (w_size - 1); w++){
    for (z = 0; z <= (z_size - 1); z++){
    for (y = 0; y <= (y_size - 1); y++){
        for (x = 0; x <= (x_size - 1); x++){
            World(w,z,y,x).tile_id = 1;
            World(w,z,y,x).animation_id = 1;
            World(w,z,y,x).animated = 0;
            World(w,z,y,x).impassable = 0;
        }
        }
        }
        }

    MAP_IS_INITIALIZED = 1;

    return 0;
    }

int luaopen_Data(lua_State *L) {
    lua_createtable(L, 0, 1);
    {
        lua_pushcfunction(L, init_world);
        lua_setfield(L, -2, "init_world");
        lua_pushcfunction(L, free_world);
        lua_setfield(L, -2, "free_world");
        lua_pushcfunction(L, set_tile);
        lua_setfield(L, -2, "set_tile");
        lua_pushcfunction(L, get_tile);
        lua_setfield(L, -2, "get_tile");
    }
    return 1;
}

#undef World
#undef world_size
#undef GLOBAL
