#include "gui.h"
#include "mymath.h"
#include "mykeyboard.h"
#include "mystr.h"
#include <vector>
#include "drawfx.h"


//GUI ELEMENT CLASS
//******************************************************

void GuiElement::update() {
  active=inside_rect(mouse_x, mouse_y, x, y, x+w, y+h);


  if (!coord_transformed) {
    coord_transformed = true;
  }

  std::vector<GuiElement *>::iterator guit;
  for (guit=attached_elements.begin();guit!=attached_elements.end();guit+=1) {
    (*guit)->update();
  }
  update_general();
}
void GuiElement::draw() {
  if ((base!=NULL) && (visible)) {
    al_draw_scaled_bitmap(base->get_bit(), 0, 0, base->Width(), base->Height(), x, y, w, h, 0);
  }
  std::vector<GuiElement *>::iterator guit;
  if (visible) {
    for (guit=attached_elements.begin();guit!=attached_elements.end();guit+=1) {
      (*guit)->draw();
    }
  }
}




/* GUI TAKEOVER ELEMENT CLASS */



void GuiTakeoverElement::update() {
  UpdateGlobalZoomFactor();
  poll_my_keyboard();
  UpdateDelta();

  active=inside_rect(mouse_x, mouse_y, x, y, x+w, y+h);

  std::vector<GuiElement *>::iterator guit;
  for (guit=attached_elements.begin();guit!=attached_elements.end();guit+=1) {
    (*guit)->update();
  }

  FramesUpdated+=1;
}



void GuiTakeoverElement::draw() {
  al_clear_to_color(al_map_rgb(0,0,0));

  if ((base!=NULL) && (visible)) {
    al_draw_bitmap(back, 0, 0, 0);
  }


  std::vector<GuiElement *>::iterator guit;
  if (visible) {
    for (guit=attached_elements.begin();guit!=attached_elements.end();guit+=1) {
      (*guit)->draw();
    }
  }


  if (BlackFade != 0) {
    al_draw_filled_rectangle(0, 0, SCREEN_W, SCREEN_H, al_map_rgba_f(0, 0, 0, BlackFade));
  }


  float rw, rh;
  rw = RSW(al_get_bitmap_width(cursor));
  rh = RSH(al_get_bitmap_height(cursor));

  Vec2D last_pos;
  last_pos = Vec2D(mick_x, mick_y);
  DrawTransformedMotionBlur(cursor, mouse_x+rw/2, mouse_y+rh/2, rw, rh, 0, 0, last_pos);

  al_flip_display();



}


void GuiTakeoverElement::main() {
  quit=false;
  while (!quit) {
    ALLEGRO_EVENT event;
    al_wait_for_event(queue, &event);
    if (event.type == ALLEGRO_EVENT_TIMER) {
      draw();
      update();
    }
  }
}





//GUI SCROLL BAR CLASS
//******************************************************


void GuiScrollBar::update_general() {
  changed = false;
  if (active) {
    if (Keyboard_Recently_Input[ALLEGRO_KEY_MOUSE_LCLICK]) {
      grabbed = true;
    }
  }
  if (grabbed) {
    if (Keyboard_Active[ALLEGRO_KEY_MOUSE_LCLICK]) {
      y = mouse_y;
      changed = true;
    }
    else grabbed = false;
  }

  static int lmouse_z;

  if (inside_rect(mouse_x, mouse_y, rx, ry, rx+rw, ry+rh)) {
    if (mouse_z < lmouse_z) {y += scroll_speed;changed=true;}
    if (mouse_z > lmouse_z) {y -= scroll_speed;changed=true;}
  }

  lmouse_z = mouse_z;

  if (y < scroll_y) y = scroll_y;
  if (y > scroll_y+scroll_h-h) y = scroll_y+scroll_h-h;
}


//GUI TEXT ELEMENT CLASS
//******************************************************

void GuiTextElement::draw() {
  if ((base!=NULL) && (visible)) {
    al_draw_scaled_bitmap(base->get_bit(), 0, 0, base->Width(), base->Height(), x, y, w, h, 0);
  }
  std::vector<GuiElement *>::iterator guit;
  if (visible) {
    for (guit=attached_elements.begin();guit!=attached_elements.end();guit+=1) {
      (*guit)->draw();
    }
    int xc;
    if (mode == GUI_TEXT_ALIGN_LEFT) xc = x;
    if (mode == GUI_TEXT_ALIGN_CENTER) xc = x+w/2-renderer->Width(message)/2;
    if (mode == GUI_TEXT_ALIGN_RIGHT) xc = x+w-renderer->Width(message);
    renderer->Print(message, xc, y+h/2+renderer->Height()/2, color);
  }
}

//GUI SCROLLABLE TEXT BOX CLASS
//******************************************************

void GuiScrollableTextBox::draw() {
  if ((base!=NULL) && (visible)) {
    al_draw_scaled_bitmap(base->get_bit(), 0, 0, base->Width(), base->Height(), x, y, w, h, 0);
  }
  std::vector<GuiElement *>::iterator guit;
  if (visible) {
    for (guit=attached_elements.begin();guit!=attached_elements.end();guit+=1) {
      (*guit)->draw();
    }
    int xc;
    int index = real_scroll_y/(renderer->Height()+2);
    if (index < 0) index = 0;
    int end;
    end = index + h/(renderer->Height()+2)+1;
    if (end > messages.size()) end = messages.size();
    for (index; index != end; index+=1) {
      renderer->PrintColorCoded(messages[index], x + 5, y + 5 + index * (renderer->Height()+2) - real_scroll_y + renderer->Height());
    }
  }
}


void GuiScrollableTextBox::update_general() {
  while (messages.size() > max_messages) {
    messages.erase(messages.begin());
  }
  if (real_scroll_y != scroll_y) {
    float d=scroll_y-real_scroll_y;
    if (mabs(d) <= 2) real_scroll_y = scroll_y;
    real_scroll_y += d / 6;
  }
  if (scroller != NULL) {
    if (scroller->has_changed()) {
      float max_scroll_y;
      max_scroll_y = messages.size() * (renderer->Height()+2);
      max_scroll_y -= h;
      if (max_scroll_y > 0) {
        scroll_y = max_scroll_y * scroller->get_percent_scroll();
      }
    }
  }
}

void GuiScrollableTextBox::add_message(std::string text) {
  std::deque<std::string> new_message;
  new_message = turn_to_paragraph(renderer, text, w);
  std::deque<std::string>::iterator mit;
  for (mit=new_message.begin();mit!=new_message.end();mit+=1) {
    messages.push_back((*mit));
  }
  if (messages.size() > h/(renderer->Height()+2)) {
    scroll_y = messages.size() * (renderer->Height()+2);
    scroll_y -= h;
    if (scroller != NULL) scroller->set_percent_scroll(1.0);
  }
}


//GUI BOX LIST CLASS
//******************************************************


void GuiBoxList::update_general() {
  has_changed=false;
  if (active) {
    if (Keyboard_Active[ALLEGRO_KEY_MOUSE_LCLICK]) {
      int lindex;
      lindex = index;
      index = ((mouse_y-y)+real_scroll_y-option_h/2) / option_h;
      if (index < 0) index=lindex;
      if (index > size-1) index=lindex;
      if (lindex != index) {
        has_changed=true;
      }
    }
  }
  if (real_scroll_y != scroll_y) {
    float d=scroll_y-real_scroll_y;
    if (mabs(d) <= 2) real_scroll_y = scroll_y;
    real_scroll_y += d / 6;
  }
  if (scroller != NULL) {
    if (scroller->has_changed()) {
      max_scroll_y = size * option_h;
      max_scroll_y -= h;
      if (max_scroll_y > 0) {
        scroll_y = max_scroll_y * scroller->get_percent_scroll();
      }
    }
  }
}

void GuiBoxList::draw() {
  if ((base!=NULL) && (visible)) {
    al_draw_scaled_bitmap(base->get_bit(), 0, 0, base->Width(), base->Height(), x, y, w, h, 0);
  }
  std::vector<GuiElement *>::iterator guit;
  if (visible) {
    for (guit=attached_elements.begin();guit!=attached_elements.end();guit+=1) {
      (*guit)->draw();
    }

    GameFont *renderer;
    renderer = game_font;

    int xc;
    int in = real_scroll_y/(renderer->Height()+2);
    if (in < 0) in = 0;
    int end;
    end = in + h/(renderer->Height()+2)+1;
    if (end > messages.size()) end = messages.size();
    for (in; in != end; in+=1) {
      renderer->PrintColorCoded(messages[in], x + 5, y + 5 + in * (renderer->Height()+2) - real_scroll_y + renderer->Height());
    }

    if (selector != NULL) {
      al_draw_scaled_bitmap(selector->get_bit(), 0, 0, selector->Width(), selector->Height(), x, y+index*option_h-real_scroll_y + option_h/2, w, option_h, 0);
    }
  }
}



//GUI BROWSER CLASS
//******************************************************


void GuiBrowser::update_general() {
  has_changed=false;
  if (active) {
    if (Keyboard_Active[ALLEGRO_KEY_MOUSE_LCLICK]) {
      int lindex;
      lindex = index;
      index = ((mouse_y-y)+real_scroll_y-option_h/2) / option_h;
      if (index < 0) index=lindex;
      if (index > size-1) index=lindex;
      if (lindex != index) {
        has_changed=true;
      }
    }
    if (Keyboard_Double_Pressed[ALLEGRO_KEY_MOUSE_LCLICK]) {
      if (type[index] == 0) browse_folder(actual_path + messages[index] + "/");
    }
  }
  if (real_scroll_y != scroll_y) {
    float d=scroll_y-real_scroll_y;
    if (mabs(d) <= 2) real_scroll_y = scroll_y;
    real_scroll_y += d / 6;
  }
  if (scroller != NULL) {
    if (scroller->has_changed()) {
      max_scroll_y = size * option_h;
      max_scroll_y -= h;
      if (max_scroll_y > 0) {
        scroll_y = max_scroll_y * scroller->get_percent_scroll();
      }
    }
  }
}


void GuiBrowser::draw() {
  if ((base!=NULL) && (visible)) {
    al_draw_scaled_bitmap(base->get_bit(), 0, 0, base->Width(), base->Height(), x, y, w, h, 0);
  }
  std::vector<GuiElement *>::iterator guit;
  if (visible) {
    for (guit=attached_elements.begin();guit!=attached_elements.end();guit+=1) {
      (*guit)->draw();
    }

    GameFont *renderer;
    renderer = game_font;

    int xc;
    int in = real_scroll_y/(renderer->Height()+2);
    if (in < 0) in = 0;
    int end;
    end = in + h/(renderer->Height()+2)+1;
    if (end > messages.size()) end = messages.size();
    for (in; in != end; in+=1) {
      if (type[in] == 0) al_draw_bitmap(folder->get_bit(), x+6, y+7 + in * (renderer->Height()+2) - real_scroll_y, 0);
      if (type[in] == 1) al_draw_bitmap(file->get_bit(), x+6, y+7 + in * (renderer->Height()+2) - real_scroll_y, 0);
      renderer->PrintColorCoded(messages[in], x + 25, y + 5 + in * (renderer->Height()+2) - real_scroll_y + renderer->Height());
    }

    if (selector != NULL) {
      al_draw_scaled_bitmap(selector->get_bit(), 0, 0, selector->Width(), selector->Height(), x, y+index*option_h-real_scroll_y + option_h/2, w, option_h, 0);
    }
  }
}



void GuiBrowser::browse_folder(std::string path) {/*
  actual_path = path;
  struct al_ffblk inf;

  char full_path[512];
  strcpy(full_path, actual_path.c_str());
  canonicalize_filename(full_path, full_path, sizeof(char) * 512);
  actual_path = ToString(full_path);

  index = 0;
  size = 0;

  messages.clear();
  type.clear();

  if (al_findfirst((actual_path+"*").c_str(), &inf, FA_DIREC) != 0) {
    return;
  }
  else {
    al_findnext(&inf);
    add_option(inf.name);
    type.push_back(0);
    while (al_findnext(&inf) == 0) {
      add_option(inf.name);
      type.push_back(0);
    };
  }
  al_findclose(&inf);


  if (al_findfirst((actual_path+filter).c_str(), &inf, FA_ALL-FA_DIREC) != 0) {
    return;
  }
  else {
    add_option(inf.name);
    type.push_back(1);
    while (al_findnext(&inf) == 0) {
      add_option(inf.name);
      type.push_back(1);
    };
  }
  al_findclose(&inf);*/
}



//GUI SWITCH ELEMENT CLASS
//******************************************************


void GuiSwitchElement::update_general() {
  has_clicked=false;
  if (active) {
    if (Keyboard_Recently_Input[ALLEGRO_KEY_MOUSE_LCLICK]) {
      state = (state==true?false:true);
      has_clicked=true;
    }
  }
}

void GuiSwitchElement::draw() {
  if ((base!=NULL) && (visible)) {
    if (!((mode == GUI_SWITCH_ELEMENT_SWAP_BLIT) && (state == true))) al_draw_bitmap(base->get_bit(), x+w/2-base->Width()/2, y+h/2-base->Height()/2, 0);
  }
  std::vector<GuiElement *>::iterator guit;
  if (visible) {
    for (guit=attached_elements.begin();guit!=attached_elements.end();guit+=1) {
      (*guit)->draw();
    }
    if (on_bit != NULL) {
      if (state) al_draw_bitmap(on_bit->get_bit(), x+w/2-on_bit->Width()/2, y+h/2-on_bit->Height()/2, 0);
    }
  }
}






//GUI BUTTON CLASS
//******************************************************


void GuiButton::update_general() {
  has_clicked=false;
  pressed = 0;
  if (!visible) return;
  if (shortcut != -1) {
    if (Keyboard_Recently_Input[shortcut]) {
      if (func!=NULL) (*func)();
      return;
    }
  }
  if (active) {
    if (Keyboard_Recently_Input[ALLEGRO_KEY_MOUSE_LCLICK]) {
      if (inside_rect(mouse_x, mouse_y, x, y, x+w, y+h)) {
        if (sound != NULL) al_play_sample(sound->get_sample(), 1.0, 0.5, 1.0, ALLEGRO_PLAYMODE_ONCE, NULL);
        rpressed = 1;
        pressed = 1;
        played_sound = true;
      }
    }
    if ((Keyboard_Active[ALLEGRO_KEY_MOUSE_LCLICK]) && (rpressed)) {
      if (inside_rect(mouse_x, mouse_y, x, y, x+w, y+h)) {
        if ((sound != NULL) && (!played_sound)) {
          al_play_sample(sound->get_sample(), 1.0, 0.5, 1.0, ALLEGRO_PLAYMODE_ONCE, NULL);
          played_sound = true;
        }
        pressed = 1;
      }
      else {
        pressed = 0;
        played_sound = false;
      }
    }
    if (Keyboard_Recently_Released[ALLEGRO_KEY_MOUSE_LCLICK]) {
      if (rpressed) {
        if (inside_rect(mouse_x, mouse_y, x, y, x+w, y+h)) {
          pressed = 0;
          rpressed = 0;
          if (func!=NULL) (*func)();
        }
        else {
          pressed = 0;
          rpressed = 0;
        }
      }
    }
  }
}

void GuiButton::draw() {
  if ((base!=NULL) && (visible)) {
    al_draw_scaled_bitmap(base->get_bit(), 0, 0, base->Width(), base->Height(), x, y, w, h, 0);
  }
  std::vector<GuiElement *>::iterator guit;
  if (visible) {
    for (guit=attached_elements.begin();guit!=attached_elements.end();guit+=1) {
      (*guit)->draw();
    }
    if (on_bit != NULL) {
      if (pressed) al_draw_scaled_bitmap(on_bit->get_bit(), 0, 0, on_bit->Width(), on_bit->Height(), x, y, w, h, 0);
    }
    if (element != NULL) {
      if (pressed) element->move(3, 3);
      element->draw();
      if (pressed) element->move(-3, -3);
    }
  }
}







//GUI TYPE BOX CLASS
//******************************************************


void GuiTypeBox::update_general() {
  has_changed = false;
  if (visible) {
    if (Keyboard_Active[ALLEGRO_KEY_MOUSE_LCLICK]) {
      if (inside_rect(mouse_x, mouse_y, x, y, x+w, y+h)) {
        writing = true;
        std::string temp;
        temp = "";
        marker_x = 0;
        marker_screen_x = 0;
        for (int i=0; i!=text.size(); i+=1) {
          temp += text[i];
          if (mouse_x > (x + 4 + game_font->Width(temp))) {
            marker_x += 1;
            marker_screen_x = game_font->Width(temp);
          }
        }
      }
      else {
        writing = false;
      }
    }

    if (writing) {
      marker_op->update();

      int i;
      static int wait=0;
        if (Keyboard_Time_Pressed[ALLEGRO_KEY_BACKSPACE] > 15) {
          wait -= 1;
          if (wait <= 0) {
            erase();
            wait = 3;
            has_changed = true;
          }
        }
      if (Keyboard_Recently_Input[ALLEGRO_KEY_LEFT]) {
        marker_x -= 1;
        if (marker_x < 0) marker_x = 0;
        set_marker_x_screen();
      }
      if (Keyboard_Recently_Input[ALLEGRO_KEY_RIGHT]) {
        marker_x += 1;
        if (marker_x > text.size()) marker_x = text.size();
        set_marker_x_screen();
      }
      for (i=0; i!=255; i+=1) {
        if (Keyboard_Recently_Input[i]) {
          if (i == ALLEGRO_KEY_BACKSPACE) {
            erase();
            has_changed = true;
          }
          else {
            char c;
            c = key_to_char(i, mode);
            if (c != NULL) type(c);
            has_changed = true;
          }
        }
      }
    }

  }
}


void GuiTypeBox::set_marker_x_screen() {
  std::string p;
  p = "";
  for (int i=0; i!=marker_x; i+=1) {
    p += text[i];
  }
  marker_screen_x = font->Width(p);
}


void GuiTypeBox::type(char c) {
  if (max_size != -1) {
    if (text.size() >= max_size) return;
  }

  if (font->Width((text+c)) > w - 8) {
    return;
  }

  std::string p;
  p="";

  int i;
  for (i=0; i!=marker_x; i+=1) {
    p += text[i];
  }
  p += c;

  for (i=marker_x; i<text.size(); i+=1) {
    p += text[i];
  }

  marker_x += 1;
  std::string ch="A";
  ch[0] = c;
  marker_screen_x += font->Width(ch);

  text = p;
}


void GuiTypeBox::erase() {
  if (marker_x == 0) return;
  std::string p;
  p="";

  std::string ch;
  ch = "A";
  ch[0] = text[marker_x];

  int i;
  for (i=0; i<marker_x-1; i+=1) {
    p += text[i];
  }
  marker_screen_x = game_font->Width(p);


  for (i=marker_x; i<text.size(); i+=1) {
    p += text[i];
  }

  text = p;

  marker_x -= 1;


}


void GuiTypeBox::draw() {
  if ((base!=NULL) && (visible)) {
    al_draw_scaled_bitmap(base->get_bit(), 0, 0, base->Width(), base->Height(), x, y, w, h, 0);
  }
  std::vector<GuiElement *>::iterator guit;
  if (visible) {
    for (guit=attached_elements.begin();guit!=attached_elements.end();guit+=1) {
      (*guit)->draw();
    }

    font->Print(text, x+4, y+h-6, al_map_rgb(0, 0, 0));
    if (writing) {
      al_set_blender(ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, al_map_rgba_f(1.0, 1.0, 1.0, 0.7 + marker_op->get_l()));
      al_draw_scaled_bitmap(marker->get_bit(), 0, 0, marker->Width(), marker->Height(), x+marker_screen_x + 4, y+h-4-font->Height(), marker->Width(), font->Height(), 0);
      al_set_blender(ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, al_map_rgb(255, 255, 255));
    }
  }
}
