#include "cache.h"
#include "fonts.h"
#include "mykeyboard.h"
#include "mymath.h"
#include <vector>
#include "globals.h"

#ifndef GUI_H_INCLUDED
#define GUI_H_INCLUDED


#define GUI_TEXT_ALIGN_LEFT       0
#define GUI_TEXT_ALIGN_CENTER     1
#define GUI_TEXT_ALIGN_RIGHT      2

class GuiElement {
  protected:
    int x, y, w, h;
    bool coord_transformed;
    bool active, visible;
    CacheBitmap *base;
    std::vector<GuiElement *> attached_elements;
  public:
    GuiElement(){}
    int get_x() {return x;}
    int get_y() {return y;}
    int get_w() {return w;}
    int get_h() {return h;}


    virtual void init(int tx, int ty, int tw, int th){
        x=tx;y=ty;w=tw;h=th;
        base=NULL;
        visible=true;
        attached_elements.clear();
        coord_transformed = false;
    }
    void set_base_bit(CacheBitmap *bit){base=bit;}
    virtual void update();
    virtual void update_general(){}
    virtual void draw();
    void attach_element(GuiElement *ge){attached_elements.push_back(ge);}


    bool is_visible() {return visible;}

    void move(int tx, int ty) {
      x+=tx; y+=ty;
      std::vector<GuiElement *>::iterator gt;
      for (gt=attached_elements.begin();gt!=attached_elements.end();gt+=1) {
        (*gt)->move(tx, ty);
      }
    }

    void set_position(int tx, int ty) {
      x=tx; y=ty;
    }

    bool is_active() {return active;}

    void hide() {
      visible = 0;
      active = 0;
      std::vector<GuiElement *>::iterator gt;
      for (gt=attached_elements.begin();gt!=attached_elements.end();gt+=1) {
        (*gt)->hide();
      }
    }
    void show() {
      visible = 1;
      active = 1;
      std::vector<GuiElement *>::iterator gt;
      for (gt=attached_elements.begin();gt!=attached_elements.end();gt+=1) {
        (*gt)->show();
      }
    }
};



class GuiTakeoverElement : public GuiElement {
  protected:
    ALLEGRO_BITMAP *back;
    bool quit;
  public:
    GuiTakeoverElement(){}
    void main();
    void update();
    void draw();
    void Quit() {quit=true;}
};



class GuiTextElement : public GuiElement {
  protected:
    GameFont *renderer;
    std::string message;
    char mode;
    ALLEGRO_COLOR color;
  public:
    GuiTextElement(){}
    virtual void init(int tx, int ty, int tw, int th, GameFont *txt, std::string msg, char md=GUI_TEXT_ALIGN_LEFT, ALLEGRO_COLOR c=al_map_rgb(0, 0, 0)){
        x=tx;y=ty;w=tw;h=th;
        base=NULL;
        visible=true;
        attached_elements.clear();
        message = msg;
        renderer=txt;
        mode = md;
        color = c;
        coord_transformed = false;
    }
    virtual void draw();
};



class GuiScrollBar : public GuiElement {
  protected:
    char mode;
    int rx, ry, rw, rh;
    float scroll_y, scroll_h;
    bool grabbed, changed;
    float scroll_speed;
  public:
    GuiScrollBar(){}
    virtual void init(int tx, int ty, int tw, int th, int sch, int rtx, int rty, int rtw, int rth, CacheBitmap *bs, char md, float sp=6){
        x=tx;y=ty;w=tw;h=th;
        rx=rtx;ry=rty;rw=rtw;rh=rth;
        scroll_y = ty;
        scroll_h = sch;
        base=bs;
        visible=true;
        attached_elements.clear();
        mode = md;
        grabbed=changed=false;
        scroll_speed = sp;
        coord_transformed = false;
    }
    virtual void update_general();
    bool has_changed() {return changed;}
    void set_percent_scroll(float p) {
      y = scroll_y + ((scroll_h-h) * p);
    }
    float get_percent_scroll() {return ((y-scroll_y) / (scroll_h-h));}
};


class GuiScrollableTextBox : public GuiElement {
  protected:
    GameFont *renderer;
    std::vector<std::string> messages;
    float scroll_y, real_scroll_y;
    GuiScrollBar *scroller;
    int max_messages;
  public:
    GuiScrollableTextBox(){}
    virtual void init(int tx, int ty, int tw, int th, GameFont *txt, int mx=256){
        x=tx;y=ty;w=tw;h=th;
        base=NULL;
        visible=true;
        attached_elements.clear();
        renderer=txt;
        scroll_y=real_scroll_y=0;
        scroller = NULL;
        max_messages = mx;
        coord_transformed = false;
    }
    void add_message(std::string text);
    virtual void update_general();
    void set_scroll_handler(GuiScrollBar *gsc) {scroller=gsc;}
    virtual void draw();
};



class GuiBoxList : public GuiElement {
  protected:
    int index, size, option_h;
    CacheBitmap *selector;
    bool has_changed;
    float real_scroll_y, scroll_y, max_scroll_y;
    GuiScrollBar *scroller;
    std::vector<std::string> messages;
    GameFont *txt;
  public:
    GuiBoxList(){}
    virtual void init(int tx, int ty, int tw, int th, int oh){
        x=tx;y=ty;w=tw;h=th;
        base=NULL;
        visible=true;
        attached_elements.clear();
        option_h=oh;
        size=0;
        index=0;
        selector=NULL;
        has_changed=true;
        scroller=NULL;
        real_scroll_y=scroll_y=0;
        messages.clear();
        coord_transformed = false;
    }
    void set_selector_bit(CacheBitmap *bit){selector=bit;}
    void add_option(std::string msg) {
      messages.push_back(msg);
      size+=1;
    }
    virtual void draw();
    virtual void update_general();
    int get_index(){return index;}
    void set_index(int v){index=v;has_changed=true;}
    bool changed(){return has_changed;}

    void clear() {
      real_scroll_y=scroll_y=max_scroll_y=0;
      has_changed = false;
      index = 0;
      size = 0;
      messages.clear();
    }

    void set_option(int in, std::string m) {
      messages[in] = m;
    }

    int get_size() {
      return messages.size();
    }

    void set_scroll_handler(GuiScrollBar *gsc) {scroller=gsc;}

    virtual std::string get_actual_option() {
      return messages[index];
    }

};



class GuiBrowser : public GuiBoxList {
  protected:
    std::vector<int> type;
    std::string filter;
    std::string actual_path;
    std::string last_path;
    std::string old_path;
    CacheBitmap *folder, *file;
    std::string base_path;
  public:
    virtual void init(int tx, int ty, int tw, int th, int oh, std::string path, std::string fl="*"){
        x=tx;y=ty;w=tw;h=th;
        base=NULL;
        visible=true;
        attached_elements.clear();
        option_h=oh;
        size=0;
        index=0;
        selector=NULL;
        has_changed=true;
        scroller=NULL;
        real_scroll_y=scroll_y=0;
        messages.clear();
        type.clear();
        filter = fl;
        base_path = path;

        browse_folder(path);
        coord_transformed = false;


        folder = load_cache_bitmap("Graphics/Interface/Folder.png");
        file = load_cache_bitmap("Graphics/Interface/File.png");
    }
    void set_filter(std::string m) {filter = m;}
    void browse_folder(std::string path);
    virtual void update_general();
    virtual void draw();

    virtual std::string get_full_actual_option() {
      std::string rt;
      rt = actual_path + messages[index];
      return rt;
    }

    virtual std::string get_actual_option() {
      /*std::string rt, t, p;
      int i=0;

      char full_path[512];
      p = base_path;
      ALLEGRO_PATH *al_p;

      strcpy(full_path, p.c_str());

      al_p = al_create_path(full_path);
      al_make_path_canonical(al_p);

      p = ToString(al_path_cstr(al_p, ALLEGRO_NATIVE_PATH_SEP));
      al_free_path(al_p);


      rt = actual_path + messages[index];
      t = "";

      for (i=p.size(); i != rt.size(); i+=1 ) {
        t.push_back(rt[i]);
      }*/
      return actual_path;
    }
};


const int GUI_SWITCH_ELEMENT_BLIT_ABOVE=0;
const int GUI_SWITCH_ELEMENT_SWAP_BLIT=1;


class GuiSwitchElement : public GuiElement {
  protected:
    CacheBitmap *on_bit;
    bool state, has_clicked;
    char mode;
  public:
    GuiSwitchElement() {}
    virtual void init(int tx, int ty, int tw, int th, CacheBitmap *ob, char md=GUI_SWITCH_ELEMENT_BLIT_ABOVE){
      x=tx;y=ty;w=tw;h=th;
      base=NULL;
      visible=true;
      attached_elements.clear();
      on_bit=ob;
      state=false;
      mode = md;
      coord_transformed = false;
    }
    void set_state(bool b){state=b;}
    bool get_state(){return state;}
    virtual void draw();
    virtual void update_general();
    bool clicked(){return has_clicked;}

};



class GuiButton : public GuiElement {
  protected:
    CacheBitmap *on_bit;
    CacheSample *sound;
    bool pressed, rpressed, has_clicked, played_sound;
    GuiElement *element;
    int shortcut;
    void (*func)();
  public:
    GuiButton() {}
    virtual void init(int tx, int ty, int tw, int th, void (*f)(), CacheBitmap *ob){
      x=tx;y=ty;w=tw;h=th;
      base=NULL;
      visible=true;
      attached_elements.clear();
      on_bit=ob;
      pressed=rpressed=has_clicked=false;
      sound = NULL;
      func = f;
      element = NULL;
      played_sound = false;
      coord_transformed = false;
      shortcut = -1;
    }

    void set_element(GuiElement *g) {
      element = g;
    }

    void set_sound(CacheSample *s) {
      sound = s;
    }

    void set_shortcut(int v) {
      shortcut = v;
    }

    virtual void draw();
    virtual void update_general();
    bool clicked(){return has_clicked;}
};



class GuiTypeBox : public GuiElement {
  protected:
    std::string text;
    int marker_x, marker_screen_x, max_size, mode;
    bool writing, has_changed;
    CacheBitmap *marker;
    GameFont *font;
    Intermitent *marker_op;
  public:
    virtual void init(int tx, int ty, int tw, int th, CacheBitmap *mr, GameFont *gf, int max_s=-1, int md=KEY_TO_CHAR_MODE_ALL, std::string def=""){
      x=tx;y=ty;w=tw;h=th;
      base=NULL;
      visible=true;
      attached_elements.clear();
      text = def;
      mode = md;
      max_size = max_s;
      writing = false;
      marker = mr;
      font = gf;
      marker_op = new Intermitent(0.3, 0.01);
      has_changed = false;
      coord_transformed = false;
    }

    void type(char c);
    void erase();

    void set_marker_x_screen();

    std::string get_text() {return text;}
    void set_text(std::string t) {
      text = t;
      marker_x = marker_screen_x = 0;
    }



    virtual void draw();
    virtual void update_general();

    bool changed() {return has_changed;}
};


#endif
