#include "LibraryManager.h"

#include "Libraries.h"
#include "Settings.h"
#include "Images.h"

// constructor
LibraryManagerPane::LibraryManagerPane(Library &library) : _library(library)
{
	CtrlLayout(*this);
	textBox.NoSb();
	
	_deltaHeight = GetSize().cy - textBox.GetSize().cy;
	actionButton <<= THISBACK(actionHandlerCb);
	versionDrop <<= THISBACK1(FillPane, false);
}

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

// install/remove/update button handler
void LibraryManagerPane::actionHandlerCb(void)
{
	// find the requested action
	MaintainerVersion sel = versionDrop.Get().ToString();
	
	if(_library.IsInstalled())
	{
		MaintainerVersion inst = _library.GetInstalledVersion();
		if(inst == sel)
		{
			// remove is requested
			_library.Remove();
		}
		else
		{
			// upgrade or downgrade
			_library.Install(sel);
		}
	}
	else
	{
		// install
		_library.Install(sel);
	}
	FillPane(false);
	WhenAction();
	
}

// sets background color
void LibraryManagerPane::BackColor(Upp::Color const &c)
{
	Background(c);
	textBox.Background(c);
}

// fill pane from platform
void LibraryManagerPane::FillPane(bool fillDrop)
{
	VectorMap<MaintainerVersion, LibraryVersion> const &versions = _library.GetVersions();
	bool isInstalled = _library.IsInstalled();
	if(fillDrop)
	{
		versionDrop.Clear();
		int installed = -1;
		for(int iVersion = 0; iVersion < versions.GetCount(); iVersion++)
		{
			MaintainerVersion ver = versions.GetKey(iVersion);
			versionDrop.Add(ver.ToString());
			if(isInstalled && ver == _library.GetInstalledVersion())
				installed = iVersion;
		}
		if(installed >= 0)
			versionDrop.SetIndex(installed);
		else
			versionDrop.SetIndex(0);
	}
	else
	{
	}
	// fill text area
	Zoom z = GetRichTextStdScreenZoom();
	textBox.SetZoom(z);

	LibraryVersion const &version = _library.GetVersions().Get(versionDrop.Get().ToString());
	String text = String("[1 [* ") + _library.GetName() + "]" + t_(" by ") + "[* " + version.GetMaintainer() + "]";
	if(_library.IsInstalled())
		text << "[/* __" << t_("Version") << "_" << _library.GetInstalledVersion() << "_" << t_("INSTALLED") << "]";
	text << "&";
	String sentence = DeQtf(version.GetSentence());
	while(sentence.Find("<br />") >= 0)
		sentence.Replace("<br />", "&");
	String paragraph = DeQtf(version.GetParagraph());
	while(paragraph.Find("<br />") >= 0)
		paragraph.Replace("<br />", "&");
	if(!sentence.IsEmpty())
		text << "[* " << sentence << "]. ";
	if(!paragraph.IsEmpty())
		text << paragraph;
	text += "&]";
	textBox.SetQTF(text);
	
	// fill button text
	if(_library.IsInstalled())
	{
		MaintainerVersion inst(_library.GetInstalledVersion());
		MaintainerVersion sel(versionDrop.Get().ToString());
		if(inst == sel)
			actionButton.SetLabel(t_("Remove"));
		else if(inst < sel)
			actionButton.SetLabel(t_("Update"));
		else
			actionButton.SetLabel(t_("Downgrade"));
	}
	else
		actionButton.SetLabel(t_("Install"));
}
	
///////////////////////////////////////////////////////////////////////////////////////////////	

// filter pane by current filters
bool LibraryManager::FilterPane(LibraryManagerPane &pane)
{
	bool show = true;
	Library const &lib = pane.GetLibrary();
	VectorMap<MaintainerVersion, LibraryVersion> const &versions = lib.GetVersions();
	int state = stateDrop.GetData();
	if(state > 0)
	{
		// 0 = any, 1 = installed, 2 = upgradable, 3 = not installed
		if(state <= 2 && !lib.IsInstalled())
			show = false;
		else if(state == 3 && lib.IsInstalled())
			show = false;
		else if(state == 2)
		{
			show = false;
			MaintainerVersion v = lib.GetInstalledVersion();
			for(int i = 0; i < versions.GetCount(); i++)
				if(versions.GetKey(i) > v)
				{
					show = true;
					break;
				}
		}
	}
	if(show && maintainerDrop.GetIndex() > 0)
	{
		// filter by maintainer
		show = false;
		String maintainer = maintainerDrop.Get();

		for(int i = 0; i < versions.GetCount(); i++)
			if(ExtractMaintainer(versions[i].GetMaintainer(), versions[i].GetAuthor()) == maintainer)
			{
				show = true;
				break;
			}
	}
	if(show && categoryDrop.GetIndex() > 0)
	{
		// filter by category
		show = false;
		String category = categoryDrop.Get();
		for(int i = 0; i < versions.GetCount(); i++)
			if(versions[i].GetCategory() == category)
			{
				show = true;
				break;
			}
	}
	String search = ToUpper(TrimBoth(~searchEdit));
	if(show && search != "")
	{
		// filter by text
		show = false;
		for(int i = 0; i < versions.GetCount(); i++)
		{
			LibraryVersion const &version = versions[i];
			if(
				ToUpper(version.GetSentence()).Find(search) >= 0 ||
				ToUpper(version.GetParagraph()).Find(search) >= 0
			)
			{
				show = true;
				break;
			}
		}
	}
	
	return show;
}

// action handler
void LibraryManager::actionCb(void)
{
	_modified = true;
	Layout();
}

// adjust layout
void LibraryManager::Layout(void)
{
	// setup scrollbar total size
	scrollBar.SetPage(panesArea.GetSize().cy);

	int _totalPanesHeight = 0;
	for(int iPane = 0; iPane < _panes.GetCount(); iPane++)
	{
		LibraryManagerPane &pane = _panes[iPane];
		if(FilterPane(pane))
			_totalPanesHeight += pane.GetSize().cy;
	}
	scrollBar.SetTotal(_totalPanesHeight);

	int y = -scrollBar.Get();
	int iColor = 0;
	for(int iPane = 0; iPane < _panes.GetCount(); iPane++)
	{
		LibraryManagerPane &pane = _panes[iPane];
		
		if(!FilterPane(pane))
		{
			pane.Hide();
			continue;
		}
		pane.BackColor((iColor++ % 2) ? Color(236, 241, 241) : Color(218, 227, 227));

		// adjust pane height to contain all text
		Zoom z = GetRichTextStdScreenZoom();
		int paneHeight = pane.textBox.Get().GetHeight(z, pane.textBox.GetSize().cx)  + pane.GetDeltaHeight();
		pane.SetRectY(pane.GetRect().top, paneHeight);

		pane.HSizePos();
		pane.TopPos(y, paneHeight);
		
		// this avoid problems when there are many panes
		// (probable UPP bug)
		if(y + paneHeight < 0 || y > GetSize().cy)
			pane.Hide();
		else
			pane.Show();
		
		y += paneHeight;
	}
}

// constructor
LibraryManager::LibraryManager()
{
	CtrlLayout(*this);
	Title(t_("Library manager"));
	Icon(FishIDEImg::Book());
	Sizeable();
	closeBtn << Breaker(IDCLOSE);
	_modified = false;
	
	stateDrop << THISBACK(Layout);
	maintainerDrop << THISBACK(Layout);
	categoryDrop << THISBACK(Layout);
	searchEdit.WhenAction << THISBACK(Layout);
	
	// fill panes with text from libraries
	// and gather providers and categories
	Index<String> maintainers;
	Index<String> categories;
	for(int iLibrary = 0; iLibrary < Libraries.GetCount(); iLibrary++)
	{
		Library &library = Libraries[iLibrary];
		VectorMap<MaintainerVersion, LibraryVersion> const &versions = library.GetVersions();
		for(int iVersion = 0; iVersion < versions.GetCount(); iVersion++)
		{
			LibraryVersion const &version = versions[iVersion];
			String maintainer = ExtractMaintainer(version.GetMaintainer(), version.GetAuthor());
			maintainers.FindAdd(maintainer);
			categories.FindAdd(version.GetCategory());
		}
		LibraryManagerPane &pane = _panes.Add(new LibraryManagerPane(library));
		pane.WhenAction = THISBACK(actionCb);
		pane.FillPane(true);
		panesArea.Add(pane);
	}
	
	// fill state drop
	stateDrop.Clear();
	stateDrop.Add(0, t_("Any"));
	stateDrop.AddSeparator();
	stateDrop.Add(1, t_("Installed"));
	stateDrop.Add(2, t_("Upgradable"));
	stateDrop.Add(3, t_("Not installed"));
	stateDrop.SetIndex(0);
	
	maintainers.RemoveKey("arduino");
	maintainers.RemoveKey("fishino");
	Vector<String> maintSorted = maintainers.PickKeys();
	Sort(maintSorted);
	
	maintainerDrop.Clear();
	maintainerDrop.Add(t_("Any"));
	maintainerDrop.AddSeparator();
	maintainerDrop.Add("fishino");
	maintainerDrop.Add("arduino");
	maintainerDrop.AddSeparator();
	for(int i = 0; i < maintSorted.GetCount(); i++)
		maintainerDrop.Add(maintSorted[i]);
	maintainerDrop.SetIndex(0);
	
	Vector<String> catSorted = 	categories.PickKeys();
	Sort(catSorted);

	categoryDrop.Clear();
	categoryDrop.Add(t_("Any"));
	categoryDrop.AddSeparator();
	for(int i = 0; i < catSorted.GetCount(); i++)
		categoryDrop.Add(catSorted[i]);
	categoryDrop.SetIndex(0);
	searchEdit.Clear();
		
	// force layout update to adjust rich text
	Layout();
	scrollBar.WhenScroll = THISBACK(Layout);
}

// destructor
LibraryManager::~LibraryManager()
{
	// if something has been modified, propagate change to IDE
	if(_modified)
		WhenChange();
}

void LibraryManager::MouseWheel(Point, int zdelta, dword)
{
	scrollBar.Wheel(zdelta * StdFont().Info().GetHeight() / 2);
}

bool LibraryManager::Key(dword key, int)
{
	return scrollBar.VertKey(key);
}

void LibraryManager::ChildMouseEvent(Ctrl *child, int event, Point p, int zdelta, dword keyflags)
{
	if((event & ACTION) == MOUSEWHEEL)
		MouseWheel(p, zdelta, keyflags);
}

