/*	Author:		Magdin Stoica
	Supervisor: Dr. Ryan Leduc
	
	Project created in conformity with the requirements for the Degree of Master of Engineering in Software Engineering, 
	Computing and Software Department, 
	McMaster University
	2003 - 2007
*/

#include <QHeaderView>
#include <QMessageBox>

#include "CommonDefinitions.h"
#include "RecentDocListUiPart.h"
#include "DesEditor.h"

namespace DESpot
{

const short RecentDocListUIPart::cDocListWidgColumnCount = 2;
const short RecentDocListUIPart::cDocNameColumnIdx = 0;
const short RecentDocListUIPart::cDocFileColumnIdx = 1;

const QString RecentDocListUIPart::cDesTag = "Des";
const QString RecentDocListUIPart::cProjectTag = "Project";
const QString RecentDocListUIPart::cDocNameAttr = "name";
const QString RecentDocListUIPart::cDocLocAttr = "location";

const QString RecentDocListUIPart::cProjectHeader = "Project Name";
const QString RecentDocListUIPart::cDesHeader = "Des Name";
const QString RecentDocListUIPart::cFileHeader = "File Path";


RecentDocListUIPart::RecentDocListUIPart(DocType docType, Ui::MainFormUI* pUiContainer, QDomElement& recentDocConfig): 
	m_docType(docType),	
	m_docListConfig(recentDocConfig)
{
	initUi(pUiContainer);

	setupConnections();

	initDocListWidget();

	loadDocList();
}

//_________________________________________________________________________________________________

RecentDocListUIPart::~RecentDocListUIPart(void)
{
}

//_________________________________________________________________________________________________

void RecentDocListUIPart::initUi(Ui::MainFormUI* pUiContainer)
{
	switch(m_docType)
	{
		case eProjectDoc:
			m_docListWidg = pUiContainer->m_recentProjectListWidg;
			m_docListWidg->setBoxWidget(pUiContainer->m_recentProjectGBox);
			m_removeCrtDocBtn = pUiContainer->m_RemoveProjectBtn;
			m_openCrtDocBtn = pUiContainer->m_openProjectBtn;

			m_docTag = cProjectTag;
			m_docHeader = cProjectHeader;
			break;

		case eDesDoc:
			m_docListWidg = pUiContainer->m_recentUsedDesListWidg;
			m_docListWidg->setBoxWidget(pUiContainer->m_recentDesGBox);
			m_openCrtDocBtn = pUiContainer->m_openDesBtn;
			m_removeCrtDocBtn = pUiContainer->m_removeDesBtn;

			m_docTag = cDesTag;
			m_docHeader = cDesHeader;

			break;
	}
}

//_________________________________________________________________________________________________

void RecentDocListUIPart::setupConnections()
{
	connect(m_docListWidg, SIGNAL(onWidthChanged(int)), 
		    this, SLOT(resizeDocListWidgHeaders(int)));

	connect(m_openCrtDocBtn, SIGNAL(pressed()), this, SLOT(onOpenCrtDoc()));
	connect(m_removeCrtDocBtn, SIGNAL(pressed()), this, SLOT(onRemoveCrtDoc()));

	connect(m_docListWidg, SIGNAL(itemActivated(QTreeWidgetItem*, int)),
			this, SLOT(onOpenCrtDoc()));

	connect(m_docListWidg, SIGNAL(onCurrentItemDeleted()),
			this, SLOT(onRemoveCrtDoc()));
}

//_________________________________________________________________________________________________

void RecentDocListUIPart::initDocListWidget()
{
	m_docListWidg->setRootIsDecorated(false);
	
	//add two columns: Doc Name | Path		
	m_docListWidg->setColumnCount(cDocListWidgColumnCount);
	
	QStringList headers;
	headers << m_docHeader << cFileHeader;
	m_docListWidg->setHeaderLabels(headers);
	m_docListWidg->header()->setStretchLastSection(true);

	resizeDocListWidgHeaders(m_docListWidg->geometry().width());
}

//_________________________________________________________________________________________________

void RecentDocListUIPart::resizeDocListWidgHeaders(int width)
{	
	int fileNameColSizeHint = m_docListWidg->header()->sectionSizeHint(cDocFileColumnIdx);

	m_docListWidg->resizeColumnToContents(cDocNameColumnIdx);
	int sizeRemaining = width - m_docListWidg->header()->sectionSize(cDocNameColumnIdx);

	if (sizeRemaining < m_docListWidg->header()->sectionSizeHint(cDocFileColumnIdx))
	{
		//there must be room at least for the header to display properlly "File Name". The rest
		//will be given to the name although some long names won't show completely
		m_docListWidg->header()->resizeSection(cDocFileColumnIdx, fileNameColSizeHint);
		m_docListWidg->header()->resizeSection(cDocNameColumnIdx, width - fileNameColSizeHint);
	}
	else
	{
		//perform the resize as there is enough renaming space to show the file name header
		m_docListWidg->header()->resizeSection(cDocFileColumnIdx, sizeRemaining);
	}
}

//_________________________________________________________________________________________________

void RecentDocListUIPart::loadDocList()
{
	QDomNode desNode = m_docListConfig.firstChild();
	while (desNode.isNull() == false)
	{
		QDomElement docElem = desNode.toElement();
		if (docElem.tagName() == m_docTag)
		{
			QString desName = docElem.attribute(cDocNameAttr);
			QString desLoc = docElem.attribute(cDocLocAttr);
			QString tooltip("%1 - %2");

			//add an item in the des list widget
			QTreeWidgetItem* docItem = new QTreeWidgetItem(m_docListWidg);
			docItem->setText(cDocNameColumnIdx, desName);
			docItem->setText(cDocFileColumnIdx, desLoc);
			docItem->setToolTip(cDocNameColumnIdx, tooltip.arg(desName, desLoc));
			docItem->setToolTip(cDocFileColumnIdx, tooltip.arg(desName, desLoc));
		}

		desNode= desNode.nextSibling();
	}

	//set the first item as the current item
	m_docListWidg->setCurrentItem(m_docListWidg->topLevelItem(0));
}

//_________________________________________________________________________________________________

bool RecentDocListUIPart::findDoc(const QString& desLocation, QTreeWidgetItem*& out_item, int& out_index)
{
	for(int iItem = 0; iItem < m_docListWidg->topLevelItemCount(); iItem++)
	{
		//obtain the project name and location
		QTreeWidgetItem* crtItem = m_docListWidg->topLevelItem(iItem);
		QString crtLoc = crtItem->text(cDocFileColumnIdx);

		if (desLocation == crtLoc)
		{
			//found it
			out_index = iItem;
			out_item = crtItem;
			return true;
		}
	}

	return false;
}

//_________________________________________________________________________________________________

bool RecentDocListUIPart::checkFormType(DespotForm* docForm)
{
	// Switch on which type of document this UI part is responsible for
	switch(m_docType)
	{
		case eProjectDoc:
			return (docForm->type() == DespotForm::eFlatProjectEditor) || 
				   (docForm->type() == DespotForm::eHierProjectEditor);

		case eDesDoc:
			return (docForm->type() == DespotForm::eDesEditor) ||
				   (docForm->type() == DespotForm::eGedDesEditor);

		default:
			assert(false); //unknown document type
			return false;
	}
}

//_________________________________________________________________________________________________

void RecentDocListUIPart::onDocumentFormOpened(DespotForm* docForm)
{	
	if (checkFormType(docForm) && docForm->openedFromFile())
	{
		QString docFile = docForm->getDocFileName();

		//if this project is already in the recently used project list move it
		//right at the top of the list
		QTreeWidgetItem* existingItem = null;
		int crtIndex = -1;
		if (findDoc(docFile, existingItem, crtIndex))
		{
			if (crtIndex > 0)
			{
				//the item was found and is not first in list so make it first
				m_docListWidg->takeTopLevelItem(crtIndex);
				m_docListWidg->insertTopLevelItem(0, existingItem);				
			}
			//else the item was found and it is first in list so there is nothing to do

			m_openedFormsMap[docForm] = existingItem;
		}
		else
		{
			//add an item in the dest list widget
			QTreeWidgetItem* docItem = new QTreeWidgetItem();
			docItem->setText(cDocNameColumnIdx, docForm->getDocName());
			docItem->setText(cDocFileColumnIdx, docFile);
			docItem->setToolTip(cDocNameColumnIdx, docFile);
			docItem->setToolTip(cDocFileColumnIdx, docFile);
			
			m_docListWidg->insertTopLevelItem(0, docItem);
			
			m_openedFormsMap[docForm] = docItem;
		}

		docForm->window()->installEventFilter(this);
	}
}

//_________________________________________________________________________________________________

void RecentDocListUIPart::onDocumentFormClosed(DespotForm* /*docForm*/)
{
}

//_________________________________________________________________________________________________

void RecentDocListUIPart::saveConfig(QDomDocument& configDoc)
{
	//clear all des elements from the initial configuration
	QDomElement docElem = m_docListConfig.firstChildElement(m_docTag);
	while (docElem.isNull() == false)
	{
		m_docListConfig.removeChild(docElem);
		
		docElem = m_docListConfig.firstChildElement(m_docTag); 
	}

	//add new elements for all the items in the configuration
	for (int iItem = 0; iItem < m_docListWidg->topLevelItemCount(); iItem++)
	{
		//obtain the des name and location
		QTreeWidgetItem* crtItem = m_docListWidg->topLevelItem(iItem);
		QString desName = crtItem->text(cDocNameColumnIdx);
		QString desLoc = crtItem->text(cDocFileColumnIdx);
		
		QDomElement docElem = configDoc.createElement(m_docTag);
		docElem.setAttribute(cDocLocAttr, desLoc);
		docElem.setAttribute(cDocNameAttr, desName);

		//add the newly created des element to the configuration data
		m_docListConfig.appendChild(docElem);
	}

}

//_________________________________________________________________________________________________

void RecentDocListUIPart::onOpenCrtDoc()
{
	QTreeWidgetItem* crtDocItem = m_docListWidg->currentItem();
	if (crtDocItem)
	{
		QString docFile = crtDocItem->text(cDocFileColumnIdx);				
		emit onOpenDocument(docFile);
	}
}

//_________________________________________________________________________________________________

void RecentDocListUIPart::onRemoveCrtDoc()
{
	QTreeWidgetItem* crtDocItem = m_docListWidg->currentItem();
	m_docListWidg->takeTopLevelItem(m_docListWidg->indexOfTopLevelItem(crtDocItem));
}

//_________________________________________________________________________________________________

bool RecentDocListUIPart::eventFilter(QObject* target, QEvent* event)
{
	if (event->type() == QEvent::Close)
	{
		//One of the windows displayed in this UiPart is beeing closed
		//Find it and remove it from the list of opened windows
		QMainWindow* closingWnd = dynamic_cast<QMainWindow*>(target);
		updateDocConfig(closingWnd); //this must be done now and not when the form notification
		                             //is sent because by then we have no information on the name of document and file
	}

	return QObject::eventFilter(target, event);
}

//_________________________________________________________________________________________________

void RecentDocListUIPart::updateDocConfig(QMainWindow* closingWnd)
{
	for(FormMapIt it = m_openedFormsMap.begin(); it != m_openedFormsMap.end(); it++)
	{
		DespotForm* crtForm = it->first;
		QTreeWidgetItem* crtItem = it->second;
		QMainWindow* crtWnd = crtForm->window();
		if (crtWnd == closingWnd)
		{
			//found the form; update the configuration
			crtItem->setText(cDocNameColumnIdx, crtForm->getDocName());
			crtItem->setText(cDocFileColumnIdx, crtForm->getDocFileName());
			crtItem->setToolTip(cDocNameColumnIdx, crtForm->getDocFileName());
			crtItem->setToolTip(cDocFileColumnIdx, crtForm->getDocFileName());
			return;
		}
	}
}

} //end of namespace DESpot
