#include "lgi/common/Lgi.h"
#include "LgiIde.h"
#include "resdefs.h"
#include "ProjectNode.h"

//////////////////////////////////////////////////////////////////////////////////
IdeCommon::IdeCommon(IdeProject *p)
{
	Project = p;
}

IdeCommon::~IdeCommon()
{
	Remove();
}

bool IdeCommon::OnOpen(LProgressDlg *Prog, LXmlTag *Src)
{
	if (Prog)
		Prog->Value(Prog->Value() + 1);

	Copy(*Src);
	if (!Serialize(Write = false))
		return false;

	for (auto c: Src->Children)
	{
		if (Prog && Prog->IsCancelled())
			break;

		bool Processed = false;
		if (c->IsTag("Node"))
		{
			ProjectNode *pn = new ProjectNode(Project);
			if (pn && (Processed = pn->OnOpen(Prog, c)))
				InsertTag(pn);
		}
		else if (!c->IsTag("Settings"))
			return false;
		if (!Processed && Prog)
			Prog->Value(Prog->Value() + 1);
	}
	
	return true;
}

void IdeCommon::CollectAllSubProjects(List<IdeProject> &c)
{
	for (auto i:*this)
	{
		ProjectNode *p = dynamic_cast<ProjectNode*>(i);
		if (!p) break;

		if (p->GetType() == NodeDependancy)
		{
			if (p->GetDep())
				c.Insert(p->GetDep());
		}
		
		p->CollectAllSubProjects(c);
	}
}

IdePlatform GetCurrentPlatform()
{
	#if defined(WIN32)
	return PlatformWin;
	#elif defined(LINUX)
	return PlatformLinux;
	#elif defined(MAC)
	return PlatformMac;
	#elif defined(HAIKU)
	return PlatformHaiku;
	#else
	#error "Not impl."
	#endif
}

void IdeCommon::CollectAllSource(LArray<LString> &c, IdePlatform Platform)
{
	for (auto i:*this)
	{
		ProjectNode *p = dynamic_cast<ProjectNode*>(i);
		if (!p) break;

		switch (p->GetType())
		{
			case NodeSrc:
			case NodeHeader:
			{
				if (Platform == PlatformCurrent)
					Platform = GetCurrentPlatform();
					
				int Flags = p->GetPlatforms();
				if (Flags & (1 << Platform))
				{
					LString path = p->GetFullPath();
					if (path)
					{
						c.Add(path);
					}
				}
				break;
			}
			default:
			{
				break;
			}
		}
		
		p->CollectAllSource(c, Platform);
	}
}

void IdeCommon::SortChildren()
{
	Items.Sort(NodeSort);
	Children.Sort([](auto a, auto b)
	{
		LTreeItem *A = dynamic_cast<LTreeItem*>(*a);
		LTreeItem *B = dynamic_cast<LTreeItem*>(*b);
		return NodeSort(A, B);
	});
	
	if (Tree)
	{
		_RePour();
		Tree->Invalidate();
	}
}

void IdeCommon::InsertTag(LXmlTag *t)
{
	LXmlTag::InsertTag(t);

	LTreeItem *i = dynamic_cast<LTreeItem*>(t);
	if (i)
	{
		Insert(i);
	}
}

bool IdeCommon::RemoveTag()
{
	bool Status = LXmlTag::RemoveTag();
	Detach();
	return Status;
}

bool IdeCommon::AddFiles(AddFilesProgress *Prog, const char *Path)
{
	bool IsDir = LDirExists(Path);
	if (IsDir)
	{
		LString s = Path;
		LString::Array a = s.Split(DIR_STR);
		IdeCommon *Sub = GetSubFolder(Project, a.Last(), true);
		if (Sub)
		{
			LDirectory d;
			for (int b = d.First(Path); b && !Prog->Cancel; b = d.Next())
			{
				char p[MAX_PATH];
				if (d.Path(p, sizeof(p)))
				{
					char *Name = d.GetName();
					char *Ext = LGetExtension(p);
					if
					(
						(
							d.IsDir()
							||
							Prog->Exts.Find(Ext ? Ext : Name)
						)
						&&
						Name != NULL
						&&
						Name[0] != '.'
					)
					{
						Sub->AddFiles(Prog, p);
					}
				}
			}
			
			// If the folder is empty then just delete...
			if (Sub->GetChild() == NULL)
			{
				Sub->Remove();
				DeleteObj(Sub);
			}
			else
			{
				Sub->SortChildren();
			}
		}
		else LgiTrace("%s:%i - GetSubFolder failed\n", _FL);
	}
	else
	{
		// LProfile p("IdeCommon::AddFiles");
		// p.HideResultsIfBelow(50);
		if (!Project->InProject(false, Path, false))
		{
			// p.Add("new node");
			ProjectNode *New = new ProjectNode(Project);
			if (New)
			{
				// p.Add("set filename");
				New->SetFileName(Path);
				// p.Add("insert");
				InsertTag(New);
				// p.Add("set dirty");
				Project->SetDirty();

				if (Prog)
					Prog->Value(Prog->Value() + 1);
				
				return true;
			}
		}
	}
	
	return false;
}

IdeCommon *IdeCommon::GetSubFolder(IdeProject *Project, char *Name, bool Create)
{
	if (Name)
	{
		for (auto i:*this)
		{
			ProjectNode *c = dynamic_cast<ProjectNode*>(i);
			if (!c) break;

			if (c->GetType() == NodeDir)
			{
				if (c->GetName() && stricmp(c->GetName(), Name) == 0)
				{
					return c;
				}
			}
		}

		ProjectNode *New = new ProjectNode(Project);
		if (New)
		{
			New->SetName(Name);
			InsertTag(New);
			Project->SetDirty();
			return New;
		}
	}

	return 0;
}