#include <nall/platform.hpp>
#include <nall/config.hpp>
#include <nall/directory.hpp>
#include <nall/function.hpp>
#include <nall/group.hpp>
#include <nall/image.hpp>
#include <nall/map.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
#include <nall/utility.hpp>
#include <nall/vector.hpp>

namespace phoenix {

struct Application;
struct Font;
struct Window;
struct Menu;
struct Sizable;
struct Layout;
struct Widget;

struct pApplication;
struct pFont;
struct pObject;
struct pTimer;
struct pWindow;
struct pAction;
struct pMenu;
struct pSeparator;
struct pItem;
struct pCheckItem;
struct pRadioItem;
struct pSizable;
struct pLayout;
struct pWidget;
struct pButton;
struct pCanvas;
struct pCheckButton;
struct pCheckLabel;
struct pComboButton;
struct pConsole;
struct pFrame;
struct pHexEdit;
struct pHorizontalScroller;
struct pHorizontalSlider;
struct pLabel;
struct pLineEdit;
struct pListView;
struct pProgressBar;
struct pRadioButton;
struct pRadioLabel;
struct pTabFrame;
struct pTextEdit;
struct pVerticalScroller;
struct pVerticalSlider;
struct pViewport;

struct Application {
  static nall::function<void ()> main;

  static void run();
  static bool pendingEvents();
  static void processEvents();
  static void quit();
  static void setName(const nall::string& name);

  Application() = delete;
  struct State;
  static void initialize();

  struct Windows {
    static nall::function<void ()> onModalBegin;
    static nall::function<void ()> onModalEnd;
  };

  struct Cocoa {
    static nall::function<void ()> onAbout;
    static nall::function<void ()> onActivate;
    static nall::function<void ()> onPreferences;
    static nall::function<void ()> onQuit;
  };
};

struct Color {
  uint8_t red, green, blue, alpha;
  uint32_t rgb() const;
  uint32_t argb() const;
  inline Color() : alpha(255), red(0), green(0), blue(0) {}
  inline Color(uint8_t red, uint8_t green, uint8_t blue) : alpha(255), red(red), green(green), blue(blue) {}
  inline Color(uint8_t alpha, uint8_t red, uint8_t green, uint8_t blue) : alpha(alpha), red(red), green(green), blue(blue) {}
};

struct Position {
  signed x, y;
  inline Position() : x(0), y(0) {}
  template<typename X, typename Y> inline Position(X x, Y y) : x(x), y(y) {}
};

struct Size {
  static const unsigned Maximum = ~0u;
  static const unsigned Minimum =  0u;

  unsigned width, height;
  inline Size() : width(0), height(0) {}
  template<typename W, typename H> inline Size(W width, H height) : width(width), height(height) {}
};

struct Geometry {
  signed x, y;
  unsigned width, height;
  Position position() const;
  Size size() const;
  nall::string text() const;
  inline Geometry() : x(0), y(0), width(0), height(0) {}
  inline Geometry(Position position, Size size) : x(position.x), y(position.y), width(size.width), height(size.height) {}
  template<typename X, typename Y, typename W, typename H> inline Geometry(X x, Y y, W width, H height) : x(x), y(y), width(width), height(height) {}
  Geometry(const nall::string& text);
};

enum class Orientation : unsigned { Horizontal, Vertical };

struct Font {
  static nall::string serif(unsigned size = 0, const nall::string& style = "");
  static nall::string sans(unsigned size = 0, const nall::string& style = "");
  static nall::string monospace(unsigned size = 0, const nall::string& style = "");
  static Size size(const nall::string& font, const nall::string& text);
  Font() = delete;
};

struct Desktop {
  static Size size();
  static Geometry workspace();
  Desktop() = delete;
};

struct Monitor {
  static unsigned count();
  static Geometry geometry(unsigned monitor);
  static unsigned primary();
};

struct Keyboard {
  #include "keyboard.hpp"
  static bool pressed(Scancode scancode);
  static bool released(Scancode scancode);
  static nall::vector<bool> state();
  Keyboard() = delete;
};

struct Mouse {
  enum class Button : unsigned { Left, Middle, Right };
  static Position position();
  static bool pressed(Button);
  static bool released(Button);
  Mouse() = delete;
};

struct BrowserWindow {
  nall::string directory();
  nall::string open();
  nall::string save();
  BrowserWindow& setFilters(const nall::lstring& filters);
  BrowserWindow& setParent(Window& parent);
  BrowserWindow& setPath(const nall::string& path);
  BrowserWindow& setTitle(const nall::string& title);

  BrowserWindow();
  ~BrowserWindow();
  struct State;
  State& state;
};

struct MessageWindow {
  enum class Buttons : unsigned {
    Ok,
    OkCancel,
    YesNo,
    YesNoCancel,
  };

  enum class Response : unsigned {
    Ok,
    Cancel,
    Yes,
    No,
  };

  Response error(Buttons = Buttons::Ok);
  Response information(Buttons = Buttons::Ok);
  Response question(Buttons = Buttons::YesNo);
  MessageWindow& setParent(Window& parent);
  MessageWindow& setText(const nall::string& text);
  MessageWindow& setTitle(const nall::string& title);
  Response warning(Buttons = Buttons::Ok);

  MessageWindow(const nall::string& text = "");
  ~MessageWindow();
  struct State;
  State& state;
};

struct Object {
  Object(pObject& p);
  Object& operator=(const Object&) = delete;
  Object(const Object&) = delete;
  virtual ~Object();
  pObject& p;
};

struct Timer : private nall::base_from_member<pTimer&>, Object {
  nall::function<void ()> onActivate;

  bool enabled() const;
  unsigned interval() const;
  void setEnabled(bool enabled = true);
  void setInterval(unsigned interval);  //in milliseconds

  Timer();
  ~Timer();
  struct State;
  State& state;
  pTimer& p;
};

struct Window : private nall::base_from_member<pWindow&>, Object {
  nall::function<void ()> onClose;
  nall::function<void (nall::lstring)> onDrop;
  nall::function<void (Keyboard::Keycode)> onKeyPress;
  nall::function<void (Keyboard::Keycode)> onKeyRelease;
  nall::function<void ()> onMove;
  nall::function<void ()> onSize;

  void append(Layout& layout);
  void append(Menu& menu);
  void append(Widget& widget);
  Color backgroundColor() const;
  bool droppable() const;
  Geometry frameGeometry();
  Geometry frameMargin();
  bool focused();
  bool fullScreen() const;
  Geometry geometry();
  nall::string menuFont() const;
  bool menuVisible() const;
  bool modal() const;
  void remove(Layout& layout);
  void remove(Menu& menu);
  void remove(Widget& widget);
  bool resizable() const;
  void setBackgroundColor(Color color);
  void setDroppable(bool droppable = true);
  void setFrameGeometry(Geometry geometry);
  void setFocused();
  void setFullScreen(bool fullScreen = true);
  void setGeometry(Geometry geometry);
  void setMenuFont(const nall::string& font);
  void setMenuVisible(bool visible = true);
  void setModal(bool modal = true);
  void setResizable(bool resizable = true);
  void setStatusFont(const nall::string& font);
  void setStatusText(const nall::string& text);
  void setStatusVisible(bool visible = true);
  void setTitle(const nall::string& text);
  void setVisible(bool visible = true);
  void setWidgetFont(const nall::string& font);
  void setWindowGeometry(Geometry geometry);
  nall::string statusFont() const;
  nall::string statusText() const;
  bool statusVisible() const;
  void synchronizeLayout();
  nall::string title() const;
  bool visible() const;
  nall::string widgetFont() const;

  Window();
  ~Window();
  struct State;
  State& state;
  pWindow& p;
};

struct Action : Object {
  bool enabled() const;
  void setEnabled(bool enabled = true);
  void setVisible(bool visible = true);
  bool visible() const;

  Action(pAction& p);
  ~Action();
  struct State;
  State& state;
  pAction& p;
};

struct Menu : private nall::base_from_member<pMenu&>, Action {
  void append(const nall::group<Action>& list);
  nall::image image() const;
  void remove(const nall::group<Action>& list);
  void setImage(const nall::image& image = nall::image{});
  void setText(const nall::string& text);
  nall::string text() const;

  Menu();
  ~Menu();
  struct State;
  State& state;
  pMenu& p;
};

struct Separator : private nall::base_from_member<pSeparator&>, Action {
  Separator();
  ~Separator();
  pSeparator& p;
};

struct Item : private nall::base_from_member<pItem&>, Action {
  nall::function<void ()> onActivate;

  nall::image image() const;
  void setImage(const nall::image& image = nall::image{});
  void setText(const nall::string& text);
  nall::string text() const;

  Item();
  ~Item();
  struct State;
  State& state;
  pItem& p;
};

struct CheckItem : private nall::base_from_member<pCheckItem&>, Action {
  nall::function<void ()> onToggle;

  bool checked() const;
  void setChecked(bool checked = true);
  void setText(const nall::string& text);
  nall::string text() const;

  CheckItem();
  ~CheckItem();
  struct State;
  State& state;
  pCheckItem& p;
};

struct RadioItem : private nall::base_from_member<pRadioItem&>, Action {
  template<typename... Args> static void group(Args&&... args) { group({std::forward<Args>(args)...}); }
  static void group(const nall::group<RadioItem>& list);

  nall::function<void ()> onActivate;

  bool checked() const;
  void setChecked();
  void setText(const nall::string& text);
  nall::string text() const;

  RadioItem();
  ~RadioItem();
  struct State;
  State& state;
  pRadioItem& p;
};

struct Sizable : Object {
  bool enabled() const;
  bool enabledToAll() const;
  Layout* layout() const;
  virtual Size minimumSize() = 0;
  Sizable* parent() const;
  virtual void setEnabled(bool enabled = true) = 0;
  virtual void setGeometry(Geometry geometry) = 0;
  virtual void setVisible(bool visible = true) = 0;
  virtual void synchronizeLayout() = 0;
  bool visible() const;
  bool visibleToAll() const;
  Window* window() const;

  Sizable(pSizable& p);
  ~Sizable();
  struct State;
  State& state;
  pSizable& p;
};

struct Layout : private nall::base_from_member<pLayout&>, Sizable {
  virtual void append(Sizable& sizable);
  virtual void remove(Sizable& sizable);
  virtual void reset();

  Layout();
  Layout(pLayout& p);
  ~Layout();
  struct State;
  State& state;
  pLayout& p;
};

struct Widget : private nall::base_from_member<pWidget&>, Sizable {
  nall::function<void ()> onSize;

  bool focused();
  nall::string font() const;
  Geometry geometry() const;
  Size minimumSize();
  void setEnabled(bool enabled = true);
  void setFocused();
  void setFont(const nall::string& font);
  void setGeometry(Geometry geometry);
  void setVisible(bool visible = true);
  void synchronizeLayout();

  Widget();
  Widget(pWidget& p);
  ~Widget();
  struct State;
  State& state;
  pWidget& p;
};

struct Button : private nall::base_from_member<pButton&>, Widget {
  nall::function<void ()> onActivate;

  nall::image image() const;
  Orientation orientation() const;
  void setImage(const nall::image& image = nall::image{}, Orientation orientation = Orientation::Horizontal);
  void setText(const nall::string& text);
  nall::string text() const;

  Button();
  ~Button();
  struct State;
  State& state;
  pButton& p;
};

struct Canvas : private nall::base_from_member<pCanvas&>, Widget {
  enum class Mode : unsigned { Color, Gradient, Image, Data };

  nall::function<void (nall::lstring)> onDrop;
  nall::function<void ()> onMouseLeave;
  nall::function<void (Position)> onMouseMove;
  nall::function<void (Mouse::Button)> onMousePress;
  nall::function<void (Mouse::Button)> onMouseRelease;

  Color color() const;
  uint32_t* data() const;
  bool droppable() const;
  nall::vector<Color> gradient() const;
  nall::image image() const;
  Mode mode() const;
  void setColor(Color color);
  void setData();
  void setDroppable(bool droppable = true);
  void setHorizontalGradient(Color left, Color right);
  void setGradient(Color topLeft, Color topRight, Color bottomLeft, Color bottomRight);
  void setImage(const nall::image& image);
  void setMode(Mode mode);
  void setSize(Size size);
  void setVerticalGradient(Color top, Color bottom);
  Size size() const;

  Canvas();
  ~Canvas();
  struct State;
  State& state;
  pCanvas& p;
};

struct CheckButton : private nall::base_from_member<pCheckButton&>, Widget {
  nall::function<void ()> onToggle;

  bool checked() const;
  nall::image image() const;
  void setChecked(bool checked = true);
  void setImage(const nall::image& image = nall::image{}, Orientation orientation = Orientation::Horizontal);
  void setText(const nall::string& text);
  nall::string text() const;

  CheckButton();
  ~CheckButton();
  struct State;
  State& state;
  pCheckButton& p;
};

struct CheckLabel : private nall::base_from_member<pCheckLabel&>, Widget {
  nall::function<void ()> onToggle;

  bool checked() const;
  void setChecked(bool checked = true);
  void setText(const nall::string& text);
  nall::string text() const;

  CheckLabel();
  ~CheckLabel();
  struct State;
  State& state;
  pCheckLabel& p;
};

struct ComboButton : private nall::base_from_member<pComboButton&>, Widget {
  nall::function<void ()> onChange;

  void append(const nall::string& text = "");
  void remove(unsigned selection);
  void reset();
  unsigned rows() const;
  unsigned selection() const;
  void setSelection(unsigned selection);
  void setText(unsigned selection, const nall::string& text);
  nall::string text() const;
  nall::string text(unsigned selection) const;

  ComboButton();
  ~ComboButton();
  struct State;
  State& state;
  pComboButton& p;
};

struct Console : private nall::base_from_member<pConsole&>, Widget {
  nall::function<void (nall::string)> onActivate;

  template<typename... Args> void print(Args&&... args) { print({args...}); }

  void print(const nall::string& text);
  void reset();

  Console();
  ~Console();
  struct State;
  State& state;
  pConsole& p;
};

struct Frame : private nall::base_from_member<pFrame&>, Widget {
  void setLayout(Layout& layout);
  void setText(const nall::string& text);
  void synchronizeLayout();
  nall::string text() const;

  Frame();
  ~Frame();
  struct State;
  State& state;
  pFrame& p;
};

struct HexEdit : private nall::base_from_member<pHexEdit&>, Widget {
  nall::function<uint8_t (unsigned)> onRead;
  nall::function<void (unsigned, uint8_t)> onWrite;

  unsigned columns() const;
  unsigned length() const;
  unsigned offset() const;
  unsigned rows() const;
  void setColumns(unsigned columns);
  void setLength(unsigned length);
  void setOffset(unsigned offset);
  void setRows(unsigned rows);
  void update();

  HexEdit();
  ~HexEdit();
  struct State;
  State& state;
  pHexEdit& p;
};

struct HorizontalScroller : private nall::base_from_member<pHorizontalScroller&>, Widget {
  nall::function<void ()> onChange;

  unsigned length() const;
  unsigned position() const;
  void setLength(unsigned length);
  void setPosition(unsigned position);

  HorizontalScroller();
  ~HorizontalScroller();
  struct State;
  State& state;
  pHorizontalScroller& p;
};

struct HorizontalSlider : private nall::base_from_member<pHorizontalSlider&>, Widget {
  nall::function<void ()> onChange;

  unsigned length() const;
  unsigned position() const;
  void setLength(unsigned length);
  void setPosition(unsigned position);

  HorizontalSlider();
  ~HorizontalSlider();
  struct State;
  State& state;
  pHorizontalSlider& p;
};

struct Label : private nall::base_from_member<pLabel&>, Widget {
  void setText(const nall::string& text);
  nall::string text() const;

  Label();
  ~Label();
  struct State;
  State& state;
  pLabel& p;
};

struct LineEdit : private nall::base_from_member<pLineEdit&>, Widget {
  nall::function<void ()> onActivate;
  nall::function<void ()> onChange;

  bool editable() const;
  void setEditable(bool editable = true);
  void setText(const nall::string& text);
  nall::string text();

  LineEdit();
  ~LineEdit();
  struct State;
  State& state;
  pLineEdit& p;
};

struct ListView : private nall::base_from_member<pListView&>, Widget {
  nall::function<void ()> onActivate;
  nall::function<void ()> onChange;
  nall::function<void (unsigned)> onToggle;

  void append(const nall::lstring& text);
  void autoSizeColumns();
  bool checkable() const;
  bool checked(unsigned selection) const;
  unsigned columns() const;
  bool headerVisible() const;
  nall::image image(unsigned selection, unsigned position) const;
  void remove(unsigned selection);
  void reset();
  unsigned rows() const;
  bool selected() const;
  unsigned selection() const;
  void setCheckable(bool checkable = true);
  void setChecked(unsigned selection, bool checked = true);
  void setHeaderText(const nall::lstring& text);
  void setHeaderVisible(bool visible = true);
  void setImage(unsigned selection, unsigned position, const nall::image& image = nall::image{});
  void setSelected(bool selected = true);
  void setSelection(unsigned selection);
  void setText(unsigned selection, const nall::lstring& text);
  void setText(unsigned selection, unsigned position, const nall::string& text);
  nall::string text(unsigned selection, unsigned position) const;

  ListView();
  ~ListView();
  struct State;
  State& state;
  pListView& p;
};

struct ProgressBar : private nall::base_from_member<pProgressBar&>, Widget {
  unsigned position() const;
  void setPosition(unsigned position);

  ProgressBar();
  ~ProgressBar();
  struct State;
  State& state;
  pProgressBar& p;
};

struct RadioButton : private nall::base_from_member<pRadioButton&>, Widget {
  template<typename... Args> static void group(Args&&... args) { group({std::forward<Args>(args)...}); }
  static void group(const nall::group<RadioButton>& list);

  nall::function<void ()> onActivate;

  bool checked() const;
  nall::image image() const;
  void setChecked();
  void setImage(const nall::image& image = nall::image{}, Orientation orientation = Orientation::Horizontal);
  void setText(const nall::string& text);
  nall::string text() const;

  RadioButton();
  ~RadioButton();
  struct State;
  State& state;
  pRadioButton& p;
};

struct RadioLabel : private nall::base_from_member<pRadioLabel&>, Widget {
  template<typename... Args> static void group(Args&&... args) { group({std::forward<Args>(args)...}); }
  static void group(const nall::group<RadioLabel>& list);

  nall::function<void ()> onActivate;

  bool checked() const;
  void setChecked();
  void setText(const nall::string& text);
  nall::string text() const;

  RadioLabel();
  ~RadioLabel();
  struct State;
  State& state;
  pRadioLabel& p;
};

struct TabFrame : private nall::base_from_member<pTabFrame&>, Widget {
  nall::function<void ()> onChange;

  void append(const nall::string& text = "", const nall::image& image = nall::image{});
  nall::image image(unsigned selection) const;
  void remove(unsigned selection);
  unsigned selection() const;
  void setImage(unsigned selection, const nall::image& image = nall::image{});
  void setLayout(unsigned selection, Layout& layout);
  void setSelection(unsigned selection);
  void setText(unsigned selection, const nall::string& text);
  void synchronizeLayout();
  unsigned tabs() const;
  nall::string text(unsigned selection) const;

  TabFrame();
  ~TabFrame();
  struct State;
  State& state;
  pTabFrame& p;
};

struct TextEdit : private nall::base_from_member<pTextEdit&>, Widget {
  nall::function<void ()> onChange;

  bool editable() const;
  void setCursorPosition(unsigned position);
  void setEditable(bool editable = true);
  void setText(const nall::string& text);
  void setWordWrap(bool wordWrap = true);
  nall::string text();
  bool wordWrap() const;

  TextEdit();
  ~TextEdit();
  struct State;
  State& state;
  pTextEdit& p;
};

struct VerticalScroller : private nall::base_from_member<pVerticalScroller&>, Widget {
  nall::function<void ()> onChange;

  unsigned length() const;
  unsigned position() const;
  void setLength(unsigned length);
  void setPosition(unsigned position);

  VerticalScroller();
  ~VerticalScroller();
  struct State;
  State& state;
  pVerticalScroller& p;
};

struct VerticalSlider : private nall::base_from_member<pVerticalSlider&>, Widget {
  nall::function<void ()> onChange;

  unsigned length() const;
  unsigned position() const;
  void setLength(unsigned length);
  void setPosition(unsigned position);

  VerticalSlider();
  ~VerticalSlider();
  struct State;
  State& state;
  pVerticalSlider& p;
};

struct Viewport : private nall::base_from_member<pViewport&>, Widget {
  nall::function<void (nall::lstring)> onDrop;
  nall::function<void ()> onMouseLeave;
  nall::function<void (Position)> onMouseMove;
  nall::function<void (Mouse::Button)> onMousePress;
  nall::function<void (Mouse::Button)> onMouseRelease;

  bool droppable() const;
  uintptr_t handle();
  void setDroppable(bool droppable = true);

  Viewport();
  ~Viewport();
  struct State;
  State& state;
  pViewport& p;
};

#include "layout/fixed-layout.hpp"
#include "layout/horizontal-layout.hpp"
#include "layout/vertical-layout.hpp"

}
