/* AbiWord
 * Copyright (C) 1998-2000 AbiSource, Inc.
 * 
 * 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.
 */

/*****************************************************************
** Only one of these is created by the application.
*****************************************************************/

#define WIN32_LEAN_AND_MEAN
#include <stdlib.h>
#include <windows.h>
#include <commctrl.h>   // includes the common control header
#ifdef _MSC_VER
#include <crtdbg.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>

#include <stdio.h>
#include <string.h>
#include <io.h>
#include <fcntl.h>

#if !defined(__WINE__) && (!defined(_MSC_VER) || _MSC_VER < 1310)
#include <iostream.h>
#elif _MSC_VER >= 1310
#include <iostream>
#endif

#include <ole2.h>

#include "ut_debugmsg.h"
#include "ut_bytebuf.h"
#include "ut_string.h"
#include "xap_Args.h"
#include "ap_Args.h"
#include "ap_Convert.h"
#include "ap_Win32Frame.h"
#include "ap_Win32App.h"
#include "spell_manager.h"

#include "ap_Strings.h"
#include "ap_LoadBindings.h"
#include "xap_EditMethods.h"
#include "xap_Menu_Layouts.h"
#include "xap_Menu_ActionSet.h"
#include "xap_Toolbar_ActionSet.h"
#include "xap_EncodingManager.h"
#include "xap_ModuleManager.h"
#include "ev_EditMethod.h"
#include "xap_Module.h"

#include "ap_Win32Resources.rc2"
#include "ap_Clipboard.h"
#include "ap_EditMethods.h"

#include "fp_Run.h"
#include "ut_Win32OS.h"
#include "ut_Win32Idle.h"
#include "ut_Language.h"

#include "ie_impexp_Register.h"

#include "ie_exp.h"
#include "ie_exp_RTF.h"
#include "ie_exp_Text.h"

#include "ie_imp.h"
#include "ie_imp_RTF.h"
#include "ie_imp_Text.h"
#include "ie_impGraphic.h"
#include "fg_Graphic.h"
#include "xav_View.h"
#include "xad_Document.h"
#include "ap_FrameData.h"
#include "ut_Win32Locale.h"

#include "ap_Strings.h"

#include "pt_PieceTable.h"

#include "gr_Painter.h"
// extern prototype - this is defined in ap_EditMethods.cpp
extern XAP_Dialog_MessageBox::tAnswer s_CouldNotLoadFileMessage(XAP_Frame * pFrame, const char * pNewFile, UT_Error errorCode);
/*****************************************************************/

AP_Win32App::AP_Win32App(HINSTANCE hInstance, XAP_Args * pArgs, const char * szAppName)
	: AP_App(hInstance, pArgs,szAppName)
{
	m_pStringSet = NULL;
	m_pClipboard = NULL;
}

AP_Win32App::~AP_Win32App(void)
{
	DELETEP(m_pStringSet);
	DELETEP(m_pClipboard);

	IE_ImpExp_UnRegisterXP ();
}

static bool s_createDirectoryIfNecessary(const char * szDir)
{
	struct _stat statbuf;
	
	if (_stat(szDir,&statbuf) == 0)								// if it exists
	{
		if ( (statbuf.st_mode & _S_IFDIR) == _S_IFDIR )			// and is a directory
			return true;

		UT_DEBUGMSG(("Pathname [%s] is not a directory.\n",szDir));
		return false;
	}

	if (CreateDirectory(szDir,NULL))
		return true;

	UT_DEBUGMSG(("Could not create Directory [%s].\n",szDir));
	return false;
}

typedef BOOL __declspec(dllimport) (CALLBACK *InitCommonControlsEx_fn)(LPINITCOMMONCONTROLSEX lpInitCtrls);

bool AP_Win32App::initialize(void)
{
	bool bSuccess = true;
	const char * szUserPrivateDirectory = getUserPrivateDirectory();
	bool bVerified = s_createDirectoryIfNecessary(szUserPrivateDirectory);
	UT_return_val_if_fail (bVerified, false);

	// load the preferences.
	
	m_prefs = new AP_Win32Prefs(this);
	UT_return_val_if_fail (m_prefs, false);
	
	m_prefs->fullInit();
		   
	// now that preferences are established, let the xap init

	m_pClipboard = new AP_Win32Clipboard();
	UT_return_val_if_fail (m_pClipboard, false);
	   
	m_pEMC = AP_GetEditMethods();
	UT_return_val_if_fail (m_pEMC, false);

	m_pBindingSet = new AP_BindingSet(m_pEMC);
	UT_return_val_if_fail (m_pBindingSet, false);
	
	m_pMenuActionSet = AP_CreateMenuActionSet();
	UT_return_val_if_fail (m_pMenuActionSet,false);

	m_pToolbarActionSet = AP_CreateToolbarActionSet();
	UT_return_val_if_fail (m_pToolbarActionSet,false);

	//////////////////////////////////////////////////////////////////
	// load the dialog and message box strings
	//////////////////////////////////////////////////////////////////
	
	{
		// assume we will be using the builtin set (either as the main
		// set or as the fallback set).
		
		AP_BuiltinStringSet * pBuiltinStringSet = new AP_BuiltinStringSet(this,AP_PREF_DEFAULT_StringSet);
		UT_return_val_if_fail (pBuiltinStringSet, false);
		m_pStringSet = pBuiltinStringSet;

		// see if we should load an alternate set from the disk
		
		const char * szDirectory = NULL;
		const char * szStringSet = NULL;

		if (   (getPrefsValue(AP_PREF_KEY_StringSet,&szStringSet))
			&& (szStringSet)
			&& (*szStringSet)
			&& (UT_stricmp(szStringSet,AP_PREF_DEFAULT_StringSet) != 0))
		{
			getPrefsValueDirectory(true,AP_PREF_KEY_StringSetDirectory,&szDirectory);
			UT_return_val_if_fail ((szDirectory) && (*szDirectory), false);

			char * szPathname = (char *)calloc(sizeof(char),strlen(szDirectory)+strlen(szStringSet)+100);
			UT_return_val_if_fail (szPathname, false);

			sprintf(szPathname,"%s%s%s.strings",
					szDirectory,
					((szDirectory[strlen(szDirectory)-1]=='\\') ? "" : "\\"),
					szStringSet);

			AP_DiskStringSet * pDiskStringSet = new AP_DiskStringSet(this);
			UT_return_val_if_fail (pDiskStringSet, false);

			if (pDiskStringSet->loadStringsFromDisk(szPathname))
			{
				pDiskStringSet->setFallbackStringSet(m_pStringSet);
				m_pStringSet = pDiskStringSet;
                UT_Language_updateLanguageNames();
				UT_DEBUGMSG(("Using StringSet [%s]\n",szPathname));
			}
			else
			{
				UT_DEBUGMSG(("Unable to load StringSet [%s] -- using builtin strings instead.\n",szPathname));				
				DELETEP(pDiskStringSet);
			}
				
			free(szPathname);
		}
	}

	// AP_App::initilize() calls for us XAP_Win32App::initialize()
	if (! AP_App::initialize())
		return false;

	
	// let various window types register themselves

	if (!AP_Win32Frame::RegisterClass(this))
	{
		UT_DEBUGMSG(("couldn't register class\n"));
		return false;
	}

	//////////////////////////////////////////////////////////////////
	// Initialize the importers/exporters
	//////////////////////////////////////////////////////////////////
	IE_ImpExp_RegisterXP ();

	//////////////////////////////////////////////////////////////////
	// initializes the spell checker.
	//////////////////////////////////////////////////////////////////
	
	{
		SpellManager::instance();
	}
	
	
	// Now we have the strings loaded we can populate the field names correctly
	int i;
	
	for (i = 0; fp_FieldTypes[i].m_Type != FPFIELDTYPE_END; i++)
	{
	    (&fp_FieldTypes[i])->m_Desc = m_pStringSet->getValue(fp_FieldTypes[i].m_DescId);
	    UT_DEBUGMSG(("Setting field type desc for type %d, desc=%s\n", fp_FieldTypes[i].m_Type, fp_FieldTypes[i].m_Desc));
	}

	for (i = 0; fp_FieldFmts[i].m_Tag != NULL; i++)
	{
	    (&fp_FieldFmts[i])->m_Desc = m_pStringSet->getValue(fp_FieldFmts[i].m_DescId);
	    UT_DEBUGMSG(("Setting field desc for field %s, desc=%s\n", fp_FieldFmts[i].m_Tag, fp_FieldFmts[i].m_Desc));
	}

    ///////////////////////////////////////////////////////////////////////
    /// Build a labelset so the plugins can add themselves to something ///
    ///////////////////////////////////////////////////////////////////////

	const char * szMenuLabelSetName = NULL;
	if (getPrefsValue( AP_PREF_KEY_StringSet, (const XML_Char**)&szMenuLabelSetName)
		&& (szMenuLabelSetName) && (*szMenuLabelSetName))
	{
		;
	}
	else
		szMenuLabelSetName = AP_PREF_DEFAULT_StringSet;

	getMenuFactory()->buildMenuLabelSet(szMenuLabelSetName);	
	
	//////////////////////////////////////////////////////////////////
	// Check for necessary DLLs now that we can do localized error messages
	//////////////////////////////////////////////////////////////////

#if 0 /* re-enable once we use unicows again */
	// Ensure that we have Unicows dll
	if (!UT_IsWinNT())
	{
		HMODULE hModule = LoadLibrary("unicows.dll");
		
		if (!hModule)
		{
			UT_String sErr(UT_String_sprintf(m_pStringSet->getValue(AP_STRING_ID_WINDOWS_NEED_UNICOWS),
											 "Unicows"));

			MessageBox(NULL, sErr.c_str(), NULL, MB_OK);

			bSuccess = false;
		}
		else
			FreeLibrary(hModule);
	}
#endif

	// Ensure that common control DLL is loaded
	HINSTANCE hinstCC = LoadLibrary("comctl32.dll");
	UT_return_val_if_fail (hinstCC, false);
	InitCommonControlsEx_fn  pInitCommonControlsEx = NULL;
	if( hinstCC != NULL )
		pInitCommonControlsEx = (InitCommonControlsEx_fn)GetProcAddress( hinstCC, "InitCommonControlsEx" );
	if( pInitCommonControlsEx != NULL )
	{
		INITCOMMONCONTROLSEX icex;
		icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
		icex.dwICC = ICC_COOL_CLASSES | ICC_BAR_CLASSES 	// load the rebar and toolbar
					| ICC_TAB_CLASSES | ICC_UPDOWN_CLASS	// and tab and spin controls
					;
		pInitCommonControlsEx(&icex);
	}
	else
	{
		InitCommonControls();

		UT_String sErr(UT_String_sprintf(m_pStringSet->getValue(AP_STRING_ID_WINDOWS_COMCTL_WARNING),
										 "Unicows"));

		MessageBox(NULL, sErr.c_str(), NULL, MB_OK);
	}

	//////////////////////////////////////////////////////////////////
	// load the all Plugins from the correct directory
	//////////////////////////////////////////////////////////////////

	char szPath[_MAX_PATH];
	char szPlugin[_MAX_PATH];
	_getExeDir( szPath, _MAX_PATH);
	strcat(szPath, "..\\Plugins\\*.dll");

    struct _finddata_t cfile;
	long findtag = _findfirst( szPath, &cfile );
	if( findtag != -1 )
	{
		do
		{	
			_getExeDir( szPlugin, _MAX_PATH );
			strcat( szPlugin, "..\\Plugins\\" );
			strcat( szPlugin, cfile.name );
			XAP_ModuleManager::instance().loadModule( szPlugin );
		} while( _findnext( findtag, &cfile ) == 0 );
	}
	_findclose( findtag );

	UT_String pluginName( getUserPrivateDirectory() ); 
	UT_String pluginDir( getUserPrivateDirectory() );
	pluginDir += "\\AbiWord\\plugins\\*.dll";
	findtag = _findfirst( pluginDir.c_str(), &cfile );
	if( findtag != -1 )
	{
		do
		{	
			pluginName = getUserPrivateDirectory();
			pluginName += "\\AbiWord\\plugins\\";
			pluginName += cfile.name;
			XAP_ModuleManager::instance().loadModule( pluginName.c_str() );
		} while( _findnext( findtag, &cfile ) == 0 );
	}
	_findclose( findtag );

	return bSuccess;
}


// if app is NULL then we use 'this'
XAP_Frame * AP_Win32App::newFrame(AP_App *app)
{
	AP_Win32Frame * pWin32Frame;
	if (app == NULL)
		pWin32Frame = new AP_Win32Frame(this);
	else
		pWin32Frame = new AP_Win32Frame(app);

	if (pWin32Frame)
		pWin32Frame->initialize();

	return pWin32Frame;
}


bool AP_Win32App::shutdown(void)
{
	if (m_prefs->getAutoSavePrefs())
		m_prefs->savePrefsFile();

	delete m_prefs;
	m_prefs = NULL;

	return true;
}

bool AP_Win32App::getPrefsValueDirectory(bool bAppSpecific,
											const XML_Char * szKey, const XML_Char ** pszValue) const
{
	if (!m_prefs)
		return false;

	const XML_Char * psz = NULL;
	if (!m_prefs->getPrefsValue(szKey,&psz))
		return false;

	if ((*psz == '/') || (*psz == '\\'))
	{
		*pszValue = psz;
		return true;
	}

	const XML_Char * dir = ((bAppSpecific) ? getAbiSuiteAppDir() : getAbiSuiteLibDir());

	static XML_Char buf[1024];
	UT_return_val_if_fail ((strlen(dir) + strlen(psz) + 2) < sizeof(buf), false);
	
	sprintf(buf,"%s\\%s",dir,psz);
	*pszValue = buf;
	return true;
}

const char * AP_Win32App::getAbiSuiteAppDir(void) const
{
	// we return a static string, use it quickly.
	
	static XML_Char buf[1024];
	UT_return_val_if_fail ((strlen(getAbiSuiteLibDir()) + strlen(ABIWORD_APP_LIBDIR) + 2) < sizeof(buf), NULL);

	sprintf(buf,"%s\\%s",getAbiSuiteLibDir(),ABIWORD_APP_LIBDIR);
	return buf;
}

HICON AP_Win32App::getIcon(void)
{

	int sy = GetSystemMetrics(SM_CYICON);
	int sx = GetSystemMetrics(SM_CXICON);
	UT_DEBUGMSG(("GetIcon(): system metrics [%d %d]\n",sx,sy));
	
	if ((sx==32) && (sy==32))
		return LoadIcon(getInstance(), MAKEINTRESOURCE(AP_RID_ICON_APPLICATION_32));
	else
		return (HICON) LoadImage(getInstance(), MAKEINTRESOURCE(AP_RID_ICON_APPLICATION_32), IMAGE_ICON, 0,0,0);
}

HICON AP_Win32App::getSmallIcon(void)
{

	int sy = GetSystemMetrics(SM_CYICON);
	int sx = GetSystemMetrics(SM_CXICON);
	UT_DEBUGMSG(("GetIcon(): system metrics [%d %d]\n",sx,sy));

	if ((sx==16) && (sy==16))
		return LoadIcon(getInstance(), MAKEINTRESOURCE(AP_RID_ICON_APPLICATION_16));
	else
		return (HICON) LoadImage(getInstance(), MAKEINTRESOURCE(AP_RID_ICON_APPLICATION_16), IMAGE_ICON, 0,0,0);
}

const XAP_StringSet * AP_Win32App::getStringSet(void) const
{
	return m_pStringSet;
}

#ifdef COPY_ON_DEMAND
/*!
    indicate to the clipboard that we can provide data in this format
    on demand
*/
void AP_Win32App::_indicateFmtToClipboard(const char * pszFmt) const
{
	UT_return_if_fail(m_pClipboard && pszFmt);
	UINT iFmt = m_pClipboard->convertFormatString(pszFmt);

	SetClipboardData(iFmt, NULL);
}

bool AP_Win32App::_cacheClipboardDoc(PD_DocumentRange *pDocRange)
{
	UT_return_val_if_fail(m_pClipboard && pDocRange, false);

	UT_ByteBuf buf;
	UT_Error status;;
	UT_Byte b = 0;

	IE_Exp_RTF * pExpRtf = new IE_Exp_RTF(pDocRange->m_pDoc);
	if (pExpRtf)
	{
		status = pExpRtf->copyToBuffer(pDocRange,&buf);

		if(status != UT_OK)
			return false;
			
		buf.append(&b,1);			// NULL terminate the string
		DELETEP(pExpRtf);
	}
	else
	{
		return false;
	}

	// now create a subdocument ...
	PD_Document * pDoc = new PD_Document(XAP_App::getApp());

	if(!pDoc)
		return false;
	
	pDoc->newDocument();
	
	PD_DocumentRange DocRange(pDoc, 2, 2);
	
	IE_Imp * pImp = 0;
	IE_Imp::constructImporter(pDoc, 0, IE_Imp::fileTypeForSuffix(".rtf"),&pImp,0);

	if(pImp)
	{
		pImp->pasteFromBuffer(&DocRange,buf.getPointer(0),buf.getLength(),NULL);
		delete pImp;
	}
	else
	{
		return false;
	}
	
	m_pClipboard->setClipboardDoc(pDoc);
	return true;
}

/*!
    copy the required format to the clipboard on demand
    see docs on WM_RENDERFORMAT
*/
bool AP_Win32App::copyFmtToClipboardOnDemand(UINT iFmt)
{
	UT_return_val_if_fail(m_pClipboard, false);

	PD_DocumentRange DocRange;
	DocRange.m_pDoc = m_pClipboard->getClipboardDoc();
	UT_return_val_if_fail(DocRange.m_pDoc, false);

	DocRange.m_pos1 = 2;
	DocRange.m_pos2 = DocRange.m_pDoc->getLastFrag()->getPos() + DocRange.m_pDoc->getLastFrag()->getLength();
	
	if(!_copyFmtToClipboard(&DocRange, iFmt))
		return false;

	return true;
}

/*!
    copy data to the clipboard in all formats on demand (this is
    called when application is exiting and leaving data on clipboard
    that and indicating that data in addtional formats is available
    see docs on WM_RENDERALLFORMATS
*/
bool AP_Win32App::copyAllFmtsToClipboardOnDemand()
{
	UT_return_val_if_fail(m_pClipboard, false);

	// I will use NULL here, since we are about to shut down anyway ...
	if(!m_pClipboard->openClipboard(NULL))			// try to lock the clipboard
		return false;

	// need to clear clipboard in order to become its owners
	m_pClipboard->clearClipboard();
	
	// what we need is to get the data from the clipboard and convert
	// it to the format requested
	PD_DocumentRange DocRange;
	DocRange.m_pDoc = m_pClipboard->getClipboardDoc();
	UT_return_val_if_fail(DocRange.m_pDoc, false);

	DocRange.m_pos1 = 2;
	DocRange.m_pos2 = DocRange.m_pDoc->getLastFrag()->getPos() + DocRange.m_pDoc->getLastFrag()->getLength();

	_copyFmtToClipboard(&DocRange, AP_CLIPBOARD_RTF);
	_copyFmtToClipboard(&DocRange, AP_CLIPBOARD_TEXTPLAIN_UCS2);
	_copyFmtToClipboard(&DocRange, AP_CLIPBOARD_TEXTPLAIN_8BIT);

	return true;
}

#endif // COPY_ON_DEMAND

/*!
    copy data in required format to the clipboard
*/
bool AP_Win32App::_copyFmtToClipboard(PD_DocumentRange * pDocRange, UINT iFmt)
{
	UT_return_val_if_fail(m_pClipboard, false);
	const char * pszFmt = m_pClipboard->convertToFormatString(iFmt);
	UT_return_val_if_fail(pszFmt, false);

	return _copyFmtToClipboard(pDocRange, pszFmt);
}

/*!
    copy data in required format to the clipboard
*/
bool AP_Win32App::_copyFmtToClipboard(PD_DocumentRange * pDocRange, const char * pszFmt)
{
	UT_return_val_if_fail(m_pClipboard && pszFmt, false);
	
	UT_ByteBuf buf;
	UT_Error status;;
	UT_Byte b = 0;

	if(0 == UT_strcmp(AP_CLIPBOARD_TEXTPLAIN_8BIT, pszFmt))
	{
		IE_Exp_Text * pExpText = new IE_Exp_Text(pDocRange->m_pDoc);
		if (pExpText)
		{
			status = pExpText->copyToBuffer(pDocRange,&buf);

			if(status != UT_OK)
				return false;
			
			buf.append(&b,1);			// NULL terminate the string
			m_pClipboard->addData(AP_CLIPBOARD_TEXTPLAIN_8BIT,
								  (UT_Byte *)buf.getPointer(0),buf.getLength());
			DELETEP(pExpText);
			UT_DEBUGMSG(("CopyToClipboard: copying %d bytes in TEXTPLAIN format.\n",
						 buf.getLength()));
		}
		else
		{
			return false;
		}
		
	}
	else if(0 == UT_strcmp(AP_CLIPBOARD_TEXTPLAIN_UCS2, pszFmt))
	{
		const char *szEnc = XAP_EncodingManager::get_instance()->getNativeUnicodeEncodingName(); 
		IE_Exp_Text * pExpUnicodeText = new IE_Exp_Text(pDocRange->m_pDoc,szEnc);
		if (pExpUnicodeText)
		{
			status = pExpUnicodeText->copyToBuffer(pDocRange,&buf);

			if(status != UT_OK)
				return false;
			
			UT_Byte b[2] = {0,0};
			buf.append(b,2);			// NULL terminate the string
			m_pClipboard->addData(AP_CLIPBOARD_TEXTPLAIN_UCS2,
								  (UT_Byte *)buf.getPointer(0),buf.getLength());
			DELETEP(pExpUnicodeText);
			UT_DEBUGMSG(("CopyToClipboard: copying %d bytes in TEXTPLAIN UNICODE format.\n",
						 buf.getLength()*2));
		}
		else
		{
			return false;
		}
	}
	else if(0 == UT_strcmp(AP_CLIPBOARD_RTF, pszFmt))
	{
		IE_Exp_RTF * pExpRtf = new IE_Exp_RTF(pDocRange->m_pDoc);
		if (pExpRtf)
		{
			status = pExpRtf->copyToBuffer(pDocRange,&buf);

			if(status != UT_OK)
				return false;
			
			buf.append(&b,1);			// NULL terminate the string
			m_pClipboard->addData(AP_CLIPBOARD_RTF,(UT_Byte *)buf.getPointer(0),buf.getLength());
			DELETEP(pExpRtf);
			UT_DEBUGMSG(("CopyFmtToClipboard: copying %d bytes in RTF format.\n",
						 buf.getLength()));
		}
		else
		{
			return false;
		}
	}

	return true;
}

/*!
    copy data to the clipboard; this is what gets called when the user
    presses Ctrl+C
*/
void AP_Win32App::copyToClipboard(PD_DocumentRange * pDocRange, bool /*bUseClipboard*/)
{
	// copy the given subset of the given document to the
	// system clipboard in a variety of formats.
	// MSFT requests that we post them in the order of
	// importance to us (most preserving to most lossy).
	//
	// TODO do we need to put something in .ABW format on the clipboard ??

	AP_Win32FrameImpl * pFrameImp = static_cast<AP_Win32FrameImpl*>(getLastFocussedFrame()->getFrameImpl());
	UT_return_if_fail(pFrameImp);
	
	if (!m_pClipboard->openClipboard(pFrameImp->getHwndDocument()))
		return;

	m_pClipboard->clearClipboard(); // this also gives us the ownership

	// Be smart: always place RTF on clipboard; the
	// remaining formats we will generate on demand.
	// most of the time it will save us creating multiple importers,
	// but when the user requests other than the default format, it
	// will be a little bit more involved
	// Tomas, June 28, 2003.

#ifndef COPY_ON_DEMAND
	_copyFmtToClipboard(pDocRange, AP_CLIPBOARD_RTF);
#else
	// we need to both cache the present doc and put rtf version on
	// the clipboard, because win32 will ask for it immediately;
	// appart from that, the rtf exporter needs some layout info to
	// deal with bidi issues, which means we cannot construct the rtf
	// from the chached doc properly
	_cacheClipboardDoc(pDocRange);
	_copyFmtToClipboard(pDocRange, AP_CLIPBOARD_RTF);
#endif
	
	// TODO Should use a finer-grain technique than IsWinNT()
	// since Win98 supports unicode clipboard.
	if (UT_IsWinNT())
	{
		// put raw unicode text on the clipboard
#ifndef COPY_ON_DEMAND
		_copyFmtToClipboard(pDocRange, AP_CLIPBOARD_TEXTPLAIN_UCS2);
#else
		_indicateFmtToClipboard(AP_CLIPBOARD_TEXTPLAIN_UCS2);
#endif
	}
	else
	{
		// put raw 8bit text on the clipboard
#ifndef COPY_ON_DEMAND
		_copyFmtToClipboard(pDocRange, AP_CLIPBOARD_TEXTPLAIN_8BIT);
#else
		_indicateFmtToClipboard(AP_CLIPBOARD_TEXTPLAIN_8BIT);
#endif
	}

	m_pClipboard->closeClipboard();				// release clipboard lock
}

//
// 
//
PBITMAPINFO CreateBitmapInfoStruct(HBITMAP hBmp)
{ 
	BITMAP 		bmp; 
	PBITMAPINFO 	pbmi; 
	WORD    	cClrBits; 

	// Retrieve the bitmap's color format, width, and height. 
    	if (!GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp)) 
		return NULL;
	
	if (bmp.bmBitsPixel==16) bmp.bmBitsPixel=24;	// 16 bit BMPs are not supported by all programs
					

	// Convert the color format to a count of bits. 
   	cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel); 
    
	if (cClrBits == 1) 
		cClrBits = 1; 
	else if (cClrBits <= 4) 
		cClrBits = 4; 
	else if (cClrBits <= 8) 
		cClrBits = 8; 
	else if (cClrBits <= 16) 
		cClrBits = 16; 
	else if (cClrBits <= 24) 
		cClrBits = 24; 
	else cClrBits = 32; 
	
	// Allocate memory for the BITMAPINFO structure. (This structure 
	// contains a BITMAPINFOHEADER structure and an array of RGBQUAD 
	// data structures.) 
	
	if (cClrBits != 24) 
	 pbmi = (PBITMAPINFO) LocalAlloc(LPTR, 
	            sizeof(BITMAPINFOHEADER) + 
	            sizeof(RGBQUAD) * (1<< cClrBits)); 
	
	// There is no RGBQUAD array for the 24-bit-per-pixel format. 	
	else 
	 pbmi = (PBITMAPINFO) LocalAlloc(LPTR, 
	            sizeof(BITMAPINFOHEADER)); 
	
	// Initialize the fields in the BITMAPINFO structure. 
	
	pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 
	pbmi->bmiHeader.biWidth = bmp.bmWidth; 
	pbmi->bmiHeader.biHeight = bmp.bmHeight; 
	pbmi->bmiHeader.biPlanes = bmp.bmPlanes; 
	pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel; 
	if (cClrBits < 24) 
	pbmi->bmiHeader.biClrUsed = (1<<cClrBits); 
	
	// If the bitmap is not compressed, set the BI_RGB flag. 
	pbmi->bmiHeader.biCompression = BI_RGB; 
	
	// Compute the number of bytes in the array of color 
	// indices and store the result in biSizeImage. 
	// For Windows NT/2000, the width must be DWORD aligned unless 
	// the bitmap is RLE compressed.
	pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8
	                          * pbmi->bmiHeader.biHeight; 
	// Set biClrImportant to 0, indicating that all of the 
	// device colors are important. 
	pbmi->bmiHeader.biClrImportant = 0; 
	return pbmi; 
} 

//
//
//
void CreateBMP(HWND hwnd, UT_ByteBuf & pBB, PBITMAPINFO pbi, 
                  HBITMAP hBMP, HDC hDC) 
{ 
	BITMAPFILEHEADER hdr;       // bitmap file-header 
	PBITMAPINFOHEADER pbih;     // bitmap info-header 
	LPBYTE lpBits;              // memory pointer 	

	if (!hBMP) return;

	pbih = (PBITMAPINFOHEADER) pbi; 
	lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);

	if (!lpBits) return;

	// Retrieve the color table (RGBQUAD array) and the bits 
	// (array of palette indices) from the DIB. 
	if (!GetDIBits(hDC, hBMP, 0, (WORD) pbih->biHeight, lpBits, pbi, 
		 DIB_RGB_COLORS)) 
	return;

	hdr.bfType = 0x4d42;        // 0x42 = "B" 0x4d = "M" 
	// Compute the size of the entire file. 
	hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) + 
			pbih->biSize + pbih->biClrUsed 
			* sizeof(RGBQUAD) + pbih->biSizeImage); 
	hdr.bfReserved1 = 0; 
	hdr.bfReserved2 = 0; 

	// Compute the offset to the array of color indices. 
	hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + 
	pbih->biSize + pbih->biClrUsed 
	* sizeof (RGBQUAD); 

	pBB.truncate (0);

	// Copy the BITMAPFILEHEADER into the .BMP file. 
	pBB.append ((const UT_Byte *)&hdr, sizeof(BITMAPFILEHEADER));
	pBB.append ((const UT_Byte *)pbih, sizeof(BITMAPINFOHEADER) + pbih->biClrUsed * sizeof (RGBQUAD));

	// Copy the array of color indices into the .BMP file.         
	pBB.append ((const UT_Byte *)lpBits, (int) pbih->biSizeImage);

	GlobalFree((HGLOBAL)lpBits);
}



void AP_Win32App::pasteFromClipboard(PD_DocumentRange * pDocRange, bool bUseClipboard, bool bHonorFormatting)
{
	// paste from the system clipboard using the best-for-us format
	// that is present.

	// We get a handle to the object in the requested format
	// and then lock it an use the system buffer -- rather
	// then copying it into our own.
	//
	// we jump thru a few bogus steps w/r/t the length of the
	// object because MSFT docs state that the length of the
	// object may be less than the length actually returned by
	// GlobalSize().
	//
	// therefore, we do a strlen() and **hope** that this is
	// right.  Oh, and the value returned by GlobalSize() varies
	// from call-to-call on the same object.... sigh.
	AP_Win32FrameImpl * pFrameImp = static_cast<AP_Win32FrameImpl*>(getLastFocussedFrame()->getFrameImpl());
	UT_return_if_fail(pFrameImp);
	
	if (!m_pClipboard->openClipboard(pFrameImp->getHwndDocument())) // lock clipboard
		return;
	
	{
		// TODO Paste the most detailed version unless user overrides.
		// TODO decide if we need to support .ABW on the clipboard.
		if (!((bHonorFormatting && _pasteFormatFromClipboard(pDocRange, AP_CLIPBOARD_RTF, ".rtf", false)) ||
			_pasteFormatFromClipboard(pDocRange, AP_CLIPBOARD_TEXTPLAIN_UCS2, ".txt", true) ||
			_pasteFormatFromClipboard(pDocRange, AP_CLIPBOARD_BMP, ".bmp", false) ||
			_pasteFormatFromClipboard(pDocRange, AP_CLIPBOARD_TEXTPLAIN_8BIT, ".txt", false)))
		{
			// TODO figure out what to do with an image and other formats....
			UT_DEBUGMSG(("PasteFromClipboard: TODO support this format..."));
		}
	}

	m_pClipboard->closeClipboard();				// release clipboard lock
	return;
}

bool AP_Win32App::_pasteFormatFromClipboard(PD_DocumentRange * pDocRange, const char * szFormat,
											const char * szType, bool bWide)
{
	HANDLE	hData;
	bool 	bSuccess = false;	
  
	if (!(hData = m_pClipboard->getHandleInFormat(szFormat)))
		return bSuccess;		
 		
 	// It's a bitmap
 	if (stricmp(szFormat, AP_CLIPBOARD_BMP)==0)
	{			
 		HBITMAP					hBitmap;
 		PBITMAPINFO 			bi;
 		HWND		 			hWnd;
 		HDC 					hdc;
 		IE_ImpGraphic*			pIEG = NULL;
 		FG_Graphic* 			pFG = NULL;	
 		UT_Error 				errorCode;		
 		UT_ByteBuf 				byteBuf;				
 		IEGraphicFileType		iegft = IEGFT_BMP;	
 		XAP_Frame* 				pFrame;						
 		AP_FrameData* 			pFrameData;		
 		FL_DocLayout*			pDocLy;	
 		FV_View* 				pView;						
		UT_ByteBuf				bBufBMP;
 		
 		hBitmap = (HBITMAP)hData;					
 		hWnd =  GetDesktopWindow();
 		hdc = GetDC(hWnd);		
 		
 		// Create a BMP file from a BITMAP
 		bi =  CreateBitmapInfoStruct(hBitmap);						
 		CreateBMP(hWnd, bBufBMP, bi, hBitmap,hdc);                  										
 		
 		// Since we are providing the file type, there is not need to pass the bytebuff filled up
 		errorCode = IE_ImpGraphic::constructImporter(&bBufBMP, iegft, &pIEG);				 				
		 				
 		if(errorCode != UT_OK)		
			return false;				  	
		 				 			
 		errorCode = pIEG->importGraphic(&bBufBMP, &pFG); 		
 		
 		if(errorCode != UT_OK || !pFG)
		{
			DELETEP(pIEG);
 			return false;
		}
 		 
 		// Insert graphic in the view
 		pFrame = getLastFocussedFrame(); 						
 		pFrameData = (AP_FrameData*) pFrame->getFrameData();		
 		pDocLy =	pFrameData->m_pDocLayout;	
 		pView =  pDocLy->getView();		
 				
 		errorCode = pView->cmdInsertGraphic(pFG);	  		  		
 	
		DELETEP(pIEG);
 		//DELETEP(pFG);		
 		
 		bSuccess = true;
 	}
 	else	
	{
		unsigned char * pData = static_cast<unsigned char *>(GlobalLock(hData));
		UT_DEBUGMSG(("Paste: [fmt %s %s][hdata 0x%08lx][pData 0x%08lx]\n",
					 szFormat, szType,  hData, pData));
		UT_uint32 iSize = GlobalSize(hData);
		UT_uint32 iStrLen = bWide
			? wcslen(reinterpret_cast<const wchar_t *>(pData)) * 2
			: strlen(reinterpret_cast<const char *>(pData));
		UT_uint32 iLen = UT_MIN(iSize,iStrLen);

		
		IE_Imp * pImp = 0;
		IE_Imp::constructImporter(pDocRange->m_pDoc, 0, IE_Imp::fileTypeForSuffix(szType), &pImp, 0);
		if (pImp)
		{
			const char * szEncoding = 0;
			if (bWide)
				szEncoding = XAP_EncodingManager::get_instance()->getUCS2LEName();
			else
				; // TODO Get code page using CF_LOCALE
			pImp->pasteFromBuffer(pDocRange,pData,iLen,szEncoding);
			delete pImp;
		}

		GlobalUnlock(hData);
		bSuccess = true;
	}
	return bSuccess;
}

bool AP_Win32App::canPasteFromClipboard(void)
{
	if (!getLastFocussedFrame()) 
		return false;

	AP_Win32FrameImpl * pFrameImp = static_cast<AP_Win32FrameImpl*>(getLastFocussedFrame()->getFrameImpl());
	UT_return_val_if_fail(pFrameImp, false);
	
	if (!m_pClipboard->openClipboard(pFrameImp->getHwndDocument()))
		return false;

	// TODO decide if we need to support .ABW format on the clipboard.	
	if (m_pClipboard->hasFormat(AP_CLIPBOARD_RTF))
		goto ReturnTrue;
	if (m_pClipboard->hasFormat(AP_CLIPBOARD_TEXTPLAIN_UCS2))
		goto ReturnTrue;
	if (m_pClipboard->hasFormat(AP_CLIPBOARD_TEXTPLAIN_8BIT))
		goto ReturnTrue;

	// If IEGFT_BMP!=0 we have a plugin that can deal with BMP format
	if (m_pClipboard->hasFormat(AP_CLIPBOARD_BMP) && IEGFT_BMP)
  		goto ReturnTrue;
  		
	m_pClipboard->closeClipboard();
	return false;

ReturnTrue:
	m_pClipboard->closeClipboard();
	return true;
}

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

#if defined(_DEBUG) && defined(_MSC_VER)
#define  SET_CRT_DEBUG_FIELD(a) \
            _CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#define  CLEAR_CRT_DEBUG_FIELD(a) \
            _CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#else
#define  SET_CRT_DEBUG_FIELD(a)   ((void) 0)
#define  CLEAR_CRT_DEBUG_FIELD(a) ((void) 0)
#endif

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

#define SPLASH 1

#if SPLASH
#include "gr_Graphics.h"
#include "gr_Win32Graphics.h"
#include "gr_Image.h"
#include "ut_bytebuf.h"
#include "ut_png.h"

static HWND hwndSplash = NULL;
static GR_Image * pSplash = NULL;
static char s_SplashWndClassName[256];

static void _hideSplash(void)
{
	if (hwndSplash)
	{
		DestroyWindow(hwndSplash);
		hwndSplash = NULL;
	}
	
	DELETEP(pSplash);
}

static LRESULT CALLBACK _SplashWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;
    
    switch (message) 
	{
    case WM_CREATE:
        // Set the timer for the specified number of ms
        SetTimer(hWnd, 0, 2000, NULL);  
        break;

#if 0		
	// Handle the palette messages in case 
	// another app takes over the palette
    case WM_PALETTECHANGED:
        if ((HWND) wParam == hWnd)
            return 0;
    case WM_QUERYNEWPALETTE:
        InvalidateRect(hWnd, NULL, FALSE);
		UpdateWindow(hWnd);
		return TRUE;
#endif     

    // Destroy the window if... 
    case WM_LBUTTONDOWN:      // ...the user pressed the left mouse button
    case WM_RBUTTONDOWN:      // ...the user pressed the right mouse button
    case WM_TIMER:            // ...the timer timed out
        _hideSplash();		  // Close the window
        break;
        
        // Draw the window
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
		{
			// TODO: find XAP_App pointer for this
			GR_Win32AllocInfo ai(hdc, hwndSplash,0);
			
			GR_Graphics * pG = XAP_App::getApp()->newGraphics(ai);
			{
				GR_Painter GP(pG);

				GP.drawImage(pSplash, 0, 0);
			}

			DELETEP(pG);
		}
        EndPaint(hWnd, &ps);
        break;
        
    default:
        return (UT_DefWindowProc(hWnd, message, wParam, lParam));
    }
    return (0);
}

static GR_Image * _showSplash(HINSTANCE hInstance, const char * szAppName)
{
	hwndSplash = NULL;
	pSplash = NULL;

	UT_ByteBuf* pBB = NULL;
	const char * szFile = NULL;

	extern unsigned char g_pngSplash[];		// see ap_wp_Splash.cpp
	extern unsigned long g_pngSplash_sizeof;	// see ap_wp_Splash.cpp

	pBB = new UT_ByteBuf();
	if (
		(szFile && szFile[0] && (pBB->insertFromFile(0, szFile)))
		|| (pBB->ins(0, g_pngSplash, g_pngSplash_sizeof))
		)
	{
		// NB: can't access 'this' members from a static member function
		ATOM a;
	
		sprintf(s_SplashWndClassName, "%sSplash", szAppName /* app->getApplicationName() */);

		a = UT_RegisterClassEx(0L, _SplashWndProc, hInstance,
							   LoadIcon(hInstance, MAKEINTRESOURCE(AP_RID_ICON_APPLICATION_32)),
							   LoadCursor(NULL, IDC_ARROW), (HBRUSH) GetStockObject(NULL_BRUSH),
							   LoadIcon(hInstance, MAKEINTRESOURCE(AP_RID_ICON_APPLICATION_16)),
							   NULL, s_SplashWndClassName);
		UT_ASSERT_HARMLESS(a);

		// get the extents of the desktop window
		RECT rect;
		GetWindowRect(GetDesktopWindow(), &rect);

		// get splash size
		UT_sint32 iSplashWidth;
		UT_sint32 iSplashHeight;
		UT_PNG_getDimensions(pBB, iSplashWidth, iSplashHeight);

		// create a centered window the size of our bitmap
		hwndSplash = UT_CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TOPMOST,s_SplashWndClassName, 
								  NULL, WS_POPUP | WS_BORDER,
								  (rect.right  / 2) - (iSplashWidth  / 2) - 1, // subtract 1 pixel to account for WS_BORDER
								  (rect.bottom / 2) - (iSplashHeight / 2) - 1, // subtract 1 pixel to account for WS_BORDER
								  iSplashWidth + 2, // must add 2 to window size, WS_BORDER takes up one pixel on each side
								  iSplashHeight + 2, // must add 2 to window size, WS_BORDER takes up one pixel on each side
								  NULL, NULL, hInstance, NULL);
		UT_ASSERT_HARMLESS(hwndSplash);
    
		if (hwndSplash) 
		{
			// create image first
			// TODO: find XAP_App pointer for this
			GR_Win32AllocInfo ai(GetDC(hwndSplash), hwndSplash,0);
			
			GR_Graphics * pG = XAP_App::getApp()->newGraphics(ai);
			
			pSplash = pG->createNewImage("splash", pBB, pG->tlu(iSplashWidth), pG->tlu(iSplashHeight));
			DELETEP(pG);
			
			// now bring the window up front & center
			ShowWindow(hwndSplash, SW_SHOWNORMAL);
			UpdateWindow(hwndSplash);
		}
	}

	DELETEP(pBB);

	return pSplash;
}
#endif

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

int AP_Win32App::WinMain(const char * szAppName, HINSTANCE hInstance, 
						 HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
	bool bShowApp = true;
	bool bShowSplash = true;
	bool bSplashPref = true;
	BOOL bInitialized = FALSE; 
	
	// this is a static function and doesn't have a 'this' pointer.
	MSG msg;

#ifdef _MSC_VER
	_CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_DEBUG );
	_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG );
	_CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_WNDW);
#endif

	// HACK: load least-common-denominator Rich Edit control
	// TODO: fix Spell dlg so we don't rely on this
	// ALT:  make it a Preview widget instead

	HINSTANCE hinstRich = LoadLibrary("riched32.dll");
	if (!hinstRich)
		hinstRich = LoadLibrary("riched20.dll");
	UT_return_val_if_fail (hinstRich, 1);
	
	AP_Win32App * pMyWin32App;

	// OLE Stuff
	if (SUCCEEDED(OleInitialize(NULL)))
            bInitialized = TRUE;                    
  
	
// We put this in a block to force the destruction of Args in the stack
{	
	// Load the command line into an XAP_Args class
#ifdef _MSC_VER	// when using MSVC use already split arguments
	XAP_Args XArgs = XAP_Args(__argc, (const char**)__argv);
#else			// but for other compiles may not be available so use szCmdLine
	UT_String szNewCmdLine = UT_String_sprintf ( "%s %s", "AbiWord.exe", szCmdLine ) ;
	XAP_Args XArgs = XAP_Args(szNewCmdLine.c_str());
#endif

	// Step 1: Initialize our application.
	pMyWin32App = new AP_Win32App(hInstance, &XArgs, szAppName);
	AP_Args Args = AP_Args(&XArgs, szAppName, pMyWin32App);

	Args.parsePoptOpts();
	pMyWin32App->initialize();
  
	bShowSplash = Args.getShowSplash();

	// Consider the user saved preferences for the Splash Screen
   	const XAP_Prefs * pPrefs = pMyWin32App->getPrefs();
	UT_ASSERT_HARMLESS(pPrefs);
    if (pPrefs && pPrefs->getPrefsValueBool (AP_PREF_KEY_ShowSplash, &bSplashPref))
	{
		bShowSplash = bShowSplash && bSplashPref;
	}

	// Step 2: Handle all non-window args.
	// process args (calls common arg handler, which then calls platform specific)
	// As best I understand, it returns true to continue and show window, or
	// false if no window should be shown (and thus we should simply exit).
	bool windowlessArgsWereSuccessful = true;
	if (!Args.doWindowlessArgs(windowlessArgsWereSuccessful))
	{
		pMyWin32App->shutdown();	// properly shutdown the app 1st
		delete pMyWin32App;
		return (windowlessArgsWereSuccessful ? 0 : -1);
	}

	// Step 3: Create windows as appropriate.
	// if some args are botched, it returns false and we should
	// continue out the door.
	// We used to check for bShowApp here.  It shouldn't be needed
	// anymore, because doWindowlessArgs was supposed to bail already. -PL
	if (!pMyWin32App->openCmdLineFiles(&Args))
	{
		pMyWin32App->shutdown();	// properly shutdown the app 1st
		delete pMyWin32App;
		return 0;
	}

#ifdef SPLASH
	if (bShowSplash)
	{
		_showSplash(hInstance, szAppName);
	}
#endif	

}
//
// This block is controlled by the Structured Exception Handle
// if any crash happens here we will recover it and save the file (cross fingers)
//	


try
{		
	UT_uint32 iHeight = 0, iWidth = 0, t_flag =0;
	UT_sint32 iPosX = 0, iPosY = 0;
		
	if (!((XAP_App::getApp()->getGeometry(&iPosX,&iPosY,&iWidth,&iHeight,&t_flag)) &&
	       ((iWidth > 0) && (iHeight > 0)))	)
		XAP_App::getApp()->getDefaultGeometry(iWidth,iHeight,t_flag);
	
	if ((t_flag & PREF_FLAG_GEOMETRY_MAXIMIZED)==PREF_FLAG_GEOMETRY_MAXIMIZED)
			iCmdShow = SW_SHOWMAXIMIZED;
	
	if (bShowApp)
	{
		// display the windows
		for(UT_uint32 i = 0;i<pMyWin32App->m_vecFrames.getItemCount();i++)
		{
			AP_Win32Frame * curFrame = (AP_Win32Frame*)pMyWin32App->m_vecFrames[i];
			UT_return_val_if_fail (curFrame, 1);
		
			HWND hwnd = curFrame->getTopLevelWindow();
			ShowWindow(hwnd, iCmdShow);
			UpdateWindow(hwnd);
		}	

		// do dispatch loop
		while(UT_GetMessage(&msg, NULL, 0, 0))
	    {
   	      	// TranslateMessage is not called because AbiWord
	      	// has its own way of decoding keyboard accelerators
	      	if (pMyWin32App->handleModelessDialogMessage(&msg)) 
				continue;
				
			TranslateMessage(&msg);	
			UT_DispatchMessage(&msg);
	    	
			// Check for idle condition
			while( !UT_Win32Idle::_isEmpty() &&
                   !PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) ) 
			{
				// Fire idle functions when no pending messages
		    	UT_Win32Idle::_fireall();
			}
	    }
	}
	
	// Un-init OLE		               
        if (bInitialized)
                OleUninitialize();

	FreeLibrary(hinstRich);

	// unload all loaded plugins (remove some of the memory leaks shown at shutdown :-)
	XAP_ModuleManager::instance().unloadAllPlugins();
	
	// Step 4: Destroy the App.  It should take care of deleting all frames.
	pMyWin32App->shutdown();
	delete pMyWin32App;
	
	
}// end of thes block is controlled by the Exception Handler

//
// If an exception happens, with "catch" the block
// and then the save it into disk
//
catch (...)
{
#ifdef DEBUG
	throw;
#endif

	AP_Win32App *pApp = (AP_Win32App *) XAP_App::getApp();
	
	UT_return_val_if_fail (pApp,1);

	// first of all, try to save the current prefs (so that any log entries are dumped
	// onto disk -- this allows us to save useful info for dbg purposes) we will enclose
	// this inside of a try/catch block, so that in the (unlikely) case something goes
	// badly wrong when writing the prefs file, we still get chance to save the open
	// documents

	try
	{
		if(pApp->getPrefs())
		{
			pApp->getPrefs()->savePrefsFile();
		}
	}
	catch(...)
	{
		// do nothing
	}
	
	UT_uint32 i = 0;
	
	IEFileType abiType = IE_Imp::fileTypeForSuffix(".abw");
	for(;i<pApp->m_vecFrames.getItemCount();i++)
	{
		AP_Win32Frame * curFrame = (AP_Win32Frame*)pApp->m_vecFrames[i];
		UT_return_val_if_fail (curFrame,1);

		// again, we want to catch any exception thrown while saving individual documents,
		// in order to run through the whole loop
		try
		{
			if (NULL == curFrame->getFilename())
				curFrame->backup(".abw.saved", abiType);
			else
				curFrame->backup(".saved", abiType);
		}
		catch(...)
		{
			// do nothing
		}
	}	

	// Tell the user was has just happened
	AP_Win32Frame * curFrame = (AP_Win32Frame*)pApp->m_vecFrames[0];
	if (curFrame)
	{
		curFrame->showMessageBox(AP_STRING_ID_MSG_Exception,XAP_Dialog_MessageBox::b_O, XAP_Dialog_MessageBox::a_OK);
		
	}
}// end of except

	SET_CRT_DEBUG_FIELD( _CRTDBG_LEAK_CHECK_DF );
	return msg.wParam;
}

/* This function takes a description and compares it all the registerd 
   importers descriptions and returns either the appropriate importer's
   IEFileType or returns IEFT_Unknown if no match was made.
*/
IEFileType AP_Win32App::_getFileTypeFromDesc(const char *desc)
{
	const char *iftDesc;
	const char *iftSuffixList;
	IEFileType ift;

	// no description given or description == 'UNKNOWN' then unknown
	if (!desc || !*desc || (UT_stricmp(desc, "Unknown")==0)) 
		return IEFT_Unknown;  

	UT_uint32 i = 0;
	while (IE_Imp::enumerateDlgLabels(i, &iftDesc, &iftSuffixList, &ift))
	{
		// TODO: change to actually test all but suffixes, 
		// ie if iftDesc == 'Some FileType (*.sft, *.someft)' then only
            // test against 'Some FileType'
		if (UT_strnicmp(iftDesc, desc, strlen(desc)) == 0)
			return ift;
		
		// try next importer
		i++;
	}

	// if we made it here then description didn't match anything, so unknown.
	return IEFT_Unknown;
}

UT_Error AP_Win32App::fileOpen(XAP_Frame * pFrame, const char * pNewFile)
{
	return ::fileOpen(pFrame, pNewFile, IEFT_Unknown);
}

bool AP_Win32App::handleModelessDialogMessage( MSG * msg )
{
	int iCounter;
	HWND hWnd = NULL;

	// Try to knock off the easy case quickly
	if( m_IdTable[ 0 ].id == -1 )
		return false;

    for( iCounter = 0; iCounter <= NUM_MODELESSID; iCounter++ )
	{
		if( m_IdTable[ iCounter ].id != -1 )
		{
			hWnd = (HWND)m_IdTable[ iCounter ].pDialog->pGetWindowHandle();

			if( hWnd && IsDialogMessage( hWnd, msg ) )
				return true;
		}
		else
			break;
	}

	return false;
}

// cmdline processing call back I reckon
void AP_Win32App::errorMsgBadArg(AP_Args * Args, int nextopt)
{
	char *pszMessage = (char*)malloc( 500 );
	strcpy( pszMessage, "Error on option " );
	strcat( pszMessage, poptBadOption (Args->poptcon, 0) );
	strcat( pszMessage, ": " );
	strcat( pszMessage, poptStrerror (nextopt) );
	strcat( pszMessage, "\nRun with --help' to see a full list of available command line options.\n" );
	MessageBox(NULL, pszMessage, "Command Line Option Error", MB_OK|MB_ICONERROR);
	free( pszMessage );
}

// cmdline processing call back I reckon
void AP_Win32App::errorMsgBadFile(XAP_Frame * pFrame, const char * file, 
							 UT_Error error)
{
	s_CouldNotLoadFileMessage (pFrame, file, error);
}

/*!
 * A callback for AP_Args's doWindowlessArgs call which handles
 * platform-specific windowless args.
 * return false if we should exit normally but Window should not be displayed
 */
bool AP_Win32App::doWindowlessArgs(const AP_Args *Args, bool & bSuccess)
{
	bSuccess = true;

	AP_Win32App * pMyWin32App = static_cast<AP_Win32App*>(Args->getApp());

	if (Args->m_sGeometry)
	{
		// [--geometry <X geometry string>]
		#if 0
		gint x = 0;
		gint y = 0;
		guint width = 0;
		guint height = 0;
		
		XParseGeometry(Args->m_sGeometry, &x, &y, &width, &height);

		// set the xap-level geometry for future frame use
		Args->getApp()->setGeometry(x, y, width, height, f);
		#endif

		parseAndSetGeometry(Args->m_sGeometry);
	}
	else
	if (Args->m_sPrintTo) 
	{
		if ((Args->m_sFile = poptGetArg (Args->poptcon)) != NULL)
		{
			UT_DEBUGMSG(("DOM: Printing file %s\n", Args->m_sFile));
			AP_Convert conv ;

			if (Args->m_sMerge)
				conv.setMergeSource (Args->m_sMerge);

			if (Args->m_impProps)
				conv.setImpProps (Args->m_impProps);
			if (Args->m_expProps)
				conv.setExpProps (Args->m_expProps);
			
			UT_String s = "AbiWord: ";
			s+= Args->m_sFile;
			
			GR_Graphics * pG = GR_Win32Graphics::getPrinterGraphics(Args->m_sPrintTo, s.c_str());
			if(!pG)
			{
				// do not assert here, if the graphics creation failed, the static
				// constructor has asserted already somewhere more relevant
				return false;
			}
			
			conv.setVerbose(Args->m_iVerbose);
			conv.print (Args->m_sFile, pG, Args->m_sFileExtension);
	      
			delete pG;
		}
		else
		{
			// couldn't load document
			printf("Error: no file to print!\n");
			bSuccess = false;
		}

		return false;
	}

	if(Args->m_sPlugin)
	{
	//
	// Start a plugin rather than the main abiword application.
	//
		const char * szName = NULL;
		XAP_Module * pModule = NULL;
		Args->m_sPlugin = poptGetArg(Args->poptcon);
		bool bFound = false;
		if(Args->m_sPlugin != NULL)
		{
			const UT_GenericVector<class XAP_Module *> *pVec = XAP_ModuleManager::instance().enumModules ();
			for (UT_uint32 i = 0; (i < pVec->size()) && !bFound; i++)
			{
				pModule = (XAP_Module *)pVec->getNthItem (i);
				szName = pModule->getModuleInfo()->name;
				if(UT_strcmp(szName,Args->m_sPlugin) == 0)
					bFound = true;
			}
		}
		if(!bFound)
		{
			printf("Plugin %s not found or loaded \n",Args->m_sPlugin);
			bSuccess = false;
			return false;
		}

//
// You must put the name of the ev_EditMethod in the usage field
// of the plugin registered information.
//
		const char * evExecute = pModule->getModuleInfo()->usage;
		EV_EditMethodContainer* pEMC = pMyWin32App->getEditMethodContainer();
		const EV_EditMethod * pInvoke = pEMC->findEditMethodByName(evExecute);
		if(!pInvoke)
		{
			printf("Plugin %s invoke method %s not found \n",
				   Args->m_sPlugin,evExecute);
			bSuccess = false;
			return false;
		}
		//
		// Execute the plugin, then quit
		//
		ev_EditMethod_invoke(pInvoke, UT_String("Called From App"));
		return false;
	}

	return true;
}


/*
	Get the user interface languages installed
	Caller should delete the allocated vector
*/	
UT_Vector*	AP_Win32App::getInstalledUILanguages(void)
{		
	const char * szDirectory = NULL;
	const XML_Char * szStringSet = NULL;
	UT_Vector* pVec = new UT_Vector();
	UT_Language lang;	
					
	for (UT_uint32 i=0; i< lang.getCount(); i++)
	{
		const char *pLangCode = (const char*)lang.getNthLangCode(i);
		if (doesStringSetExist(pLangCode))
			pVec->addItem(strdup((char*)pLangCode));	
		else
		{	
			/*The en-US is the default internal string set and wont be found on disk but it should be also listed*/
			if (strcmp(pLangCode, "en-US")==0)
				pVec->addItem(strdup((char*)pLangCode));		
		}
		
	}		

	return pVec;
}

/*
	Does a stringSet exist on disk?
*/
bool	AP_Win32App::doesStringSetExist(const char* pLocale)
{
	FILE* in;
	const char * szDirectory = NULL;	

	UT_return_val_if_fail(pLocale, false);
	
	getPrefsValueDirectory(true,AP_PREF_KEY_StringSetDirectory,&szDirectory);
	UT_return_val_if_fail(((szDirectory) && (*szDirectory)), false);

	char * szPathname = (char *)calloc(sizeof(char),strlen(szDirectory)+strlen(pLocale)+100);
	UT_return_val_if_fail(szPathname, false);
				
	sprintf(szPathname,"%s%s%s.strings",
				szDirectory,
				((szDirectory[strlen(szDirectory)-1]=='\\') ? "" : "\\"),
				pLocale);				
	
	in =  fopen(szPathname, "r");	
	free (szPathname);
	
	if (in)
	{
		fclose(in);		
		return true;
	}			
	
	return false;
}

/* From UCS4 To WinLocale */
UT_String  	AP_Win32App::s_fromUCS4ToWinLocale(const UT_UCS4Char * szIn)
{		
	UT_UCS4String sUCS4(szIn);
	UT_String sRslt;
	
	char *pText = UT_convert ((char *)sUCS4.ucs4_str(),
							  sUCS4.length()*sizeof(UT_UCS4Char),
							  ucs4Internal(),
							  XAP_App::getApp()->getDefaultEncoding(),
							  NULL, NULL);
	sRslt = pText;
	free(pText);
	return sRslt;

}

/* From WinLocale To UCS4*/
UT_UCS4String	AP_Win32App::s_fromWinLocaleToUCS4(const char* szIn)
{
	UT_UCS4Char * src = new UT_UCS4Char[strlen(szIn)+1];	
	UT_UCS4_strcpy_char(src, (char*)szIn);	
	UT_UCS4String sRslt(src);	
	delete src;

	return sRslt;
}

/* From  UTF8 To WinLocale */
UT_String 		AP_Win32App::s_fromUTF8ToWinLocale(const char* szInUTF8)
{
	UT_UTF8String utf8(szInUTF8);	
	UT_UCS4String sUCS4(utf8.ucs4_str());
	return AP_Win32App::s_fromUCS4ToWinLocale(sUCS4.ucs4_str());
}

/* From WinLocale To UTF8*/
UT_UTF8String	AP_Win32App::s_fromWinLocaleToUTF8(const char* szIn)
{
	UT_UCS4String sUCS4 = AP_Win32App::s_fromWinLocaleToUCS4(szIn);
	UT_UTF8String sRslt(sUCS4.utf8_str());	

	return sRslt;
}

GR_Graphics * AP_Win32App::newDefaultScreenGraphics() const
{
	XAP_Frame * pFrame = findValidFrame();
	UT_return_val_if_fail( pFrame, NULL );
	
	AP_Win32FrameImpl * pFI = (AP_Win32FrameImpl *) pFrame->getFrameImpl();
	UT_return_val_if_fail( pFI, NULL );

	return pFI->createDocWndGraphics();
}
