#ifndef __CONSTANTS_H__
#define __CONSTANTS_H__
#include <vector>
#include <ncurses.h>
#include <string>
#include "position.h"
#include "fraction.h"

static const int INF = 0x3F3F3F3F;

enum result : int {NOTHING, DIED, GO_DOWN, GO_UP, HIT, MOVED,
                   MISS, TERMINATE, APPLIED, APPLIED_NOTHING,
                   TOGGLE_THE_WORLD, TOGGLE_STAR_PLATINUM, RESTART_GAME,
                   UNKNOWN, INVENTORY, THROWN
                  };

struct long_result {
        result res;
        std::string msg;
};

enum game_status : int {TERMINATED, MAIN_MENU, IN_GAME, OPTIONS,
                        DEAD, WON, ESCAPED, RESTART
                       };

enum game_command : int {GAME_COMMAND_TERMINATE = 0,
                         MOVE_NORTH, MOVE_SOUTH, MOVE_EAST, MOVE_WEAT,
                         MOVE_NORTHEAST, MOVE_NORTHWEST,
                         MOVE_SOUTHEAST, MOVE_SOUTHWEST,
                         APPLY_NORTH, APPLY_SOUTH, APPLY_EAST, APPLY_WEST,
                         APPLY_NORTHEAST, APPLY_NORTHWEST,
                         APPLY_SOUTHEAST, APPLY_SOUTHWEST,
                         APPLY_PANIC, // for curses_input specifically
                         ATTACK_NORTH, ATTACK_SOUTH, ATTACK_EAST, ATTACK_WEST,
                         ATTACK_NORTHEAST, ATTACK_NORTHWEST,
                         ATTACK_SOUTHEAST, ATTACK_SOUTHWEST,
                         UP_STAIRS, DOWN_STAIRS,
                         THE_WORLD, STAR_PLATINUM, GAME_RESTART,
                         GAME_COMMAND_PASS, GAME_COMMAND_PANIC,
                         ENTER, TOGGLE_INVENTORY,
                         THROW_NORTH, THROW_SOUTH, THROW_EAST, THROW_WEST,
                         THROW_NORTHEAST, THROW_NORTHWEST,
                         THROW_SOUTHEAST, THROW_SOUTHWEST,
                         SELECT_SHADE, SELECT_DROW, SELECT_VAMPIRE,
                         SELECT_GOBLIN, SELECT_TROLL
                        };

// Character generation related
static const int RACE_CNT = 23;
enum race : int {SHADE = 0, DROW, VAMPIRE, TROLL,
                 GOBLIN, HUMAN, DWARF, ELF,
                 ORC, MERCHANT, DRAGON, HALFLING,
                 RT_800, MR_GOOSE, MONK, BRAWLER,
                 ASSASSIN, VIKING, SWORDSMAN,
                 LEPRECHAUN, WITCH, HACKER, BABY_DRAGON
                };

static const char CHAR_REP[RACE_CNT] = {
        's', 'd', 'v', 't', 'g', 'H', 'W', 'E', 'O', 'M', 'D', 'L',
        't', 'g', 'm', 'b', 'a',
        'V', 'S', 'l', 'Z', 'h', 'B'
};

static const int MAX_HP[RACE_CNT] = {
        125, 150, INF, 120, 110, 140, 100, 140, 180, 30, 150, 100,
        600, 130, 125, 120, 100,
        150, 100, 80, 100, 90, 140
};
static const int STARTING_HP[RACE_CNT] = {
        125, 150, 50, 120, 110, 140, 100, 140, 180, 30, 150, 100,
        600, 130, 100, 120, 100,
        150, 100, 80, 100, 90, 140
};
static const int STARTING_ATK[RACE_CNT] = {
        25, 25, 25, 25, 15, 20, 20, 30, 30, 70, 20, 15,
        40, 25, 70, 20, 30,
        30, 25, 10, 20, 15, 20
};
static const int STARTING_DEF[RACE_CNT] = {
        25, 15, 25, 15, 20, 20, 30, 10, 25, 5, 20, 20,
        50, 20, 0, 20, 10,
        25, 15, 15, 15, 30, 40
};
static const fraction STARTING_HR[RACE_CNT] = {
        {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},
        {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2},
        {2, 3}, {INF, 1}, {1, 1}, {3, 4}, {1, 1},
        {1, 3}, {1, 1}, {1, 2}, {1, 2}, {1, 2}, {1, 3}
};


// Potion-related
static const int POTION_TYPE_CNT = 14;
static const int DEFAULT_POTION_TYPE_CNT = 6;
enum potion_type : int {RESTORE_HEALTH = 0, BOOST_ATK, BOOST_DEF,
                        POISON_HEALTH, WOUND_ATK, WOUND_DEF,
                        CONTINUOUS_RESTORATION, SAVAGE_STRIKE,
                        ECHOING_RESIL, TEMPEST_TANTRUM,
                        BERZERK_BREW, BORROW_LIFE,
                        FINE_BOOZE, IRONCLAD_WARD
                       };

// Calculation priorities
static const int CALC_BASE = 0;
static const int CALC_MID  = 1;
static const int CALC_LAST = 2;


static const int DIRECTION_CNT = 8;
// IMPORTANT: east is positive for x and SOUTH is positive for y
// initializes all directions to an int
enum direction : int { NORTH = 0, SOUTH, EAST, WEST, NORTHEAST,
                       NORTHWEST, SOUTHEAST, SOUTHWEST
                     };

static const position MOVE[DIRECTION_CNT] = {
        {0, -1}, {0, 1}, {1, 0}, {-1, 0},
        {1, -1}, {-1, -1}, {1, 1}, {-1, 1}
};

static const int MAP_HEIGHT     = 25;
static const int MAP_WIDTH      = 79;
static const int DISPLAY_HEIGHT = 30;
static const int DISPLAY_WIDTH  = 79;
static const int DISPLAY_BUFFER_SIZE = DISPLAY_HEIGHT * DISPLAY_WIDTH +
                                       DISPLAY_WIDTH * 3;

// TODO: list all extra features
// using constants to keep track of features
// method: features: FEATURE_XXX | FEATURE_YYY
// That is: use bit manipulation
// check if feature is enabled:
// features & FEATURE_XXX
typedef unsigned int feature; // can extend to unsigned long (long) if needed
static const feature FEATURE_NCURSES       = 1 << 0;
static const feature FEATURE_RAND_MAP      = 1 << 1;
static const feature FEATURE_ENEMIES_CHASE = 1 << 2;
static const feature FEATURE_INVENTORY     = 1 << 3;
static const feature FEATURE_THROW         = 1 << 4;
static const feature FEATURE_REVISIT       = 1 << 5;
static const feature FEATURE_WALK_OVER     = 1 << 6;
static const feature FEATURE_SEED          = 1 << 7;
static const feature FEATURE_IN_FILE       = 1 << 8;
static const feature FEATURE_OUT_FILE      = 1 << 9;
static const feature FEATURE_EXTRA_STUFF   = 1 << 10;
static const feature FEATURE_EXTRA_LEVELS  = 1 << 11;
static const feature FEATURE_DOORS         = 1 << 12;
static const feature FEATURE_READ_MAP      = 1 << 13;

static const feature FEATURE_LIST_COMMANDS = 1 << 23;
static const feature FEATURE_LIST_RACES    = 1 << 24;
static const feature FEATURE_LIST_ENEMIES  = 1 << 25;
static const feature FEATURE_LIST_POTIONS  = 1 << 26;
static const feature FEATURE_PANIC_SEED    = 1 << 27;
static const feature FEATURE_PANIC_FILE    = 1 << 28;
static const feature FEATURE_PANIC         = 1 << 29;
static const feature FEATURE_CONFLICT      = 1 << 30;
static const feature FEATURE_LIST_ARGS     = 1 << 31;

static const int RETURN_FINE     = 0;
static const int RETURN_PANICKED = 1;

static const int COLOR_BLACK_ON_WHITE = 8;

static const int GOLD_NORMAL   = 1;
static const int GOLD_SMALL    = 2;
static const int GOLD_MERCHANT = 4;
static const int GOLD_DRAGON   = 6;

static const size_t WHAT_ENEMY = 1 << 29;
static const size_t WHAT_WALL  = 1 << 30;
static const size_t WHAT_SPACE = 1 << 31;

static const position POS_NIL = {0, 0};

#endif
