/* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */

/* AbiWord
 * Copyright (C) 1998 AbiSource, Inc.
 * Copyright (C) 2003 Hubert Figuiere
 * 
 * This program 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.
 * 
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
 * 02111-1307, USA.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "ap_Features.h"
#include "ut_types.h"
#include "ut_string.h"
#include "ut_assert.h"
#include "ut_debugmsg.h"
#include "ev_Toolbar_Layouts.h"
#include "ev_Toolbar_Actions.h"
#include "xap_App.h"
#include "xap_Toolbar_Layouts.h"
#include "xap_Prefs.h"
#include "xap_Prefs_SchemeIds.h"
#include "ap_Toolbar_Id.h"
#include "ap_Strings.h"
#include "ap_Prefs_SchemeIds.h"

/*****************************************************************
******************************************************************
** Here we begin a little CPP magic to load the layout for each
** toolbar layout in the application.  It is important that all of
** the ...Layout_*.h files allow themselves to be included more
** than one time.
******************************************************************
*****************************************************************/

#define BeginLayout(Name, Label, prefKey)		static struct XAP_Toolbar_Factory_lt s_ltTable_##Name[] = {
#define ToolbarItem(id)			{ EV_TLF_Normal,		(id)					},
#define Spacer()				{ EV_TLF_Spacer,		AP_TOOLBAR_ID__BOGUS1__	},
#define EndLayout()				};

#include "ap_Toolbar_Layouts_All.h"

#undef BeginLayout
#undef ToolbarItem
#undef Spacer
#undef EndLayout

/*****************************************************************
******************************************************************
** Here we begin a little CPP magic to construct a table containing
** the names and addresses of all the tables we constructed in the
** previous section.
******************************************************************
*****************************************************************/

#define BeginLayout(Name, Label, prefKey)		{ #Name, Label, prefKey, G_N_ELEMENTS(s_ltTable_##Name), s_ltTable_##Name },
#define ToolbarItem(id)			/*nothing*/
#define Spacer()				/*nothing*/
#define EndLayout()				/*nothing*/

static struct XAP_Toolbar_Factory_tt s_ttTable[] =
{

#include "ap_Toolbar_Layouts_All.h"
	
};

#undef BeginLayout
#undef ToolbarItem
#undef Spacer
#undef EndLayout

/*****************************************************************
******************************************************************
** Put it all together and have a "load Layout by Name"
******************************************************************
*****************************************************************/


XAP_Toolbar_Factory_vec::XAP_Toolbar_Factory_vec(const char * szName)
{
	m_name = szName;
	m_label = 0;
	m_prefKey = NULL;
	m_Vec_lt.clear();
}

XAP_Toolbar_Factory_vec::XAP_Toolbar_Factory_vec(XAP_Toolbar_Factory_tt * orig)
{
	m_name = orig->m_name;
	m_label = orig->m_label;
	m_prefKey = orig->m_prefKey;
	UT_uint32 i = 0;
	m_Vec_lt.clear();
	for(i=0; i < orig->m_nrEntries; i++)
	{
		XAP_Toolbar_Factory_lt * plt = new XAP_Toolbar_Factory_lt;
		plt->m_flags = orig->m_lt[i].m_flags;
		plt->m_id = orig->m_lt[i].m_id;
		m_Vec_lt.addItem((void *) plt);
	}
}

XAP_Toolbar_Factory_vec::XAP_Toolbar_Factory_vec(EV_Toolbar_Layout * orig)
	: m_label(0),
		m_prefKey(NULL)
{
	m_name = orig->getName();
	UT_uint32 i = 0;
	m_Vec_lt.clear();
	for(i=0; i < orig->getLayoutItemCount(); i++)
	{
		XAP_Toolbar_Factory_lt * plt = new XAP_Toolbar_Factory_lt;
		plt->m_flags = orig->getLayoutItem(i)->getToolbarLayoutFlags();
		plt->m_id = orig->getLayoutItem(i)->getToolbarId();
		m_Vec_lt.addItem((void *) plt);
	}
}

XAP_Toolbar_Factory_vec::~XAP_Toolbar_Factory_vec(void)
{
	UT_VECTOR_PURGEALL(XAP_Toolbar_Factory_lt *,m_Vec_lt);
}


UT_uint32 XAP_Toolbar_Factory_vec::getNrEntries(void)
{
	return m_Vec_lt.getItemCount();
}

/*!
 * Used to manually construct a XAP_Toolbar_Factory_vec from a preference
 * scheme
 */
void XAP_Toolbar_Factory_vec::add_lt(XAP_Toolbar_Factory_lt * plt)
{
	m_Vec_lt.addItem((void *) plt);
}

XAP_Toolbar_Factory_lt * XAP_Toolbar_Factory_vec::getNth_lt(UT_uint32 i)
{
	XAP_Toolbar_Factory_lt * plt = (XAP_Toolbar_Factory_lt *) m_Vec_lt.getNthItem(i);
	return plt;
}


void XAP_Toolbar_Factory_vec::insertItemBefore(void * p, XAP_Toolbar_Id id)
{
	UT_sint32 i = 0;
	bool bFound = false;
	for(i=0; !bFound && (i< m_Vec_lt.getItemCount()); i++)
	{
		XAP_Toolbar_Factory_lt * plt = (XAP_Toolbar_Factory_lt *) m_Vec_lt.getNthItem(i);
		if(plt->m_id == id)
		{
			m_Vec_lt.insertItemAt(p,i);
			bFound = true;
			break;
		}
	}
	UT_ASSERT_HARMLESS(bFound);
}


void XAP_Toolbar_Factory_vec::insertItemAfter(void * p, XAP_Toolbar_Id id)
{
	UT_sint32 i = 0;
	bool bFound = false;
	for(i=0; !bFound && (i< m_Vec_lt.getItemCount()); i++)
	{
		XAP_Toolbar_Factory_lt * plt = (XAP_Toolbar_Factory_lt *) m_Vec_lt.getNthItem(i);
		if(plt->m_id == id)
		{
			if((i+1) == m_Vec_lt.getItemCount())
			{
				m_Vec_lt.addItem(p);
			}
			else
			{
				m_Vec_lt.insertItemAt(p,i+1);
			}
			bFound = true;
			break;
		}
	}
	UT_ASSERT_HARMLESS(bFound);
}

void XAP_Toolbar_Factory_vec::insertLastItem(void * p)
{
	m_Vec_lt.addItem(p);
}

bool XAP_Toolbar_Factory_vec::removeToolbarId(XAP_Toolbar_Id id)
{
	UT_sint32 i = 0;
	bool bFound = false;
	for(i=0; !bFound && (i< m_Vec_lt.getItemCount()); i++)
	{
		XAP_Toolbar_Factory_lt * plt = (XAP_Toolbar_Factory_lt *) m_Vec_lt.getNthItem(i);
		if(plt->m_id == id)
		{
			m_Vec_lt.deleteNthItem(i);
			bFound = true;
			DELETEP(plt);
			break;
		}
	}
	UT_ASSERT_HARMLESS(bFound);
	return true;
}

const char * XAP_Toolbar_Factory_vec::getToolbarName(void)
{
	return m_name.c_str();
}

XAP_String_Id XAP_Toolbar_Factory_vec::getLabelStringID(void)
{
	return m_label;
}

const gchar * XAP_Toolbar_Factory_vec::getPrefKey(void)
{
	return m_prefKey;
}

/***************************************************************************/

XAP_Toolbar_Factory::XAP_Toolbar_Factory(XAP_App * pApp)
	: m_pApp(pApp)
{
	UT_uint32 i = 0;
	UT_uint32 count = G_N_ELEMENTS(s_ttTable);
//
// FIXME: Put in check on preference
//
	for(i=0; i < count; i++)
	{
		XAP_Toolbar_Factory_vec * pVec = new XAP_Toolbar_Factory_vec(&s_ttTable[i]);
		m_vecTT.addItem((void *) pVec);
	}
}


XAP_Toolbar_Factory::~XAP_Toolbar_Factory(void)
{
	UT_VECTOR_PURGEALL(XAP_Toolbar_Factory_vec *,m_vecTT);
	UT_VECTOR_PURGEALL(UT_UTF8String*, m_tbNames);
}

/*!
	Get the toolbar names.
	
	\note return value should NOT be copied.... because UT_Vector doesn't like copy for now.
 */
const UT_Vector &
XAP_Toolbar_Factory::getToolbarNames(void)
{
	const XAP_StringSet * pSS = m_pApp->getStringSet();
	UT_uint32 i;
	UT_uint32 count = m_vecTT.getItemCount();
	
	//here we can introduce a serious optimization by checking 
	//that we don't have a already set m_tbNames....
	//for now we just clear and restart.
	UT_VECTOR_PURGEALL(UT_UTF8String*, m_tbNames);
	m_tbNames.clear();
	for (i = 0; i < count; i++) {
		XAP_Toolbar_Factory_vec * pVec = (XAP_Toolbar_Factory_vec *) m_vecTT.getNthItem(i);
		XAP_String_Id label =  pVec->getLabelStringID();
		UT_UTF8String * str = new UT_UTF8String;
		pSS->getValueUTF8(label,*str);
		m_tbNames.addItem(str);
	}
	return m_tbNames;
}

/*!
	Returns the number of toolbars in the factory.
 */
UT_uint32	XAP_Toolbar_Factory::countToolbars(void) const
{
	return m_vecTT.getItemCount();
}

/*!
	Return the Prefs key for the toolbar.
 */
const
gchar* XAP_Toolbar_Factory::prefKeyForToolbar(UT_uint32 t) const
{
	XAP_Toolbar_Factory_vec * pVec = (XAP_Toolbar_Factory_vec *) m_vecTT.getNthItem(t);
	return pVec->getPrefKey();
}


EV_Toolbar_Layout * XAP_Toolbar_Factory::CreateToolbarLayout(const char * szName)
{
	UT_uint32 count = m_vecTT.getItemCount();  // NO toolabrs
	UT_uint32 i = 0;
	bool bFound = false;
	EV_Toolbar_Layout * pLayout = NULL;

	for (i=0; !bFound && (i < count); i++)
	{
		XAP_Toolbar_Factory_vec * pVec = (XAP_Toolbar_Factory_vec *) m_vecTT.getNthItem(i);
		const char * szCurName =  pVec->getToolbarName();
		if (g_ascii_strcasecmp(szName,szCurName)==0)
		{
			bFound = true;
			pLayout = new EV_Toolbar_Layout(pVec->getToolbarName(),pVec->getNrEntries());
			
			UT_return_val_if_fail (pLayout, NULL);
			UT_uint32 k = 0;
			for (k=0; k < pVec->getNrEntries(); k++)
			{
				XAP_Toolbar_Factory_lt * plt = pVec->getNth_lt(k);
				UT_DebugOnly<bool> bResult = pLayout->setLayoutItem(k, plt->m_id, plt->m_flags);
				UT_ASSERT_HARMLESS(bResult);
			}
			break;
		}
	}
	UT_ASSERT_HARMLESS(bFound);
	if(bFound)
	{
		return pLayout;
	} 
	else {
		fprintf (stderr, "%s:%d: Layout `%s' not found\n", __FILE__, __LINE__, szName);
	}
	return NULL;
}

EV_Toolbar_Layout * XAP_Toolbar_Factory::DuplicateToolbarLayout(const char * szName)
{
	return CreateToolbarLayout(szName);
}

/*!
 * This restores a toolbar layout in memory to a version previously constructed
 * and used as Toolbar.
 */
void XAP_Toolbar_Factory::restoreToolbarLayout(EV_Toolbar_Layout *pTB)
{
	UT_return_if_fail (pTB);
	UT_String strName = pTB->getName();
	UT_uint32 count = m_vecTT.getItemCount();  // NO toolabrs
	UT_uint32 i = 0;
	bool bFound = false;
	XAP_Toolbar_Factory_vec * pVec = NULL;
	for (i=0; !bFound && (i < count); i++)
	{
		pVec = (XAP_Toolbar_Factory_vec *) m_vecTT.getNthItem(i);
		const char * szCurName =  pVec->getToolbarName();
		if (g_ascii_strcasecmp(strName.c_str(),szCurName)==0)
		{
			bFound = true;
			break;
		}
	}
	UT_ASSERT_HARMLESS(bFound);
	DELETEP(pVec);
	pVec = new XAP_Toolbar_Factory_vec(pTB);
	m_vecTT.setNthItem(i, (void *) pVec, NULL);
}


/*!
 * This method inserts an icon before the icon number beforeId
 */			
bool  XAP_Toolbar_Factory::addIconBefore(const char * szName,
								   XAP_Toolbar_Id newId, 
								   XAP_Toolbar_Id beforeId)
{
	UT_uint32 count = m_vecTT.getItemCount();  // NO toolabrs
	UT_uint32 i = 0;
	bool bFound = false;
	XAP_Toolbar_Factory_vec * pVec = NULL;
	for (i=0; !bFound && (i < count); i++)
	{
		pVec = (XAP_Toolbar_Factory_vec *) m_vecTT.getNthItem(i);
		const char * szCurName =  pVec->getToolbarName();
		if (g_ascii_strcasecmp(szName,szCurName)==0)
		{
			bFound = true;
			break;
		}
	}
	UT_ASSERT_HARMLESS(bFound);
	if(!bFound)
	{
		return false;
	}
	XAP_Toolbar_Factory_lt * plt = new  XAP_Toolbar_Factory_lt;
	plt->m_id = newId;
	plt->m_flags = EV_TLF_Normal;
	pVec->insertItemBefore((void *) plt, beforeId);
	return true;
}

/*!
 * This method adds an icon at the last position on a toolbar.
 */			
bool  XAP_Toolbar_Factory::addIconAtEnd(const char * szName,
								   XAP_Toolbar_Id newId )
{
	UT_uint32 count = m_vecTT.getItemCount();  // NO toolabrs
	UT_uint32 i = 0;
	bool bFound = false;
	XAP_Toolbar_Factory_vec * pVec = NULL;
	for (i=0; !bFound && (i < count); i++)
	{
		pVec = (XAP_Toolbar_Factory_vec *) m_vecTT.getNthItem(i);
		const char * szCurName =  pVec->getToolbarName();
		if (g_ascii_strcasecmp(szName,szCurName)==0)
		{
			bFound = true;
			break;
		}
	}
	UT_ASSERT_HARMLESS(bFound);
	if(!bFound)
	{
		return false;
	}
	XAP_Toolbar_Factory_lt * plt = new  XAP_Toolbar_Factory_lt;
	plt->m_id = newId;
	plt->m_flags = EV_TLF_Normal;
	pVec->insertLastItem((void *) plt);
	return true;
}

			
bool  XAP_Toolbar_Factory::addIconAfter(const char * szName,
								   XAP_Toolbar_Id newId, 
								   XAP_Toolbar_Id afterId)
{
	UT_uint32 count = m_vecTT.getItemCount();  // NO toolabrs
	UT_uint32 i = 0;
	bool bFound = false;
	XAP_Toolbar_Factory_vec * pVec = NULL;
	for (i=0; !bFound && (i < count); i++)
	{
		pVec = (XAP_Toolbar_Factory_vec *) m_vecTT.getNthItem(i);
		const char * szCurName =  pVec->getToolbarName();
		if (g_ascii_strcasecmp(szName,szCurName)==0)
		{
			bFound = true;
			break;
		}
	}
	UT_ASSERT_HARMLESS(bFound);
	if(!bFound)
	{
		return false;
	}
	XAP_Toolbar_Factory_lt * plt = new  XAP_Toolbar_Factory_lt;
	plt->m_id = newId;
	plt->m_flags = EV_TLF_Normal;
	pVec->insertItemAfter((void *) plt, afterId);
	return true;
}

			
bool  XAP_Toolbar_Factory::removeIcon(const char * szName,
									  XAP_Toolbar_Id nukeId)
{
	UT_uint32 count = m_vecTT.getItemCount();  // NO toolabrs
	UT_uint32 i = 0;
	bool bFound = false;
	XAP_Toolbar_Factory_vec * pVec = NULL;
	for (i=0; !bFound && (i < count); i++)
	{
		pVec = (XAP_Toolbar_Factory_vec *) m_vecTT.getNthItem(i);
		const char * szCurName =  pVec->getToolbarName();
		if (g_ascii_strcasecmp(szName,szCurName)==0)
		{
			bFound = true;
			break;
		}
	}
	UT_ASSERT_HARMLESS(bFound);
	if(!bFound)
	{
		return false;
	}
	pVec->removeToolbarId(nukeId);
	return true;
}

/*!
 * This method saves the current toolbar layouts in the current preference
 * scheme. There are 3 generic keys.
 * The Number of entries ((Base Key for Nr entries)+(TB name))
 * The ith ID ((Base Key for id)+(TB name)+(i))
 * The ith Flag ((Base Key for flag)+(TB name)+(i))
 */
bool  XAP_Toolbar_Factory::saveToolbarsInCurrentScheme(void)
{
	XAP_Prefs *pPrefs = m_pApp->getPrefs();
	XAP_PrefsScheme *pScheme = pPrefs->getCurrentScheme(true);
	char buf[100];
	XAP_Toolbar_Factory_vec * pVec = NULL;
	UT_uint32 numTB = m_vecTT.getItemCount();  // NO toolabrs
	UT_uint32 iTB,iLay;
	for(iTB=0; iTB< numTB;iTB++)
	{
		UT_String sTBBase = XAP_PREF_KEY_ToolbarNumEntries;
		pVec = (XAP_Toolbar_Factory_vec *) m_vecTT.getNthItem(iTB);
		const char * szCurName =  pVec->getToolbarName();
//
// Save Number of entries in contructed key
//
		sTBBase +=szCurName;
		UT_uint32 NrEntries = pVec->getNrEntries();
		UT_DEBUGMSG(("SEVIOR: Number of entries in TB %d \n",NrEntries));
		sprintf(buf,"%d",NrEntries);
		pScheme->setValue((const gchar *)sTBBase.c_str(),(const gchar *) buf );
//
// Loop through this toolbar definition and save it in the preferences
//		
		for(iLay =0; iLay< NrEntries;iLay++)
		{
			XAP_Toolbar_Factory_lt * plt = pVec->getNth_lt(iLay);
			sTBBase = XAP_PREF_KEY_ToolbarID;
			sTBBase += szCurName;
//
// Save id in contructed key
//
			XAP_Toolbar_Id curId = plt->m_id;
			EV_Toolbar_LayoutFlags curFlag = plt->m_flags;
			sprintf(buf,"%d",iLay);
			sTBBase += buf;
			sprintf(buf,"%d",curId);
			pScheme->setValue((const gchar *) sTBBase.c_str(),(const gchar *) buf );
//
// Save flags in contructed key
//
			sTBBase = XAP_PREF_KEY_ToolbarFlag;
			sTBBase += szCurName;
			sprintf(buf,"%d",iLay);
			sTBBase += buf;
			sprintf(buf,"%d",curFlag);
			pScheme->setValue((const gchar *) sTBBase.c_str(),(const gchar *) buf );
		}
	}
	return true;
}


/*!
 * This method restores the toolbar layouts from the current preference
 * scheme. There are 3 generic keys.
 * The Number of entries ((Base Key for Nr entries)+(TB name))
 * The ith ID ((Base Key for id)+(TB name)+(i))
 * The ith Flag ((Base Key for flag)+(TB name)+(i))
 */
bool  XAP_Toolbar_Factory::restoreToolbarsFromCurrentScheme(void)
{
//
// First delete the current layouts.
//
	UT_VECTOR_PURGEALL(XAP_Toolbar_Factory_vec *,m_vecTT);
	m_vecTT.clear();
//
// Get the current scheme
//
	XAP_Prefs *pPrefs = m_pApp->getPrefs();
	XAP_PrefsScheme *pScheme = pPrefs->getCurrentScheme(true);
	char buf[100];
	XAP_Toolbar_Factory_vec * pVec = NULL;
//
// Get number of toolbars hardwired into abiword.
//
	UT_uint32 numTB = G_N_ELEMENTS(s_ttTable);  // NO toolabrs
	UT_uint32 iTB,iLay;
	for(iTB=0; iTB< numTB;iTB++)
	{
		UT_String sTBBase = XAP_PREF_KEY_ToolbarNumEntries;
		const char * szCurName =  s_ttTable[iTB].m_name;
		sTBBase +=szCurName;
		const gchar * szNrEntries = NULL;
		UT_uint32 NrEntries = 0;
//
// Get Number of entries if the correct key exists. Otherwise use defaults.
//
		pScheme->getValue((const gchar *)sTBBase.c_str(),&szNrEntries);
		if(szNrEntries && *szNrEntries)
		{	
			pVec = new XAP_Toolbar_Factory_vec(szCurName);
			m_vecTT.addItem((void *) pVec);
			NrEntries = atoi(szNrEntries);
//
// Loop through this toolbar definition and restore it from the preferences
//		
			for(iLay =0; iLay< NrEntries;iLay++)
			{
//
// Restore id from the contructed key
//
				sTBBase = XAP_PREF_KEY_ToolbarID;
				sTBBase += szCurName;
				sprintf(buf,"%d",iLay);
				sTBBase += buf;
				const gchar * szCurId = NULL;
				pScheme->getValue((const gchar *)sTBBase.c_str(),&szCurId);
				if(szCurId == NULL)
				{
					continue;
				}
				UT_return_val_if_fail (szCurId && *szCurId, false);
				XAP_Toolbar_Id curId = (XAP_Toolbar_Id) atoi(szCurId);
//
// Here we should check whether the ID exists or not
// 
				EV_Toolbar_Action * pAction = m_pApp->getToolbarActionSet()->getAction(curId);
				if (pAction == NULL) {
					UT_DEBUGMSG (("Found an unknown toolbar item in prefs. Ignoring.\n"));
					continue;
				}
//
// Restore flags from the constructed key
//
				sTBBase = XAP_PREF_KEY_ToolbarFlag;
				sTBBase += szCurName;
				sprintf(buf,"%d",iLay);
				sTBBase += buf;
				const gchar * szCurFlag = NULL;
				pScheme->getValue((const gchar *)sTBBase.c_str(),&szCurFlag);
				if(szCurFlag != NULL)
				{
					EV_Toolbar_LayoutFlags curFlag = (EV_Toolbar_LayoutFlags) atoi(szCurFlag);
//
// Build element and add it into the Toolbar layout
//
					XAP_Toolbar_Factory_lt * plt = new XAP_Toolbar_Factory_lt;
					plt->m_id = curId;
					plt->m_flags = curFlag;
					pVec->add_lt(plt);
				}
			}
		}
//
// Use default hardwired layout
//
		else
		{
			pVec = new XAP_Toolbar_Factory_vec(&s_ttTable[iTB]);
			m_vecTT.addItem((void *) pVec);
		}
	}
	return true;
}



