/*
    Variables Plugin for Miranda-IM (www.miranda-im.org)
    Copyright 2003-2006 P. Boon

    This program is mir_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 "variables.h"
#include "parse_external.h"
#include "ac/ac.h"

static int (WINAPI *acEval)(const char *, char *) = NULL;
static int (WINAPI *acFormat)(const char *, char *) = NULL;
static int (WINAPI *acInitClient)(const char *, int, int, int, int) = NULL;
static void (WINAPI *acUninit)() = NULL;

static unsigned int lastAMIPFailure = -1;

static TCHAR *getFullWinampTitleText() {

	TCHAR *szTitle, *szWinText;
	HWND hwndWinamp;

	hwndWinamp = FindWindow(_T("STUDIO"), NULL);
	if (hwndWinamp == NULL)
		hwndWinamp = FindWindow(_T("Winamp v1.x"),NULL);

	if (hwndWinamp == NULL)
		return NULL;

	szWinText = (TCHAR*)mir_alloc((GetWindowTextLength(hwndWinamp) + 1)*sizeof(TCHAR));
	if (szWinText == NULL)
		return NULL;

	if (GetWindowText(hwndWinamp, szWinText, GetWindowTextLength(hwndWinamp)+1) == 0) {
		mir_free(szWinText);
		return NULL;
	}
	szTitle = (TCHAR*)mir_alloc((2*_tcslen(szWinText)+1)*sizeof(TCHAR));
	if (szTitle == NULL) {
		mir_free(szWinText);
		return NULL;
	}
	_tcscpy(szTitle, szWinText);
	_tcscpy(szTitle+_tcslen(szTitle), szWinText);
	mir_free(szWinText);

	return szTitle;
}

static TCHAR *parseWinampSong(ARGUMENTSINFO *ai) {

	TCHAR *szTitle, *scur, *cur, *res;

	if (ai->argc != 1) {
		return NULL;
	}
	res = NULL;
	szTitle = getFullWinampTitleText();
	if (szTitle == NULL) {
		return NULL;
	}
	scur = _tcschr(szTitle, _T('.'));
	cur = _tcsstr(scur, _T(" - Winamp"));
	if ((scur == NULL) || (cur == NULL) || (scur >= cur) || (scur > (szTitle + _tcslen(szTitle) - 2)) || (cur > (szTitle + _tcslen(szTitle)))) {
		mir_free(szTitle);
		return NULL;
	}
	scur++;
	scur++;
	*cur = '\0';
	res = mir_tstrdup(scur);
	mir_free(szTitle);
	ai->flags |= AIF_DONTPARSE;
	
	return res;
}

static TCHAR *parseWinampState(ARGUMENTSINFO *ai) {

	TCHAR *szTitle, *scur, *cur, *res;

	if (ai->argc != 1) {
		return NULL;
	}
	res = NULL;
	szTitle = getFullWinampTitleText();
	if (szTitle == NULL) {
		return NULL;
	}
	scur = _tcschr(szTitle, _T('.'));
	cur = _tcsstr(scur, _T(" - Winamp"));
	if ((scur == NULL) || (cur == NULL)) {
		mir_free(szTitle);
		return mir_tstrdup(TranslateT("Stopped"));
	}
	if ((!_tcsncmp(cur+10, _T("[Stopped]"), 9))) {
		mir_free(szTitle);
		return mir_tstrdup(TranslateT("Stopped"));
	}
	if ((!_tcsncmp(cur+10, _T("[Paused]"), 8))) {
		mir_free(szTitle);
		return mir_tstrdup(TranslateT("Paused"));
	}
	mir_free(szTitle);
	return mir_tstrdup(_T("Playing"));
}

static unsigned int checkAMIP() {

	if (lastAMIPFailure == 0) {
		log_debugA("AMIP initialized");
		return 0;
	}
	if (GetTickCount() - lastAMIPFailure < AMIP_TIMEOUT) {
		log_debugA("AMIP not initialized, not attempting");
		return -1;
	}
	if (acInitClient("127.0.0.1", 60333, 1000, 5, 1)) {
		lastAMIPFailure = 0;
		log_debugA("AMIP now initialized");
		
		return 0; // success
	}
	log_debugA("AMIP failed to initialized");
	if (lastAMIPFailure == 0) {
		/* if this is the first failure after a succesful init, call uninit for a cleanup (maybe it'll help for the next try ;)) */
		acUninit();
	}
	lastAMIPFailure = GetTickCount();
	
	return -1;
}

static TCHAR *parseAMIPEval(ARGUMENTSINFO *ai) {

	TCHAR *tszRes;
	char *cmd;
	char szRes[AC_BUFFER_SIZE];

	tszRes = NULL;
	if (ai->argc != 2) {
		return NULL;
	}

	cmd = mir_t2a(ai->targv[1]);

	if (checkAMIP() != 0) {
		log_debugA("checkAMIP failed");
	
		return NULL;
	}
	ZeroMemory(&szRes, sizeof(szRes));
	if (AC_ERR_NOERROR == acEval(cmd, szRes)) {

		tszRes = mir_a2t(szRes);

	}
	else {
		lastAMIPFailure = GetTickCount();
	}
	mir_free(cmd);

	return tszRes;
}

static TCHAR *parseAMIPFormat(ARGUMENTSINFO *ai) {

	TCHAR *tszRes;
	char *cmd;
	char szRes[AC_BUFFER_SIZE];

	tszRes = NULL;
	if (ai->argc != 2) {
		return NULL;
	}

	cmd = mir_t2a(ai->targv[1]);

	if (checkAMIP() != 0) {
	
		return NULL;
	}
	if (AC_ERR_NOERROR == acFormat(cmd, szRes)) {

		tszRes = mir_a2t(szRes);

	}
	else {
		lastAMIPFailure = GetTickCount();
	}
	mir_free(cmd);

	return tszRes;
}

static int initAMIP() {

	HMODULE hModule;
	
	hModule = LoadLibraryA("ac.dll");
	if (hModule == NULL) {
		char path[MAX_PATH];
		char *cur;

		GetModuleFileNameA(NULL, path, sizeof(path));
		cur = strrchr(path, '\\');
		if (cur != NULL)
			strcpy(cur+1, "ac.dll");
		else
			strcpy(cur, "ac.dll");
		hModule = LoadLibraryA(path);
	}
	if (hModule == NULL) {
		return -1;
	}
	acInitClient = (int (__stdcall *)(const char *,int ,int ,int ,int ))GetProcAddress(hModule, "ac_init_client");
	acEval = (int (__stdcall *)(const char *,char *))GetProcAddress(hModule, "ac_eval");
	acFormat = (int (__stdcall *)(const char *,char *))GetProcAddress(hModule, "ac_format");
	acUninit = (void (__stdcall *)())GetProcAddress(hModule, "ac_uninit");
	
	return 0;
}

int registerExternalTokens() {

	registerIntToken(_T(WINAMPSONG), parseWinampSong, TRF_FIELD, "External Applications\tretrieves song name of the song currently playing in Winamp");
	registerIntToken(_T(WINAMPSTATE), parseWinampState, TRF_FIELD, "External Applications\tretrieves current Winamp state (Playing/Paused/Stopped)");
	if (!initAMIP()) {
		registerIntToken(_T(AMIPEVAL), parseAMIPEval, TRF_FUNCTION, "External Applications\t(x)\tretrieves info from AMIP (x is var_<variable> with any AMIP variable)");
		registerIntToken(_T(AMIPFORMAT), parseAMIPFormat, TRF_FUNCTION|TRF_UNPARSEDARGS, "External Applications\t(x)\tretrieves info from AMIP (x is AMIP format string)");
	}
	else {
		log_infoA("Variables: ac.dll for AMIP not found");
	}

	return 0;
}

int deInitExternal() {

	if (acUninit != NULL) {
		acUninit();
	}
	
	return 0;
}