/*
 *  Copyright (C) 2008 Kristian Kristola
 *
 *  This program is distributed under the terms of the
 *  GNU General Public License.
 *
 *  This file is part of Dave the Ordinary Spaceman.
 *
 *  Dave the Ordinary Spaceman is free software: you can redistribute
 *  it and/or modify it under the terms of the GNU General Public
 *  License as published by the Free Software Foundation, either
 *  version 3 of the License, or (at your option) any later version.
 *
 *  Dave the Ordinary Spaceman is distributed in the hope that it
 *  will be useful, but WITHOUT ANY WARRANTY; without even the
 *  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 *  PURPOSE.  See the GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Dave the Ordinary Spaceman. If not, see
 *  <http://www.gnu.org/licenses/>.
 *
 */

#ifndef __ELOISAN_DIABEETIKON_INJEKTIORUISKU_TORILLA_OSTETTIIN_RAHALLA__
#define __ELOISAN_DIABEETIKON_INJEKTIORUISKU_TORILLA_OSTETTIIN_RAHALLA__

#include <list>
#include <map>
#include <string>
#include <vector>
#include <set>
#include "level.h"
#include "teletext.h"

using namespace std;

union SDL_Event;
//class Level;
//class Level::Block;

class HasCallback
{
public:
  virtual ~HasCallback() = 0;
  virtual void handle_callback(const string &label, const float value) = 0;
};

class Widget
{
public:
  Widget(int x, int y, int w, int h, const string &label);
  virtual ~Widget();
  virtual void render();
  virtual void handle(SDL_Event *e);
  void set_bounds(int a, int b, int c, int d);
  void set_label_pos(int x, int y);

protected:
  int x, y;
  int w, h;
  void pop();
  bool is_inside(const int tx, const int ty) const;
  string label_str;

private:
  Teletext *label;
  int label_x, label_y;
};

class Number : public Widget
{
public:
  Number(int x, int y, int w, int h, float v, float min, float max, const string &label);
  Number(int x, int y, int w, int h, int v, int min, int max, const string &label);
  ~Number();
  void render();
  void handle(SDL_Event *e);
  void set_sensitivity(float s);
  void set(float v);
  float get() const;

private:
  enum {
    FLOAT, INT
  } type;
  float factor;
  float tmp_value;
  float value;
  float min, max;
  Teletext *text;
  bool adjusting;
};

class Editor : public Level, public HasCallback
{
public:
  Editor();
  ~Editor();
  void load();
  void handle(SDL_Event *e);
  void render();
  void cycle();
  void set_level(Level *l);
  Block *get_block(const int x, const int y) const;
  void handle_callback(const string &label, const float value);
  void update_options();
  void cleanup();

private:
  struct Region
  {
    float x, y;
    float w, h;
    Region(){}
    Region(float a, float b, float c, float d)
    {
      x = a; y = b;
      w = c; h = d;
    }
    bool is_inside(float xx, float yy) const
    {
      return x <= xx && xx <= x + w &&
             y <= yy && yy <= y + h;
    }
  };
private:
  Level *level;
  map<Level::Block *, Region> regions;
  vector<vector<Level::Block *> > grid;
  map<pair<string, Block::Type::Family>, Vector> affix;
  void load(const string &name, const Block::Type::Family family, int pass);
  float top, right;         // Dimensions for graphics
  float right_total;        // Dimensions for blocks
  string brush;
  Block::Type::Family brush_family;
  Region indicator;
  Teletext *message;
  enum Q {
    NOTHING, SAVE, LOAD, NEW, OTHER
  } question;
  float palette_offset, palette_offset_speed;

  class GUI {
  public:
    GUI();
    ~GUI();
    Number layer;
    Number r, g, b;
    Number layer_opq;
    Number touchpad;
    Number hide_inactive;
    Number level;
    Number program;
    Teletext *block_name;
  } gui;

  bool turn_hide_inactive_on;
  vector<int> opacities;
  void save_opacities();
  void restore_opacities();
};

#endif
