//---------------------------------------------------------------------------
#include <vcl.h>
#include <StrUtils.hpp>
#include <stdio.h>
#include <iostream>
#include <sstream>
#pragma hdrstop
#include "RTEditor.h"
#include "SWI-cpp_hack.h"
#include "ImpExp.h"
#include "FSTools.h"
#include "ComplexDetectorDemo.h"
#include "BlahoDetectorDemo.h"
#include "ComplexDetectorESF.h"
#include "Error.h"
#include "PrologSources.h"
#include "CameraDllHandler.h"

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

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

//---------------------------------------------------------------------------
TRTEditor::TRTEditor()
{
	FProlog = NULL;
	FTexts = NULL;
	FPrologSources = new TStringList();
	FWidth = FHeight = FOutputWidth = FOutputHeight = FDetectorsDelay = 0;
	FInitiallized = false;
	PL_action(PL_ACTION_GUIAPP, TRUE);
	UseOnlineCameras = false;
//	DetectorsCreate();
}

//---------------------------------------------------------------------------
TRTEditor::~TRTEditor()
{
	if (FProlog)
	{
		PL_set_engine(PL_ENGINE_MAIN, NULL);
		delete FProlog;
	}
	if (FPrologSources)
	{
		delete FPrologSources;
	}
	ClearQueues();
	DetectorsFree();
}

//---------------------------------------------------------------------------
void TRTEditor::DetectorsCreate()
{
	DetectorsFree();
	if (UseOnlineCameras)
	{
		FDetectors.push_back(new TBlahoDetectorDemo());
	}
	else
	{
		FDetectors.push_back(new TComplexDetectorESF());
	}
//	FDetectors.push_back(new TComplexDetectorDemo());
}

//---------------------------------------------------------------------------
void TRTEditor::DetectorsFree()
{
	for (std::vector<TComplexDetector*>::iterator i = FDetectors.begin(); i != FDetectors.end(); i++)
	{
		delete *i;
	}
	FDetectors.clear();
}

//---------------------------------------------------------------------------
void TRTEditor::DetectorsInit(int MaxQueueSize)
{
	for (std::vector<TComplexDetector*>::iterator i = FDetectors.begin(); i != FDetectors.end(); i++)
	{
		(*i)->Init(Sources, MaxQueueSize);
	}
}

//---------------------------------------------------------------------------
void TRTEditor::DetectorsBreak()
{
	for (std::vector<TComplexDetector*>::iterator i = FDetectors.begin(); i != FDetectors.end(); i++)
	{
		(*i)->Break();
	}
}

//---------------------------------------------------------------------------
void TRTEditor::ClearQueues()
{
	while (!FVideo.empty())
	{
		delete FVideo.front();
		FVideo.pop();
	}
	while (!FAudio.empty())
	{
		delete FAudio.front();
		FAudio.pop();
	}
}

//---------------------------------------------------------------------------
void TRTEditor::Init(TMode AMode, int AStep, int AEditingDelay, int ADetectorsDelay, bool AVideo, bool AAudio, TExtendedSources::EResize AResizeInput, TExtendedSources::EResize AResizeOutput)
{
	if (FInitiallized)
	{
		throw TError("Editor already initialized!");
	}

	DetectorsCreate();

	FTime = 0;
	FStep = AStep;
	FDetectorsDelay = ADetectorsDelay;
	FImport = false;
	FDetectorsImpExp.Clear();

	if (AMode == mAuto)
	{
		FMode = mHalfRT;
		int ID = ImpExp.FindDefaultMessageID(TImpExp::detOutput);
		if (ID >= 0)
		{
			for (TEvents::iterator i = ImpExp.Events.begin(); i != ImpExp.Events.end(); i++)
			{
				if ((*i)->ID == ID)
				{
					FMode = mOutput;
					break;
				}
			}
		}
	}
	else
	{
		FMode = AMode;
	}

	if (FProlog)
	{
		PL_set_engine(PL_ENGINE_MAIN, NULL);
		delete FProlog;
		FProlog = NULL;
	}
	ClearQueues();

	Sources.Init(AEditingDelay + ADetectorsDelay, AResizeInput);
	if (FMode == mHalfRT || FMode == mRT || FMode == mRTF)
	{
		int argc = 0;
		argv[argc++] = "libpl.dll";
		argv[argc++] = "-L32m";
		argv[argc++] = "-G32m";
		argv[argc++] = "-T32m";
		argv[argc++] = "-A32m";
		argv[argc++] = "-nosignals";
		try
		{
			FProlog = new PlEngine(argc, argv);
		}
		catch (PlError &ex)
		{
			throw Exception(ex.message);
		}

		PL_set_engine(PL_ENGINE_MAIN, NULL);
		try
		{
			try
			{
				PlFrame frame;

				// Nacteni zdrojovych kodu v Prologu
				TPrologSources PrologSources;
				for (int i = 0; i < FPrologSources->Count; i++)
				{
					if (PrologSources.IsBuiltIn(FPrologSources->Strings[i].c_str()))
					{
						PlFrame frame;
						char *buf = PrologSources.GetSource(FPrologSources->Strings[i].c_str());
						int size = strlen(buf);

						int s = 0, p = 0;
						AnsiString c;
						while (p < size)
						{
							char b = buf[p];
							switch (s)
							{
							case 0:
								if (islower(b))
								{
									s++;
									c += b;
								}
								break;

							case 1:
								c += b;
								if (b == '\n')
								{
									s++;
								}
								break;

							case 2:
								if (islower(b))
								{
									PlCall("assert", PlCompound(c.c_str()));
									c = "";
									c += b;
									s = 0;
								}
								else
								{
									c += b;
									s--;
								}
								break;
							}
							p++;
						}

						if (c != "")
						{
							PlCall("assert", PlCompound(c.c_str()));
						}
					}
					else
					{
						PlCall("consult", PlCompound(("'" + NormalizeFilePathProlog(FPrologSources->Strings[i].c_str()) + "'").c_str()));
					}
				}

				// Vytvoreni seznamu kamer a casovych znacek
				int MaxLength = 0;
				unsigned int Max = 0, Step = 0;
				for (unsigned int i = 0; i < Sources.size(); i++)
				{
					if (Sources[i]->Camera >= 0)
					{
						std::stringstream c;
						c << "camera(" << Sources[i]->Camera << ", " << Sources[i]->Width << ", " << Sources[i]->Height << ")";
						PlCall("assert", PlCompound(c.str().c_str()));
						if (Sources[i]->Length > MaxLength)
						{
							MaxLength = Sources[i]->Length;
						}

						TAVFile::TFrameRate fr = Sources[i]->FrameRate;
						unsigned int l = TAVFile::Round((1000.0 * double(fr.Scale) * double(Sources[i]->Length)) / double(fr.Rate)) + Sources[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 (FStep < 0)
				{
					FStep = Step;
				}
				/*
				int Length = 10000;
				if (Length > 0 && Max > Length)
				{
					Max = Length;
				}
				*/
				PlCall("assert", PlCompound("begin(0)"));
				PlCall("assert", PlCompound(("end(" + IntToStr(Max) + ")").c_str()));
				PlCall("assert", PlCompound(("step(" + IntToStr(Step) + ")").c_str()));

				// Vlozeni udalsti do databaze
				if (FMode == mHalfRT)
				{
					for (unsigned int t = 0; t < ImpExp.EventTypes.size(); t++)
					{
						TEvents::iterator i = ImpExp.Events.begin();
						while (i != ImpExp.Events.end())
						{
							ee::TEvent *m = *i;
							if (m->ID == (int)t)
							{
								PlCall("assert", PlCompound(ImpExp.Event2Prolog(m).c_str()));
							}
							i++;
						}
					}
				}

				// Nastaveni modu
				AnsiString ModeStr;
				if (FMode == mHalfRT)
				{
					ModeStr = "half_realtime";
				}
				else
				{
					ModeStr = "realtime";
				}
				PlCall("assert", PlCompound(("rule_configuration_user(s_mode, " + ModeStr + ")").c_str()));

				// Inicializace v Prologu
/*/!!!/*/				PlCall("init");

				// Doplneni udalosti nastaveni
				int ID = ImpExp.GetDefaultMessageID(TImpExp::detSetup);
				PlTermv av(1);
				PlQuery q("setup_events", av);
				if (q.next_solution())
				{
					TParameters Parameters;
					AnsiString s;
					PlTail l(av[0]);
					PlTerm e;
					while(l.next(e))
					{
						if (e.arity() == 2)
						{
							TParameter p((char*)e[1], (char*)e[2]);
							Parameters.push_back(p);
						}
						s = s + (char *)e + " ";
					}

					ee::TEvent *ev = new ee::TEvent();
					ev->Time = 0;
					ev->ID = ID;
					ev->Parameters = Parameters;
					ImpExp.InsertMessage(ev);
				}

				UpdateSetup();
			}
			catch (PlException &ex)
			{
				throw Exception((char*)ex);
			}
			PL_handle_signals();
			PL_set_engine(NULL, NULL);
		}
		catch (...)
		{
			PL_handle_signals();
			PL_set_engine(NULL, NULL);
			throw;
		}
	}

	FWidth = FHeight = FOutputWidth = FOutputHeight = 0;
	FHasVideo = AVideo && Sources.GetFrameSize(FWidth, FHeight);
	FHasAudio = AAudio && Sources.GetAudioPrms(FChannels, FSamplesPerSec);

	switch (AResizeOutput)
	{
	case TExtendedSources::rHalf:
		FWidth = FWidth / 2;
		FHeight = FHeight / 2;
		break;

	case TExtendedSources::rQuarter:
		FWidth = FWidth / 4;
		FHeight = FHeight / 4;
		break;
	}

	if (FHasVideo)
	{
		if (SetupInputAspectRatio > 0)
		{
			FWidth = TAVFile::Round(SetupInputAspectRatio * FHeight);
		}

		FOutputWidth = FWidth;
		FOutputHeight = FHeight;

		if (SetupCropAspectRatio > 0)
		{
			FOutputWidth = TAVFile::Round(SetupCropAspectRatio * FOutputHeight);
		}
	}

	FItem = ImpExp.Events.begin();
	TParameters Parameters;
	SetParameters(Parameters);
	FStatistics.Clear();

	// Nastaveni parametru detektoru
	if (FMode == mRTF)
	{
		int ID = ImpExp.GetDefaultMessageID(TImpExp::detDetector);
		for (ee::TEvents::iterator e = ImpExp.Events.begin(); e != ImpExp.Events.end(); e++)
		{
			if ((*e)->ID == ID)
			{
				AnsiString Name;
				int Camera = -1;
				if (GetParameterString((*e)->Parameters, "Name", Name) && GetParameterInt((*e)->Parameters, "Camera", Camera))
				{
					TParameter *Paramater = GetParameter((*e)->Parameters, "Config", NULL);
					if (Paramater)
					{
						if (ExtractFilePath(Paramater->Value) == "")
						{
							Paramater->Value = ExtractFilePath(LoadedFileName) + "\\" + Paramater->Value;
						}
					}

					for (std::vector<TComplexDetector*>::iterator d = FDetectors.begin(); d != FDetectors.end(); d++)
					{
						(*d)->SetConfiguration(Name.c_str(), Camera, (*e)->Parameters);
					}
				}
			}
		}
	}

	DetectorsInit(ADetectorsDelay);
	FInitiallized = true;
//!!!//    delete FProlog;
//!!!//	FProlog = NULL;
}

//---------------------------------------------------------------------------
void TRTEditor::Reset(int AEditingDelay, int ADetectorsDelay)
{
	if (!FInitiallized)
	{
		throw TError("Editor not initialized!");
	}

	if (FMode == mHalfRT || FMode == mRT || FMode == mRTF)
	{
		PL_set_engine(PL_ENGINE_MAIN, NULL);
	}
	try
	{
		FTime = 0;
		FDetectorsDelay = ADetectorsDelay;
		FImport = false;
		FDetectorsImpExp.Clear();

		DetectorsBreak();
		Sources.Init(AEditingDelay + ADetectorsDelay, Sources.GetResize());
		DetectorsInit(ADetectorsDelay);

		ClearQueues();
		FItem = ImpExp.Events.begin();
		FStatistics.Clear();

		try
		{
			if (FMode == mHalfRT || FMode == mRT || FMode == mRTF)
			{
				PlFrame f;
				// Inicializace v Prologu
/*!!!*/				PlCall("init_main");
			}
		}
		catch (PlException &ex)
		{
			throw Exception((char*)ex);
		}

		if (FMode == mHalfRT || FMode == mRT || FMode == mRTF)
		{
			PL_handle_signals();
			PL_set_engine(NULL, NULL);
		}
	}
	catch (...)
	{
		if (FMode == mHalfRT || FMode == mRT || FMode == mRTF)
		{
			PL_handle_signals();
			PL_set_engine(NULL, NULL);
		}
	}
}

//---------------------------------------------------------------------------
void TRTEditor::Do(bool ASkipVideo, bool ASkipAudio, bool ASkipProlog)
{
	if (!FInitiallized)
	{
		throw TError("Editor not initialized!");
	}

	if (FMode == mHalfRT || FMode == mRT || FMode == mRTF)
	{
		PL_set_engine(PL_ENGINE_MAIN, NULL);
	}
	try
	{
		clock_t StartTime, SourcesTime, ImportTime, PrologTime, EditingTime, TotalTime;
		StartTime = SourcesTime = ImportTime = PrologTime = EditingTime = TotalTime = clock();

		Sources.SetTime(FTime);
		SourcesTime = clock();
		try
		{
			int Delay = FStep * Sources.GetDelay();

			if (FMode == mRT)
			{
				PlFrame f;
				bool Import = false;
				while (FItem != ImpExp.Events.end() && (*FItem)->Time <= FTime)
				{
					Import = true;
					ee::TEvent *m = *FItem;
					PlCall("assert", PlCompound(ImpExp.Event2Prolog(m).c_str()));
					FItem++;
				}
				if (Import)
				{
/*!!!*/					PlCall("import_step");
				}
/*!!!*/				PlCall("real_time_generate", PlCompound(IntToStr(FTime).c_str()));
			}
			else if (FMode == mRTF)
			{
				// Detekce
				for (std::vector<TComplexDetector*>::iterator i = FDetectors.begin(); i != FDetectors.end(); i++)
				{
					(*i)->Do(FTime, Sources);
					FDetectorsImpExp.CopyEvents(**i);
					(*i)->Clear();
				}

				// Prenos vysledku do Prologu
				int DetectorsDelay = FStep * (FDetectorsDelay);
				if (FTime >= DetectorsDelay)
				{
					int DetectorsTime = FTime - DetectorsDelay;

					PlFrame f;
					bool Import = false;
					while (!FDetectorsImpExp.Events.empty() && (*FDetectorsImpExp.Events.begin())->Time <= DetectorsTime)
					{
						Import = true;
						ee::TEvent *m = *FDetectorsImpExp.Events.begin();
						AnsiString s = FDetectorsImpExp.Event2Prolog(m);
						PlCall("assert", PlCompound(s.c_str()));
						if (FTexts)
						{
							FTexts->Insert(0, s);
						}
						FDetectorsImpExp.Events.erase(FDetectorsImpExp.Events.begin());
					}
					if (Import)
					{
/*!!!*/						PlCall("import_step");
					}

/*!!!*/					PlCall("real_time_generate", PlCompound(IntToStr(DetectorsTime).c_str()));
				}
			}
			ImportTime = clock();

//			ASkipProlog = false;
			if (FTime >= Delay)
			{
				int DispTime = FTime - Delay;
				if (FMode == mHalfRT || FMode == mRT || FMode == mRTF)
				{
					if (!ASkipProlog)
					{
						PlFrame f;
						PlTermv av(2);
						av[0] = DispTime;
						char *RuleName;
						if (FMode == mRT || FMode == mRTF)
						{
							RuleName = "realtime_step";
						}
						else
						{
							RuleName = "main_step";
						}
//!!!
						PlQuery q(RuleName, av);
						if (q.next_solution())
						{
							TParameters Parameters;
							//AnsiString s;
							PlTail l(av[1]);
							PlTerm e;
							while(l.next(e))
							{
								if (e.arity() == 2)
								{
									TParameter p((char*)e[1], (char*)e[2]);
									Parameters.push_back(p);
								}
								//s = s + (char *)e + " ";
							}
							SetParameters(Parameters);
							if (FTexts)
							{
								AnsiString s = TImpExp::Event2Prolog(DispTime, TImpExp::GetDefaultEvent(TImpExp::detOutput).Name, Parameters);
								FTexts->Insert(0, s);
								//AnsiString s = Event2Prolog(m);
								//FTexts->Insert(0, IntToStr(DispTime) + " " + s);
							}
						}
//!!!*/
					}
				}
				else if (FMode == mOutput)
				{
					while (FItem != ImpExp.Events.end() && (*FItem)->Time <= DispTime)
					{
						if ((*FItem)->ID == OutputID)
						{
							TParameters &Parameters = (*FItem)->Parameters;
							SetParameters(Parameters);
							if (FTexts)
							{
								AnsiString s = ImpExp.Event2Prolog(*FItem);
								FTexts->Insert(0, s);
								//FTexts->Insert(0, Parameters2String(Parameters));
							}
						}
						FItem++;
					}
				}

				PrologTime = clock();

				TImg *Video;
				if (FHasVideo)
				{
					if (!ASkipVideo)
					{
						Video = new TImg(FWidth, FHeight);
					}
					else
					{
						Video = NULL;
					}
				}
				else
				{
					Video = NULL;
				}

				TWave *Audio;
				if (FHasAudio)
				{
					Audio = new TWave(FChannels, FSamplesPerSec);
					FAudio.push(Audio);
				}
				else
				{
					Audio = NULL;
				}

				Process(Video, Audio);

				if (FHasVideo)
				{
					if (Video && (FWidth != FOutputWidth || FHeight != FOutputHeight))
					{
						TImg *Frame = new TImg(FOutputWidth, FOutputHeight);
						Frame->CropFrom(*Video);
						FVideo.push(Frame);
						delete Video;
					}
					else
					{
						FVideo.push(Video);
					}
				}

				EditingTime = clock();
			}
			FTime += FStep;
		}
		catch (PlException &ex)
		{
			throw Exception((char*)ex);
		}

		FStatistics.Sources = 1000.0 * (SourcesTime - StartTime) / CLK_TCK;
		FStatistics.Import = 1000.0 * (ImportTime - SourcesTime) / CLK_TCK;
		FStatistics.Prolog = 1000.0 * (PrologTime - ImportTime) / CLK_TCK;
		FStatistics.Editing = 1000.0 * (EditingTime - PrologTime) / CLK_TCK;
		FStatistics.Total = 1000.0 * (EditingTime - StartTime) / CLK_TCK;

		if (FMode == mHalfRT || FMode == mRT || FMode == mRTF)
		{
			PL_handle_signals();
			PL_set_engine(NULL, NULL);
		}
	}
	catch (...)
	{
		if (FMode == mHalfRT || FMode == mRT || FMode == mRTF)
		{
			PL_handle_signals();
			PL_set_engine(NULL, NULL);
		}
	}
}

//---------------------------------------------------------------------------
TAVFile::TFrameInfo TRTEditor::GetFrameInfo()
{
	TAVFile::TFrameInfo fi;
	fi.Width = FOutputWidth;
	fi.Height = FOutputHeight;
	fi.FrameRate.Rate = 1000000 / FStep;
	fi.FrameRate.Scale = 1000;
	return fi;
}

//---------------------------------------------------------------------------
TAVFile::TAudioInfo TRTEditor::GetAudioInfo()
{
	TAVFile::TAudioInfo ai;
	ai.Channels = FChannels;
	ai.SamplesPerSec = FSamplesPerSec;
	return ai;
}

//---------------------------------------------------------------------------
TImg* TRTEditor::GetVideo()
{
	if (!FHasVideo)
	{
		return NULL;
	}

	if (FVideo.empty())
	{
		Do();
	}

	if (FVideo.empty())
	{
		return NULL;
	}
	else
	{
		TImg *Video = FVideo.front();
		FVideo.pop();
		return Video;
	}
}

//---------------------------------------------------------------------------
void TRTEditor::SkipVideo()
{
	if (!FHasVideo)
	{
		return;
	}

/*
	if (FVideo.empty())
	{
		FHasVideo = false;
		Do();
		FHasVideo = true;
	}
*/

	if (!FVideo.empty())
	{
		TImg *Video = FVideo.front();
		FVideo.pop();
		delete Video;
	}
}

//---------------------------------------------------------------------------
TWave* TRTEditor::GetAudio()
{
	if (!FHasAudio)
	{
		return NULL;
	}

	while (!Sources.Eof())
	{
		if (FAudio.empty())
		{
			Do();
		}

		if (!FAudio.empty())
		{
			TWave *Audio = FAudio.front();
			FAudio.pop();
			if (Audio->Size > 0)
			{
				return Audio;
			}
			else
			{
				delete Audio;
			}
		}
	}
	return NULL;
/*
	if (FAudio.empty())
	{
		Do();
	}

	if (FAudio.empty())
	{
		return NULL;
	}
	else
	{
		TWave *Audio = FAudio.front();
		FAudio.pop();
		return Audio;
	}
*/
}

//---------------------------------------------------------------------------
unsigned int TRTEditor::GetVideoQueueLength()
{
	return FVideo.size();
}

//---------------------------------------------------------------------------
void TRTEditor::SkipAudio()
{
	if (!FHasAudio)
	{
		return;
	}

/*
	if (FAudio.empty())
	{
		FHasAudio = false;
		Do();
		FHasAudio = true;
	}
*/

	if (!FAudio.empty())
	{
		TWave *Audio = FAudio.front();
		FAudio.pop();
		delete Audio;
	}
}

//---------------------------------------------------------------------------
// Ovladani pravidel v Prologu
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
TRTEditor::TFloatControls TRTEditor::GetControls(TControlType Type)
{
	TFloatControls Controls;
	if (!FProlog)
	{
		return Controls;
	}

	PL_set_engine(PL_ENGINE_MAIN, NULL);
	try
	{
		try
		{
			PlFrame f;

			if (Type == ctCConst)
			{
				PlTermv av(1);
				PlQuery q("camera", av);
				while (q.next_solution())
				{
					TFloatControl Control((char*)av[0]);
					Controls.push_back(Control);
				}
			}
			else
			{
				PlTermv av(1);
				PlQuery q("person", av);
				while (q.next_solution())
				{
					TFloatControl Control((char*)av[0]);
					Controls.push_back(Control);
				}
			}

			for (TFloatControls::iterator i = Controls.begin(); i != Controls.end(); i++)
			{
				PlFrame f;
				if (Type == ctCConst)
				{
					PlTermv av(3);
					av[0] = "c_const";
					av[1] = StrToInt(i->Name);
					PlQuery q("rule_configuration", av);
					if (q.next_solution())
					{
						i->Value = atof((char*)av[2]);
					}
					else
					{
						i->Value = 0;
					}
				}
				else if (Type == ctPConst)
				{
					PlTermv av(3);
					av[0] = "p_const";
					av[1] = i->Name.c_str();
					PlQuery q("rule_configuration", av);
					if (q.next_solution())
					{
						i->Value = atof((char*)av[2]);
					}
					else
					{
						i->Value = 0;
					}
				}
				else if (Type == ctPMult)
				{
					PlTermv av(3);
					av[0] = "s_person_mult";
					av[1] = i->Name.c_str();
					PlQuery q("rule_configuration", av);
					if (q.next_solution())
					{
						i->Value = atof((char*)av[2]);
					}
					else
					{
						i->Value = 0;
					}
				}
			}
		}
		catch (PlException &ex)
		{
			throw Exception((char*)ex);
		}

		if (FMode > 0)
		{
			PL_handle_signals();
			PL_set_engine(NULL, NULL);
		}
	}
	catch (...)
	{
		if (FMode > 0)
		{
			PL_handle_signals();
			PL_set_engine(NULL, NULL);
		}
		throw;
	}

	return Controls;
}

//---------------------------------------------------------------------------
void TRTEditor::SetControl(TControlType Type, TFloatControl Control)
{
	if (!FProlog)
	{
		return;
	}

	PL_set_engine(PL_ENGINE_MAIN, NULL);
	try
	{
		try
		{
			PlFrame f;
			char Buffer[1024];

			switch (Type)
			{
			case ctCConst:
				sprintf(Buffer, "retractall(rule_configuration_user(c_const, %s, _))", Control.Name.c_str());
				break;
			case ctPConst:
				sprintf(Buffer, "retractall(rule_configuration_user(p_const, %s, _))", Control.Name.c_str());
				break;
			case ctPMult:
				sprintf(Buffer, "retractall(rule_configuration_user(s_person_mult, %s, _))", Control.Name.c_str());
				break;
			}
			PlCall(Buffer);

			switch (Type)
			{
			case ctCConst:
				sprintf(Buffer, "assert(rule_configuration_user(c_const, %s, %f))", Control.Name.c_str(), Control.Value);
				break;
			case ctPConst:
				sprintf(Buffer, "assert(rule_configuration_user(p_const, %s, %f))", Control.Name.c_str(), Control.Value);
				break;
			case ctPMult:
				sprintf(Buffer, "assert(rule_configuration_user(s_person_mult, %s, %f))", Control.Name.c_str(), Control.Value);
				break;
			}
			PlCall(Buffer);
		}
		catch (PlException &ex)
		{
			throw Exception((char*)ex);
		}

		if (FMode > 0)
		{
			PL_handle_signals();
			PL_set_engine(NULL, NULL);
		}
	}
	catch (...)
	{
		if (FMode > 0)
		{
			PL_handle_signals();
			PL_set_engine(NULL, NULL);
		}
	}
}

//---------------------------------------------------------------------------
// Bordel
//---------------------------------------------------------------------------

