/*
Miranda SmileyAdd Plugin
Copyright (C) 2004-2005 Rein-Peter de Boer (peacow) and followers

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.
*/

//imagedataobject
//code taken partly from public example on the internet, source unknown.

#include "headers.h"

struct EMFCACHE
{
	HENHMETAFILE hEmf;
	HICON hIcon;
	EMFCACHE *prev;
	EMFCACHE *next;
} *emfCache = 0;
int emfCacheSize = 0;
CRITICAL_SECTION csEmfCache;

void LoadEmfCache()
{
	InitializeCriticalSection(&csEmfCache);
}

void UnloadEmfCache()
{
	while (emfCache)
	{
		EMFCACHE *tmp = emfCache->next;
		delete emfCache;
		emfCache = tmp;
	}
	DeleteCriticalSection(&csEmfCache);
}

HENHMETAFILE CacheIconToEmf(HICON hIcon)
{
	HENHMETAFILE result = 0;
	EnterCriticalSection(&csEmfCache);
	for (EMFCACHE *p = emfCache; p; p = p->next)
		if (p->hIcon == hIcon)
		{
			if (p->prev)
			{
				p->prev->next = p->next;
				if (p->next) p->next->prev = p->prev;
				p->prev = 0;
				emfCache->prev = p;
				p->next = emfCache;
				emfCache = p;
				result = CopyEnhMetaFile(emfCache->hEmf, 0);
				break;
			}
		}

	// cache new item
	if (!result)
	{
		EMFCACHE *newItem = new EMFCACHE;
		newItem->prev = 0;
		newItem->next = emfCache;
		if (emfCache) emfCache->prev = newItem;
		emfCache = newItem;
		emfCacheSize++;

		HDC emfdc = CreateEnhMetaFile(NULL, NULL, NULL, _T("icon"));
		DrawIconEx(emfdc, 0, 0, (HICON)hIcon, 16, 16, 0, NULL, DI_NORMAL);
		emfCache->hIcon = hIcon;
		emfCache->hEmf = CloseEnhMetaFile(emfdc);
		result = CopyEnhMetaFile(emfCache->hEmf, 0);
	}

	// tail cutoff
	if (emfCacheSize > 20)
	{
		int n = 0;
		EMFCACHE *p;
		for (p = emfCache; p; p = p->next)
			if (++n > 20)
				break;
		while (p->next)
		{
			EMFCACHE *tmp = p->next;
			p->next = p->next->next;
			delete tmp;
		}
		if (p->next) p->next->prev = p;
		emfCacheSize = 20;
	}

	LeaveCriticalSection(&csEmfCache);

	return result;
}

HRESULT CreateDataObject(const FORMATETC *fmtetc, const STGMEDIUM *stgmed, UINT count, IDataObject **ppDataObject);

// returns true on success, false on failure
//bool InsertBitmap(IRichEditOle* pRichEditOle, HBITMAP hBitmap, HGLOBAL hGlobal)
bool InsertBitmap(IRichEditOle* pRichEditOle, HENHMETAFILE hEmf)
{
    SCODE sc;

    // Get the image data object
    //
	static const FORMATETC lc_format[] =
	{ 
		{ CF_ENHMETAFILE, 0, DVASPECT_CONTENT, -1, TYMED_ENHMF }//,
//		{ CF_BITMAP, 0, DVASPECT_CONTENT, -1, TYMED_GDI },
//		{ CF_TEXT,   0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL } 
	};

	STGMEDIUM lc_stgmed[] =
	{
		{ TYMED_ENHMF, { (HBITMAP)hEmf }, 0 }//,
//		{ TYMED_GDI, { hBitmap }, 0 },
//		{ TYMED_HGLOBAL, { (HBITMAP)hGlobal }, 0 }
	};

	IDataObject *pods;
	CreateDataObject(lc_format, lc_stgmed, 1, &pods);

    // Get the RichEdit container site
    //
    IOleClientSite *pOleClientSite; 
    pRichEditOle->GetClientSite(&pOleClientSite);

    // Initialize a Storage Object
    //
    LPLOCKBYTES lpLockBytes = NULL;
    sc = CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes);
    if (sc != S_OK) 
	{
        pOleClientSite->Release();
        return false; 
    }

    IStorage *pStorage; 
    sc = StgCreateDocfileOnILockBytes(lpLockBytes,
                                      STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &pStorage);
    if (sc != S_OK) 
    {
		lpLockBytes->Release();
        pOleClientSite->Release();
        return false; 
    }

    // The final ole object which will be inserted in the richedit control
    //
    IOleObject *pOleObject;
    sc = OleCreateStaticFromData(pods, IID_IOleObject, OLERENDER_FORMAT, 
                                 (LPFORMATETC)lc_format, pOleClientSite, pStorage, (void **)&pOleObject);
    if (sc != S_OK) 
    {
        pStorage->Release();
		lpLockBytes->Release();
        pOleClientSite->Release();
        return false;
    }

    // all items are "contained" -- this makes our reference to this object
    //  weak -- which is needed for links to embedding silent update.
    OleSetContainedObject(pOleObject, TRUE);

    // Now Add the object to the RichEdit 
    //
	REOBJECT reobject = { 0 };

	reobject.cbStruct = sizeof(REOBJECT);
    reobject.cp = REO_CP_SELECTION ;
    reobject.dvaspect = DVASPECT_CONTENT;
    reobject.poleobj = pOleObject;
    reobject.polesite = pOleClientSite;
    reobject.pstg = pStorage;
    reobject.dwFlags = REO_BELOWBASELINE;

    sc = pOleObject->GetUserClassID(&reobject.clsid);
    if (sc != S_OK) 
	{
        pOleObject->Release();
        pStorage->Release();
		lpLockBytes->Release();
		pOleClientSite->Release();
        return false;
    }

    // Insert the bitmap at the current location in the richedit control
    //
    sc = pRichEditOle->InsertObject(&reobject);

    // Release all unnecessary interfaces
    //
    pOleObject->Release();
    pStorage->Release();
    lpLockBytes->Release();
    pOleClientSite->Release();
    pods->Release();

	return sc == S_OK;
}
/*
int RichEditVersion(void) 
{
    // get size of version information
    DWORD dummy;
    DWORD size = ::GetFileVersionInfoSize(_T("riched20.dll"), &dummy);
    if (!size) return -1;  // unexpected failure

    // allocate a buffer for version information
    BYTE* buffer = (BYTE*) new BYTE[size];

    // get the version information
    if (!::GetFileVersionInfo(_T("riched20.dll"), 0, size, buffer)) 
	{
        delete[] buffer;
        return -1;  // unexpected faiure
    }

    // get the static version information
    VS_FIXEDFILEINFO* vsInfo;
    UINT vsInfoSize;
    if (!::VerQueryValue(buffer, _T("\\"), (LPVOID*) &vsInfo, &vsInfoSize)) 
	{
        delete[] buffer;
        return -1;  // unexpected failure
    }

    int FileVersionMinor = LOWORD(vsInfo->dwFileVersionMS);

    // free the buffer
    delete[] buffer;

    return FileVersionMinor ? 3 : 2;
}

bool g_HiddenTextSupported =  RichEditVersion() == 3;
*/