/*
 *  $Id: string.c,v 1.17 2005/05/30 13:03:13 lordjaxom Exp $
 */

#include "xml/string.h"
#include "render.h"

static const char *Tokens[__COUNT_TOKEN__] = {
	"DateTime", "FreeDiskSpace", "AudioTrack", "AudioChannel",

	// Channel Display
	"ChannelNumber", "ChannelName", "ChannelShortName", "ChannelBouquet", "ChannelPortal", 
	"ChannelSource", "ChannelID", "PresentStartDateTime", "PresentVPSDateTime", 
	"CurrentEventsTitle1", "CurrentEventsStartDateTime1", "CurrentEventsStopDateTime1", "CurrentEventsChannelNumber1", "CurrentEventsChannelName1", "CurrentEventsIsRecording1", "CurrentEventsTitle2", "CurrentEventsStartDateTime2", "CurrentEventsStopDateTime2", "CurrentEventsChannelNumber2", "CurrentEventsChannelName2", "CurrentEventsIsRecording2",
	"CurrentEventsTitle3", "CurrentEventsStartDateTime3", "CurrentEventsStopDateTime3", "CurrentEventsChannelNumber3", "CurrentEventsChannelName3", "CurrentEventsIsRecording3",
	"TimerConflict",
	"PresentEndDateTime", "PresentDuration", "PresentProgress", "PresentRemaining",
	"PresentLanguageCode", "PresentLanguageDescription", "PresentVideoAR",
	"PresentTitle", "PresentShortText", "PresentDescription", "FollowingStartDateTime", 
	"FollowingVPSDateTime", "FollowingEndDateTime", "FollowingDuration",
	"FollowingTitle", "FollowingShortText", "FollowingDescription", "Language",
	"HasTeletext", "ChannelHasTeletext", "HasMultilang", "ChannelHasMultilang", "HasDolby", 
	"ChannelHasDolby", "IsEncrypted", "ChannelIsEncrypted", "IsRadio", "ChannelIsRadio",
	"IsRecording", "CurrentRecording", "HasVPS", "HasTimer", "IsRunning", "ChannelHasVPS",
	"PresentHasTimer", "PresentIsRunning", "PresentHasVPS", "FollowingHasTimer", 
	"FollowingIsRunning", "FollowingHasVPS",
	
	// Volume Display
	"VolumeCurrent", "VolumeTotal", "IsMute", "VolumeIsMute",
	
	// Message Display
	"Message", "MessageStatus", "MessageInfo", "MessageWarning",
	"MessageError",
	
	// Replay Display
	"ReplayTitle", "ReplayPositionIndex", "ReplayDurationIndex", "ReplayPrompt", 
	"ReplayName", "ReplayDateTime", "ReplayShortText", "ReplayDescription",
	"ReplayLanguageCode", "ReplayLanguageDescription", "ReplayVideoAR",
	"IsPlaying", "ReplayIsPlaying", "IsFastForward", "ReplayIsFastForward", "IsFastRewind", 
	"ReplayIsFastRewind", "IsSlowForward", "ReplayIsSlowForward", "IsSlowRewind", 
	"ReplayIsSlowRewind", "IsPausing", "ReplayIsPausing",
	"ReplayPosition", "ReplayDuration", "ReplayRemaining", "ReplayMode", "ReplayIsShuffle",
	"ReplayIsLoop",

	// Menu Page
	"MenuTitle", "MenuGroup", "IsMenuGroup", "MenuItem", "IsMenuItem", "MenuCurrent", 
	"IsMenuCurrent", "MenuText", "RecordingName", "RecordingDateTime", "RecordingTitle",
	"RecordingShortText", "RecordingDescription", "RecordingLanguageCode",
	"RecordingVideoAR", "RecordingSize", "RecordingLength", "RecordingCuttedLength", "OsdWidth", "OsdHeight",
	"RecordingLanguageDescription", "ButtonRed", "ButtonGreen", 
	"ButtonYellow", "ButtonBlue", "CanScrollUp", "CanScrollDown"
};

std::string txToken::Token(const txToken &Token) 
{
	std::string result = (std::string)"{" + Tokens[Token.Type];
	//if (Token.Attrib.length() > 0)
	//	result += ":" + Token.Attrib;
	result += "}";
	
	return result;
}

cxString::tStringList cxString::mStrings;

cxString::cxString(cxObject *Parent, bool Translate):
		mObject(Parent),
		mSkin(Parent->Skin()),
		mTranslate(Translate)
{
	mStrings.push_back(this);
}

cxString::~cxString()
{
	tStringList::iterator it = mStrings.begin();
	for (; it != mStrings.end(); ++it) {
		if ((*it) == this) {
			mStrings.erase(it);
			break;
		}
	}
}

void cxString::Reparse(void)
{
	tStringList::iterator it = mStrings.begin();
	for (; it != mStrings.end(); ++it) {
		if ((*it)->mTranslate && (*it)->mText.length() > 0)
			(*it)->Parse((*it)->mOriginal, true);
	}
}

bool cxString::Parse(const std::string &Text, bool Translate) 
{
	std::string trans = Translate ? mSkin->Translate(Text) : Text;
	const char *text = trans.c_str();
	const char *ptr = text, *last = text;
	bool inToken = false;
	bool inAttrib = false;
	int offset = 0;

	Dprintf("parsing: %s\n", Text.c_str());
	mOriginal = Text;
	mText = "";
	mTokens.clear();

	for (; *ptr; ++ptr) {
		if (inToken && *ptr == '\\') {
			if (*(ptr + 1) == '\0') {
				esyslog("ERROR: Stray \\ in token attribute\n");
				return false;
			}

			++ptr;
			continue;
		} 
		else if (*ptr == '{') {
			if (inToken) {
				esyslog("ERROR: Unexpected '{' in token");
				return false;
			}

			mText.append(last, ptr - last);
			last = ptr + 1;
			inToken = true;
		}
		else if (*ptr == '}' || (inToken && *ptr == ':')) {
			if (!inToken) {
				esyslog("ERROR: Unexpected '}' outside of token");
				return false;
			}

			if (inAttrib) {
				if (*ptr == ':') {
					esyslog("ERROR: Unexpected ':' inside of token attribute");
					return false;
				}

				int pos = -1;
				std::string attr;
				attr.assign(last, ptr - last);
				while ((pos = attr.find('\\', pos + 1)) != -1) {
					switch (attr[pos + 1]) {
					case 'n':
						attr.replace(pos, 2, "\n");
						break;

					default:
						attr.erase(pos, 1);
					}
				}

				txToken &lastToken = mTokens[mTokens.size() - 1];
				if (attr == "clean")
					lastToken.Attrib = aClean;
				else if (attr == "rest")
					lastToken.Attrib = aRest;
				else {
					char *end;
					int n = strtol(attr.c_str(), &end, 10);
					Dprintf("attr: %s, n: %d, end: |%s|\n", attr.c_str(), n, end);
					if (end != attr.c_str() && *end == '\0') {
						Dprintf("a number\n");
						lastToken.Attrib = n;
					} else
						lastToken.Attrib = attr;
				} 

				inAttrib = false;
				inToken = false;
			} else {
				int i;
				for (i = 0; i < (int)__COUNT_TOKEN__; ++i) {
					if ((size_t)(ptr - last) == strlen(Tokens[i]) 
							&& memcmp(last, Tokens[i], ptr - last) == 0) {
						txToken token((exToken)i, offset, "");
						mTokens.push_back(token);
						break;
					}
				}

				if (i == (int)__COUNT_TOKEN__) {
					esyslog("ERROR: Unexpected token {%.*s}", (int)(ptr - last), last);
					return false;
				}

				if (*ptr == ':')
					inAttrib = true;
				else
					inToken = false;
			}

			last = ptr + 1;
		}
		else if (!inToken)
			++offset;
	}

	if (inToken) {
		esyslog("ERROR: Expecting '}' in token");
		return false;
	}

	mText.append(last, ptr - last);

	if (mTranslate && !Translate && mText.length() > 0)
		Parse(Text, true);
	return true;
}

cxType cxString::Evaluate(void) const 
{
	std::string result;
	int offset = 0;

	if (mText.length() == 0 && mTokens.size() == 1)
		return cText2SkinRender::GetToken(mTokens[0]);

	for (uint i = 0; i < mTokens.size(); ++i) {
		result.append(mText.c_str() + offset, mTokens[i].Offset - offset);
		result.append(cText2SkinRender::GetToken(mTokens[i]));
		offset = mTokens[i].Offset;
	}
	result.append(mText.c_str() + offset);
	return result;
}

