/*
IEView Plugin for Miranda IM
Copyright (C) 2005-2010 Piotr Piastucki
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 "Template.h"
#include "Utils.h"
TokenDef::TokenDef(const char *tokenString) {
	this->tokenString = tokenString;
	this->tokenLen = (int)strlen(tokenString);
	this->token = 0;
	this->escape = 0;
}
TokenDef::TokenDef(const char *tokenString, int token, int escape) {
	this->tokenString = tokenString;
	this->token = token;
	this->tokenLen = (int)strlen(tokenString);
	this->escape = escape;
}
Token::Token(int type, const char *text, int escape) {
	next = NULL;
	this->type = type;
	this->escape = escape;
	if (text!=NULL) {
		this->text = Utils::dupString(text);
	} else {
		this->text = NULL;
	}
}
Token::~Token() {
	if (text!=NULL) {
		delete text;
	}
}
Token * Token::getNext() {
	return next;
}
void Token::setNext(Token *ptr) {
	next = ptr;
}
int Token::getType() {
	return type;
}
int Token::getEscape() {
	return escape;
}
const char *Token::getText() {
	return text;
}
Template::Template(const char *name, const char *text) {
	next = NULL;
	tokens = NULL;
	this->text = Utils::dupString(text);
	this->name = Utils::dupString(name);
	tokenize();
}
Template::~Template() {
	if (text != NULL) delete text;
	if (name != NULL) delete name;
	Token *ptr = tokens, *ptr2;
	tokens = NULL;
	for (;ptr!=NULL;ptr = ptr2) {
		ptr2 = ptr->getNext();
		delete ptr;
	}
}
const char *Template::getText() {
	return text;
}
const char *Template::getName() {
	return name;
}
Template* Template::getNext() {
	return next;
}
bool Template::equals(const char *name) {
	if (!strcmp(name, this->name)) {
		return true;
	}
	return false;
}
static TokenDef tokenNames[] = {
	TokenDef("%name%", Token::NAME, 0),
	TokenDef("%time%", Token::TIME, 0),
	TokenDef("%text%", Token::TEXT, 0),
	TokenDef("%date%", Token::DATE, 0),
	TokenDef("%base%", Token::BASE, 0),
	TokenDef("%avatar%", Token::AVATAR, 0),
	TokenDef("%cid%", Token::CID, 0),
	TokenDef("%proto%", Token::PROTO, 0),
	TokenDef("%avatarIn%", Token::AVATARIN, 0),
	TokenDef("%avatarOut%", Token::AVATAROUT, 0),
	TokenDef("%nameIn%", Token::NAMEIN, 0),
	TokenDef("%nameOut%", Token::NAMEOUT, 0),
	TokenDef("%uin%", Token::UIN, 0),
	TokenDef("%uinIn%", Token::UININ, 0),
	TokenDef("%uinOut%", Token::UINOUT, 0),
	TokenDef("%nickIn%", Token::NICKIN, 0),
	TokenDef("%nickOut%", Token::NICKOUT, 1),
	TokenDef("%statusMsg%", Token::STATUSMSG, 0),
	TokenDef("%fileDesc%", Token::FILEDESC, 0),
	TokenDef("%\\name%", Token::NAME, 1),
	TokenDef("%\\time%", Token::TIME, 1),
	TokenDef("%\\text%", Token::TEXT, 1),
	TokenDef("%\\date%", Token::DATE, 1),
	TokenDef("%\\base%", Token::BASE, 1),
	TokenDef("%\\avatar%", Token::AVATAR, 1),
	TokenDef("%\\cid%", Token::CID, 1),
	TokenDef("%\\proto%", Token::PROTO, 1),
	TokenDef("%\\avatarIn%", Token::AVATARIN, 1),
	TokenDef("%\\avatarOut%", Token::AVATAROUT, 1),
	TokenDef("%\\nameIn%", Token::NAMEIN, 1),
	TokenDef("%\\nameOut%", Token::NAMEOUT, 1),
	TokenDef("%\\uin%", Token::UIN, 1),
	TokenDef("%\\uinIn%", Token::UININ, 1),
	TokenDef("%\\uinOut%", Token::UINOUT, 1),
	TokenDef("%\\nickIn%", Token::NICKIN, 1),
	TokenDef("%\\nickOut%", Token::NICKOUT, 1),
	TokenDef("%\\statusMsg%", Token::STATUSMSG, 1),
	TokenDef("%\\fileDesc%", Token::FILEDESC, 1)
};
void Template::tokenize() {
	if (text!=NULL) {
//		debugView->writef("Tokenizing: %s
---
", text);
		char *str = Utils::dupString(text);
		Token *lastToken = NULL;
		int lastTokenType = Token::PLAIN;
		int lastTokenEscape = 0;
		int l = (int)strlen(str);
		for (int i=0, lastTokenStart=0; i<=l;) {
			Token *newToken;
			int newTokenType = 0, newTokenSize = 0, newTokenEscape = 0;
			if (str[i]=='\0') {
				newTokenType = Token::END;
				newTokenSize = 1;
				newTokenEscape = 0;
			} else {
				bool found = false;
				for (unsigned int j=0; j<(sizeof(tokenNames)/sizeof(tokenNames[0])); j++) {
					if (!strncmp(str+i, tokenNames[j].tokenString, tokenNames[j].tokenLen)) {
						newTokenType = tokenNames[j].token;
						newTokenSize = tokenNames[j].tokenLen;
						newTokenEscape = tokenNames[j].escape;
						found = true;
						break;
					}
				}
				if (!found) {
					newTokenType = Token::PLAIN;
					newTokenSize = 1;
					newTokenEscape = 0;
				}
			}
			if (newTokenType != Token::PLAIN) {
				if (str[i + newTokenSize] == '%') {
					//newTokenSize++;
				}
				str[i] = '\0';
			}
			if ((lastTokenType!=newTokenType || lastTokenEscape != newTokenEscape) && i!=lastTokenStart) {
				if (lastTokenType == Token::PLAIN) {
					newToken = new Token(lastTokenType, str+lastTokenStart, lastTokenEscape);
				} else {
					newToken = new Token(lastTokenType, NULL, lastTokenEscape);
				}
				if (lastToken != NULL) {
					lastToken->setNext(newToken);
				} else {
					tokens = newToken;
				}
				lastToken = newToken;
				lastTokenStart = i;
			}
			lastTokenEscape = newTokenEscape;
			lastTokenType = newTokenType;
			i += newTokenSize;
		}
		delete str;
	}
}
Token * Template::getTokens() {
	return tokens;
}
TemplateMap* TemplateMap::mapList = NULL;
TemplateMap::TemplateMap(const char *name) {
	entries = NULL;
	next = NULL;
	filename = NULL;
	this->name = Utils::dupString(name);
	this->grouping = false;
	this->rtl = false;
}
TemplateMap::~TemplateMap() {
	if (name != NULL) {
		delete name;
	}
	if (filename != NULL) {
		delete filename;
	}
	clear();
}
TemplateMap* TemplateMap::add(const char *id, const char *filename) {
	TemplateMap *map;
	for (map=mapList; map!=NULL; map=map->next) {
		if (!strcmp(map->name, id)) {
			map->clear();
			map->setFilename(filename);
			return map;
		}
	}
	map = new TemplateMap(id);
	map->setFilename(filename);
	map->next = mapList;
	mapList = map;
	return map;
}
void TemplateMap::addTemplate(const char *name, const char *text) {
	Template *tmplate = new Template(name, text);
	tmplate->next = entries;
	entries = tmplate;
}
void TemplateMap::clear() {
	Template *ptr, *ptr2;
	ptr = entries;
	entries = NULL;
	for (;ptr!=NULL;ptr=ptr2) {
		ptr2 = ptr->getNext();
		delete ptr;
	}
}
static TokenDef templateNames[] = {
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef(""),
	TokenDef("")
};
TemplateMap* TemplateMap::loadTemplateFile(const char *id, const char *filename, bool onlyInfo) {
	FILE* fh;
	char lastTemplate[1024], tmp2[1024];
	unsigned int i=0;
	TemplateMap *tmap;
	if (filename == NULL || strlen(filename) == 0) {
		return NULL;
	}
	fh = fopen(filename, "rt");
	if (fh == NULL) {
		return NULL;
	}
	if (!onlyInfo) {
		tmap = TemplateMap::add(id, filename);
	} else {
		tmap = new TemplateMap(id);
	}
	char store[4096];
	bool wasTemplate = false;
	char *templateText = NULL;
	int templateTextSize = 0;
	while (fgets(store, sizeof(store), fh) != NULL) {
		if (sscanf(store, "%s", tmp2) == EOF) continue;
		//template start
		bool bFound = false;
		for (unsigned i = 0; i < sizeof(templateNames) / sizeof (templateNames[0]); i++) {
			if (!strncmp(store, templateNames[i].tokenString, templateNames[i].tokenLen)) {
				bFound = true;
				break;
			}
		}
		if (bFound) {
			if (wasTemplate) {
				tmap->addTemplate(lastTemplate, templateText);
			}
			if (templateText!=NULL) {
				free (templateText);
			}
			templateText = NULL;
			templateTextSize = 0;
			wasTemplate = true;
			sscanf(store, "