/*
IEView history viewer plugin for Miranda IM

Copyright � 2005-2006 Cristian Libotean

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

#include "stdafx.h"

#ifdef _DEBUG
int LogInit()
{
	FILE *fout = fopen("IEHistory.log", "wt");
	fclose(fout);
	return 0;
}
int Log(char *format, ...)
{
	char		str[4096];
	va_list	vararg;
	int tBytes;
	FILE *fout = fopen("IEHistory.log", "at");
	if (!fout)
		{
//			MessageBox(0, "can't open file", NULL, MB_OK);
		}

	va_start(vararg, format);
	
	tBytes = _vsnprintf(str, sizeof(str), format, vararg);
	if (tBytes > 0)
		{
			str[tBytes] = 0;
		}

	va_end(vararg);
	if (str[strlen(str) - 1] != '\n')
		{
			strcat(str, "\n");
		}
	fputs(str, fout);
	fclose(fout);
	return 0;
}
#endif



int Info(char *title, char *format, ...)
{
	char str[4096];
	va_list vararg;
	int tBytes;
	va_start(vararg, format);
	tBytes = snprintf(str, sizeof(str), format, vararg);
	if (tBytes > 0)
		{
			str[tBytes] = 0;
		}
	va_end(vararg);
	return MessageBoxA(0, str, title, MB_OK | MB_ICONINFORMATION);		
}

/*
returns the name of a contact
*/

TCHAR *GetContactName(MCONTACT contact)
{
	CONTACTINFO ctInfo={sizeof(ctInfo)};
//	if(db_mc_isMeta(contact))
//		contact=db_mc_getMostOnline(contact);
	ctInfo.szProto = GetContactProto(contact);
	ctInfo.dwFlag = CNF_DISPLAY;
#ifdef _UNICODE
	ctInfo.dwFlag += CNF_UNICODE;
#endif
	ctInfo.hContact = contact;
	if(CallService(MS_CONTACT_GETCONTACTINFO,0,(LPARAM)&ctInfo)){
		return NULL;
	}
	TCHAR* buffer = _tcsdup(ctInfo.pszVal);
	mir_free(ctInfo.pszVal);
	return buffer;
}

/*
Moves a control with regard to certain anchors (like delphi, c#, ...)
Somebody please improve on this code ...
*/

void ScreenToClient(HWND hWnd, LPRECT rect)
{
	POINT pt;
	int cx = rect->right - rect->left;
	int cy = rect->bottom - rect->top;
	pt.x = rect->left;
	pt.y = rect->top;
	ScreenToClient(hWnd, &pt);
	rect->left = pt.x;
	rect->top = pt.y;
	rect->right = pt.x + cx;
	rect->bottom = pt.y + cy;
}

void AnchorMoveWindow(HWND window, const WINDOWPOS *parentPos, int anchors)
{
	RECT rParent;
	RECT rChild;
	
	if (parentPos->flags & SWP_NOSIZE)
		{
			return;
		}
	GetWindowRect(parentPos->hwnd, &rParent);
	rChild = AnchorCalcPos(window, &rParent, parentPos, anchors);
	MoveWindow(window, rChild.left, rChild.top, rChild.right - rChild.left, rChild.bottom - rChild.top, FALSE);
}

RECT AnchorCalcPos(HWND window, const RECT *rParent, const WINDOWPOS *parentPos, int anchors)
{
	RECT rChild;
	RECT rTmp;

	GetWindowRect(window, &rChild);
	ScreenToClient(parentPos->hwnd, &rChild);

	int cx = rParent->right - rParent->left;
	int cy = rParent->bottom - rParent->top;
	if ((cx == parentPos->cx) && (cy == parentPos->cy))
		{
			return rChild;
		}
	if (parentPos->flags & SWP_NOSIZE)
		{
			return rChild;
		}

	rTmp.left = parentPos->x - rParent->left;
	rTmp.right = (parentPos->x + parentPos->cx) - rParent->right;
	rTmp.bottom = (parentPos->y + parentPos->cy) - rParent->bottom;
	rTmp.top = parentPos->y - rParent->top;
	
	cx = (rTmp.left) ? -rTmp.left : rTmp.right;
	cy = (rTmp.top) ? -rTmp.top : rTmp.bottom;	
	
	rChild.right += cx;
	rChild.bottom += cy;
	//expanded the window accordingly, now we need to enforce the anchors
	if ((anchors & ANCHOR_LEFT) && (!(anchors & ANCHOR_RIGHT)))
		{
			rChild.right -= cx;
		}
	if ((anchors & ANCHOR_TOP) && (!(anchors & ANCHOR_BOTTOM)))
		{
			rChild.bottom -= cy;
		}
	if ((anchors & ANCHOR_RIGHT) && (!(anchors & ANCHOR_LEFT)))
		{
			rChild.left += cx;
		}
	if ((anchors & ANCHOR_BOTTOM) && (!(anchors & ANCHOR_TOP)))
		{
			rChild.top += cy;
		}
	return rChild;
}

void UnixTimeToFileTime(time_t t, LPFILETIME pft)
{
 // Note that LONGLONG is a 64-bit value
 LONGLONG ll;

 ll = Int32x32To64(t, 10000000) + 116444736000000000;
 pft->dwLowDateTime = (DWORD)ll;
 pft->dwHighDateTime = ll >> 32;
}

void UnixTimeToSystemTime(time_t t, LPSYSTEMTIME pst)
{
	FILETIME ft;
	SYSTEMTIME st;
	UnixTimeToFileTime(t, &ft);
	FileTimeToSystemTime(&ft, &st);
	SystemTimeToTzSpecificLocalTime(NULL, &st, pst);
}

HANDLE GetNeededEvent(HANDLE hEvent, int num, int direction)
{
	int i;
	typedef HANDLE (__stdcall *db_event_step_t)(MCONTACT hContact,HANDLE hDbEvent);
	db_event_step_t db_event_step;
	if(direction==DIRECTION_BACK){
		db_event_step=db_event_prev;
	}else{
		db_event_step=db_event_next;
	}
	
	for (i = 0; i < num; ++i){
		hEvent = db_event_step(0,hEvent);
	}
	return hEvent;
}

SearchResult SearchHistory(MCONTACT contact, HANDLE hFirstEvent,  void *searchData, int direction, int type)
{
	if (hFirstEvent == NULL){
		typedef HANDLE (__stdcall *db_event_start_t)(MCONTACT contact);
		db_event_start_t db_event_start=(direction==DIRECTION_BACK) ? db_event_last : db_event_first;
		hFirstEvent=db_event_start(contact);
	}
	int index = 0;
	HANDLE hEvent = hFirstEvent;
	void *buffer = NULL;
	TCHAR *search;
	bool found = false;
	int oldSize, newSize;
	oldSize = newSize = 0;
	
	DBEVENTINFO dbEvent = {0};
	dbEvent.cbSize = sizeof(dbEvent);
	
	while ((!found) && (hEvent)){
		newSize = db_event_getBlobSize(hEvent);
		if (newSize > oldSize)
			{
				buffer = (TCHAR *) realloc(buffer, newSize);
				oldSize = newSize;
			}
		dbEvent.pBlob = (PBYTE) buffer;
		dbEvent.cbBlob = newSize;
		if (db_event_get(hEvent,&dbEvent) == 0){ //successful
			switch (type)
				{
					case SEARCH_TEXT:
						{
#ifdef _UNICODE
							wchar_t TEMP[2048];
							size_t size = strlen((char *) dbEvent.pBlob) + 1;
							if (size < dbEvent.cbBlob)
							{
								search = (wchar_t *) &dbEvent.pBlob[size];
							}
							else{
								MultiByteToWideChar(CP_ACP, 0, (char *) buffer, (int)size, TEMP, 2048);
								search = TEMP;
							}
#else
							search = (char *) buffer;
#endif
							TCHAR *data = (TCHAR *) searchData;
							TCHAR *tmp = _tcsstr(search, data);
							if (tmp)
								{
									found = true;
								}
							break;
						}
					case SEARCH_TIME:
						{
							SYSTEMTIME time;
							TimeSearchData *data = (TimeSearchData *) searchData;
							UnixTimeToSystemTime((time_t) dbEvent.timestamp, &time);
							found = ((data->flags & TSDF_DATE_SET) || (data->flags & TSDF_TIME_SET)) ? true : false;
							if (data->flags & TSDF_DATE_SET)
								{
									found = ((time.wYear == data->time.wYear) && (time.wMonth == data->time.wMonth) && (time.wDay == data->time.wDay));
								}
							if (data->flags & TSDF_TIME_SET)
								{
									found = found & ((time.wHour == data->time.wHour) && (time.wMinute == data->time.wMinute));
								}
							break;
						}
				}
		}
		if (!found){
			hEvent = GetNeededEvent(hEvent, 1, direction);
			index++;
		}
	}
	free(buffer);
	SearchResult sr;
	sr.index = index;
	sr.hEvent = hEvent;
	return sr;
}