/*
		Copyright 2006-2023 The QElectroTech Team
		This file is part of QElectroTech.

		QElectroTech 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.

		QElectroTech 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 QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/

#include "fileelementcollectionitem.h"

#include "../qetapp.h"
#include "../qeticons.h"
#include "elementslocation.h"

#include <QDir>

/**
	@brief FileElementCollectionItem::FileElementCollectionItem
	Constructor
*/
FileElementCollectionItem::FileElementCollectionItem()
{}

/**
	@brief FileElementCollectionItem::setRootPath
	Set path has root path for this file item.
	Use this function only to set the beginning of a file collection.
	@param path
	@param set_data
	@param hide_element
	@return true if path exist.
*/
bool FileElementCollectionItem::setRootPath(const QString& path,
					    bool set_data,
					    bool hide_element)
{
	QDir dir(path);
	if (dir.exists())
	{
		m_path = path;
		populate(set_data, hide_element);
		return true;
	}

	return false;
}

/**
	@brief FileElementCollectionItem::fileSystemPath
	@return the file system path of this item
*/
QString FileElementCollectionItem::fileSystemPath() const
{
	if (isCollectionRoot())
		return m_path;

	FileElementCollectionItem *feci =
			static_cast<FileElementCollectionItem *> (parent());
	if (feci)
		return feci->fileSystemPath() + "/" + m_path;
	else
		return QString();//Null string
}

/**
	@brief FileElementCollectionItem::dirPath
	@return the dir path of this item (if this item is a dir return the path,
	if item is an element return the path of the parent directory)
*/
QString FileElementCollectionItem::dirPath() const
{
	if (isDir())
		return fileSystemPath();
	else if (parent() && parent()->type() == FileElementCollectionItem::Type)
		return static_cast<FileElementCollectionItem*>(parent())->fileSystemPath();
	else
		return QString();//Null string
}

/**
	@brief FileElementCollectionItem::isDir
	@return true if this item represent a directory
*/
bool FileElementCollectionItem::isDir() const
{
	if (m_path.endsWith(".elmt"))
		return false;
	else
		return true;

}

/**
	@brief FileElementCollectionItem::isElement
	@return true if this item represent an element
*/
bool FileElementCollectionItem::isElement() const
{
	return (!isDir());
}

/**
	@brief FileElementCollectionItem::localName
	@return the located name of this item
*/
QString FileElementCollectionItem::localName()
{
	if (!text().isNull())
		return text();

	else if (isDir()) {
		if (isCollectionRoot()) {
			if (m_path == QETApp::commonElementsDirN())
				setText(QObject::tr("Collection QET"));
			else if (m_path == QETApp::customElementsDirN())
				setText(QObject::tr("Collection utilisateur"));
			else
				setText(QObject::tr("Collection inconnue"));
		}
		else
		{
			QString str(fileSystemPath() + "/qet_directory");
			pugi::xml_document docu;
			if(docu.load_file(str.toStdString().c_str()))
			{
				if (QString(docu.document_element().name())
						== "qet-directory")
				{
					NamesList nl;
					nl.fromXml(docu.document_element());
					setText(nl.name());
				}
			}
		}
	}
	else if (isElement()) {
		ElementsLocation loc(collectionPath());
		setText(loc.name());
	}

	return text();
}

/**
	@brief FileElementCollectionItem::localName
	Surcharged method, unlike the default method,
	avoid to create an elementLocation and so, gain time.
	@param location
	@return
*/
QString FileElementCollectionItem::localName(const ElementsLocation &location)
{
	if (!text().isNull())
		return text();

	else if (isDir()) {
		localName();
	}
	else if (isElement()) {
		setText(location.name());
	}

	return text();
}

/**
	@brief FileElementCollectionItem::name
	@return The collection name of this item
*/
QString FileElementCollectionItem::name() const
{
	if (isCollectionRoot())
		return QString();
	else
		return m_path;
}

/**
	@brief FileElementCollectionItem::collectionPath
	@return The path of this item relative to the collection.
*/
QString FileElementCollectionItem::collectionPath() const
{
	if (isCollectionRoot()) {
		if (m_path == QETApp::commonElementsDirN())
			return "common://";
		else
			return "custom://";
	}
	else if (parent() && parent()->type()
		 == FileElementCollectionItem::Type) {
		ElementCollectionItem *eci =
				static_cast<ElementCollectionItem*>(parent());
		if (eci->isCollectionRoot())
			return eci->collectionPath() + m_path;
		else
			return eci->collectionPath() + "/" + m_path;
	}
	else
		return QString();
}

/**
	@brief FileElementCollectionItem::isCollectionRoot
	@return true if this item represent the root of collection
*/
bool FileElementCollectionItem::isCollectionRoot() const
{
	if (m_path == QETApp::commonElementsDirN()
			|| m_path == QETApp::customElementsDirN())
		return true;
	else
		return false;
}

/**
	@brief FileElementCollectionItem::isCommonCollection
	@return True if this item represent the common collection
*/
bool FileElementCollectionItem::isCommonCollection() const
{
	return fileSystemPath().startsWith(QETApp::commonElementsDirN());
}

/**
	@brief FileElementCollectionItem::isCustomCollection
	@return True if this item represent the custom collection
*/
bool FileElementCollectionItem::isCustomCollection() const
{
	return fileSystemPath().startsWith(QETApp::customElementsDirN());
}

/**
	@brief FileElementCollectionItem::addChildAtPath
	Ask to this item item to add a child
	with collection name collection_name
	@param collection_name
*/
void FileElementCollectionItem::addChildAtPath(const QString &collection_name)
{
	if (collection_name.isEmpty())
		return;

	FileElementCollectionItem *feci = new FileElementCollectionItem();
	insertRow(rowForInsertItem(collection_name), feci);
	feci->setPathName(collection_name);
	feci->setUpData();
}

/**
	@brief FileElementCollectionItem::setUpData
	SetUp the data of this item
*/
void FileElementCollectionItem::setUpData()
{
	if (isDir())
	{
		localName();
		setFlags(Qt::ItemIsSelectable
			 | Qt::ItemIsDragEnabled
			 | Qt::ItemIsDropEnabled
			 | Qt::ItemIsEnabled);
	}
	else
	{
		setFlags(Qt::ItemIsSelectable
			 | Qt::ItemIsDragEnabled
			 | Qt::ItemIsEnabled);
		
		//Set the local name and all informations of the element
		//in the data Qt::UserRole+1, these data will be use for search.
		ElementsLocation loc(collectionPath());
		DiagramContext context = loc.elementInformations();
		QStringList search_list;
		for (QString& key : context.keys())
		{ search_list.append(context.value(key).toString()); }
		search_list.append(localName(loc));
		setData(search_list.join(" "));
	}

	setToolTip(collectionPath());
}

/**
	@brief FileElementCollectionItem::setUpIcon
	SetUp the icon of this item.
	Because icon use several memory,
	we use this method for setup icon instead setUpData.
*/
void FileElementCollectionItem::setUpIcon()
{
	if (!icon().isNull())
		return;

	if (isCollectionRoot()) {
		if (m_path == QETApp::commonElementsDirN())
			setIcon(QIcon(":/ico/16x16/qet.png"));
		else
			setIcon(QIcon(":/ico/16x16/go-home.png"));
	}
	else
	{
		if (isDir()) {
			setIcon(QET::Icons::Folder);
		} else {
			ElementsLocation loc(collectionPath());
			setIcon(loc.icon());
		}
	}
}

/**
	@brief FileElementCollectionItem::setPathName
	Set the name of this item in the file system path.
	This item must have a parent,
	because they should be a child item of another.
	For create a new file collection see setRootPath.
	@param path_name
	@param set_data
	@param hide_element
*/
void FileElementCollectionItem::setPathName(const QString& path_name,
					    bool set_data,
					    bool hide_element)
{
	m_path = path_name;

	//This isn't an element, we create the childs
	if (!path_name.endsWith(".elmt"))
		populate(set_data, hide_element);
}

/**
	@brief FileElementCollectionItem::populate
	Create the childs of this item
	@param set_data : if true, call setUpData for every child of this item
	@param hide_element
*/
void FileElementCollectionItem::populate(bool set_data, bool hide_element)
{
	QDir dir (fileSystemPath());

		//Get all directory in this directory.
	for (auto& str :
		 dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name))
	{
		FileElementCollectionItem *feci = new FileElementCollectionItem();
		appendRow(feci);
		feci->setPathName(str, set_data, hide_element);
		if (set_data)
			feci->setUpData();
	}

	if (hide_element)
		return;

		//Get all elmt file in this directory
	dir.setNameFilters(QStringList() << "*.elmt");
	for (auto& str :
		 dir.entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::Name))
	{
		FileElementCollectionItem *feci = new FileElementCollectionItem();
		appendRow(feci);
		feci->setPathName(str, set_data);
		if (set_data)
			feci->setUpData();
	}
}
