#include "EditorCanvas.hpp"

EditorCanvas::EditorCanvas(wxFrame *parent, std::shared_ptr<Game> game)
    : wxPanel(parent), game(game), NeedRedraw(false) {
  hide_icon = LoadPNG("hide", wxSize(CGEditor::status.MoveIconWidth,
                                     CGEditor::status.MoveIconWidth));
  t.ResizePieces(CGEditor::status.MoveIconWidth);
  
  // Theme:
  default_font=wxFont(*wxNORMAL_FONT).MakeBold();
  color_scrollbar_bg=wxColour(243,243,243);
  color_scrollbar=*wxLIGHT_GREY;
  color_margin=wxColour(243,243,243);
  color_comments_bg=wxColour(255, 255, 204);
  color_current_move_bg=wxColour(216, 216, 216);
  color_menu_item_bg=wxColour(216, 216, 216);

  Bind(wxEVT_KEY_DOWN, [p=this](wxKeyEvent &e){e.ResumePropagation(1);e.Skip();});
  Bind(wxEVT_KEY_UP, [p=this](wxKeyEvent &e){e.ResumePropagation(1);e.Skip();});
}

void EditorCanvas::OnPaint(wxPaintEvent &event) {
  wxPaintDC current_dc(this);
  dc = &current_dc;

  // Refresh canvas size
  wxSize sz = GetClientSize();
  CGEditor::status.CanvasWidth = sz.GetWidth();
  CGEditor::status.CanvasHeight = sz.GetHeight();
  CGEditor::status.UseMoveIcons =
      true; // Piece image should be drawn before the move ?

  const wxPoint pt = wxGetMousePosition();
  CGEditor::status.MouseX = pt.x - this->GetScreenPosition().x;
  CGEditor::status.MouseY = pt.y - this->GetScreenPosition().y;
  CGEditor::Draw();
}

/**
 * @brief Convenient fonction to center text
 *
 * @param e Element to center
 * @return wxPoint The centered version of e according to wdWidget API
 */
wxPoint EditorCanvas::Middle(cgeditor::Element e) {
  wxSize sz = dc->GetTextExtent(e.text);
  return (wxPoint(e.x + (e.width - sz.GetWidth()) / 2,
                  e.y + (e.height - sz.GetHeight()) / 2));
}

void EditorCanvas::DrawElement(const cgeditor::Element &e) {
  // TODO: Optimize brush!!!! Always instanciated at each call
  dc->SetPen(wxNullPen);
  dc->SetBrush(*wxRED_BRUSH);
  dc->SetFont(default_font);
  if (e.prop & cgeditor::Property::Rectangle) {
    if (e.prop & cgeditor::Property::Scrollbarbg) {
      dc->SetBrush(color_scrollbar_bg);
    } else if (e.prop & cgeditor::Property::Scrollbar) {
      dc->SetBrush(color_scrollbar);
    } else if (e.prop & cgeditor::Property::Margin) {
      dc->SetBrush(wxBrush(color_margin));
    } else if (e.prop & cgeditor::Property::Comment) {
      dc->SetBrush(wxBrush(color_comments_bg));
    } else if (e.prop & cgeditor::Property::Button) {
      if (e.prop & cgeditor::Property::On) {
        dc->DrawBitmap(hide_icon, e.x, e.y);
        return;
      }
      dc->SetBrush(*wxBLACK_BRUSH);
    }
    wxRect recToDraw(e.x, e.y, e.width, e.height);
    dc->DrawRectangle(recToDraw);
  } else if (e.prop & cgeditor::Property::Text ||
             e.prop & cgeditor::Property::Image) {
    if (e.prop & cgeditor::Property::Image) {
      // Draw your pieces images instead
      std::uint32_t y = Middle(e).y - CGEditor::status.MoveIconWidth / 2;
      char p = 'P';
      if (e.prop & cgeditor::Property::Knight) {
        p = 'N';
      } else if (e.prop & cgeditor::Property::Bishop) {
        p = 'B';
      } else if (e.prop & cgeditor::Property::Queen) {
        p = 'Q';
      } else if (e.prop & cgeditor::Property::King) {
        p = 'K';
      } else if (e.prop & cgeditor::Property::Rook) {
        p = 'R';
      }
      if (e.prop & cgeditor::Property::Black) {
        p = std::tolower(p);
      }
      if (e.prop & cgeditor::Property::Current) {
        wxRect recToDraw(e.x, e.y, e.width, e.height);
        dc->SetBrush(wxBrush(color_current_move_bg));
        dc->DrawRectangle(recToDraw);
      }
      dc->DrawBitmap(*t.Get(p), e.x, y);
    } else if (e.prop & cgeditor::Property::Comment) {
      dc->DrawText(wxString(e.text), wxPoint(e.x, e.y));
    } else if (e.prop & cgeditor::Property::Menuitem) {
      wxRect recToDraw(e.x, e.y, e.width, e.height);
      dc->SetBrush(wxBrush(color_menu_item_bg));
      dc->DrawRectangle(recToDraw);
      dc->DrawText(wxString(e.text), wxPoint(e.x, Middle(e).y));
    } else {
      std::string text=e.text;
      if (e.prop & cgeditor::Property::Move) {
        if (e.prop & cgeditor::Property::Current) {
          wxRect recToDraw(e.x, e.y, e.width, e.height);
          dc->SetBrush(wxBrush(color_current_move_bg));
          dc->DrawRectangle(recToDraw);
        }
        if(e.prop & cgeditor::Property::Nag){
          if(text=="$0")
            text="";
          else if(text=="$1")
            text="!";
          else if(text=="$2")
            text="?";
          else if(text=="$3")
            text="!!";
          else if(text=="$4")
            text="??";
          else if(text=="$5")
            text="!?";
          else if(text=="$6")
            text="?!";
          else if(text=="$10")
            text="=";
          else if(text=="$13")
            text="∞";
          else if(text=="$14")
            text="⩲";
          else if(text=="$15")
            text="⩱";
          else if(text=="$16")
            text="±";
          else if(text=="$17")
            text="∓";
          else if(text=="$18")
            text="+-";
          else if(text=="$19")
            text="-+";
          else if(text=="$22"||text=="$23")
            text="⨀";
          else if(text=="$26"||text=="$27")
            text="○";
          else if(text=="$32"||text=="$33")
            text="⟳";
          else if(text=="$36"||text=="$37")
            text="↑";
          else if(text=="$40"||text=="$41")
            text="→";
          else if(text=="$44" || text=="$45")
            text="⯹";
          else if(text=="$138" || text=="$139")
            text="⨁";
          else
            text="NA";
        }
        // Draw move text
        if (CGEditor::status.UseMoveIcons) {
          dc->DrawText(wxString(text), wxPoint(e.x, Middle(e).y));
        } else {
          dc->DrawText(wxString(text), Middle(e));
        }
      } else {
        dc->DrawText(wxString(text), Middle(e));
      }
    }
  }
}
void EditorCanvas::HandleEvent(const cgeditor::Event &e) {
  if (e.type == cgeditor::Event::Goto) {
    game->SetCurrent((HalfMove *)e.move);
  } else if (e.type == cgeditor::Event::Delete) {
    game->DeleteMove((HalfMove *)e.move);  
  } else if (e.type == cgeditor::Event::Promote) {
    game->PromoteMove((HalfMove *)e.move);
  } else if (e.type == cgeditor::Event::SetAsMainline) {
    game->SetMoveAsMainline((HalfMove *)e.move);   
  }
  wxCommandEvent event(GAME_CHANGE, GetId());
  event.SetEventObject(this);
  ProcessEvent(event);
}

void EditorCanvas::MouseEvent(wxMouseEvent &event) {
  if (event.Dragging()) {
    CGEditor::status.LeftClick = false;
    CGEditor::status.IsDrag = true;
    Refresh();
  } else if (event.LeftDown()) {
    SetFocus();
    CGEditor::status.LeftClick = true;
    Refresh();
  } else if (event.RightDown()) {
    SetFocus();
    CGEditor::status.RightClick = true;
    Refresh();
  } else if (event.GetWheelRotation() != 0) {
    SetFocus();
    if (event.GetWheelRotation() < 0) {
      CGEditor::status.EventVScroll = 50;
    } else {
      CGEditor::status.EventVScroll = -50;
    }
    Refresh();
  }

  // Should another draw of CGEditor be made?
  if (NeedRedraw) {
    Refresh();
    NeedRedraw = false;
  }
}

void EditorCanvas::SetMoves(HalfMove *moves, HalfMove *current) {
  CGEditor::status.Moves = moves;
  CGEditor::status.CurrentMove = current;

  Refresh();
}

wxBEGIN_EVENT_TABLE(EditorCanvas, wxPanel) EVT_PAINT(EditorCanvas::OnPaint)
    EVT_MOUSE_EVENTS(EditorCanvas::MouseEvent) wxEND_EVENT_TABLE()
