/*
(c) Oleg V. Dolomanov 2002-3
This source code is provided without warranty of any kind.
The author is not responsible for losses of information or any other 
damage caused by this code. You use it on your own risk. You can distribute, 
modify and incorporate this code into any non-commercial packages without 
author's permission. Acknowledgements are not necessary, but would be 
appreciated.
*/

#include <vcl.h>
#include <stdio.h>
#pragma hdrstop

#include "cif.h"

/******************************************************************************/
/******************************************************************************/
void _fastcall FormatString(AnsiString &S, int count, bool Right, char Char)
{
	int l = S.Length();
	if( l > count )
	{
//		S.SetLength(count);
		S += Char;
		return;
	}
	if( Right)
		for( int i=0; i < count-l; i++ )
			S += Char;
	else
		for( int i=0; i < count-l; i++ )
			S.Insert(Char, 1);

}
/******************************************************************************/
void _fastcall FormatString(AnsiString &T)
{
	if( !T.Length() )
		return;
	while( T[1] == ' ' )
	{
		T.Delete(1,1);
		if( !T.Length() )
			return;
	}
	for( int i=1; i < T.Length(); i++ )
	{
		if( T[i] == ' ' && T[i+1] == ' ' )
		{
			T.Delete(i, 1);
			i--;
			continue;
		}
	}
	if( T[T.Length()] == ' ' )
		T.Delete(T.Length(), 1);
}
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
TCif::TCif()
{
	Lines = new TStringList;
	FParameters = new TStringList;
}
TCif::~TCif()
{
	Clear();
	delete Lines;
	delete FParameters;
}
void _fastcall TCif::Clear()
{
	TCifData *D;
	for( int i=0; i < Lines->Count; i++ )
	{
		if( Lines->Objects[i] )
		{
			D = (TCifData*)Lines->Objects[i];
			delete D->Data;
			delete D;
		}
	}
	Lines->Clear();
	FParameters->Clear();
	FDataName = "";
	FWeightA = "";
	FWeightB = "";
}
void _fastcall TCif::Format()
{
	TCifData *D;
	AnsiString Tmp, Tmp1;
	int Length;
	for( int i=0; i < Lines->Count; i++ )
	{
		if( Lines->Objects[i] )
		{
			D = (TCifData*)Lines->Objects[i];
			for( int j=0; j < D->Data->Count; j++ )
			{
				Tmp = D->Data->Strings[j];
				FormatString(Tmp);
				Length = Tmp.Length();
				if( Length )
				{
					if( Tmp[1] == '\'' || Tmp[1] == '"' || Tmp[1] == ';' || Tmp[1] == '?' )
					{
						Tmp.Delete(1,1);
						D->String = true;
						Length--;
						if( !Length )
						{
							D->Data->Delete(j);
							j--;
							continue;
						}
					}
					if( Tmp[Length] == '\'' || Tmp[Length] == '"' || Tmp[Length] == ';' )
					{
						D->String = true;
						Tmp.Delete(Length,1);
					}
					D->Data->Strings[j] = Tmp;
				}
				else
				{
					D->Data->Delete(j);
					j--;
				}
			}
			for( int j=0; j < D->Data->Count; j++ )
			{
				Tmp = D->Data->Strings[j];
				Length = Tmp.Length();
				if( Length > 78 )
				{
					D->Data->Strings[j] = Tmp.SubString(1, 80);
					Tmp.Delete(1, 80);
					if( j < (D->Data->Count-1) )
						D->Data->Insert(j+1, Tmp);
					else
						D->Data->Add(Tmp);
				}
			}
		}
	}
}

void _fastcall TCif::LoadFromFile(AnsiString FileName)
{
	AnsiString Tmp, Val, Param, Tmp1, Tmp2;
	char *str, Char;
	bool String;
	int counter;
	TCifData *D;
	Clear();
	Lines->LoadFromFile(FileName);
	for( int i=0; i < Lines->Count; i++ )
	{
		Tmp = Lines->Strings[i];
		FormatString(Tmp);
		if( !Tmp.Length() )
			continue;
next_loop:
		if( Tmp == "loop_" )
		{
			Char = '_';
			while( Char == '_' )	// skip loop definition
			{
				i++;
				if( i >= Lines->Count )
					return;
				Tmp = Lines->Strings[i];
				FormatString(Tmp);
				if( !Tmp.Length() )
					continue;
				else
					Char = Tmp[1];

			}
			Char = 'a';
			while( Char != '_' )	// skip loop data
			{
				i++;
				if( i >= Lines->Count )
					return;
				Tmp = Lines->Strings[i];
				FormatString(Tmp);
				if( Tmp == "loop_" )
					goto next_loop;
				if( !Tmp.Length() )
					continue;
				else
					Char = Tmp[1];
			}
		}
		if( Tmp[1] == '_' )	// parameter
		{
			String = false;

			str = new char[Tmp.Length()+1];
			strcpy(str, Tmp.c_str());
			Param = strtok(str, " ");
			FParameters->Add(Param);
			Val = strtok(NULL, "@");
			FormatString(Val);
			delete [] str;
			D = new TCifData;
			D->Data = new TStringList;
            D->String = false;
			Lines->Objects[i] = (TObject*)D;
			if( (i < (Lines->Count-1)) )
			{
				Char = 'a';
				Tmp1 = Lines->Strings[i+1];
				FormatString(Tmp1);
				if( Tmp1.Length() )			Char = Tmp1[1];
				if( Char != '_' )
				{
					while( Char != '_' )
					{
						if( Tmp1.Length() > 4 )
						{
							Tmp2 = Tmp1.SubString(1,4).LowerCase();
							if( Tmp2 == "data" || Tmp2 == "loop" )
							{
								if( Val.Length() )
									D->Data->Insert(0, Val);
								goto leave_loop;
							}
							String = true;
						}
						if( Tmp1.Length() )
							String = true;
						D->Data->Add(Lines->Strings[i+1]);
						Lines->Delete(i+1);
						if( (i+1) >= Lines->Count )
						{
							goto leave_loop;
						}
						Tmp1 = Lines->Strings[i+1];
						FormatString(Tmp1);
						Char = 'a';
						if( Tmp1.Length() )
							Char = Tmp1[1];
					}
				}
				if( Val.Length() )
					D->Data->Insert(0, Val);
			}
			else	// should go only once
			{
				if( Val.Length() )
					D->Data->Add(Val);
				Lines->Strings[i] = Param;
			}
leave_loop:
			Lines->Strings[i] = Param;
			D->String = String;
		}
		else
		{
			if( !FDataName.Length() )
			{
				Tmp1 = Tmp.SubString(1,4).LowerCase();
				if( Tmp1 == "data" )
				{
					FDataName = Tmp.SubString(6,Tmp.Length()).UpperCase();
					FormatString(FDataName);
					Tmp1 += '_';
					Tmp1 += FDataName;
					Lines->Strings[i] = Tmp1;
				}
			}
		}
	}
	Format();
	/******************************************************************/
	/*search fo the weigting sceme*************************************/
	D = new TCifData;
	D->Data = new TStringList;
	if( GetParameter( "_refine_ls_weighting_details", D) )
	{
		if( D->Data->Count == 1 )
		{
			Tmp1 = D->Data->Strings[0];
			for( int k=1; k <= Tmp1.Length(); k++ )
			{
				if( Tmp1[k] == '+' )
				{
					if( !FWeightA.Length() )
					{
						while( Tmp1[k] != ')' )
						{
							k++;
							if( k >= Tmp1.Length() )
								break;
							FWeightA += Tmp1[k];
						}
						k--;
						continue;
					}
					if( !FWeightB.Length() )
					{
						while( Tmp1[k] != ']' )
						{
							k++;
							if( k >= Tmp1.Length() )
								break;
							FWeightB += Tmp1[k];
						}
						FWeightB.Delete(FWeightB.Length(), 1); // remove the [ bracket
					}
				}
			}
		}
	}
	delete D->Data;
	delete D;
	/******************************************************************/

}
void _fastcall TCif::SaveToFile(AnsiString FileName)
{
	FILE *F = fopen(FileName.c_str(), "wt+");
	if( !F )
	{
		Application->MessageBox("Cannot open file specified.", "Error", MB_OK|MB_ICONERROR);
		return;
	}
	AnsiString Tmp;
	TCifData *D;
	for( int i=0; i < Lines->Count; i++ )
	{
		Tmp = Lines->Strings[i];
		if( Lines->Objects[i] )
		{
			FormatString(Tmp, 34, true, ' ');
			D = (TCifData*)Lines->Objects[i];
			if( D->Data->Count > 1 )
			{
				fprintf(F, "%s\n", Tmp.c_str());
				fprintf(F, ";\n");
				for( int j=0; j < D->Data->Count; j++ )
				{
					fprintf(F, "%s\n", D->Data->Strings[j].c_str());
				}
				fprintf(F, ";\n");
			}
			else
			{
				if( D->Data->Count == 1 )
				{
					if( (D->Data->Strings[0].Length() + 34) > 80 )
					{
						fprintf(F, "%s\n", Tmp.c_str());
						fprintf(F, ";\n");
						fprintf(F, "%s\n", D->Data->Strings[0].c_str());
						fprintf(F, ";\n");
					}
					else
					{
						if( D->String )
						{
							Tmp += '\'';
							Tmp += D->Data->Strings[0];
							Tmp += '\'';
						}
						else
							Tmp += D->Data->Strings[0];
						fprintf(F, "%s\n", Tmp.c_str());

					}
				}
			}
		}
		else
		{
			fprintf(F, "%s\n", Tmp.c_str());
		}

	}
	fclose(F);
}
bool _fastcall TCif::GetParameter(AnsiString Param, AnsiString &Params)
{
	if( Param[1] != '_' )
		return false;
	int i = Lines->IndexOf(Param);
	if( i >= 0 )
	{
		TCifData *Data = (TCifData*)Lines->Objects[i];
		if( Data->Data->Count == 1 )
		{
			Params = Data->Data->Strings[0];
			return true;
		}
		return false;
	}
	return false;
}
bool _fastcall TCif::GetParameter(AnsiString Param, double &Val)
{
	if( Param[1] != '_' )
		return false;
	int i = Lines->IndexOf(Param);
	if( i >= 0 )
	{
		TCifData *Data = (TCifData*)Lines->Objects[i];
		if( Data->Data->Count == 1 )
		{
			Val = atof(Data->Data->Text.c_str());
			return true;
		}
		return false;
	}
	return false;
}
bool _fastcall TCif::GetParameter(AnsiString Param, TCifData *Params)
{
	if( Param[1] != '_' )
		return false;
	int i = Lines->IndexOf(Param);
	if( i >= 0 )
	{
		TCifData *Data = (TCifData*)Lines->Objects[i];
		Params->Data->Assign(Data->Data);
		Params->String = Data->String;
		return true;
	}
	return false;
}
bool _fastcall TCif::SetParameter(AnsiString Param, TCifData *Params)
{
	int i = Lines->IndexOf(Param);
	if( i >= 0 )
	{
		TCifData *Data = (TCifData*)Lines->Objects[i];
		Data->Data->Assign(Params->Data);
		Data->String = Params->String;
		return true;
	}
	return false;
}

//---------------------------------------------------------------------------

#pragma package(smart_init)

