#pragma once

#include "ref.h"

#include "dk_menu_controls.h"

//private types and classes used for the menu.
class CMenu;
    class CMenuMain;
    class CMenuSub;
        class CMenuSubHelp;
        class CMenuSubQuit;


//an enum for each bitmap
typedef enum {
    //the cursor images.
    DKB_CURSOR_00,
    DKB_CURSOR_01,
    DKB_CURSOR_02,
    DKB_CURSOR_03,
    DKB_CURSOR_04,
    DKB_CURSOR_05,
    DKB_CURSOR_06,
    DKB_CURSOR_07,
    DKB_CURSOR_08,
    DKB_CURSOR_09,

    //the background images.
    DKB_BACK00,
    DKB_BACK01,
    DKB_BACK02,
    DKB_BACK10,
    DKB_BACK11,
    DKB_BACK12,

    DKB_NUM,
} dk_interface_bmp;

//a structure to keep track of our bitmaps.
typedef struct interface_bmp_desc_s {
    //the name of the pic.
    char *name;
    int flags;
} interface_bmp_desc;

//the name of each main menu button.
typedef enum {
    DKMB_NEWGAME,
    DKMB_MULTIPLAYER,
    DKMB_LOADGAME,
    DKMB_SAVEGAME,
    DKMB_SOUND,
    DKMB_VIDEO,
    DKMB_MOUSE,
    DKMB_KEYBOARD,
    DKMB_JOYSTICK,
    DKMB_GENERAL,
    DKMB_ADVANCED,
    DKMB_DEMOS,
    DKMB_HELP,
    DKMB_QUIT,

    DKMB_NUM_BUTTONS,
    DKMB_NONE
} dk_main_button;

//the different possible status's for each button
typedef enum {
    BS_START, 
    BS_HILIGHT_FORWARD,
    BS_HILIGHT_BACKWARD,
    BS_HILIGHT, 
    BS_SELECT_FORWARD,
    BS_SELECT_BACKWARD,
    BS_SELECTED,
} dk_button_status;

//the different possible status's for the box/banner at the top of the screen.
typedef enum {
    HS_CLOSED,
    HS_SLIDE_FORWARD,
    HS_OPENING,
    HS_OPEN,
    HS_OPEN_WIGGLE,
    HS_CLOSING,
} dk_header_status;

//functions we use.
void DKM_NewMousePos();
void DKM_Animate();

extern "C" void M_PopMenu();
extern "C" float CalcFov(float fov_x, float width, float height);

//the different menus call this to get entity structures to fill in.
entity_t *NewEntity();

//the amount of times needed for the various animations.
#define ANIMATION_HILIGHT_TIME 500
#define ANIMATION_SELECT_TIME 600
#define ANIMATION_BANNER_TURN 100
#define ANIMATION_BANNER_WIGGLE 1000

#define SHUTDOWN_SEQUENCE_TIME 500

#define CURSOR_TOTAL_TIME 400
#define CURSOR_NUM_FRAMES 9

//macro that does list box hit test, returns the index that was selected, or -1 if we are off the box.
#define list_box_hit_test(left, top, right, bottom, x, y, num) \
    (((x) > (left) && (x) < (right) && (y) > (top) && (y) < (bottom)) ? (compute_select_index((top), (y), (bottom), (num))) : -1)

//macro used to compute selected index given the top, bottom, and current y, plus the number of indexes spanned.
#define compute_select_index(top, y, bottom, num) bound_max_inline(bound_min_inline(int(float((y) - (top))/float((bottom) - (top)) * (num)), 0), (num) - 1)

//base class for all menu screens classes.
class CMenu {
public:
    CMenu();
    virtual ~CMenu();

    //called when the menu is first entered.
    virtual void Enter();
    //called when the menu is exited.
    virtual void Exit();

    //moves things based on the time elapsed.
    virtual void Animate(int elapsed_time);

    //draws the menu
    virtual void DrawBackground();
    virtual void DrawForeground();
    //add's the menu's 3d entities to the list.
    virtual void PlaceEntities();

    //called when the mouse is moved.  returns true if this menu handled the movement.
    virtual bool MousePos(int x, int y);

    //called when the mouse is clicked down and released. returns true if the
    //click was handled.
    virtual bool MouseDown(int x, int y);
    virtual bool MouseUp(int x, int y);

    //accepts keyboard input.  
    //returns true if the key was handled.
    virtual bool Keydown(int key);
    virtual bool Keyup(int key);
};

//class for the main menu with the 14 buttons.
class CMenuMain : public CMenu {
public:
    CMenuMain();
    ~CMenuMain();

    //main draw function.
    void Draw();

protected:
    //the 14 buttons.
    CMenuSub *sub_menu[DKMB_NUM_BUTTONS];

    //the button that is currently selected.
    dk_main_button selection;

    //does whatever processing is required to get the given button out of selected mode
    void CheckUnselect(dk_main_button button);

    //renders the 3d stuff.
    void RenderView();

    //puts the different 3-d entities in the scene.
    void PlaceButtons();
    void PlaceBanner();

    //selects one of our sub-menus.
    void Select(dk_main_button button);

    //the state of the banner.
    dk_header_status banner_status;
    //the anmount of time the banner has been in its current state.
    int banner_animation_time;
    //the name that is showing on the banner.
    dk_main_button banner_text;

    //array of entities that will be returned by NewEntity.
    entity_t entities[128];
    int num_entities;

    //true if we are closing the interface.
    bool shutting_down;
    //the time spent in our shutdown sequence.
    int shutdown_time;
    //a string we will write to the console upon leaving.
    char console_shutdown_string[2048];

public:
    //sets the console shutdown string.
    void ShutdownString(const char *format, ...);

    //starts the shutdown sequence.
    void Shutdown();

    //returns a pointer to an entity structure that will be drawn.
    entity_t *NewEntity();

    //enters the specified sub-menu.
    void Enter(dk_main_button button);

    virtual void Enter();
    virtual void Exit();
    virtual void Animate(int elapsed_time);
    virtual void PlaceEntities();
    virtual bool MousePos(int x, int y);
    virtual bool MouseDown(int x, int y);
    virtual bool MouseUp(int x, int y);
    virtual bool Keydown(int key);
    virtual bool Keyup(int key);

    void ShuttingDown(int elapsed_time);
};

//base class for all menus off of the sub-menu
class CMenuSub : public CMenu {
public:
    CMenuSub();

    //vars we need to keep track of the animations for the button.
    dk_button_status status;

    //the state that the animation should eventually go.
    dk_button_status dest_status;

    //the amount of time we have spent in this state.
    int time;

    bool enabled;

    //returns the correct frame to display for the current time and status
    int Frame();
};

//classes for the submenus.
class CMenuSubQuit : public CMenuSub {
public:
    CMenuSubQuit();
    virtual void Enter();
    virtual void Animate(int elapsed_time);
    virtual void DrawForeground();
    virtual void PlaceEntities();
    virtual bool Keydown(int key);
    virtual bool MousePos(int x, int y);
    virtual bool MouseDown(int x, int y);
    virtual bool MouseUp(int x, int y);

protected:
    //our yes and no buttons.
    CInterfaceButton yes;
    CInterfaceButton no;
};

class CMenuSubHelp : public CMenuSub {
public:
    CMenuSubHelp();
    virtual void DrawForeground();
    virtual bool Keydown(int key);
};

#define NUM_DEMOS 8

class CMenuSubDemos : public CMenuSub {
public:
    CMenuSubDemos();
    virtual void Enter();
    virtual void Animate(int elapsed_time);
    virtual void DrawForeground();
    virtual void PlaceEntities();
    virtual bool Keydown(int key);
    virtual bool MousePos(int x, int y);
    virtual bool MouseDown(int x, int y);
    virtual bool MouseUp(int x, int y);

protected:
    CInterfaceButton start[NUM_DEMOS];
};

class CMenuSubAdvanced : public CMenuSub {
public:
    CMenuSubAdvanced();
    virtual void DrawForeground();
    virtual bool Keydown(int key);
};

class CMenuSubGeneral : public CMenuSub {
public:
    CMenuSubGeneral();
    virtual void DrawForeground();
    virtual bool Keydown(int key);
};

class CMenuSubJoystick : public CMenuSub {
public:
    CMenuSubJoystick();
    virtual void DrawForeground();
    virtual bool Keydown(int key);
};

class CMenuSubKeyboard : public CMenuSub {
public:
    CMenuSubKeyboard();
    virtual void Enter();
    virtual void Animate(int elapsed_time);
    virtual void DrawForeground();
    virtual void PlaceEntities();
    virtual bool Keydown(int key);
    virtual bool MousePos(int x, int y);
    virtual bool MouseDown(int x, int y);
    virtual bool MouseUp(int x, int y);

protected:
    //our "restore defaults" button.
    CInterfaceButton defaults;
    //the up and down buttons for the listbox.
    CInterfaceButton listbox_up;
    CInterfaceButton listbox_down;

    //the border around the listbox.
    CInterfaceBox border;
    //border around the hilighted item
    CInterfaceBox hilight_box;

    //the item at the top of the list of controls.
    int top_index;

    //true if the up/down button should be drawn.
    bool show_up_button;
    bool show_down_button;

    //sets the index of the item that should show at the top of the visible portion of the listbox.
    void TopIndex(int num);

    //puts the hilight box over the specified row/column
    void Hilight(int row, int column);
    //sizes the hilight box.
    void HilightSize(int time);

    //true if we have something hilighted.
    bool hilight_showing;
    //the row/column that is hilighted.
    int hilight_row, hilight_col;

    //starts/aborts/completes the control assignment process
    void AssignStart();
    void AssignAbort();
    void AssignComplete(int key);
    void AssignDelete();

    //true if we are setting a control, waiting for the user to press a key.
    bool assigning_control;
    //time elapsed in our hilight box's animation.
    int hilight_animation_time;
};

//each mouse action has a name.
typedef enum {
    MA_X_AXIS,
    MA_Y_AXIS,
    MA_BUTTON1,
    MA_BUTTON2,
    MA_BUTTON3,

    MA_NUM_ACTIONS,
    MA_NONE,
} mouse_action;

class CMenuSubMouse : public CMenuSub {
public:
    CMenuSubMouse();
    virtual void Enter();
    virtual void Animate(int elapsed_time);
    virtual void DrawForeground();
    virtual void PlaceEntities();
    virtual bool Keydown(int key);
    virtual bool MousePos(int x, int y);
    virtual bool MouseDown(int x, int y);
    virtual bool MouseUp(int x, int y);

protected:
    //box for the mouse actions.
    CInterfaceBox action_box;
    //selection box for the action box.
    CInterfaceBox action_hilight_box;

    //box for command list
    CInterfaceBox command_box;
    //box for command list hilight
    CInterfaceBox command_hilight_box;
    //up and down buttons for command box.
    CInterfaceButton command_up;
    CInterfaceButton command_down;

    //the checkbox for reversing mouse axis
    CInterfaceButton reverse_axis;
    //the sensitivity slider.
    CInterfaceSlider sensitivity;

    //true if the up/down button should be drawn.
    bool show_up_button;
    bool show_down_button;

    //the strings we will display to indicate what the mouse actions are bound to.
    char *mouse_bindings[5];

    void FindBindings();

    //returns the action that is under the given x-y coordinate.
    mouse_action HitAction(int x, int y);
    //returns the line in the command list under the given coordinate, or -1 if the coordinate is off the list.
    int HitCommand(int x, int y);

    //puts the hilight box around the given item.
    void PositionActionHilight(int index);
    void PositionCommandHilight(int index);

    //the item that we clicked on and selected.
    mouse_action selection;

    //the item that the cursor is over.
    mouse_action action_hilight;
    
    //the command that the cursor is over.
    int command_hilight;

    //the index that is at the top of the command list.
    int top_index;

    //the number of items that are currently in the command list.
    int num_command_items;

    //selects the given action.
    void SelectAction(mouse_action action);

    //selects the command at the given index.
    void SelectCommand(int index);

    //makes the command list display the given index at the top.
    void TopIndex(int index);
};

typedef enum {
    VM_SOFTWARE,
    VM_GL_3DFX,
    VM_GL_DEFAULT,
    VM_GL_POWERVR,

    VM_NUM_MODES
} video_mode;

#define gl_mode(mode) (mode == VM_GL_3DFX || mode == VM_GL_DEFAULT || mode == VM_GL_POWERVR)

class CMenuSubVideo : public CMenuSub {
public:
    CMenuSubVideo();
    virtual void Enter();
    virtual void Animate(int elapsed_time);
    virtual void DrawForeground();
    virtual void PlaceEntities();
    virtual bool Keydown(int key);
    virtual bool MousePos(int x, int y);
    virtual bool MouseDown(int x, int y);
    virtual bool MouseUp(int x, int y);

protected:
    //the settings when we entered the menu.
    video_mode start_mode;
    int start_res;
    bool start_fullscreen;
    bool start_gl_8bit;
    int start_gl_quality;
    float start_gl_gamma;

    //modifies the refresh settings variables.
    void ApplyChanges();

    //the apply changes button.
    CInterfaceButton apply_changes;
    //returns true if we should display the apply changes button.
    bool ShowApplyChanges();

    //the current video mode.
    video_mode cur_mode;
    //true if we have the mode string hilighted.
    bool mode_hilighted;
    //a box to use to hilight the mode.
    CInterfaceBox mode_hilight;

    //determines the current video mode by examining system variables.
    void GetMode();

    //true if we are picking a mode.
    bool picking_mode;
    //a box to surround the list of video modes
    CInterfaceBox mode_list_box;
    //hilight box for the mode list.
    CInterfaceBox mode_list_hilight_box;
    //moves the hilight box to the given line.
    void ModeListHilight(int line);
    //the mode that is hilighted in the list. -1 means none.
    int mode_list_hilight;

    //the separator between the driver name and the options.
    CInterfaceLine separator;

    //makes the menu draw a new mode, but doesnt actually change any system settings.
    void SelectMode(video_mode mode);

    //slider to pick the resolution.
    CInterfaceSlider resolution_slider;

    //slider to pick the screen size.
    CInterfaceSlider screen_size_slider;

    //slider to pick the brightness
    CInterfaceSlider brightness_slider;

    //controls for the software mode
    CInterfaceButton soft_fullscreen;
    CInterfaceButton soft_stipple_alpha;

    //controls for gl modes.
    CInterfaceSlider gl_texture_slider;
    CInterfaceButton gl_8bit_button;
    CInterfaceButton gl_fullscreen;

    //values for the buttons.
    bool fullscreen;
    bool gl_8bit;
};

class CMenuSubSound : public CMenuSub {
public:
    CMenuSubSound();
    virtual void DrawForeground();
    virtual bool Keydown(int key);
};

class CMenuSubSavegame : public CMenuSub {
public:
    CMenuSubSavegame();
    virtual void DrawForeground();
    virtual bool Keydown(int key);
};

class CMenuSubLoadgame : public CMenuSub {
public:
    CMenuSubLoadgame();
    virtual void DrawForeground();
    virtual bool Keydown(int key);
};

class CMenuSubMultiplayer : public CMenuSub {
public:
    CMenuSubMultiplayer();
    virtual void DrawForeground();
    virtual bool Keydown(int key);
};

#define NUM_NEWGAMES 12

class CMenuSubNewgame : public CMenuSub {
public:
    CMenuSubNewgame();
    virtual void Enter();
    virtual void Animate(int elapsed_time);
    virtual void DrawForeground();
    virtual void PlaceEntities();
    virtual bool Keydown(int key);
    virtual bool MousePos(int x, int y);
    virtual bool MouseDown(int x, int y);
    virtual bool MouseUp(int x, int y);

protected:
    CInterfaceButton start[12];
};


