//---------------------------------------------------------------------------
#ifdef __BORLANDC__
#include <system.hpp>
#include <Menus.hpp>
#include <StrUtils.hpp>
#include <Dialogs.hpp>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <libxml/tree.h>
#include <algorithm>
#include <ctype.h>
#include <sstream>
#pragma hdrstop
#include "ImpExp.h"
#include "Error.h"
#include "FSTools.h"
#include "avfile_utils.h"

//---------------------------------------------------------------------------
#pragma package(smart_init)

//---------------------------------------------------------------------------
using namespace ee;

//---------------------------------------------------------------------------
TImpExp::TDefaultEvent TImpExp::DefaultEvents[] =
{
	{"Output", NULL, NULL, -1},
	{"Start speaking", "F2", "Speaking", 0},
	{"Stop speaking", "F3", "Speaking", 1},
	{"Graph", NULL, NULL, -1},
	{"Setup", NULL, NULL, -1},
	{"Detector", NULL, NULL, -1}
};

//---------------------------------------------------------------------------
TImpExp::TImpExp()
{
	TimeFormat = tfTime;
	UseXml = True;
	HubClient = new Client();
}

//---------------------------------------------------------------------------
TImpExp::~TImpExp()
{
	Clear();
	if (HubClient != NULL)
	{
		delete HubClient;
		HubClient = NULL;
	}
}

//---------------------------------------------------------------------------
void TImpExp::Clear()
{
	Sources.clear();
	EventTypes.clear();
	FreeEvents();
}

//---------------------------------------------------------------------------
void TImpExp::FreeEvents()
{
	TEvents::iterator e = Events.begin();
	while (e != Events.end())
	{
		delete *e;
		e++;
	}
	Events.clear();
}

//---------------------------------------------------------------------------
void TImpExp::InitializeInsertMessage()
{
	LastInsertedEvent = Events.end();
}

//---------------------------------------------------------------------------
void TImpExp::InsertMessage(TEvent *e)
{
	LastInsertedEvent = Events.insert(std::upper_bound(Events.begin(), Events.end(), e, LessEventTime()), e);
	LastEvent = Events.end();
}

//---------------------------------------------------------------------------
void TImpExp::InsertMessage(int Time, const char *Type, TParameters Parameters)
{
	TEvent *e = new TEvent();
	e->Time = Time;
	e->ID = GetMessageID(Type);
	e->Parameters = Parameters;
	InsertMessage(e);
}

//---------------------------------------------------------------------------
int TImpExp::FindMessageID(const char *Name)
{
	for (unsigned int i = 0; i < EventTypes.size(); i++)
	{
		if (AnsiSameText(EventTypes[i].Desc, Name))
		{
			return i;
		}
	}
	return -1;
}

//---------------------------------------------------------------------------
int TImpExp::GetMessageID(const char *Name)
{
	int ID = FindMessageID(Name);
	if (ID < 0)
	{
		EventTypes.push_back(TEventType(Name));
		ID = EventTypes.size() - 1;
	}
	return ID;
}

//---------------------------------------------------------------------------
int TImpExp::FindGroupID(const char *Desc)
{
	for (unsigned int i = 0; i < Groups.size(); i++)
	{
		if (Groups[i].Desc == Desc)
		{
			return i;
		}
	}
	return -1;
}

//---------------------------------------------------------------------------
int TImpExp::GetGroupID(const char *Desc)
{
	int ID = FindGroupID(Desc);
	if (ID < 0)
	{
		Groups.push_back(TEventTypeGroup(Desc, DefaultGroupMeaning));
		ID = Groups.size() - 1;
	}
	return ID;
}

//---------------------------------------------------------------------------
int TImpExp::AddGroup(TEventTypeGroup Group)
{
	Groups.push_back(Group);
	int ID = Groups.size() - 1;
	return ID;
}

//---------------------------------------------------------------------------
bool GetNodeString(xmlDocPtr doc, xmlNodePtr Parent, const char *Name, AnsiString &String)
{
	xmlNodePtr Children = Parent->xmlChildrenNode;
	while (Children != NULL && xmlStrcmp(Children->name, (const xmlChar *)Name))
	{
		Children = Children->next;
	}
	if (Children != NULL)
	{
		xmlChar *Value = xmlNodeListGetString(doc, Children->xmlChildrenNode, 1);
		try
		{
			String = (char*)Value;
			xmlFree(Value);
			return true;
		}
		catch (...)
		{
			xmlFree(Value);
		}
	}
	return false;
}

//---------------------------------------------------------------------------
int	TImpExp::xmlGetPropInt(xmlNodePtr Node, const xmlChar *Name, const int Default)
{
	xmlChar *ValueStr = xmlGetProp(Node, Name);

	if (ValueStr)
	{
		int Value = StrToIntDef((char*)ValueStr, Default);
		xmlFree(ValueStr);
		return Value;
	}
	else
	{
		return Default;
	}
}


//---------------------------------------------------------------------------
void TImpExp::Load(const char *FileName, bool Import, bool UseCameraOffset, int ForceCamera)
{
	AnsiString FN = FileName;

	if (AnsiString("*HUB*").AnsiCompare(FN.SubString(0, 5)) == 0)
	{
		//ShowMessage(AnsiString("HUB ") + FN);
		UseXml = False;
	}
		else
	{
		//ShowMessage(AnsiString("XML ") + FN);
		UseXml = True;
	}
	InputFileName = ExtractFileName(ExcludeTrailingBackslash(ExtractFilePath(FN)));

	if (UseXml)
	{
		LoadXML(FileName, Import, UseCameraOffset, ForceCamera);
	}
	else
	{
		LoadFromHub(FileName, Import, UseCameraOffset, ForceCamera);
	}
}

//---------------------------------------------------------------------------
void TImpExp::LoadFromHub(const char *FileName, bool Import, bool UseCameraOffset, int ForceCamera)
{
	int Offset = 0;

	if (!HubClient->writeHeader())
	{
		return;
	}

	AnsiString Qobject, Qattribute, Qvalue;
	string name, object, attribute, value;
	int timetag;
	int count = 0;

	SSXMLParser parser("");
	TTimedTriples triples;
	TTimedTriple triple;

	// input data
	Qobject.printf("%s\..*", InputFileName.c_str());
	HubClient->writeQuery(Qobject.c_str(), ".*", ".*");
	parser = HubClient->readReply();
	HubClient->cls();
	// parse triples
	triples.Add(parser.input);
/*
	//--- output data
	Qobject.printf("%s-out\..*", InputFileName.c_str());
	HubClient->writeQuery(Qobject.c_str(), ".*", ".*");
	parser = HubClient->readReply();
	HubClient->cls();
	// parse triples
	triples.Add(parser.input);
*/
	//-------------------------------------------
	// event groups
	//-------------------------------------------
	std::vector<TID_Translate> Group_Translate;

	// get count
	Qobject.printf("%s\.EventGroups\.Group", InputFileName.c_str());
	if (triples.getTimedTriple(triple, Qobject.c_str(), "Count", ""))
	{
		count = StrToInt(triple.value.c_str());
	}

	string EGDesc, EGMeaning = DefaultGroupMeaning.c_str();
	bool EGEnabled = false;
	// get event groups
	for (int i = 0; i < count; i++)
	{
		Qobject.printf("%s\.EventGroups\.Group\.%d", InputFileName.c_str(), i);

		if (triples.getTimedTriple(triple, Qobject.c_str(), "Desc", ""))
		{
			EGDesc = triple.value;
		}
		if (triples.getTimedTriple(triple, Qobject.c_str(), "Meaning", ""))
		{
			EGMeaning = triple.value;
		}
		if (triples.getTimedTriple(triple, Qobject.c_str(), "Enabled", ""))
		{
			EGEnabled = StrToInt(triple.value.c_str());
		}

		TID_Translate Translate;
		Translate.ID1 = i;
		Translate.ID2 = FindGroupID(EGDesc.c_str());
		if (Translate.ID2 < 0)
		{
			Translate.ID2 = AddGroup(TEventTypeGroup(EGDesc.c_str(), EGMeaning.c_str(), EGEnabled));
		}
		if ((int)Group_Translate.size() <= i)
		{
			Group_Translate.push_back(Translate);
		}
		else
		{
			Group_Translate[i] = Translate;
		}
	}
	count = 0;

	//-------------------------------------------
	// event types
	//-------------------------------------------
	std::vector<TID_Translate> Type_Translate;

	// get count
	Qobject.printf("%s\.EventTypes\.Type", InputFileName.c_str());
	if (triples.getTimedTriple(triple, Qobject.c_str(), "Count", ""))
	{
		count = StrToInt(triple.value.c_str());
	}

	string ETName, ETOffset, ETKey, ETValue;
	int ETParametersCount = 0,
		ETSecondaryCount = 0,
		ETSecondaryParametersCount = 0;
	for (int i = 0; i < count; i++)
	{
		ETName = "";
		Qobject.printf("%s\.EventTypes\.Type\.%d", InputFileName.c_str(), i);

		if (triples.getTimedTriple(triple, Qobject.c_str(), "Name", ""))
		{
			ETName = triple.value;
		}

		TID_Translate Translate;
		Translate.ID1 = i;
		Translate.ID2 = FindMessageID(ETName.c_str());
		if (Translate.ID2 < 0)
		{
			TEventType Message(ETName.c_str());
			Translate.ID2 = EventTypes.size();
			Message.Group = -1;
			Message.GroupIndex = -1;

			if (triples.getTimedTriple(triple, Qobject.c_str(), "Offset", ""))
			{
				Message.Offset = StrToIntDef(triple.value.c_str(), 0);
			}
			if (triples.getTimedTriple(triple, Qobject.c_str(), "CheckEndPoints", ""))
			{
				Message.CheckEndPoints = bool(StrToInt(triple.value.c_str()));
			}
			if (triples.getTimedTriple(triple, Qobject.c_str(), "Key", ""))
			{
				Message.Key = TextToShortCut(triple.value.c_str());
			}
			if (triples.getTimedTriple(triple, Qobject.c_str(), "Group", ""))
			{
				Message.Group = StrToInt(triple.value.c_str());
			}
			if (triples.getTimedTriple(triple, Qobject.c_str(), "GroupIndex", ""))
			{
				Message.GroupIndex = StrToInt(triple.value.c_str());
			}
			if (triples.getTimedTriple(triple, Qobject.c_str(), "Parameters.Count", ""))
			{
				ETParametersCount = StrToInt(triple.value.c_str());
			}
			if (triples.getTimedTriple(triple, Qobject.c_str(), "SecondaryKeys.Count", ""))
			{
				ETSecondaryCount = StrToInt(triple.value.c_str());
			}

			// parameters
			for (int p = 0; p < ETParametersCount; p++)
			{
				ETName = ETValue = "";
				Qattribute.printf("Parameters.%d.", p);

				if (triples.getTimedTriple(triple, Qobject.c_str(), string(Qattribute.c_str()) + "Name", ""))
				{
					ETName = triple.value;
				}
				if (triples.getTimedTriple(triple, Qobject.c_str(), string(Qattribute.c_str()) + "Value", ""))
				{
					ETValue = triple.value;
				}

				if (!ETName.empty() && !ETValue.empty())
				{
					if ((int)Message.Parameters.size() <= p)
					{
						Message.Parameters.push_back(TParameter(ETName.c_str(), ETValue.c_str()));
					}
					else
					{
						Message.Parameters[p] = TParameter(ETName.c_str(), ETValue.c_str());
					}
				}
				ETParametersCount = 0;
			}

			if (Message.Group != -1)
			{
				std::vector<TID_Translate>::iterator it = Group_Translate.begin();
				bool found = false;
				while (it != Group_Translate.end() && !found)
				{
					if (it->ID1 == Message.Group)
					{
						found = true;
						Message.Group = it->ID2;
					}
					it++;
				}
				if (!found)
				{
					TID_Translate Translate;
					Translate.ID1 = Message.Group;
					Message.Group = AddGroup(TEventTypeGroup("Group " + IntToStr(Message.Group), DefaultGroupMeaning));
					Translate.ID2 = Message.Group;
					Group_Translate.push_back(Translate);
				}
			}

			// secondary keys
			for (int k = 0; k < ETSecondaryCount; k++)
			{
				ETKey = ETOffset = "";
				Qattribute.printf("SecondaryKeys.%d.", k);

				if (triples.getTimedTriple(triple, Qobject.c_str(), string(Qattribute.c_str()) + "Key", ""))
				{
					ETKey = triple.value;
				}
				if (triples.getTimedTriple(triple, Qobject.c_str(), string(Qattribute.c_str()) + "Offset", ""))
				{
					ETOffset = triple.value;
				}
				if (triples.getTimedTriple(triple, Qobject.c_str(), string(Qattribute.c_str()) + "Parameters.Count", ""))
				{
					ETSecondaryParametersCount = StrToInt(triple.value.c_str());
				}

				TSecondaryKey SecondaryKey(TextToShortCut(ETKey.c_str()));
				if (!ETOffset.empty())
				{
					SecondaryKey.Offset = StrToIntDef(ETOffset.c_str(), 0);
				}

				// parameters
				for (int p = 0; p < ETSecondaryParametersCount; p++)
				{
					ETName = ETValue = "";
					Qattribute.printf("SecondaryKeys.%d.Parameters.%d.", k, p);

					if (triples.getTimedTriple(triple, Qobject.c_str(), string(Qattribute.c_str()) + "Name", ""))
					{
						ETName = triple.value;
					}
					if (triples.getTimedTriple(triple, Qobject.c_str(), string(Qattribute.c_str()) + "Value", ""))
					{
						ETValue = NormalizeFilePath(triple.value);
					}

					if (!ETName.empty() && !ETValue.empty())
					{
						if ((int)SecondaryKey.Parameters.size() <= p)
						{
							SecondaryKey.Parameters.push_back(TParameter(ETName.c_str(), ETValue.c_str()));
						}
						else
						{
							SecondaryKey.Parameters[p] = TParameter(ETName.c_str(), ETValue.c_str());
						}
					}
				}
				ETSecondaryParametersCount = 0;

				if ((int)Message.SecondaryKeys.size() <= k)
				{
					Message.SecondaryKeys.push_back(SecondaryKey);
				}
				else
				{
					Message.SecondaryKeys[k] = SecondaryKey;
				}
			}
			ETSecondaryCount = 0;

			EventTypes.push_back(Message);
		}
		if ((int)Type_Translate.size() <= i)
		{
			Type_Translate.push_back(Translate);
		}
		else
		{
			Type_Translate[i] = Translate;
		}
	}
	count = 0;

	//-------------------------------------------
	// sources
	//-------------------------------------------

	// get time format
	TTimeFormat NewTimeFormat = tfTime;
	if (!Import)
	{
		Qobject.printf("%s\.Sources", InputFileName.c_str());

		if (triples.getTimedTriple(triple, Qobject.c_str(), "TimeFormat", ""))
		{
			if (triple.value.compare("Frames") == 0)
			{
				NewTimeFormat = tfFrames;
			}
		}

		Qobject.printf("%s\.Sources\.Source", InputFileName.c_str());

		// get count
		if (triples.getTimedTriple(triple, Qobject.c_str(), "Count", ""))
		{
			count = StrToInt(triple.value.c_str());
		}

		for (int i = 0; i < count; i++)
		{
			TSource Src;
			Src.FileName = "";
			Src.Camera = -1;
			Src.Offset = Src.Loop = Src.Width = Src.Height = Src.Length = 0;
			Src.FrameRate.Rate = Src.FrameRate.Scale = 1;

			Qobject.printf("%s\.Sources\.Source\.%d", InputFileName.c_str(), i);

			if (triples.getTimedTriple(triple, Qobject.c_str(), "FileName", ""))
			{
				Src.FileName = NormalizeFilePath(triple.value.c_str());
			}
			if (triples.getTimedTriple(triple, Qobject.c_str(), "FileName", ""))
			{
				Src.FileName = NormalizeFilePath(triple.value.c_str());
			}
			if (triples.getTimedTriple(triple, Qobject.c_str(), "Camera", ""))
			{
				Src.Camera = StrToInt(triple.value.c_str());
			}
			if (triples.getTimedTriple(triple, Qobject.c_str(), "Offset", ""))
			{
				Src.Offset = StrToInt(triple.value.c_str());
			}
			if (triples.getTimedTriple(triple, Qobject.c_str(), "Width", ""))
			{
				Src.Width = StrToInt(triple.value.c_str());
			}
			if (triples.getTimedTriple(triple, Qobject.c_str(), "Height", ""))
			{
				Src.Height = StrToInt(triple.value.c_str());
			}
			if (triples.getTimedTriple(triple, Qobject.c_str(), "Rate", ""))
			{
				Src.FrameRate.Rate = StrToInt(triple.value.c_str());
			}
			if (triples.getTimedTriple(triple, Qobject.c_str(), "Scale", ""))
			{
				Src.FrameRate.Scale = StrToInt(triple.value.c_str());
			}
			if (triples.getTimedTriple(triple, Qobject.c_str(), "Length", ""))
			{
				Src.Length = StrToInt(triple.value.c_str());
			}
			if (triples.getTimedTriple(triple, Qobject.c_str(), "Loop", ""))
			{
				Src.Loop = StrToInt(triple.value.c_str());
			}

			if ((int)Sources.size() <= i)
			{
				Sources.push_back(Src);
			}
			else
			{
				Sources[i] = Src;
			}
		}
		TimeFormat = NewTimeFormat;
	}
	count = 0;

	//-------------------------------------------
	// events
	//-------------------------------------------

	// get count
	Qobject.printf("%s\.Events\.Event", InputFileName.c_str());

	// get count
	if (triples.getTimedTriple(triple, Qobject.c_str(), "Count", ""))
	{
		count = StrToInt(triple.value.c_str());
	}

	string EvTime, EvName, EvValue;
	int EvParametersCount = 0;
	// get events
	for (int i = 0; i < count; i++)
	{
		TEvent *m = new TEvent();
		Qobject.printf("%s\.Events\.Event\.%d", InputFileName.c_str(), i);

		if (triples.getTimedTriple(triple, Qobject.c_str(), "ID", ""))
		{
			m->ID = StrToInt(triple.value.c_str());
		}
		if (triples.getTimedTriple(triple, Qobject.c_str(), "Text", ""))
		{
			m->Text = triple.value.c_str();
		}
		if (triples.getTimedTriple(triple, Qobject.c_str(), "Time", ""))
		{
			EvTime = triple.value;
		}
		if (triples.getTimedTriple(triple, Qobject.c_str(), "Parameters.Count", ""))
		{
			EvParametersCount = StrToInt(triple.value.c_str());
		}

		// parameters
		for (int p = 0; p < EvParametersCount; p++)
		{
			EvName = EvValue = "";
			Qattribute.printf("Parameters.%d.", p);

			if (triples.getTimedTriple(triple, Qobject.c_str(), string(Qattribute.c_str()) + "Name", ""))
			{
				EvName = triple.value;
			}
			if (triples.getTimedTriple(triple, Qobject.c_str(), string(Qattribute.c_str()) + "Value", ""))
			{
				EvValue = triple.value;
			}

			if (!EvName.empty() && !EvValue.empty())
			{
				if ((int)m->Parameters.size() <= p)
				{
					m->Parameters.push_back(TParameter(EvName.c_str(), EvValue.c_str()));
				}
				else
				{
					m->Parameters[p] = TParameter(EvName.c_str(), EvValue.c_str());
				}
			}
		}
		EvParametersCount = 0;

		std::vector<TID_Translate>::iterator it = Type_Translate.begin();
		bool found = false;
		while (it != Type_Translate.end() && !found)
		{
			if (it->ID1 == m->ID)
			{
				found = true;
				m->ID = it->ID2;
			}
			it++;
		}

		if (found)
		{
			m->Time = StrToInt(EvTime.c_str());

			if (ForceCamera >= 0)
			{
				TParameter *Parameter = GetParameter(m->Parameters, "Camera", "");
				if (Parameter != NULL)
				{
					Parameter->Value = IntToStr(ForceCamera);
				}
			}
			if (NewTimeFormat != TimeFormat)
			{
				int Camera;
				if (GetParameterInt(m->Parameters, "Camera", Camera))
				{
					m->Time = ConvertCameraTime(Camera, m->Time, NewTimeFormat, TimeFormat);
				}
			}
			if (UseCameraOffset)
			{
				int Camera;
				if (GetParameterInt(m->Parameters, "Camera", Camera))
				{
					m->Time += GetCameraOffset(Camera);
				}
			}
			m->Time += Offset;
			InsertMessage(m);
		}
		else
		{
			// ShowMessage("Event type not found!");
		}
	}
}

//---------------------------------------------------------------------------
void TImpExp::LoadFromXml(const char *FileName, bool Import, bool UseCameraOffset, int ForceCamera)
{
	int Offset = 0;
	/*
	InitializeInsertMessage();
	if (!Import)
	{
		CloseAll();
	}
	else
	{
		if (!FormOffset->GetOffset(Offset))
		{
			return;
		}
	}
	*/
	xmlDocPtr doc = xmlParseFile(FileName);
	if (doc == NULL)
	{
		throw TError("Could not open file!");
	}

	try
	{
		xmlNodePtr cur = xmlDocGetRootElement(doc);
		if (cur == NULL)
		{
			throw TError("Empty document!");
		}

		if (xmlStrcmp(cur->name, (const xmlChar *) "AVEvents"))
		{
			throw TError("Document of the wrong type!");
		}

		// event groups
		std::vector<TID_Translate> Group_Translate;

		// event groups [old]
		xmlNodePtr childcur = cur->xmlChildrenNode;
		while (childcur != NULL && xmlStrcmp(childcur->name, (const xmlChar *)"Groups"))
		{
			childcur = childcur->next;
		}

		if (childcur != NULL)
		{
			xmlNodePtr eventscur = childcur->xmlChildrenNode;
			while (eventscur != NULL)
			{
				if (!xmlStrcmp(eventscur->name, (const xmlChar *)"Name"))
				{
					xmlChar *IDChar = xmlGetProp(eventscur, (xmlChar*)"ID");
					if (IDChar != NULL)
					{
						try
						{
							try
							{
								TID_Translate Translate;
								Translate.ID1 = StrToInt((char*)IDChar);
								xmlChar *Name = xmlNodeListGetString(doc, eventscur->xmlChildrenNode, 1);
								try
								{
									bool Enabled = false;
									xmlChar *EnabledChar = xmlGetProp(eventscur, (xmlChar*)"Enabled");
									if (EnabledChar != NULL)
									{
										try
										{
											Enabled = StrToInt((char*)EnabledChar);
										}
										catch (...)
										{
										}
										xmlFree(EnabledChar);
									}
									Translate.ID2 = FindGroupID((const char*)Name);
									if (Translate.ID2 < 0)
									{
										Translate.ID2 = AddGroup(TEventTypeGroup((char*)Name, "State", Enabled));
									}
									Group_Translate.push_back(Translate);
									xmlFree(Name);
								}
								catch (...)
								{
									xmlFree(Name);
									throw;
								}
							}
							catch (...)
							{
							}
							xmlFree(IDChar);
						}
						catch (...)
						{
							xmlFree(IDChar);
							throw;
						}
					}
				}
				eventscur = eventscur->next;
			}
		}

		// event groups [new]
		childcur = cur->xmlChildrenNode;
		while (childcur != NULL && xmlStrcmp(childcur->name, (const xmlChar *)"EventGroups"))
		{
			childcur = childcur->next;
		}

		if (childcur != NULL)
		{
			xmlNodePtr eventscur = childcur->xmlChildrenNode;
			while (eventscur != NULL)
			{
				if (!xmlStrcmp(eventscur->name, (const xmlChar *)"Group"))
				{
					AnsiString ID;
					if (GetNodeString(doc, eventscur, "ID", ID))
					{
						AnsiString Name;
						GetNodeString(doc, eventscur, "Name", Name);
						try
						{
							TID_Translate Translate;
							Translate.ID1 = StrToInt(ID);
							bool Enabled = false;
							AnsiString EnabledStr;
							if (GetNodeString(doc, eventscur, "Enabled", EnabledStr))
							{
								try
								{
									Enabled = StrToInt(EnabledStr);
								}
								catch (...)
								{
								}
							}

							AnsiString Meaning;
							if (!GetNodeString(doc, eventscur, "Meaning", Meaning))
							{
								Meaning = DefaultGroupMeaning;
							}
							Translate.ID2 = FindGroupID(Name.c_str());
							if (Translate.ID2 < 0)
							{
								Translate.ID2 = AddGroup(TEventTypeGroup(Name.c_str(), Meaning, Enabled));
							}
							Group_Translate.push_back(Translate);
						}
						catch (...)
						{
						}
					}
				}
				eventscur = eventscur->next;
			}
		}

		// event types
		std::vector<TID_Translate> Type_Translate;

		// event types [old]
		childcur = cur->xmlChildrenNode;
		while (childcur != NULL && xmlStrcmp(childcur->name, (const xmlChar *)"Events"))
		{
			childcur = childcur->next;
		}

		if (childcur != NULL)
		{
			xmlNodePtr eventscur = childcur->xmlChildrenNode;
			while (eventscur != NULL)
			{
				if (!xmlStrcmp(eventscur->name, (const xmlChar *)"Name"))
				{
					xmlChar *Name = xmlNodeListGetString(doc, eventscur->xmlChildrenNode, 1);
					xmlChar *ID = xmlGetProp(eventscur, (xmlChar*)"ID");
					if (ID != NULL)
					{
						try
						{
							TID_Translate Translate;
							Translate.ID1 = StrToInt((char*)ID);
							Translate.ID2 = FindMessageID((char*)Name);

							if (Translate.ID2 < 0)
							{
								TEventType Message((char*)Name);
								Translate.ID2 = EventTypes.size();

								xmlChar *Key = xmlGetProp(eventscur, (xmlChar*)"Key");
								if (Key != NULL)
								{
									Message.Key = TextToShortCut((char*)Key);
									xmlFree(Key);
								}

								xmlChar *Group = xmlGetProp(eventscur, (xmlChar*)"Group");
								if (Group != NULL)
								{
									try
									{
										Message.Group = StrToInt((char*)Group);
										std::vector<TID_Translate>::iterator i = Group_Translate.begin();
										bool found = false;
										while (i != Group_Translate.end() && !found)
										{
											if (i->ID1 == Message.Group)
											{
												found = true;
												Message.Group = i->ID2;
											}
											i++;
										}
										if (!found)
										{
											TID_Translate Translate;
											Translate.ID1 = Message.Group;
											Message.Group = AddGroup(TEventTypeGroup("Group " + IntToStr(Message.Group), "State"));
											Translate.ID2 = Message.Group;
											Group_Translate.push_back(Translate);
										}

										xmlChar *GroupIndex = xmlGetProp(eventscur, (xmlChar*)"GroupIndex");
										try
										{
											Message.GroupIndex = StrToInt((char*)GroupIndex);
										}
										catch (...)
										{
											Message.Group = -1;
											Message.GroupIndex = -1;
										}
										xmlFree(GroupIndex);
									}
									catch (...)
									{
										Message.Group = -1;
										Message.GroupIndex = -1;
									}
									xmlFree(Group);
								}

								EventTypes.push_back(Message);
							}
							Type_Translate.push_back(Translate);
						}
						catch (...)
						{
						}
						xmlFree(ID);
					}
					xmlFree(Name);
				}
				eventscur = eventscur->next;
			}
		}

		// event types [new]
		childcur = cur->xmlChildrenNode;
		while (childcur != NULL && xmlStrcmp(childcur->name, (const xmlChar *)"EventTypes"))
		{
			childcur = childcur->next;
		}

		if (childcur != NULL)
		{
			xmlNodePtr filecur = childcur->xmlChildrenNode;
			while (filecur != NULL)
			{
				if (!xmlStrcmp(filecur->name, (const xmlChar *)"Type"))
				{
					AnsiString ID;
					if (GetNodeString(doc, filecur, "ID", ID))
					{
						AnsiString Name;
						GetNodeString(doc, filecur, "Name", Name);
						try
						{
							TID_Translate Translate;
							Translate.ID1 = StrToInt(ID);
							Translate.ID2 = FindMessageID(Name.c_str());

							if (Translate.ID2 < 0)
							{
								TEventType Message(Name);
								Translate.ID2 = EventTypes.size();

								AnsiString Offset;
								if (GetNodeString(doc, filecur, "Offset", Offset))
								{
									Message.Offset = StrToIntDef(Offset, 0);
								}

								AnsiString Key;
								if (GetNodeString(doc, filecur, "Key", Key))
								{
									Message.Key = TextToShortCut(Key);
								}

								xmlNodePtr eventscur = filecur->xmlChildrenNode;
								while (eventscur != NULL && xmlStrcmp(eventscur->name, (const xmlChar *)"Parameters"))
								{
									eventscur = eventscur->next;
								}
								if (eventscur != NULL)
								{
									xmlAttrPtr ap = eventscur->properties;
									while (ap != NULL)
									{
										xmlChar *Value = xmlGetProp(eventscur, ap->name);
										if (Value != NULL)
										{
											Message.Parameters.push_back(TParameter((char*)ap->name, (char*)Value));
											xmlFree(Value);
										}
										ap = ap->next;
									}
								}

								AnsiString Group;
								if (GetNodeString(doc, filecur, "Group", Group))
								{
									try
									{
										Message.Group = StrToInt(Group);
										std::vector<TID_Translate>::iterator i = Group_Translate.begin();
										bool found = false;
										while (i != Group_Translate.end() && !found)
										{
											if (i->ID1 == Message.Group)
											{
												found = true;
												Message.Group = i->ID2;
											}
											i++;
										}
										if (!found)
										{
											TID_Translate Translate;
											Translate.ID1 = Message.Group;
											Message.Group = AddGroup(TEventTypeGroup("Group " + IntToStr(Message.Group), DefaultGroupMeaning));
											Translate.ID2 = Message.Group;
											Group_Translate.push_back(Translate);
										}

										AnsiString GroupIndex;
										if (GetNodeString(doc, filecur, "GroupIndex", GroupIndex))
										{
											try
											{
												Message.GroupIndex = StrToInt(GroupIndex);
											}
											catch (...)
											{
												Message.Group = -1;
												Message.GroupIndex = -1;
											}
										}
									}
									catch (...)
									{
										Message.Group = -1;
										Message.GroupIndex = -1;
									}
								}

								xmlNodePtr Secondary = filecur->xmlChildrenNode;
								while (Secondary != NULL)
								{
									if (!xmlStrcmp(Secondary->name, (const xmlChar *)"Secondary"))
									{
										AnsiString Key;
										if (GetNodeString(doc, Secondary, "Key", Key))
										{
											TSecondaryKey SecondaryKey(TextToShortCut(Key));
											AnsiString Offset;
											if (GetNodeString(doc, Secondary, "Offset", Offset))
											{
												SecondaryKey.Offset = StrToIntDef(Offset, 0);
											}

											xmlNodePtr eventscur = Secondary->xmlChildrenNode;
											while (eventscur != NULL && xmlStrcmp(eventscur->name, (const xmlChar *)"Parameters"))
											{
												eventscur = eventscur->next;
											}
											if (eventscur != NULL)
											{
												xmlAttrPtr ap = eventscur->properties;
												while (ap != NULL)
												{
													xmlChar *Value = xmlGetProp(eventscur, ap->name);
													if (Value != NULL)
													{
														SecondaryKey.Parameters.push_back(TParameter((char*)ap->name, (char*)Value));
														xmlFree(Value);
													}
													ap = ap->next;
												}
											}

											Message.SecondaryKeys.push_back(SecondaryKey);
										}
									}
									Secondary = Secondary->next;
								}

								EventTypes.push_back(Message);
							}
							Type_Translate.push_back(Translate);
						}
						catch (...)
						{
						}
					}
				}
				filecur = filecur->next;
			}
		}

		// file
		childcur = cur->xmlChildrenNode;
		while (childcur != NULL && xmlStrcmp(childcur->name, (const xmlChar *)"File"))
		{
			childcur = childcur->next;
		}

		TTimeFormat NewTimeFormat = tfTime;
		if (childcur != NULL)
		{
			xmlNodePtr filecur = childcur->xmlChildrenNode;
			while (filecur != NULL && xmlStrcmp(filecur->name, (const xmlChar *)"TimeFormat"))
			{
				filecur = filecur->next;
			}
			if (filecur != NULL)
			{
				xmlChar *tf = xmlNodeListGetString(doc, filecur->xmlChildrenNode, 1);
				if (!xmlStrcmp(tf, (xmlChar*)"Frames"))
				{
					NewTimeFormat = tfFrames;
				}
				else
				{
					NewTimeFormat = tfTime;
				}
				xmlFree(tf);
			}
			else
			{
				NewTimeFormat = tfTime;
			}

			if (!Import)
			{
				filecur = childcur->xmlChildrenNode;
				while (filecur != NULL)
				{
					if (!xmlStrcmp(filecur->name, (const xmlChar *)"Source"))
					{
						TSource Src;
						xmlChar *fn = xmlNodeListGetString(doc, filecur->xmlChildrenNode, 1);
						Src.FileName = (char*)fn;
						xmlFree(fn);
						Src.Camera = xmlGetPropInt(filecur, (const xmlChar*)"Camera", -1);
						Src.Offset = xmlGetPropInt(filecur, (const xmlChar*)"Offset", 0);
						Src.Loop = xmlGetPropInt(filecur, (const xmlChar*)"Loop", 0);
						Src.Width = xmlGetPropInt(filecur, (const xmlChar*)"Width", 0);
						Src.Height = xmlGetPropInt(filecur, (const xmlChar*)"Height", 0);
						Src.FrameRate.Rate = xmlGetPropInt(filecur, (const xmlChar*)"Rate", 1);
						Src.FrameRate.Scale = xmlGetPropInt(filecur, (const xmlChar*)"Scale", 1);
						Src.Length = xmlGetPropInt(filecur, (const xmlChar*)"Length", 0);
						Sources.push_back(Src);
					}
					filecur = filecur->next;
				}
			}

			if (!Import)
			{
				TimeFormat = NewTimeFormat;
			}

			{
				xmlNodePtr filecur = childcur->xmlChildrenNode;
				while (filecur != NULL)
				{
					if (!xmlStrcmp(filecur->name, (const xmlChar *)"Event"))
					{
						xmlNodePtr eventscur = filecur->xmlChildrenNode;
						while (eventscur != NULL && xmlStrcmp(eventscur->name, (const xmlChar *)"ID"))
						{
							eventscur = eventscur->next;
						}

						if (eventscur != NULL)
						{
							TEvent *m = new TEvent();
							try
							{
								xmlChar *id = xmlNodeListGetString(doc, eventscur->xmlChildrenNode, 1);
								try
								{
									m->ID = StrToInt((char*)id);
									xmlFree(id);
								}
								catch(...)
								{
									xmlFree(id);
									throw;
								}

								eventscur = filecur->xmlChildrenNode;
								while (eventscur != NULL && xmlStrcmp(eventscur->name, (const xmlChar *)"Text"))
								{
									eventscur = eventscur->next;
								}
								if (eventscur != NULL)
								{
									xmlChar *text = xmlNodeListGetString(doc, eventscur->xmlChildrenNode, 1);
									if (text != NULL)
									{
										m->Text = (char*)text;
										xmlFree(text);
									}
								}

								eventscur = filecur->xmlChildrenNode;
								while (eventscur != NULL && xmlStrcmp(eventscur->name, (const xmlChar *)"Parameters"))
								{
									eventscur = eventscur->next;
								}
								if (eventscur != NULL)
								{
									// parameters [old]
									xmlAttrPtr ap = eventscur->properties;
									while (ap != NULL)
									{
										xmlChar *Value = xmlGetProp(eventscur, ap->name);
										if (Value != NULL)
										{
											m->Parameters.push_back(TParameter((char*)ap->name, (char*)Value));
											xmlFree(Value);
										}
										ap = ap->next;
									}

									// parameters [new]
									xmlNodePtr param = eventscur->xmlChildrenNode;
									while (param != NULL)
									{
										xmlChar *Value = xmlNodeListGetString(doc, param->xmlChildrenNode, 1);
										if (Value != NULL)
										{
											m->Parameters.push_back(TParameter((char*)param->name, (char*)Value));
											xmlFree(Value);
										}
										param = param->next;
									}
								}

								eventscur = filecur->xmlChildrenNode;
								while (eventscur != NULL && xmlStrcmp(eventscur->name, (const xmlChar *)"Time"))
								{
									eventscur = eventscur->next;
								}
								if (eventscur != NULL)
								{
									std::vector<TID_Translate>::iterator i = Type_Translate.begin();
									bool found = false;
									while (i != Type_Translate.end() && !found)
									{
										if (i->ID1 == m->ID)
										{
											found = true;
											m->ID = i->ID2;
										}
										i++;
									}

									if (found)
									{
										xmlChar *Time = xmlNodeListGetString(doc, eventscur->xmlChildrenNode, 1);
										try
										{
											m->Time = StrToInt((char*)Time);
											if (ForceCamera >= 0)
											{
												TParameter *Parameter = GetParameter(m->Parameters, "Camera", "");
												if (Parameter != NULL)
												{
													Parameter->Value = IntToStr(ForceCamera);
												}
											}

											if (NewTimeFormat != TimeFormat)
											{
												int Camera;
												if (GetParameterInt(m->Parameters, "Camera", Camera))
												{
													m->Time = ConvertCameraTime(Camera, m->Time, NewTimeFormat, TimeFormat);
												}
											}
											/*
											if (NewTimeFormat != TimeFormat)
											{
												if (vl->Count > 0)
												{
													TFormVideo *fv = (TFormVideo*)vl->Items[0];
													m->Time = fv->ConvertTimeFormat(m->Time, NewTimeFormat, TimeFormat);
												}
												else
												{
													TimeFormat = NewTimeFormat;
												}
											}
											*/
											if (UseCameraOffset)
											{
												int Camera;
												if (GetParameterInt(m->Parameters, "Camera", Camera))
												{
													m->Time += GetCameraOffset(Camera);
												}
											}
											m->Time += Offset;
											InsertMessage(m);
										}
										catch (...)
										{
										}
										xmlFree(Time);
									}
									else
									{
										// ShowMessage("Event type not found!");
									}
								}
							}
							catch (...)
							{
							}
						}
					}
					filecur = filecur->next;
				}

#if 0
				// titles
				filecur = childcur->xmlChildrenNode;
				while (filecur != NULL)
				{
					if (!xmlStrcmp(filecur->name, (const xmlChar *)"Title"))
					{
						xmlNodePtr eventscur = filecur->xmlChildrenNode;
						while (eventscur != NULL && xmlStrcmp(eventscur->name, (const xmlChar *)"Text"))
						{
							eventscur = eventscur->next;
						}

						if (eventscur != NULL)
						{
							TTitle *m = new TTitle();
							xmlChar *text = xmlNodeListGetString(doc, eventscur->xmlChildrenNode, 1);
							m->Text = (char*)text;
							xmlFree(text);
							eventscur = filecur->xmlChildrenNode;
							while (eventscur != NULL && xmlStrcmp(eventscur->name, (const xmlChar *)"Time"))
							{
								eventscur = eventscur->next;
							}
							if (eventscur != NULL)
							{
								xmlChar *Time = xmlNodeListGetString(doc, eventscur->xmlChildrenNode, 1);
								try
								{
									m->Time = StrToInt((char*)xmlNodeListGetString(doc, eventscur->xmlChildrenNode, 1)) + Offset;
									if (NewTimeFormat != TimeFormat)
									{
										if (vl->Count > 0)
										{
											TFormVideo *fv = (TFormVideo*)vl->Items[0];
											m->Time = fv->ConvertTimeFormat(m->Time, NewTimeFormat, TimeFormat);
										}
										else
										{
											TimeFormat = NewTimeFormat;
										}
									}
									m->Time += Offset;
									InsertTitle(m);
								}
								catch (...)
								{
								}
								xmlFree(Time);
							}
						}
					}
					filecur = filecur->next;
				}
#endif
			}
		}

#if 0
		if (!Import)
		{
			try
			{
				xmlNodePtr editorcur = cur->xmlChildrenNode;
				while (editorcur != NULL && xmlStrcmp(editorcur->name, (const xmlChar *)"Editor"))
				{
					editorcur = editorcur->next;
				}

				if (editorcur != NULL)
				{
					xmlNodePtr eventscur = editorcur->xmlChildrenNode;
					while (eventscur != NULL && xmlStrcmp(eventscur->name, (const xmlChar *)"Events"))
					{
						eventscur = eventscur->next;
					}
					if (eventscur != NULL)
					{
						childcur = eventscur->xmlChildrenNode;
						while (childcur != NULL && xmlStrcmp(childcur->name, (const xmlChar *)"Visible"))
						{
							childcur = childcur->next;
						}
						if (childcur != NULL)
						{
							SetVisibleEvents(NodeGetInt(doc, childcur));
						}

						childcur = eventscur->xmlChildrenNode;
						while (childcur != NULL && xmlStrcmp(childcur->name, (const xmlChar *)"Columns"))
						{
							childcur = childcur->next;
						}
						if (childcur != NULL)
						{
							childcur = childcur->xmlChildrenNode;
							while (childcur != NULL)
							{
								int i = StringGridMessages->Rows[0]->IndexOf((char*)childcur->name);
								if (i >= 0)
								{
									xmlChar *v = (char*)xmlNodeListGetString(doc, childcur->xmlChildrenNode, 1);
									if (v != NULL)
									{
										StringGridMessages->ColWidths[i] = StrToInt((char*)v);
										xmlFree(v);
									}
								}
								childcur = childcur->next;
							} 
						}
					}

					xmlNodePtr titlescur = editorcur->xmlChildrenNode;
					while (titlescur != NULL && xmlStrcmp(titlescur->name, (const xmlChar *)"Titles"))
					{
						titlescur = titlescur->next;
					}
					if (titlescur != NULL)
					{
						childcur = titlescur->xmlChildrenNode;
						while (childcur != NULL && xmlStrcmp(childcur->name, (const xmlChar *)"Visible"))
						{
							childcur = childcur->next;
						}
						if (childcur != NULL)
						{
							SetVisibleTitles(NodeGetInt(doc, childcur));
						}

						childcur = titlescur->xmlChildrenNode;
						while (childcur != NULL && xmlStrcmp(childcur->name, (const xmlChar *)"Columns"))
						{
							childcur = childcur->next;
						}
						if (childcur != NULL)
						{
							childcur = childcur->xmlChildrenNode;
							while (childcur != NULL)
							{
								int i = StringGridTitles->Rows[0]->IndexOf((char*)childcur->name);
								if (i >= 0)
								{
									xmlChar *v = xmlNodeListGetString(doc, childcur->xmlChildrenNode, 1);
									if (v != NULL)
									{
										StringGridTitles->ColWidths[i] = StrToInt((char*)v);
										xmlFree(v);
									}
								}
								childcur = childcur->next;
							}
						}
					}

					xmlNodePtr windowscur = editorcur->xmlChildrenNode;
					while (windowscur != NULL && xmlStrcmp(windowscur->name, (const xmlChar *)"Windows"))
					{
						windowscur = windowscur->next;
					}
					if (windowscur != NULL)
					{
						childcur = windowscur->xmlChildrenNode;
						while (childcur != NULL)
						{
							char *n = (char*)childcur->name;
							if (strncmp(n, "Media", 5) == 0)
							{
								int i = StrToInt(n + 5);
								if ((i >= 0) && (i < vl->Count))
								{
									TFormVideo *f = vl->GetItem(i);
									xmlNodePtr tmp;

									tmp = FindChildNode(childcur, "Visible");
									if (tmp != NULL)
									{
										f->Visible = NodeGetInt(doc, tmp);
									}
									tmp = FindChildNode(childcur, "Size");
									if (tmp != NULL)
									{
										f->SetSizeID(NodeGetInt(doc, tmp));
									}
									tmp = FindChildNode(childcur, "Left");
									if (tmp != NULL)
									{
										f->Left = NodeGetInt(doc, tmp);
									}
									tmp = FindChildNode(childcur, "Top");
									if (tmp != NULL)
									{
										f->Top = NodeGetInt(doc, tmp);
									}
									tmp = FindChildNode(childcur, "Width");
									if (tmp != NULL)
									{
										f->Width = NodeGetInt(doc, tmp);
									}
									tmp = FindChildNode(childcur, "Height");
									if (tmp != NULL)
									{
										f->Height = NodeGetInt(doc, tmp);
									}
								}
							}
							childcur = childcur->next;
						}

						LoadFormDimension(doc, windowscur, FormEventList, "EventsList", ActionEvents, true);
						LoadFormDimension(doc, windowscur, FormEventButtons, "EventsButtons", ActionEventButtons, true);
						LoadFormDimension(doc, windowscur, FormEventTypeGroups, "EventsGroups", ActionEventTypeGroups, true);
						LoadFormDimension(doc, windowscur, FormOutput, "Output", ActionOutput);
						LoadFormDimension(doc, windowscur, FormTimeLine, "TimeLine", ActionTimeLine);
						LoadFormDimension(doc, windowscur, FormGraph, "Graph", ActionGraph);
					}
				}
			}
			catch (...)
			{
			}
		}
#endif
		/*
		if (!Import)
		{
			XMLFile = FileName;
			SetTitle(XMLFile.c_str());
		}
		*/
		xmlFreeDoc(doc);
//		UpdateAll();
	}
	catch (...)
	{
		xmlFreeDoc(doc);
//		CloseAll();
		throw;
	}
}

//---------------------------------------------------------------------------
int TImpExp::GetCameraOffset(int Camera)
{
	std::vector<TSource>::iterator i = Sources.begin();
	while (i != Sources.end())
	{
		if (i->Camera == Camera)
		{
			return i->Offset;
		}
		i++;
	}
	return 0;
}

//---------------------------------------------------------------------------
int TImpExp::ConvertCameraTime(int Camera, int Time, TTimeFormat Old, TTimeFormat New)
{
	std::vector<TSource>::iterator i = Sources.begin();
	while (i != Sources.end())
	{
		if (i->Camera == Camera)
		{
			return i->ConvertTimeFormat(Time, Old, New);
		}
		i++;
	}
	return Time;
}

//---------------------------------------------------------------------------
void TImpExp::ImportProlog(const char *FileName)
{
	FILE *f = fopen(FileName, "r");
	if (f == NULL)
	{
		throw TError("Could not open file!");
	}

	InitializeInsertMessage();
	TEvent *Event = NULL;
	TParameter Parameter;
	try
	{
		AnsiString Temp;
		bool Ok = true, Comment = false;
		int State = 0;
		while (Ok && !feof(f))
		{
			int c = getc(f);
			if (c == '%')
			{
				Comment = true;
			}
			if (Comment && c == '\n')
			{
				Comment = false;
			}
			if (!isspace(c) && !Comment)
			{
				switch (State)
				{
				case 0:
					if (c != '(')
					{
						Temp += char(c);
					}
					else
					{
						if (AnsiStartsText("event_", Temp))
						{
							Event = new TEvent();
							Event->ID = GetMessageID(Temp.c_str() + 6);
							Temp = "";
							State++;
						}
						else
						{
							Temp = "";
							Comment = true;
						}
					}
					break;

				case 1:
					if (isdigit(c))
					{
						Temp += char(c);
					}
					else if (c == ',')
					{
						Event->Time = StrToInt(Temp);
						Temp = "";
						State++;
					}
					else
					{
						Ok = false;
					}
					break;

				case 2:
					if (c == '[')
					{
						State++;
					}
					else
					{
						Ok = false;
					}
					break;

				case 3:
					if (c == '(')
					{
						Parameter.Name = "";
						Parameter.Value = "";
						State++;
					}
					else if (c == ']')
					{
						State = 100;
					}
					else
					{
						Ok = false;
					}
					break;

				case 4:
					if (c == ',')
					{
						State++;
					}
					else
					{
						Parameter.Name += char(c);
					}
					break;

				case 5:
					if (c == ')')
					{
#ifdef __BORLANDC__
						Parameter.Value = AnsiReplaceStr(Parameter.Value, ".", ",");
#else
						for (int i = 1; i <= Parameter.Value.Length(); i++)
						{
							if (Parameter.Value[i] == '.')
							{
								Parameter.Value[i] = ',';
							}
						}
#endif
						Event->Parameters.push_back(Parameter);
						State++;
					}
					else
					{
						Parameter.Value += char(c);
					}
					break;

				case 6:
					if (c == ']')
					{
						State = 100;
					}
					else if (c == ',')
					{
						State = 3;
					}
					break;

				case 100:
					if (c == ')')
					{
						State++;
					}
					else
					{
						Ok = false;
					}
					break;

				case 101:
					if (c == '.')
					{
						InsertMessage(Event);
						Event = NULL;
						State = 0;
					}
					else
					{
						Ok = false;
					}
					break;
				}
			}
		}
		if (Event != NULL)
		{
			delete Event;
		}
		fclose(f);
	}
	catch (...)
	{
		if (Event != NULL)
		{
			delete Event;
		}
		fclose(f);
		throw;
	}
}

//---------------------------------------------------------------------------
void TImpExp::Save(const char *FileName)
{
	UseXml = (AnsiString("*HUB*").AnsiCompare(AnsiString(FileName).SubString(0, 5)) != 0);

	if (UseXml)
	{
		SaveToXml(FileName);
	}
	else
	{
		SaveToHub(FileName);
	}
}

//---------------------------------------------------------------------------
void TImpExp::SaveToHub(const char *FileName)
{
	AnsiString object, attribute, value;

	if (!HubClient->writeHeader())
	{
		return;
	}

	HubClient->writeln("<Updates>");

	// save event groups
	object.printf("%s.EventGroups.Group", InputFileName.c_str());
	HubClient->writeTimedTriple(object.c_str(), "Count", IntToStr(Groups.size()).c_str());
	for (unsigned int i = 0; i < Groups.size(); i++)
	{
		object.printf("%s.EventGroups.Group.%d", InputFileName.c_str(), i);

		HubClient->writeTimedTriple(object.c_str(), "Desc", Groups[i].Desc.c_str());
		HubClient->writeTimedTriple(object.c_str(), "Meaning", Groups[i].Meaning.c_str());
		HubClient->writeTimedTriple(object.c_str(), "Enabled", IntToStr(Groups[i].Enabled).c_str());
	}

	// save event types
	object.printf("%s.EventTypes.Type", InputFileName.c_str());
	HubClient->writeTimedTriple(object.c_str(), "Count", IntToStr(EventTypes.size()).c_str());
	for (unsigned int i = 0; i < EventTypes.size(); i++)
	{
		object.printf("%s.EventTypes.Type.%d", InputFileName.c_str(), i);

		HubClient->writeTimedTriple(object.c_str(), "Name", EventTypes[i].Desc.c_str());
		if (EventTypes[i].Key != 0)
		{
			HubClient->writeTimedTriple(object.c_str(), "Key", ShortCutToText(EventTypes[i].Key).c_str());
		}
		if (EventTypes[i].CheckEndPoints != false)
		{
			HubClient->writeTimedTriple(object.c_str(), "CheckEndPoints", IntToStr((int)(EventTypes[i].CheckEndPoints)).c_str());
		}
		if (EventTypes[i].Group >= 0 && EventTypes[i].GroupIndex >= 0)
		{
			HubClient->writeTimedTriple(object.c_str(), "Group", IntToStr(EventTypes[i].Group).c_str());
			HubClient->writeTimedTriple(object.c_str(), "GroupIndex", IntToStr(EventTypes[i].GroupIndex).c_str());
		}
		HubClient->writeTimedTriple(object.c_str(), "Offset", IntToStr(EventTypes[i].Offset).c_str());
		// parameters
		TParameters &Parameters = EventTypes[i].Parameters;
		HubClient->writeTimedTriple(object.c_str(), "Parameters.Count", IntToStr(Parameters.size()).c_str());
		for (int j = 0; j < (int)Parameters.size(); j++)
		{
			attribute.printf("Parameters.%d.", j);

			HubClient->writeTimedTriple(object.c_str(), string(attribute.c_str()) + "Name", Parameters[j].Name.c_str());
			HubClient->writeTimedTriple(object.c_str(), string(attribute.c_str()) + "Value", Parameters[j].Value.c_str());
		}
		// secondary keys
		TSecondaryKeys &SecondaryKeys = EventTypes[i].SecondaryKeys;
		HubClient->writeTimedTriple(object.c_str(), "SecondaryKeys.Count", IntToStr(SecondaryKeys.size()).c_str());
		for (unsigned int j = 0; j < SecondaryKeys.size(); j++)
		{
			attribute.printf("SecondaryKeys.%d.", j);

			HubClient->writeTimedTriple(object.c_str(), string(attribute.c_str()) + "Key", ShortCutToText(SecondaryKeys[j].Key).c_str());
			HubClient->writeTimedTriple(object.c_str(), string(attribute.c_str()) + "Offset", IntToStr(SecondaryKeys[j].Offset).c_str());
			// parameters
			TParameters &Parameters = SecondaryKeys[j].Parameters;
			attribute.printf("SecondaryKeys.%d.Parameters.Count", j);

			HubClient->writeTimedTriple(object.c_str(), attribute.c_str(), IntToStr(Parameters.size()).c_str());
			for (int k = 0; k < (int)Parameters.size(); k++)
			{
				attribute.printf("SecondaryKeys.%d.Parameters.%d.", j, k);

				HubClient->writeTimedTriple(object.c_str(), string(attribute.c_str()) + "Name", Parameters[k].Name.c_str());
				HubClient->writeTimedTriple(object.c_str(), string(attribute.c_str()) + "Value", Parameters[k].Value.c_str());
			}
		}
	}

	// save time format
	object.printf("%s.Sources", InputFileName.c_str());

	char *TimeFormatDesc;
	if (TimeFormat == tfFrames)
	{
		TimeFormatDesc = "Frames";
	}
	else
	{
		TimeFormatDesc = "Milliseconds";
	}
	HubClient->writeTimedTriple(object.c_str(), "TimeFormat", TimeFormatDesc);

	// save source files
//	AnsiString FileNamePath = ExtractFilePath(AnsiString(FileName));
	object.printf("%s.Sources.Source", InputFileName.c_str());
	HubClient->writeTimedTriple(object.c_str(), "Count", IntToStr(Sources.size()).c_str());
	for (unsigned int i = 0; i < Sources.size(); i++)
	{
		AnsiString MediaFile = Sources[i].FileName.c_str();
/*
		if (FileNamePath == ExtractFilePath(MediaFile))
		{
			MediaFile = MediaFile.SubString(FileNamePath.Length() + 1, MediaFile.Length() - FileNamePath.Length());
		}
*/
		object.printf("%s.Sources.Source.%d", InputFileName.c_str(), i);

		HubClient->writeTimedTriple(object.c_str(), "FileName", MediaFile.c_str());
		if (Sources[i].Camera >= 0)
		{
			HubClient->writeTimedTriple(object.c_str(), "Camera", IntToStr(Sources[i].Camera).c_str());
		}
		if (Sources[i].Offset != 0)
		{
			HubClient->writeTimedTriple(object.c_str(), "Offset", IntToStr(Sources[i].Offset).c_str());
		}
		if (Sources[i].Width != 0)
		{
			HubClient->writeTimedTriple(object.c_str(), "Width", IntToStr(Sources[i].Width).c_str());
		}
		if (Sources[i].Height != 0)
		{
			HubClient->writeTimedTriple(object.c_str(), "Height", IntToStr(Sources[i].Height).c_str());
		}
		if (Sources[i].FrameRate.Rate != 1 || Sources[i].FrameRate.Scale != 1)
		{
			HubClient->writeTimedTriple(object.c_str(), "Rate", IntToStr(Sources[i].FrameRate.Rate).c_str());
			HubClient->writeTimedTriple(object.c_str(), "Scale", IntToStr(Sources[i].FrameRate.Scale).c_str());
		}
		if (Sources[i].Length != 0)
		{
			HubClient->writeTimedTriple(object.c_str(), "Length", IntToStr(Sources[i].Length).c_str());
		}
		if (Sources[i].Loop != 0)
		{
			HubClient->writeTimedTriple(object.c_str(), "Loop", IntToStr(Sources[i].Loop).c_str());
		}
	}

	// save all events
	object.printf("%s.Events.Event", InputFileName.c_str());
	HubClient->writeTimedTriple(object.c_str(), "Count", IntToStr(Events.size()).c_str());
	for (unsigned int i = 0; i < Events.size(); i++)
	{
		object.printf("%s.Events.Event.%d", InputFileName.c_str(), i);

		HubClient->writeTimedTriple(object.c_str(), "ID", IntToStr(Events[i]->ID).c_str());
		HubClient->writeTimedTriple(object.c_str(), "Time", IntToStr(Events[i]->Time).c_str());
		HubClient->writeTimedTriple(object.c_str(), "Text", Events[i]->Text.c_str());
		// parameters
		TParameters &Parameters = Events[i]->Parameters;
		HubClient->writeTimedTriple(object.c_str(), "Parameters.Count", IntToStr(Parameters.size()).c_str());
		for (int j = 0; j < (int)Parameters.size(); j++)
		{
			attribute.printf("Parameters.%d.", j);

			HubClient->writeTimedTriple(object.c_str(), string(attribute.c_str()) + "Name", Parameters[j].Name.c_str());
			HubClient->writeTimedTriple(object.c_str(), string(attribute.c_str()) + "Value", Parameters[j].Value.c_str());
		}
	}

	HubClient->writeln("</Updates>");
}

//---------------------------------------------------------------------------
void TImpExp::SaveToXml(const char *FileName)
{
#if 1
	xmlDocPtr doc = xmlNewDoc((const xmlChar*)"1.0");
	if (doc == NULL)
	{
		throw TError("Could not create xml document!");
	}
	try
	{
		xmlNodePtr root = xmlNewDocNode(doc, NULL, (const xmlChar*)"AVEvents", NULL);
		if (root == NULL)
		{
			throw TError("Could not create root node!");
		}
		xmlDocSetRootElement(doc, root);

		xmlNodePtr groups = xmlNewChild(root, NULL, (const xmlChar*)"EventGroups", NULL);
		for (unsigned int i = 0; i < Groups.size(); i++)
		{
			xmlNodePtr group = xmlNewChild(groups, NULL, (const xmlChar*)"Group", NULL);
			xmlNewChild(group, NULL, (const xmlChar*)"ID", (xmlChar*)IntToStr(i).c_str());
			xmlNewChild(group, NULL, (const xmlChar*)"Name", (xmlChar*)Groups[i].Desc.c_str());
			xmlNewChild(group, NULL, (const xmlChar*)"Meaning", (xmlChar*)Groups[i].Meaning.c_str());
			xmlNewChild(group, NULL, (const xmlChar*)"Enabled", (xmlChar*)IntToStr(Groups[i].Enabled).c_str());
		}

		xmlNodePtr types = xmlNewChild(root, NULL, (const xmlChar*)"EventTypes", NULL);
		for (unsigned int i = 0; i < EventTypes.size(); i++)
		{
			xmlNodePtr event = xmlNewChild(types, NULL, (const xmlChar*)"Type", NULL);
			xmlNewChild(event, NULL, (const xmlChar*)"ID", (xmlChar*)IntToStr(i).c_str());
			xmlNewChild(event, NULL, (const xmlChar*)"Name", (xmlChar*)EventTypes[i].Desc.c_str());
			if (EventTypes[i].Key != 0)
			{
				xmlNewChild(event, NULL, (const xmlChar*)"Key", (xmlChar*)(ShortCutToText(EventTypes[i].Key)).c_str());
			}
			if (EventTypes[i].Group >= 0 && EventTypes[i].GroupIndex >= 0)
			{
				xmlNewChild(event, NULL, (const xmlChar*)"Group", (xmlChar*)(IntToStr(EventTypes[i].Group)).c_str());
				xmlNewChild(event, NULL, (const xmlChar*)"GroupIndex", (xmlChar*)(IntToStr(EventTypes[i].GroupIndex)).c_str());
			}
			xmlNewChild(event, NULL, (const xmlChar*)"Offset", (xmlChar*)IntToStr(EventTypes[i].Offset).c_str());
			TParameters &Parameters = EventTypes[i].Parameters;
			int s = Parameters.size();
			if (s > 0)
			{
				xmlNodePtr prop = xmlNewChild(event, NULL, (const xmlChar*)"Parameters", NULL);
				for (int j = 0; j < s; j++)
				{
					xmlSetProp(prop, (xmlChar*)Parameters[j].Name.c_str(), (xmlChar*)Parameters[j].Value.c_str());
				}
			}
			TSecondaryKeys &SecondaryKeys = EventTypes[i].SecondaryKeys;
			for (unsigned int j = 0; j < SecondaryKeys.size(); j++)
			{
				xmlNodePtr secondary = xmlNewChild(event, NULL, (const xmlChar*)"Secondary", NULL);
				xmlNewChild(secondary, NULL, (const xmlChar*)"Key", (xmlChar*)(ShortCutToText(SecondaryKeys[j].Key)).c_str());
				xmlNewChild(secondary, NULL, (const xmlChar*)"Offset", (xmlChar*)IntToStr(SecondaryKeys[j].Offset).c_str());
				TParameters &Parameters = SecondaryKeys[j].Parameters;
				int s = Parameters.size();
				if (s > 0)
				{
					xmlNodePtr prop = xmlNewChild(secondary, NULL, (const xmlChar*)"Parameters", NULL);
					for (int k = 0; k < s; k++)
					{
						xmlSetProp(prop, (xmlChar*)Parameters[k].Name.c_str(), (xmlChar*)Parameters[k].Value.c_str());
					}
				}
			}
		}

		xmlNodePtr times = xmlNewChild(root, NULL, (const xmlChar*)"File", NULL);
/*
		AnsiString FileNamePath = ExtractFilePath(FileName);
*/
		for (unsigned int i = 0; i < Sources.size(); i++)
		{
			AnsiString MediaFile = Sources[i].FileName.c_str();
/*
			if (FileNamePath == ExtractFilePath(MediaFile))
			{
				MediaFile = MediaFile.SubString(FileNamePath.Length() + 1, MediaFile.Length() - FileNamePath.Length());
			}
*/
			xmlNodePtr videosrc = xmlNewChild(times, NULL, (const xmlChar*)"Source", (xmlChar*)MediaFile.c_str());
			int cam = Sources[i].Camera;
			if (cam >= 0)
			{
				xmlSetProp(videosrc, (const xmlChar*)"Camera", (xmlChar*)IntToStr(cam).c_str());
			}

			int off = Sources[i].Offset;
			if (off != 0)
			{
				xmlSetProp(videosrc, (const xmlChar*)"Offset", (xmlChar*)IntToStr(off).c_str());
			}

			if (Sources[i].Width != 0)
			{
				xmlSetProp(videosrc, (const xmlChar*)"Width", (xmlChar*)IntToStr(Sources[i].Width).c_str());
			}
			if (Sources[i].Height != 0)
			{
				xmlSetProp(videosrc, (const xmlChar*)"Height", (xmlChar*)IntToStr(Sources[i].Height).c_str());
			}

			if (Sources[i].FrameRate.Rate != 1 || Sources[i].FrameRate.Scale != 1)
			{
				xmlSetProp(videosrc, (const xmlChar*)"Rate", (xmlChar*)IntToStr(Sources[i].FrameRate.Rate).c_str());
				xmlSetProp(videosrc, (const xmlChar*)"Scale", (xmlChar*)IntToStr(Sources[i].FrameRate.Scale).c_str());
			}

			if (Sources[i].Length != 0)
			{
				xmlSetProp(videosrc, (const xmlChar*)"Length", (xmlChar*)IntToStr(Sources[i].Length).c_str());
			}

			if (Sources[i].Loop != 0)
			{
				xmlSetProp(videosrc, (const xmlChar*)"Loop", (xmlChar*)IntToStr(Sources[i].Loop).c_str());
			}
		}

		char *TimeFormatDesc;
		if (TimeFormat == tfFrames)
		{
			TimeFormatDesc = "Frames";
		}
		else
		{
			TimeFormatDesc = "Milliseconds";
		}
		xmlNodePtr timeformat = xmlNewChild(times, NULL, (const xmlChar*)"TimeFormat", (xmlChar*)TimeFormatDesc);
/*
		if (TimeFormat == tfFrames)
		{
			double FrameRate = 0;
			for (int i = 0; i < vl->Count; i++)
			{
				TFormVideo *fv = (TFormVideo*)vl->Items[i];
				if ((fv->av->GetOpenMode() == TAVFile::omRead) && (fv->av->GetOpenType() & TAVFile::otVideo))
				{
					TAVFile::TFrameRate fr = fv->av->GetFrameInfo().FrameRate;
					FrameRate = double(fr.Rate) / double(fr.Scale);
					break;
				}
			}
			if (FrameRate > 0)
			{
				xmlSetProp(timeformat, "FrameRate", FloatToStr(FrameRate).c_str());
			}
		}
*/
		for (unsigned int i = 0; i < Events.size(); i++)
		{
			xmlNodePtr event = xmlNewChild(times, NULL, (const xmlChar*)"Event", NULL);
			/*xmlNodePtr eid = */xmlNewChild(event, NULL, (const xmlChar*)"ID", (xmlChar*)IntToStr(Events[i]->ID).c_str());
			/*xmlNodePtr etime = */xmlNewChild(event, NULL, (const xmlChar*)"Time", (xmlChar*)IntToStr(Events[i]->Time).c_str());
			/*xmlNodePtr etext = */xmlNewChild(event, NULL, (const xmlChar*)"Text", (xmlChar*)Events[i]->Text.c_str());

			int s = Events[i]->Parameters.size();
			if (s > 0)
			{
				xmlNodePtr prop = xmlNewChild(event, NULL, (const xmlChar*)"Parameters", NULL);
				for (int j = 0; j < s; j++)
				{
					xmlNodePtr par = xmlNewChild(prop, NULL, (const xmlChar*)Events[i]->Parameters[j].Name.c_str(), (xmlChar*)Events[i]->Parameters[j].Value.c_str());
				}
/*
				for (int j = 0; j < s; j++)
				{
					xmlSetProp(prop, (xmlChar*)Events[i]->Parameters[j].Name.c_str(), (xmlChar*)Events[i]->Parameters[j].Value.c_str());
				}
*/
			}
		}
#if 0
		for (unsigned int i = 0; i < Titles.size(); i++)
		{
			xmlNodePtr event = xmlNewChild(times, NULL, "Title", NULL);
			/*xmlNodePtr etime = */xmlNewChild(event, NULL, "Time", IntToStr(Titles[i]->Time).c_str());
			/*xmlNodePtr eid = */xmlNewChild(event, NULL, "Text", Titles[i]->Text.c_str());
		}
#endif
		if (!xmlSaveFormatFile(FileName, doc, 1))
		{
			throw TError("Could not write xml document!");
		}

		xmlFreeDoc(doc);
	}
	catch (...)
	{
		xmlFreeDoc(doc);
		throw;
	}
#endif
}

//---------------------------------------------------------------------------
bool TImpExp::GetFileParameters(const char *FileName, TSource &Source)
{
	TAVFile *AVFile = AVFileOpen(FileName, TAVFile::otVideo);
	if (AVFile)
	{
		TAVFile::TFrameInfo FrameInfo = AVFile->GetFrameInfo();
		Source.FrameRate = FrameInfo.FrameRate;
		Source.Length = AVFile->GetVideoLength();
		Source.Width = FrameInfo.Width;
		Source.Height = FrameInfo.Height;
		delete AVFile;
		return true;
	}
	else
	{
		return false;
	}
}

//---------------------------------------------------------------------------
void TImpExp::CreateMedia(const char *DirName)
{
	DIR *RootDir;
	struct dirent *RootEnt;
	int Offset = -10000;

	if ((RootDir = opendir(DirName)) == NULL)
	{
		throw TError("Unable to open directory!");
	}

	while ((RootEnt = readdir(RootDir)) != NULL)
	{
		if (strncmp(RootEnt->d_name, "Cam", 3) == 0)
		{
			DIR *CamDir;
			if ((CamDir = opendir((std::string(DirName) + PATH_DELIMINER + std::string(RootEnt->d_name)).c_str())) != NULL)
			{
				struct dirent *CamEnt;
				while ((CamEnt = readdir(CamDir)) != NULL)
				{
					int Len = strlen(CamEnt->d_name);
					if (Len >= 4 && strncmp(CamEnt->d_name, "Cam", 3) == 0 && strncmp(CamEnt->d_name + Len - 4, ".avi", 3) == 0)
					{
						TSource Source;
						Source.Camera = CamEnt->d_name[3] - '0';
						Source.Offset = Offset + ((((CamEnt->d_name[6] - '0') * 10 + CamEnt->d_name[7] - '0') * 60 + (CamEnt->d_name[8] - '0') * 10 + CamEnt->d_name[9] - '0') * 60 + (CamEnt->d_name[10] - '0') * 10 + CamEnt->d_name[11] - '0') * 1000 + (CamEnt->d_name[13] - '0') * 100 + (CamEnt->d_name[14] - '0') * 10 + CamEnt->d_name[15] - '0';
						Source.FileName = std::string(RootEnt->d_name) + PATH_DELIMINER + std::string(CamEnt->d_name);
						GetFileParameters((std::string(DirName) + PATH_DELIMINER + std::string(RootEnt->d_name) + PATH_DELIMINER + std::string(CamEnt->d_name)).c_str(), Source);
						Sources.push_back(Source);
					}
				}
				closedir(CamDir);
			}
		}
		else if (strcmp(RootEnt->d_name, "audio") == 0)
		{
			struct stat statbuf;
			const char *AudioFile = "Lapel-mix.wav";
			if (stat((std::string(DirName) + PATH_DELIMINER + std::string(RootEnt->d_name) + PATH_DELIMINER + std::string(AudioFile)).c_str(), &statbuf) == 0)
			{
				TSource Source;
				Source.Offset = 10000 + Offset;
				Source.FileName = std::string(RootEnt->d_name) + PATH_DELIMINER + std::string(AudioFile);
				Sources.push_back(Source);
			}
		}
	}

	closedir(RootDir);
	TimeFormat = tfTime;
}

//---------------------------------------------------------------------------
void TImpExp::UpdateMedia()
{
	for (TSources::iterator i = Sources.begin(); i != Sources.end(); i++)
	{
		// uplna cesta
		bool OK = GetFileParameters(NormalizeFilePath(i->FileName.c_str()).c_str(), *i);
		// prohledavani zadanych adresaru
		std::vector<std::string>::iterator m = MediaPath.begin();
		while (!OK && m != MediaPath.end())
		{
			OK = GetFileParameters((*m + PATH_DELIMINER + NormalizeFilePath(i->FileName.c_str())).c_str(), *i);
			m++;
		}
	}
}

//---------------------------------------------------------------------------
AnsiString TImpExp::AnsiString2Prolog(AnsiString s, bool Event)
{
	if (s == "")
	{
		return "''";
	}
	bool FileName = false;
	for (int i = 1; i <= s.Length(); i++)
	{
		switch (s[i])
		{
		case '.':
			if (!Event)
			{
				break;
			}
		case ' ':
		case '(':
		case ')':
		case '[':
		case ']':
			s[i] = '_';
			break;
		case ',':
			s[i] = '.';
			break;
		case WIN32_PATH_DELIMINER:
		case POSIX_PATH_DELIMINER:
			FileName = true;
			break;
		}
		s[i] = tolower(s[i]);
	}
	if (FileName)
	{
		s = "\'" + s + "\'";
	}
	return s;
}

//---------------------------------------------------------------------------
AnsiString TImpExp::Event2Prolog(int Time, const char *Type, ee::TParameters Parameters)
{
	std::stringstream h;
	h << "event_" << AnsiString2Prolog(Type, true).c_str();
	h << "(" << Time << ", [";

	for (unsigned int j = 0; j < Parameters.size(); j++)
	{
		if (j > 0)
		{
			h << ", ";
		}
		h << "(" << TImpExp::AnsiString2Prolog(Parameters[j].Name).c_str() << ", "
		  << TImpExp::AnsiString2Prolog(Parameters[j].Value).c_str() << ")";
	}
	h << "]).\n";
	return h.str().c_str();
}

//---------------------------------------------------------------------------
AnsiString TImpExp::Event2Prolog(TEvent *e)
{
	return Event2Prolog(e->Time, EventTypes[e->ID].Desc.c_str(), e->Parameters);
}

//---------------------------------------------------------------------------
void TImpExp::ExportProlog(const char *FileName)
{
	FILE *f = fopen(FileName, "w");
	if (f == NULL)
	{
		throw TError("Could not create file!");
	}

	unsigned int Max = 0, Step = 0;
	for (TSources::iterator i = Sources.begin(); i != Sources.end(); i++)
	{
		TAVFile::TFrameRate fr = i->FrameRate;
		unsigned int l = TAVFile::Round((1000.0 * double(fr.Scale) * double(i->Length)) / double(fr.Rate)) + i->Offset;
		if (l > Max)
		{
			Max = l;
		}
		unsigned int s = TAVFile::Round((1000.0 * double(fr.Scale)) / double(fr.Rate));
		if ((Step == 0) || (Step > s))
		{
			Step = s;
		}
	}
	if (Step == 0)
	{
		Step = 1;
	}

	if (Max > 0)
	{
		fprintf(f, "begin(%d).\n", 0);
		fprintf(f, "end(%d).\n", Max);
		fprintf(f, "step(%d).\n", Step);
	}

	for (TSources::iterator i = Sources.begin(); i != Sources.end(); i++)
	{
		if (i->Camera >= 0)
		{
			fprintf(f, "camera(%d, %d, %d).\n", i->Camera, i->Width, i->Height);
		}
	}

	for (unsigned int t = 0; t < EventTypes.size(); t++)
	{
		TEvents::iterator i = Events.begin();
		while (i != Events.end())
		{
			TEvent *m = *i;
			if (m->ID == (int)t)
			{
				AnsiString h = "event_" + AnsiString2Prolog(EventTypes[m->ID].Desc, true);
				fprintf(f, "%s(%d, [", h.c_str(), m->Time);
				for (unsigned int j = 0; j < m->Parameters.size(); j++)
				{
					if (j > 0)
					{
						fprintf(f, ", ");
					}
					fprintf(f, "(%s, %s)", AnsiString2Prolog(m->Parameters[j].Name).c_str(), AnsiString2Prolog(m->Parameters[j].Value).c_str());
				}
				fprintf(f, "]).\n");
			}
			i++;
		}
	}

	fclose(f);
}

//---------------------------------------------------------------------------
void TImpExp::LoadXML(const char *FileName, bool Import, bool UseCameraOffset, int ForceCamera)
{
	xmlDocPtr doc = xmlParseFile(FileName);
	if (doc == NULL)
	{
		throw TError("Could not open file!");
	}

	try
	{
		xmlNodePtr cur = xmlDocGetRootElement(doc);
		if (cur == NULL)
		{
			throw TError("Empty document!");
		}

		if (!xmlStrcmp(cur->name, (const xmlChar *) "AVEvents"))
		{
			LoadFromXml(FileName, Import, UseCameraOffset, ForceCamera);
		}
		else if (!xmlStrcmp(cur->name, (const xmlChar *) "Trans"))
		{
			ImportTranscription(FileName);
		}
		else if (!xmlStrcmp(cur->name, (const xmlChar *) "annotation"))
		{
			ImportAnvil(FileName);
		}
		else
		{
			throw TError("Document of the wrong type!");
		}

		xmlFreeDoc(doc);
	}
	catch (...)
	{
		xmlFreeDoc(doc);
		throw;
	}
}

//---------------------------------------------------------------------------
void TImpExp::ImportTranscription(const char *FileName)
{
	int Offset = 0;
/*
	if (!FormOffset->GetOffset(Offset))
	{
		return;
	}
*/
	xmlDocPtr doc = xmlParseFile(FileName);
	if (doc == NULL)
	{
		throw TError("Could not open file!");
	}

	try
	{
		xmlNodePtr cur = xmlDocGetRootElement(doc);
		if (cur == NULL)
		{
			throw TError("Empty document!");
		}

		if (xmlStrcmp(cur->name, (const xmlChar*)"Trans"))
		{
			throw TError("Document of the wrong type!");
		}

		xmlNodePtr episode_cur = cur->xmlChildrenNode;
		while (episode_cur != NULL)
		{
			if (xmlStrcmp(episode_cur->name, (const xmlChar *)"Episode") == 0)
			{
				xmlNodePtr section_cur = episode_cur->xmlChildrenNode;
				while (section_cur != NULL)
				{
					if (xmlStrcmp(section_cur->name, (const xmlChar *)"Section") == 0)
					{
						xmlNodePtr turn_cur = section_cur->xmlChildrenNode;
						while (turn_cur != NULL)
						{
							if (xmlStrcmp(turn_cur->name, (const xmlChar *)"Turn") == 0)
							{
								xmlNodePtr sync_cur = turn_cur->xmlChildrenNode;
								while (sync_cur != NULL)
								{
									if (xmlStrcmp(sync_cur->name, (const xmlChar *)"Sync") == 0)
									{
										xmlNodePtr text_cur = sync_cur->next;
										if (text_cur != NULL && xmlStrcmp(text_cur->name, (const xmlChar *)"text") == 0)
										{
											xmlChar *chan_str = xmlGetProp(sync_cur, (const xmlChar *)"chan");
											xmlChar *time_str = xmlGetProp(sync_cur, (const xmlChar *)"time");
											if (xmlStrcmp(chan_str, (const xmlChar *)"default"))
											{
												int ID, Time = atof((char*)time_str) * 1000.0 + Offset;
												AnsiString Text = Trim(AnsiString((char*)text_cur->content));
												if (Text == "GAP(OTHER)" || Text == "" || Text == "..")
												{
													ID = GetDefaultMessageID(detStopSpeaking);
												}
												else
												{
													ID = GetDefaultMessageID(detStartSpeaking);
												}
												TParameters Parameters;
												try
												{
													AnsiString Person;
													Person = char('A' + StrToInt((const char*)chan_str));
													Parameters.push_back(TParameter("Person", Person));
//													Parameters.push_back(TParameter("Text", Text));
													if (Time >= 0)
													{
														TEvent *e = new TEvent();
														e->Time = Time;
														e->ID = ID;
														e->Parameters = Parameters;
														e->Text = Text;
														InsertMessage(e);
//														AddEvent(Time, ID, Parameters, Text);
													}
												}
												catch (...)
												{
												}
											}
											xmlFree(chan_str);
											xmlFree(time_str);
										}
									}
									sync_cur = sync_cur->next;
								}
							}
							turn_cur = turn_cur->next;
						}
					}
					section_cur = section_cur->next;
				}
			}
			episode_cur = episode_cur->next;
		}

		xmlFreeDoc(doc);
	}
	catch (...)
	{
		xmlFreeDoc(doc);
		throw;
	}
}

//---------------------------------------------------------------------------
int TImpExp::FindDefaultMessageID(const TDefaultEventType Type)
{
	return FindMessageID(DefaultEvents[Type].Name);
}

//---------------------------------------------------------------------------
int TImpExp::GetDefaultMessageID(const TDefaultEventType Type)
{
	int ID = FindMessageID(DefaultEvents[Type].Name);
	if (ID < 0)
	{
		int Key;
		if (DefaultEvents[Type].Key != NULL)
		{
			Key = TextToShortCut(DefaultEvents[Type].Key);
		}
		else
		{
			Key = 0;
		}
		int Group;
		if (DefaultEvents[Type].Group != NULL)
		{
			Group = GetGroupID(DefaultEvents[Type].Group);
		}
		else
		{
			Group = -1;
		}
		TParameters Parameters;
		TSecondaryKeys SecondaryKeys;
		EventTypes.push_back(TEventType(DefaultEvents[Type].Name, Key, Group, DefaultEvents[Type].GroupIndex, 0, Parameters, SecondaryKeys));
		ID = EventTypes.size() - 1;
	}
	return ID;
}

//---------------------------------------------------------------------------
void TImpExp::ImportAnvil(const char *FileName)
{
	int Offset = 0;

	xmlDocPtr doc = xmlParseFile(FileName);
	if (doc == NULL)
	{
		throw TError("Could not open file!");
	}

	try
	{
		xmlNodePtr cur = xmlDocGetRootElement(doc);
		if (cur == NULL)
		{
			throw TError("Empty document!");
		}

		if (xmlStrcmp(cur->name, (const xmlChar*)"annotation"))
		{
			throw TError("Document of the wrong type!");
		}

		xmlNodePtr body_cur = cur->xmlChildrenNode;
		while (body_cur != NULL)
		{
			if (xmlStrcmp(body_cur->name, (const xmlChar *)"body") == 0)
			{
				xmlNodePtr track_cur = body_cur->xmlChildrenNode;
				while (track_cur != NULL)
				{
					if (xmlStrcmp(track_cur->name, (const xmlChar *)"track") == 0)
					{
						xmlChar *NameChar = xmlGetProp(track_cur, (const xmlChar *)"name");
						if (NameChar != NULL)
						{
							int ID = GetMessageID((const char*)NameChar);
							xmlFree(NameChar);

							xmlNodePtr el_cur = track_cur->xmlChildrenNode;
							while (el_cur != NULL)
							{
								if (xmlStrcmp(el_cur->name, (const xmlChar *)"el") == 0)
								{
									xmlChar *IndexChar = xmlGetProp(el_cur, (const xmlChar *)"index");
									xmlChar *StartChar = xmlGetProp(el_cur, (const xmlChar *)"start");
									xmlChar *EndChar = xmlGetProp(el_cur, (const xmlChar *)"end");
									if (IndexChar != NULL && StartChar != NULL && EndChar != NULL)
									{
										int Index = StrToInt((char*)IndexChar);
										for (int i = 0; StartChar[i] != 0; i++)
										{
											if (StartChar[i] == '.')
											{
												StartChar[i] = ',';
											}
										}
										int Start = 1000.0 * StrToFloat((const char*)StartChar);
										for (int i = 0; EndChar[i] != 0; i++)
										{
											if (EndChar[i] == '.')
											{
												EndChar[i] = ',';
											}
										}
										int End = 1000.0 * StrToFloat((char*)EndChar);

										TParameters Parameters;
										xmlNodePtr attribute_cur = el_cur->xmlChildrenNode;
										while (attribute_cur != NULL)
										{
											if (xmlStrcmp(attribute_cur->name, (const xmlChar *)"attribute") == 0)
											{
												xmlChar *NameChar = xmlGetProp(attribute_cur, (const xmlChar *)"name");
												if (NameChar != NULL)
												{
													xmlChar *ValueChar = xmlNodeListGetString(doc, attribute_cur->xmlChildrenNode, 1);
													if (ValueChar != NULL)
													{
														char *n = (char*)NameChar;
														while (*n != 0)
														{
															if (*n == ' ')
															{
																*n = '_';
															}
															n++;
														}
														Parameters.push_back(TParameter((char*)NameChar, (char*)ValueChar));
														xmlFree(ValueChar);
													}
													xmlFree(NameChar);
												}
											}
											attribute_cur = attribute_cur->next;
										}

										Parameters.push_back(TParameter("Length", IntToStr(End - Start)));

										TEvent *Event = new TEvent();
										Event->Time = Start;
										Event->ID = ID;
										Event->Parameters = Parameters;
										InsertMessage(Event);
//										AddEvent(Start, ID, Parameters);
									}
									xmlFree(IndexChar);
									xmlFree(StartChar);
									xmlFree(EndChar);
								}
								el_cur = el_cur->next;
							}
						}
					}
					track_cur = track_cur->next;
				}
			}
			body_cur = body_cur->next;
		}
		xmlFreeDoc(doc);
	}
	catch (...)
	{
		xmlFreeDoc(doc);
		throw;
	}
}

typedef struct
{
	std::string nxt_agent, camera, role;
}
TSpeaker;

//---------------------------------------------------------------------------
void TImpExp::UpdateConfig(const char *FileName, const char *Meeting)
{
	std::vector<TSpeaker> Speakers;

	xmlDocPtr doc = xmlParseFile(FileName);
	if (doc == NULL)
	{
		throw TError("Could not open file!");
	}

	try
	{
		xmlNodePtr cur = xmlDocGetRootElement(doc);
		if (cur == NULL)
		{
			throw TError("Empty document!");
		}

		if (xmlStrcmp(cur->name, (const xmlChar*)"root"))
		{
			throw TError("Document of the wrong type!");
		}

		xmlNodePtr body_cur = cur->xmlChildrenNode;
		while (body_cur != NULL)
		{
			if (xmlStrcmp(body_cur->name, (const xmlChar *)"meeting") == 0)
			{
				xmlChar *Observation = xmlGetProp(body_cur, (const xmlChar *)"observation");
				if (Observation)
				{
					if (xmlStrcmp(Observation, (const xmlChar*)Meeting) == 0)
					{
						xmlNodePtr speaker_cur = body_cur->xmlChildrenNode;
						while (speaker_cur != NULL)
						{
							if (xmlStrcmp(speaker_cur->name, (const xmlChar *)"speaker") == 0)
							{
								xmlChar *nxt_agent = xmlGetProp(speaker_cur, (const xmlChar *)"nxt_agent");
								xmlChar *camera = xmlGetProp(speaker_cur, (const xmlChar *)"camera");
								xmlChar *role = xmlGetProp(speaker_cur, (const xmlChar *)"role");
								if (nxt_agent && camera && role)
								{
									TSpeaker Speaker;
									Speaker.nxt_agent = (char*)nxt_agent;
									Speaker.camera = (char*)camera;
									Speaker.role = (char*)role;
									Speakers.push_back(Speaker);
								}
								if (nxt_agent)
								{
									xmlFree(nxt_agent);
								}
								if (camera)
								{
									xmlFree(camera);
								}
								if (role)
								{
									xmlFree(role);
								}
							}
							speaker_cur = speaker_cur->next;
						}
					}
					xmlFree(Observation);
				}
			}
			body_cur = body_cur->next;
		}
		xmlFreeDoc(doc);
	}
	catch (...)
	{
		xmlFreeDoc(doc);
		throw;
	}

	for (TEvents::iterator i = Events.begin(); i != Events.end(); i++)
	{
		for (std::vector<TSpeaker>::iterator s = Speakers.begin(); s != Speakers.end(); s++)
		{
			TParameter *Parameter;
			Parameter = GetParameter((*i)->Parameters, "individual", NULL);
			if (Parameter && Parameter->Value.c_str() == s->role)
			{
				Parameter->Value = s->camera.c_str();
			}
			Parameter = GetParameter((*i)->Parameters, "Person", NULL);
			if (Parameter && Parameter->Value.c_str() == s->nxt_agent)
			{
				Parameter->Value = s->camera.c_str();
			}
		}
	}
}

//---------------------------------------------------------------------------
void TImpExp::AddMediaPath(const char *DirName)
{
	MediaPath.push_back(DirName);
}

//---------------------------------------------------------------------------
void TImpExp::ClearMediaPath()
{
	MediaPath.clear();
}

//---------------------------------------------------------------------------
void TImpExp::CopyEvents(TImpExp &Source)
{
	for (TEvents::iterator e = Source.Events.begin(); e != Source.Events.end(); e++)
	{
		InsertMessage((*e)->Time, Source.EventTypes[(*e)->ID].Desc.c_str(), (*e)->Parameters);
	}
}

//---------------------------------------------------------------------------
TImpExp::TDefaultEvent TImpExp::GetDefaultEvent(TDefaultEventType Type)
{
	return DefaultEvents[Type];
}

