#ifndef _FishIDE_Project_h_
#define _FishIDE_Project_h_

#include <CtrlLib/CtrlLib.h>
#include <CodeEditor/CodeEditor.h>

#include <plugin/astyle/astyle.h>
#include <plugin/pcre/Pcre.h>

#undef CR0
#undef CR1
#undef CR2

// trick to access TabBarCtrl internals....
/*
#define private public
*/
#include <TabBar/TabBar.h>
/*
#undef private
*/

#include "Images.h"
#include "IdeFilePool.h"
#include "Controls.h"
#include "Builder.h"
#include "Theme.h"
#include "FileInfo.h"
#include "Dialogs.h"

using namespace Upp;

enum MessagePanes
{
	OUTPUTPANE		= 0,
	ERRORPANE,
	SERIALPANE,
	FINDFILESPANE,

	LASTPANE
};

class Project : public ParentCtrl
{
	public:
	
		enum LibraryState
		{
			NotUsedLib = 0,
			UsedLib = 1,
			DependentLib = 2
		};
		
	private:
	
		Splitter			_hSplitter, _vSplitter;
		Splitter			_filesLibsSplitter;
		
		ColumnList			_libsList;
		FileList			_filesList;
		
		TabBar				_filesTab;
		ParentCtrl			_editPane;
		
		TabBarCtrl			_bottomPane;

//		LineEdit			_outputPane;
		RichTextCtrl		_outputPane;
		String				_outputText;

		ArrayCtrl			_errorPane;
		SerialMonitorCtrl	_serialPane;
		ArrayCtrl			_findInFilesPane;
		
		// project's name
		String				_name;
		
		// project's folder
		String				_folder;
		
		// project's files (paths relative to sketch folder)
		Vector<String>		_files;
		
		// project's opened libraries
		VectorMap<String, LibraryState> _libraries;
		
		// non project files (absolute paths)
		Vector<String>		_otherFiles;
		
		// list of opened files and current file path
		// used on loading/storing
		Array<FileInfo>		_openedFiles;
		String				_currentFile;
		
		// get file extension image from path
		Image GetFileIcon(String const &path);
		
		// update other file list
		// (used when changing platform, for example
		void UpdateOthers(void);

		// fills lists
		void FillLibsList(void);
		void FillFilesList(void);
		void FillLists(void);
		
		// library selection handler
		void libSelectCb(void);
		
		// file selection handler
		void fileSelectCb(void);
		
		// selecting current tab, sets corresponding library and file inside lists
		void SetLists();
		
		// clears project content
		void ClearProject(void);
		
		// synchronize .ino to libs
		void SyncINOToLib(void);

		// given the file path, get the FileInfo object for file, open it if needed
		// and add to opened files list
		FileInfo *GetFileInfo(String const &path);

		// synchronize project folder with internal structures
		// to be called before streaming out and after streaming in
		void SynchProjectFolder(void);
		
		// find a project file index by full path; return its index or -1 if none
		int FindProjectFile(String const &filePath) const;
		
		// find a library index given a file path; return its index, or -1 if none
		// in libIndex the library index is returned
		int FindLibraryFile(String const &filePath, int &libIndex) const;
		
		// find an "others file" index by file path
		int FindOtherFile(String const &filePath);
		
	protected:
	
		// internal save
		bool Save0(String const &path, bool force = false);
		
		// delete a file which may be opened in a tab
		// (closes the tab first, and release all the editors)
		bool deleteFile(String const &path);
		
		// create a file, with default content depending on path
		bool createFile(String const &path, bool stub = false, String const &libName = "");

		// remove control when closing tab
		void closeTabCb(Value tab);
		void closeTabsCb(ValueArray tabs);
		
		// lib and files right click menus callbacks
		void libsContextCb(Bar &bar);
		void filesContextCb(Bar &bar);
		
		// library add, remove and create callbacks
		void libOpenCb(bool addToProject);
		void libCloseCb(int libIdx);
		void libAddCb(int libIdx);
		void libRemoveCb(int libIdx);
		void libCreateCb(bool addToProject);
		void libDuplicateCb(int libIdx);

		// add/remove files from library callbacks
		void libRemoveFileCb(int iLib, int iFile);
		void libAddFileCb(int iLib);
		
		// add/remove files from project callbacks
		void projectRemoveFileCb(int iFile);
		void projectAddFileCb(void);

		// add/remove/delete file from others file list
		void othersDeleteFileCb(int iFile);
		void othersRemoveFileCb(int iFile);
		void othersAddFileCb(void);
		
		// BUILD STUFFS
		
		// compile a file
		void compileFileCb(int libIdx, int fileIdx);
		
		// error pane click callback
		void errorPaneCb(void);
		
		// find in files pane click callback
		void findInFilesPaneCb(void);

		// splitter changes callback
		void splitterCb(void);
		
		// add a library to project
		bool AddLibraryToProject(String const &libName);
		
		// remove a library to project
		bool RemoveLibraryFromProject(String const &libName);
				
		// show build results in output pane -- internal function
		void ShowResults0(void);
		
		// make a path relative or absolute of important ide folders
		String RelativePath(String s) const;
		String AbsolutePath(String s) const;
		
		enum {
			TIMEID_PERIODIC = ParentCtrl::TIMEID_COUNT,
			TIMEID_COUNT
		};
		
	public:

		typedef Project CLASSNAME;
		
		// constructor
		Project(String const &path);
		
		// destructor -- save project on exit
		~Project(void);
		
		// callback when an editor is updated
		void editorUpdateCb(void);
		
		// activate project -- just re-grab the editor in current tab
		void Activate(void) { ShowTab(""); }
		
		// close a file from opened tab
		bool closeFile(String const &path);
		
		// find a library by an include
		Ptr<LibraryInfo> FindLibrary(String const &include) const;

		// find used libraries
		Vector<Ptr<LibraryInfo>> FindLibraries(void) const;
		
		// clear build results
		void ClearBuildResults(void);
	
		// show build results in output pane
		void ShowBuildResults(String const &output);
		void ShowBuildErrors(String const &output);

		// shows messages in error pane
		void ShowMessages(Vector<BuilderClass::ErrorLine> const &errLines);
		
		// create default project content based on type
		void CreateDefaultContent(void);
		
		// opens a project
		bool Open(void);
		
		// save a project
		bool Save(bool force = false);
		
		// save as -- copies all data in a new folder
		bool SaveAs(String const &path);
		
		// import an arduino sketch
		bool Import(String const &arduPath);

		// return project's title
		String GetTitle(void) const { return GetFileTitle(_name); }
		
		// return project's name
		String const &GetName(void) const { return _name; }
		
		// return project's folder
		String const &GetFolder(void) const { return _folder; }
		
		// return project's full path
		String GetFullPath(void) const;
		
		// return project's .INO path
		String GetINOPath(void) const;
		
		// xml support
		void Xmlize(XmlIO &xml);
		
		////// BUILD STUFFS ///////
		
		// builds the project
		bool Build(void) { return Builder.Build(this);}
		
		// upload to board
		bool Upload(void) { return Builder.Upload(this); }

		// show disassembly output
		bool ShowDisasm(void);

		// change handler - used to update menus and so
		Callback WhenChange;

		// splitters changes callback
		// used to synch splitter positions between projects
		// and to store their position(s) on exit
		Callback3<int, int, int> WhenSplitter;

		// sets splitter positions -- ProjectsCtrl handles it
		void SetSplitters(int h, int v, int fl);
		
		// Formats a string of code with a given formatter
		static WString FormatCodeString(WString const &Src, astyle::ASFormatter &Formatter);

		// Formats editor's code with Ide format parameters
		void FormatCode();
		
		// show path and other info on titlebar
		void ShowTitle(void);

		// given a path shows the tab, creating it if needed
		void ShowTab(String path);
		
		// display a message pane
		void ShowMessagePane(int pane);
		
		// handle changes in settings
		void SettingsChanged(void);
		
		// propagate theme apply to all opened editors
		void ThemeChanged(Theme const *t = NULL);
		
		// deleting file event -- used to forward closing
		// to all project that uses it
		Event<String> WhenDeletingFile;
		
		// get the find in files pane -- needed for finder
		ArrayCtrl &GetFindInFilesPane(void) { return _findInFilesPane; }
};

namespace Upp
{
	NTL_MOVEABLE(Project::LibraryState);

	template<>void Xmlize(XmlIO &xml, Project::LibraryState &state);
};

#endif
