#include "Dialogs.h"
#include "Settings.h"
#include "Images.h"
#include "LibraryPool.h"

///////////////////////////////////////////////////////////////////////
// ProgressPopup
///////////////////////////////////////////////////////////////////////

// constructor
ProgressPopup::ProgressPopup(String const &title)
{
	CtrlLayout(*this);
	progressText = title;
	progress.Percent();
	progress.Set(0, 100000);
	Size sz = GetScreenSize();
	Size csz = GetLayoutSize();
	SetRect((sz.cx - csz.cx) / 2, (sz.cy - csz.cy) / 2, csz.cx, csz.cy);
	
	_opened = false;
}

// destructor
ProgressPopup::~ProgressPopup()
{
	if(_opened)
		Close();
}

// show / hide me
void ProgressPopup::Show(void)
{
	if(_opened)
		return;
	PopUp();
	_opened = true;
}

void ProgressPopup::Hide(void)
{
	if(!_opened)
		return;
	Close();
	_opened = false;
}

// set progress
void ProgressPopup::Set(int pos, int max)
{
	progress.Set(pos, max);
	Ctrl::ProcessEvents();
}


///////////////////////////////////////////////////////////////////////
// CreateLibraryDialog
///////////////////////////////////////////////////////////////////////

// check dialog data
bool CreateLibraryDialog::Accept(void)
{
	// check if we're using a correct package name
	// (only letters and numbers and underscore and - sign
	String name = ~nameEdit;
	bool ok = !name.IsEmpty();
	for(int i = 0; i < name.GetCount(); i++)
	{
		char c = name[i];
		if(!IsAlNum(c) && c != '_' && c != '-')
		{
			ok = false;
			break;
		}
	}
	if(!ok)
	{
		Exclamation(t_("Invalid library name"));
		return false;
	}
	
	// check if library exists already
	String libPath = AppendFileName(Settings.GetUserLibsRoot(), String(~nameEdit));
	if(DirectoryExists(libPath))
	{
		Exclamation(Format(t_("Library '%s' already exists&Please choose another name"), ~nameEdit));
		return false;
	}
	
	// check architectures
	String arch = ToLower(TrimBoth(~architecturesEdit));
	if(arch.IsEmpty())
	{
		Exclamation(t_("Wrong 'architectures' field&must be '*' or a list of comma separated names"));
		return false;
	}
	if(arch != "*")
	{
		Vector<String>archs = Split(arch, ",");
		for(int i = 0; i < archs.GetCount(); i++)
		{
			String s = TrimBoth(archs[i]);
			for(int j = 0; j < s.GetCount(); j++)
				if(!isalnum(s[j]) && s[j] != '_')
				{
					Exclamation(t_("Wrong 'architectures' field&must be '*' or a list of comma separated names&containing only letters, numbers or underscores"));
					return false;
				}
		}
	}
	
	return true;
}

// constructor
CreateLibraryDialog::CreateLibraryDialog()
{
	CtrlLayout(*this);
	Title(t_("Create a new library"));
	
	// defaults to create both stubs
	exampleOption = 1;
	
	nameEdit.Clear();
	versionMajorEdit <<= 1;
	versionMinorEdit <<= 0;
	versionReleaseEdit <<= 0;
	
	categoryDrop.Clear();
	categoryDrop
		.Add("Display")
		.Add("Communication")
		.Add("Signal Input/Output")
		.Add("Sensors")
		.Add("Device Control")
		.Add("Timing")
		.Add("Data Storage")
		.Add("Data Processing")
		.Add("Other")
		.SetIndex(8)
	;
	architecturesEdit <<= "*";

	// connect buttons
	okBtn.Ok() << Acceptor(IDOK);
	cancelBtn.Cancel() << Rejector(IDCANCEL);
	
}
		
///////////////////////////////////////////////////////////////////////
// AddLibraryDialog
///////////////////////////////////////////////////////////////////////

// check dialog data
bool AddLibraryDialog::Accept(void)
{
	// check if we selected a library
	if(libsTab.GetCursor() < 0 || ctrls[libsTab.GetCursor()].GetCursor() < 0)
	{
		Exclamation(t_("Please select a library first"));
		return false;
	}
	
	return true;
}

// add and fill a list
void AddLibraryDialog::AddList(String const &type, VectorMap<String, String> const &names)
{
	ArrayCtrl &ctrl = ctrls.Add();
	ctrl.EvenRowColor(Blend(SColorPaper, SColorInfo, 100));
	ctrl.OddRowColor();
	ctrl.AddColumn(t_("Name"), 1).NoEdit();
	ctrl.AddColumn(t_("Description"), 3).NoEdit();
	ctrl.WhenLeftDouble << Acceptor(IDOK);
	libsTab.AddCtrl(ctrl, type);
	for(int i = 0; i < names.GetCount(); i++)
	{
		ctrl.Add();
		ctrl.Set(i, 0, names.GetKey(i));
		ctrl.Set(i, 1, names[i]);
	}
}
	

// constructor
AddLibraryDialog::AddLibraryDialog()
{
	CtrlLayout(*this);
	Title(t_("Open library"));
	
	// no close crosses
	libsTab.Crosses(false);

	AddList(t_("Platform"), LibraryPool.GetNamesDescs(LibraryInfo::PLATFORM));
	AddList(t_("System")  , LibraryPool.GetNamesDescs(LibraryInfo::SYSTEM));
	AddList(t_("User")    , LibraryPool.GetNamesDescs(LibraryInfo::USER));

	libsTab.SetCursor(0);
	Sizeable().Zoomable();

	// connect buttons
	okBtn.Ok() << Acceptor(IDOK);
	cancelBtn.Cancel() << Rejector(IDCANCEL);
}
		
// gets selected library
String AddLibraryDialog::GetLibrary(void)
{
	int iTab = libsTab.GetCursor();
	if(iTab < 0)
		return "";
	ArrayCtrl *c = (ArrayCtrl *)libsTab.GetCtrl(iTab);
	int idx = c->GetCursor();
	if( idx < 0)
		return "";
	return c->Get(idx, 0);
}

///////////////////////////////////////////////////////////////////////
// AddFilesDialog
///////////////////////////////////////////////////////////////////////

// constructor
AddFilesDialog::AddFilesDialog(String const &basePath, String const &libName)
{
	_basePath = basePath;
	_libName = libName;
	_checkExists = true;
}

// execute the dialog
bool AddFilesDialog::Run(void)
{
	if(!_basePath.IsEmpty())
		BaseDir(_basePath);
	else
		LoadFromGlobal(*this, "OthersFileDialogs");
		
	if(!_libName.IsEmpty())
		Title(Format(t_("Add files to '%s'"), _libName));
	else
		Title(t_("Create new files"));
	Multi();
	NoAsking();
	while(true)
	{
		if(!FileSel::ExecuteOpen())
			return false;
		
		if(_basePath.IsEmpty())
			StoreToGlobal(*this, "OthersFileDialogs");

		_paths.Clear();
		for(int i = 0; i < GetCount(); i++)
			_paths << GetFile(i);
		
		// check if any file is already existing
		if(_checkExists)
		{
			Vector<String> exists;
			for(int i = 0; i < _paths.GetCount(); i++)
				if(FileExists(AppendFileName(_basePath, _paths[i])))
					exists << _paths[i];
			if(!exists.IsEmpty())
			{
				if(!PromptYesNo(Format(t_("File(s) %s exist. Overwrite ?"), Join(exists, ","))))
				{
					_paths.Clear();
					continue;
				}
			}
		}
		return true;
	}
}

// gets the full selected path
Vector<String> const &AddFilesDialog::GetPaths(void) const
{
	return _paths;
}

/////////////////////////////////////////////////////////////////////////////////

// constructor
RenameExampleDialog::RenameExampleDialog(String const &name)
{
	CtrlLayout(*this);
	okBtn.Ok() <<= Acceptor(IDOK);
	cancelBtn.Cancel() <<= Rejector(IDCANCEL);
	newName = name;
	Title(Format(t_("Sketch '%s' already exists. Enter a new name:"), name));
}

// destructor
RenameExampleDialog::~RenameExampleDialog()
{
}

bool RenameExampleDialog::Accept(void)
{
	String name = ~newName;
	if(name.IsEmpty())
	{
		Exclamation(t_("Enter a valid sketch name"));
		return false;
	}
	String destPath = AppendFileName(Settings.GetSketchFolder(), name);
	if(DirectoryExists(destPath))
	{
		Exclamation(Format(t_("Sketch '%s' already exists.&Please choose a different name"), name));
		return false;
	}
	bool ok = RealizeDirectory(destPath);
	if(!ok)
	{
		Exclamation(t_("Enter a valid sketch name"));
		return false;
	}
	DirectoryDelete(destPath);
	return true;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void FindInFilesDlg::Sync()
{
	replace.Enable((int)~style);
	bool b = !regexp;
	wildcards.Enable(b);
	ignorecase.Enable(b);
	wholeword.Enable(b);
	folder.Enable(!workspace);
	folder_lbl.Enable(!workspace);
}

FindInFilesDlg::FindInFilesDlg()
{
	regexp <<= style <<= THISBACK(Sync);
	readonly.Add(Null, "All files");
	readonly.Add(0, "Writable");
	readonly.Add(1, "Read only");
	readonly <<= Null;
	workspace <<= THISBACK(Sync);
}

void FindInFilesDlg::Setup(bool replacing)
{
	Title(replacing ? "Find and replace in files" : "Find in files");
	replace_lbl.Show(replacing);
	style.Show(replacing);
	replace_lbl2.Show(replacing);
	replace.Show(replacing);
	Size sz = GetLayoutSize();
	if (!replacing)
		sz.cy -= replace.GetRect().bottom - folder.GetRect().bottom;
	Rect r = GetRect();
	r.SetSize(sz);
	SetRect(r);
	ActiveFocus(find);
}

bool FindInFilesDlg::Key(dword key, int count)
{
	if (key == K_CTRL_I)
	{
		if (find.HasFocus())
		{
			find <<= itext;
			return true;
		}
		if (replace.HasFocus())
		{
			replace <<= itext;
			return true;
		}
	}
	return TopWindow::Key(key, count);
}
