// ---------------------------------------------------------------------------
// 
//   Lily Engine alpha
// 
//   Copyright (c) 2010 Clifford Jolly
//     http://cliffjolly.com
//     cliff@cliffjolly.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 2 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, write to the Free Software
//   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
//   USA
// -------------------------- END HEADER -------------------------------------

#pragma once

#include <string>
#include <vector>

#ifdef WIN32
#include <SDL.h>
#else
#include <SDL/SDL.h>
#endif

#include <boost/function.hpp>

#include "../math/vector2d.h"

#include "junkeditor.h"


class Entity;
class World;
class Widget;
class EditorUndoAction;

/** @brief Overlay, event handler, and external UI facilitating in-engine editing. */
class EditorUI {
	public:
		/** @brief Constructor.
		 * @param world The World to attach to.
		 * */
		EditorUI(World *world, bool debugOnly = false);
		~EditorUI(void);
		
		/** @brief Get the last object selected.
		 * @return The name of the last object selected.
		 * */
		std::string getLastSelected(void) const;
		
		/** @brief Get a list of all the selected objects.
		 * @param selection An std::vector<std::string> to store the
		 *   names of all the selected objects in.
		 * @note As multiple selections aren't supported, this doesn't
		 *   do much more than getLastSelected().
		 * */
		void getAllSelected(std::vector<std::string> &selection) const;
		
		/** @brief Handle an SDL_Event.
		 * @param event The event to handle.
		 * @return true if the editor made use of the event and it
		 *   should override other game events, false if it should be
		 *   handled normally by the normal event system.
		 * */
		bool handleEvent(SDL_Event *event);
		
		/** @brief Frame update.
		 * Call this every frame. Handles interface updating.
		 * */
		void update(void);
		
		/** @brief Draw the editor overlay.
		 * */
		void draw(void);
		
		/** @brief Set the visibility of the editor.
		 * @note The editor will be inactive if it is invisible.
		 * @param visible true if the editor should be visible, false
		 *   to hide the editor.
		 * */
		void setVisible(bool visible);
		
		/** @brief Determine if the editor is visible.
		 * @return true if it is visible, false if it is hidden.
		 * */
		bool getVisible(void) const;
		
		/** @brief Update the inspector to properly show a new object
		 *   or new attributes.
		 * */
		void updateInspector(void);
		
		/** @brief Update the currently selected object so its internal
		 *   values match the ones shown in the inspector.
		 * */
		void updateFromInspector(void);
		
		/** @brief Select a single object.
		 * @param name The name of the object to be selected.
		 * */
		void selectObject(const std::string &name);
		
		/** @brief Build the spawn list from the World.
		 * Lists of what things can be spawned in using the Entity
		 * adder window of the editor are defined in Lua and stored in
		 * the world object. This updates the Entity adder window to
		 * match the list stored in the world object.
		 * */
		void populateSpawnList(void);
		
		/// Widgets for the interface. UIJunk version.
		JunkEditor junkInterface;

		/** @brief Enable visibilty in the game of things normally only
		 * visible in the editor. Ugly hack. But whatever. */
		bool overrideEditorOnlyVisibility;
		
		/// Get the root widget - presumably to draw and pass events
		/// into.
		Widget *getRootWidget(void);

        /// Nuke all the undo actions. Do this every time we load or
        /// do something that the undo system won't be able to handle
        /// (layer deletions, etc).
        void clearUndoActions(void);

        /// Do an undo action and pop it off the stack.
        void undo(void);
		
        /// Add a non-standard undo action.
        void addUndoAction(const std::string &desc, boost::function<void()> action);

        /// Shift everything on a layer by full-tile increments.
        void shiftLayer(int layer, int x, int y);

	private:
		
		World *world;
		bool visible;
		std::vector<std::string> selection;
		
		Entity *dragObject;
        Entity *linkObject;
		Vector2D *dragPoint;
		Vector2D dragOffset;
		Vector2D originalDragPos;
		Vector2D lastMousePos;
		int gridSpacing;
		bool gridSnapping;
		bool screenDragging;
		
		bool tileDrawing;
		bool tileDrawingHeld;
		int lastActiveLayer;
		
		void drawTiles(int x, int y, int tile);
		int pickTile(int x, int y);
		void rebuildTiles(void);
		bool ignoreNextMouseUp;
        
        void updateLightSliders(void);

        std::vector<EditorUndoAction*> undoActions;
};

