//  SuperTux
//  Copyright (C) 2015 Hume2 <teratux.mail@gmail.com>
//
//  This program 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.
//
//  This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.

#ifndef HEADER_SUPERTUX_EDITOR_EDITOR_HPP
#define HEADER_SUPERTUX_EDITOR_EDITOR_HPP

#include <functional>
#include <vector>
#include <string>

#include "editor/overlay_widget.hpp"
#include "editor/toolbox_widget.hpp"
#include "editor/layers_widget.hpp"
#include "editor/scroller_widget.hpp"
#include "supertux/screen.hpp"
#include "supertux/world.hpp"
#include "util/currenton.hpp"
#include "util/file_system.hpp"
#include "util/log.hpp"
#include "video/surface_ptr.hpp"

class GameObject;
class Level;
class ObjectGroup;
class Path;
class Savegame;
class Sector;
class TileSet;
class UndoManager;
class World;

class Editor final : public Screen,
                     public Currenton<Editor>
{
public:
  static bool is_active();

public:
  static bool s_resaving_in_progress;

public:
  Editor();
  ~Editor();

  virtual void draw(Compositor&) override;
  virtual void update(float dt_sec, const Controller& controller) override;

  virtual void setup() override;
  virtual void leave() override;

  void event(const SDL_Event& ev);
  void resize();

  void disable_keyboard() { m_enabled = false; }

  Level* get_level() const { return m_level.get(); }

  void set_world(std::unique_ptr<World> w);
  World* get_world() const { return m_world.get(); }

  TileSet* get_tileset() const { return m_tileset; }
  TileSelection* get_tiles() const { return m_toolbox_widget->get_tiles(); }
  std::string get_tileselect_object() const { return m_toolbox_widget->get_object(); }

  EditorToolboxWidget::InputType get_tileselect_input_type() const { return m_toolbox_widget->get_input_type(); }

  int get_tileselect_select_mode() const;
  int get_tileselect_move_mode() const;

  std::string get_levelfile() const { return m_levelfile; }

  void set_level(const std::string& levelfile_) {
    m_levelfile = levelfile_;
    m_reload_request = true;
  }

  std::string get_level_directory() const;

  void open_level_directory();

  bool is_testing_level() const { return m_leveltested; }

  /** Checks whether the level can be saved and does not contain
      obvious issues (currently: check if main sector and a spawn point
      named "main" is present) */
  void check_save_prerequisites(const std::function<void ()>& callback) const;
  void check_unsaved_changes(const std::function<void ()>& action);

  void load_sector(const std::string& name);
  void delete_current_sector();

  void update_node_iterators();
  void esc_press();
  void delete_markers();
  void sort_layers();

  void select_tilegroup(int id);
  const std::vector<Tilegroup>& get_tilegroups() const;
  void change_tileset();

  void select_objectgroup(int id);
  const std::vector<ObjectGroup>& get_objectgroups() const;

  void scroll(const Vector& velocity);

  bool is_level_loaded() const { return m_levelloaded; }

  void edit_path(Path* path, GameObject* new_marked_object) {
    m_overlay_widget->edit_path(path, new_marked_object);
  }

  void add_layer(GameObject* layer) { m_layers_widget->add_layer(layer); }

  GameObject* get_selected_tilemap() const { return m_layers_widget->get_selected_tilemap(); }

  Sector* get_sector() { return m_sector; }

  void undo();
  void redo();

private:
  void set_sector(Sector* sector);
  void set_level(std::unique_ptr<Level> level, bool reset = true);
  void reload_level();
  void quit_editor();
  void save_level();
  void test_level();
  void update_keyboard(const Controller& controller);

protected:
  std::unique_ptr<Level> m_level;
  std::unique_ptr<World> m_world;

  std::string m_levelfile;
  std::string m_test_levelfile;

public:
  bool m_quit_request;
  bool m_newlevel_request;
  bool m_reload_request;
  bool m_reactivate_request;
  bool m_deactivate_request;
  bool m_save_request;
  bool m_test_request;

  std::unique_ptr<Savegame> m_savegame;

private:
  Sector* m_sector;

  bool m_levelloaded;
  bool m_leveltested;

  TileSet* m_tileset;

  std::vector<std::unique_ptr<Widget> > m_widgets;
  EditorOverlayWidget* m_overlay_widget;
  EditorToolboxWidget* m_toolbox_widget;
  EditorLayersWidget* m_layers_widget;

  bool m_enabled;
  SurfacePtr m_bgr_surface;

  std::unique_ptr<UndoManager> m_undo_manager;
  bool m_ignore_sector_change;

private:
  Editor(const Editor&) = delete;
  Editor& operator=(const Editor&) = delete;
};

#endif

/* EOF */
