// ---------------------------------------------------------------------------
// 
//   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 -------------------------------------

#ifndef JUNKEDITOR_H
#define JUNKEDITOR_H

#include <map>
#include <string>

#include "world.h"

class Widget;
class WidgetText;
class WidgetSlider;
class WidgetButton;
class WidgetContainer;
class WidgetSelectChild;
class FileWindow;

/** Various inspector data types for attributes. */
enum InspectorDataType {
	INSPECTOR_BOOL,
	INSPECTOR_INT,
	INSPECTOR_DOUBLE,
	INSPECTOR_STRING,
	INSPECTOR_READONLYSTRING,
	INSPECTOR_DIVIDER
};

class JunkEditor {
	public:
		JunkEditor(World *world, bool enableSaves = true);
		~JunkEditor(void);

		// --------------------------------------------------------------------
		// Attributes and inspector window
		// --------------------------------------------------------------------

		/** @brief Clears the list of attributes. */
		void clearAttributes(void);
		
		/** @brief Add a new attribute to the list of attributes.
			@param name Name of the attribute.
			@param type One of INSPECTOR_* specifying the type of the data to add.
		*/
		void addAttribute(const std::string &name, InspectorDataType type);
		
		// Functions to set attributes of various types
		
		/** @brief Set a string attribute.
			@param name Name of the attribute.
			@param value Value to set.
		*/
		void setStringAttribute(const std::string &name, const std::string &value);
		
		/** @brief Set a boolean attribute.
			@param name Name of the attribute.
			@param value Value to set.
		*/
		void setBoolAttribute(const std::string &name, bool value);
		
		/** @brief Set an integer attribute.
			@param name Name of the attribute.
			@param value Value to set.
		*/
		void setIntAttribute(const std::string &name, int value);
		
		/** @brief Set a double attribute.
			@param name Name of the attribute.
			@param value Value to set.
		*/
		void setDoubleAttribute(const std::string &name, double value);
	
		// Functions to get attributes of various types
		
		/** @brief Get a string attribute.
			@param name Name of the attribute.
			@return The value in the attribute.
		*/
		std::string getStringAttribute(const std::string &name);

		/** @brief Get a boolean attribute.
			@param name Name of the attribute.
			@return The value in the attribute.
		*/
		bool getBoolAttribute(const std::string &name);
		
		/** @brief Get an integer attribute.
			@param name Name of the attribute.
			@return The value in the attribute.
		*/
		int getIntAttribute(const std::string &name);
		
		/** @brief Get a double attribute.
			@param name Name of the attribute.
			@return The value in the attribute.
		*/
		double getDoubleAttribute(const std::string &name);
	
		// --------------------------------------------------------------------
		// Entity creation stuff
		// --------------------------------------------------------------------

		/** @brief Clears the list of Entitites that can be added. */
		void clearEntityPaletteList(void);
		
		/** @brief Adds an Entity type of the given name to the list.
			@param name Name of the Entity type.
		*/
		void addEntityPaletteItem(const std::string &name);
		
		/** @brief Removes an entry from the Entity palette list.
			@param name Name of the Entity type to remove.
		*/
		void removeEntityPaletteItem(const std::string &name);
		
		/** @brief Gets the next Entity to add.
			@return A string, identical to whatever was added with addEntityPaletteItem()
				indicating an Entity that should be added, or a zero-length string if
				none needs to be added.
		*/
		std::string getNewEntity(void);

		// --------------------------------------------------------------------
		// Load/Save stuff
		// --------------------------------------------------------------------

		/** @brief Get the name of a file to save as.
			@return The name of a file to save the current world into or a zero-length
				string if no save is pending.
		*/
		std::string getSave(void);
		
		/** @brief Get the name of a file to load.
			@return The name of the file to load or a zero-length string if no load is
				pending.
		*/
		std::string getLoad(void);
		
		/** @brief If the "New" option has been selected from the File menu since the last time
			this function was called, it will return true.
			@return true if the world should be cleared.
		*/
		bool getNew(void);
		
		// --------------------------------------------------------------------
		// Misc stuff
		// --------------------------------------------------------------------		
		
		/** @brief Pumps the events. Do once per frame. */
		void update(float screenWidth, float screenHeight);
		
		/** @brief See if any attribute has changed since the last call.
			@return true if an attribute has changed.
		*/
		bool attributesChanged(void);
	
		/** @brief Get visiblity of the windows.
		 * @return true if visible, false otherwise.
		 * */
		bool getVisible(void) const;
		
		/** @brief Set visibility of the windows.
		 * @param vis true to make visible, false to hide.
		 * */
		void setVisible(bool vis);
		
		// --------------------------------------------------------------------
		// Layer stuff
		// --------------------------------------------------------------------

		/** @brief Get the status of the layer visibility checkbox for
		 * a given layer.
		 * @param layer The layer to check.
		 * @return true if the layer should be visible, false otherwise.
		 * */
		bool isLayerVisible(int layer) const;
		
		/** @brief Get the active layer.
		 * @return The active layer number.
		 * */
		int getActiveLayer(void) const;

        /// Set the active layer.
        void setActiveLayer(int layerNum);

        /// Update the list of layers to match whatever the world's state is.
        void updateLayerList(World *world);

		// --------------------------------------------------------------------
		// Tile palette
		// --------------------------------------------------------------------
		
		/** @brief Rebuild the tile palette window icons.
		 * Do this every time you change the tileset or tile size.
		 * @param tileSet The tileset.
		 * @param tileSize The size of each tile, in pixels.
		 * */
		void rebuildTiles(const std::string &tileSet, int tileSize);
		
		/// The size of each tile, in pixels. If it's changed, then the user wants it changed. React accordingly.
		int tileSize;
		
		/** @brief Get the current tile.
		 * @return The tile number, or a randomly selected tile from the selection, if multiple.
		 * */
		int getCurrentTile(void);
		
		/// List of all the currently selected tiles.
		std::vector<int> currentTiles;
		
		/// True if the user wants to clear all the tiles on the current layer.
		bool clearTiles;
		
		/// Contains a filename if the user wants to change the current tileset.
		std::string newTilesFile;
		
		/// Number of attributes in the inspector
		int numAttributes;
	
		/// True if the tiles tab is open.
		bool tilesGroupSelected;
		
		/// true if the save window is open
		bool saveDialogOpen;
		/// true if the load window is open
		bool loadDialogOpen;
		/// The current level file name
		std::string levelFileName;
		
		
		/// The file name to save as if something was selected
		std::string nextSaveName;
		/// The file name to load if something was selected
		std::string nextLoadName;
		/// The name of a new entity to add if something was added
		std::string nextEntName;
		/// true if the user has selected to start a new level
		bool wantClearData;
		
		/// Visibility of the editor
		bool visible;
		
		/// Which layer is currently the one being edited.
		int activeLayer;
		
		/// Console lines awaiting execution.
		std::vector<std::string> consoleCommands;
		/// History of typed console commands.
		std::vector<std::string> consoleHistory;
		/// Position in the history buffer.
		int historyPosition;

		// --------------------------------------------------------------------
		// Blah blah blah
		// --------------------------------------------------------------------
		
		/** @brief Append the console output.
		 * @param str The text to add to the console.
		 */
		void appendConsoleOutput(const std::string &str);

		/// Get the root widget.
		Widget *getRootWidget(void);

		/// Let us know if mouse events shouldn't fall through.
		bool mouseOverAWidget;

		/// Mark entity data as needing an update back to the Entity.
		void flagDataDirty(void);

		/// Add a command to the list of commands to execute.
		void addConsoleCommand(const std::string &command);

		/// Just turns off all the tile buttons for non-multi-select.
		void unsetAllTileButtons(void);

		/// Add a tile to the list of tiles to randomly choose from.
		void addPickedTile(int tile);
		
		/// Clear the list of tiles to choose from.
		void clearPickedTiles(void);

		Widget *getTopWidget(void);
		int getWidgetStackSize(void);
		
		// TODO: Move this stuff back to private.
		std::vector<Widget*> rootWidgetStack;
		Widget *newFileConfirm;
        Widget *layerDestroyConfirm;
		Widget *hiddenRoot;
		
		// File selection windows for different purposes.
		FileWindow *loadWindow;
		FileWindow *saveWindow;
		FileWindow *tileFileWindow;
		
		WidgetText *tab_tileFilename;

		std::string gameName;
		
        void updateLightSliders(const Vector3D &ambient, bool retro, bool disable);

        bool getLightsDirty(void);
        
        // FIXME: Make this private.
        bool lightsDirty;

        Vector3D getAmbientLights(void);
        bool getRetro(void);
        bool getLightsDisabled(void);
        bool getLightLayersLinked(void);
        bool getTintInactiveLayers(void);
	private:
	
		bool dataDirty;

		// Stuff that needs to be remembered and accessed directly
		// later. Other Widgets can be forgotten about as long as
		// they're in the hierarchy. (They get nuked with the root when
		// it goes.)
		Widget *rootContainer;
        std::vector<Widget*> layerButtons;
        std::vector<Widget*> layerVisButtons;
		WidgetButton *tileButton;
		WidgetContainer *tab_inspectorContainer;
		WidgetContainer *tab_inspectorContainer_lastGroup;
		WidgetContainer *tab_tileContainerGrid;
		WidgetContainer *tab_tileContainer;
		WidgetText *tab_tileSize;
		WidgetContainer *tab_entContainer;
		WidgetSelectChild *tabPane;
		WidgetText *consoleOutput;
		WidgetSlider *consoleSlider;
        WidgetContainer *tab_lighting;
        WidgetSlider *lighting_ambient_redSlider;
        WidgetSlider *lighting_ambient_greenSlider;
        WidgetSlider *lighting_ambient_blueSlider;
        WidgetButton *lighting_settings_retroEffectsButton;
        WidgetButton *lighting_settings_linkLayersButton;
        WidgetButton *lighting_settings_disableButton;
        WidgetButton *lighting_settings_tintInactiveButton;
		bool readjustConsoleSliderAfterUpdate;
        WidgetContainer *layerSelection;
        WidgetText *layer_nameEntry;
        WidgetText *layer_camScaleEntry;
        WidgetButton *layer_lightToggle;
        WidgetButton *layer_fullbrightToggle;
        WidgetButton *layer_combineToggle;
        WidgetButton *layer_tilesAsLightsToggle;

		std::map<std::string, Widget *> valueWidgets;
};

// Uhh... Ignore this. Damn this code is looking hacky.
void setJunkEditorButtonDefaults(WidgetButton *button);
void setJunkEditorSliderDefaults(WidgetSlider *slider);

#endif
