program jef_program_utils;

uses 'jef_program_variables.pas';

//20101224-JeF
procedure LoadMovieList;
var
	RecordCount, i: integer;
	jCodeList, Codes, text, s: string;
	EditionList: boolean;
	PathDialog: TOpenDialog;
	sl:TStringList;
begin
	sl:=TStringList.Create;
	jCodeList:='';
	PathDialog:=TOpenDialog.Create(nil);
	PathDialog.Title:=GetLangStr(2800);
	s:=GetStrOption('RecentMovieListLoadPath');
	if (s>'') and MyFileExists(s) then begin
		PathDialog.FileName:=s;
		while (length(s)>1) and (copy(s,length(s),1)<>'\') do delete(s,length(s),1);
		PathDialog.InitialDir:=s;
	end
	else begin
		PathDialog.InitialDir:=copy(ScriptsPath,1,length(ScriptsPath)-8);
		PathDialog.FileName:=PathDialog.InitialDir+'\*.csv';
	end;
	PathDialog.Filter:='*.csv';
	PathDialog.FilterIndex := 1;
	if PathDialog.Execute and MyFileExists(PathDialog.FileName) then begin
		EditionList:=False;
		SetStrOption('RecentMovieListLoadPath', PathDialog.FileName);
		SetStrXFvar(9002,'ListType','Movie');
		s:=PathDialog.FileName;
		while (pos('/',s)>0) do delete(s,1,pos('/',s));
		while (pos('\',s)>0) do delete(s,1,pos('\',s));
		text:=format('%s&nbsp;<a href="custom900200000:2"><img src="%s" border="0" alt="%s"></a>',
					[s,GetRscPath('LoadMovieList.png'),PathDialog.FileName]);
		s:=GetLangStr(2802);
		if (pos('%s',s)=0) then s:=s+' %s';
		text:=ReplaceStr(s,'%s',text);
		SetStrXFvar(9002,'sqldesc',text);
		SetStrXFvar(9002,'sql','nothing');
		SetIntXFvar(9002,'CurPageNbr',1);
		text := PathDialog.FileName;
		while (pos('\',text)>0) do delete(text,1,pos('\',text));
		sl.LoadFromFile(PathDialog.FileName);
		Codes := '';
		for i:=0 to sl.Count - 1 do begin
			s := sl[i];
			if (pos(';FALSE',UpperCase(s))>0) then continue;
			delete(s,1,pos(';',s));
			if (pos(';',s)>0) then s := copy(s,1,pos(';',s)-1);
			if (UpperCase(copy(s,1,3))='ED:') then begin
				EditionList:=True;
				delete(s,1,3);
			end;
			Codes := Codes + s + ',';
		end;
		if (Codes>'') then delete(Codes,length(Codes),1);
		sl.CommaText:=Codes;
		for i:=50 to sl.Count - 1 do if (i mod 50 = 0) then sl[i]:='|'+sl[i];
		jCodeList:=sl.CommaText;
	end;
	PathDialog.Free;
	if (jCodeList>'') then begin
		with sl do begin
			Clear;
			Add('select distinct m.title, m.code ');
			Add('from movies m');
			if EditionList
				then Add('left outer join editions e on e.movie=m.code');
			Add('where m.in_collection=1 and(');
		end;
		Codes:=jCodeList;
		while (Codes>'') do begin
			i:=pos('|',Codes);
			if (i>0) then begin
				s:=copy(Codes,1,i-1);
				delete(Codes,1,i);
			end
			else begin
				s:=Codes;
				Codes:='';
			end;
			if EditionList
				then sl.Add(format('e.code in (%s) or ', [s]))
			else sl.Add(format('m.code in (%s) or ', [s]));
		end;
		s:=sl[sl.Count-1];
		delete(s,length(s)-3,4);
		s:=s+')';
		sl[sl.Count-1]:=s;
		sl.Add('order by m.title');
		SetStrXFvar(9002,'sql',sl.Text);
	end;
	sl.Free;
end;

//20101224-JeF
procedure LoadPersonList;
var
	RecordCount, i: integer;
	jCodeList, Codes, text, s: string;
	PathDialog: TOpenDialog;
	sl:TStringList;
begin
	sl:=TStringList.Create;
	jCodeList:='';
	PathDialog:=TOpenDialog.Create(nil);
	PathDialog.Title:=GetLangStr(2803);
	s:=GetStrOption('RecentPersonListLoadPath');
	if (s>'') and MyFileExists(s) then begin
		PathDialog.FileName:=s;
		while (length(s)>1) and (copy(s,length(s),1)<>'\') do delete(s,length(s),1);
		PathDialog.InitialDir:=s;
	end
	else begin
		PathDialog.InitialDir:=copy(ScriptsPath,1,length(ScriptsPath)-8);
		PathDialog.FileName:=PathDialog.InitialDir+'\*.csv';
	end;
	PathDialog.Filter:='*.csv';
	PathDialog.FilterIndex := 1;
	if PathDialog.Execute and MyFileExists(PathDialog.FileName) then begin
		SetStrOption('RecentPersonListLoadPath', PathDialog.FileName);
		SetStrXFvar(9003,'ListType','Person');
		s:=PathDialog.FileName;
		while (pos('/',s)>0) do delete(s,1,pos('/',s));
		while (pos('\',s)>0) do delete(s,1,pos('\',s));
		text:=format('%s&nbsp;<a href="custom900300000:2"><img src="%s" border="0" alt="%s"></a>',
					[s,GetRscPath('LoadPersonList.png'),PathDialog.FileName]);
		s:=GetLangStr(2805);
		if (pos('%s',s)=0) then s:=s+' %s';
		text:=ReplaceStr(s,'%s',text);
		SetStrXFvar(9003,'sqldesc',text);
		SetStrXFvar(9003,'sql','nothing');
		SetIntXFvar(9003,'CurPageNbr',1);
		text := PathDialog.FileName;
		while (pos('\',text)>0) do delete(text,1,pos('\',text));
		sl.LoadFromFile(PathDialog.FileName);
		Codes := '';
		for i:=0 to sl.Count - 1 do begin
			s := sl[i];
			if (pos(';FALSE',UpperCase(s))>0) then continue;
			delete(s,1,pos(';',s));
			if (pos(';',s)>0) then s := copy(s,1,pos(';',s)-1);
			Codes := Codes + s + ',';
		end;
		if (Codes>'') then delete(Codes,length(Codes),1);
		sl.CommaText:=Codes;
		for i:=50 to sl.Count - 1 do if (i mod 50 = 0) then sl[i]:='|'+sl[i];
		jCodeList:=sl.CommaText;
	end;
	PathDialog.Free;
	if (jCodeList>'') then begin
		with sl do begin
			Clear;
			Add('select distinct p.name, p.code ');
			Add('from persons p');
			Add('where (');
		end;
		Codes:=jCodeList;
		while (Codes>'') do begin
			i:=pos('|',Codes);
			if (i>0) then begin
				s:=copy(Codes,1,i-1);
				delete(Codes,1,i);
			end
			else begin
				s:=Codes;
				Codes:='';
			end;
			sl.Add(format('p.code in (%s) or ', [s]));
		end;
		s:=sl[sl.Count-1];
		delete(s,length(s)-3,4);
		s:=s+')';
		sl[sl.Count-1]:=s;
		sl.Add('order by p.name');
		SetStrXFvar(9003,'sql',sl.Text);
	end;
	sl.Free;
end;

function BuildEpisodesList(MovieCode, Step: integer): string;
var
	RecordCount, i, j: integer;
	jMovieTitle, jVideoFileFolder, jPageTitle, jPageContent, jFileExt, s, s2: string;
	jTag: array[1..8] of string;
	sl: TStringList;
begin
	jHomePageCode:='0';
	jFileExt:=Uppercase(ClearExtraSDQuotes(GetStrOption('IgnoreFileExt')));
	sl:=TStringList.Create;
	s:='select title, filename from movies where code='+IntToStr(Moviecode)+';';
	RecordCount:=ExecuteSQL(s);
	jMovieTitle:=GetStringField('title');
	s2:=ClearExtraSDQuotes(GetStringField('filename'));
	s:='select filename from editions where movie='+IntToStr(MovieCode)+' and filename>'' ;';
	RecordCount:=ExecuteSQL(s);
	if (RecordCount>0) then s2:=ClearExtraSDQuotes(GetStringField('filename'));
	while (length(s2)>0) and (s2[length(s2)]<>'/') and (s2[length(s2)]<>'\') do delete(s2,length(s2),1);
	jVideoFileFolder:=s2;
	case Step of
		1:	begin
				jEpRootDir:=jVideoFileFolder;
			end;
		2:	begin
				//jEpRootDir:=InputBox('Episodes Root Folder','Folder',jEpRootDir);
				jEpRootDir:=PromptForPath('Episodes Root Folder',jEpRootDir,'','',0,0);
			end;
		3:	begin
				sl.Text:='dir "'+jEpRootDir+'" /S /A-D /B /O:GEN > "'+jEpRootDir+'FileList.txt"';
				sl.Text:=AnsiToAscii(sl.Text);
				sl.SaveToFile(jEpRootDir+'FileList.bat');
			end;
		5:	begin
				sl.LoadFromFile(jEpRootDir+'FileList.txt');
				i:=1;
				while (i<=sl.count) do begin
					if (length(sl[i-1]) < 6)
						then s:=UpperCase(sl[i-1])
					else s:=UpperCase(copy(sl[i-1],length(sl[i-1])-5,6));
					if (pos('.',s)>0) then while (s[1]<>'.') and (s>'') do delete(s,1,1);
					if (InList(s,jFileExt))  	// '.TXT,.NFO,.ASX,.BAT,.DB' 
					or (pos('.',s)=0) then begin
						sl.Delete(i-1);
						continue;
					end;
					sl[i-1]:=AsciiToAnsi(sl[i-1]);
					i:=i+1;
				end;
				sl.Sort;
				sl.SaveToFile(jEpRootDir+'FileList.txt');
				sl.SaveToFile(jVideoFileFolder+'EpFilesList.txt');
			end;
		6:	begin
				sl.LoadFromFile(jVideoFileFolder+'EpFilesList.txt');
				s:=format('select * from episodes where movie=%d order by season, episode', [MovieCode]);
				RecordCount:=ExecuteSQL(s);
				i:=1;
				while (i<=sl.Count) and (i<=RecordCount) do begin
					j:=pos('=',sl[i-1]);
					if (j>0) then delete(sl[i-1],1,j);
					s:=IntToStr(GetIntegerField('season'));
					while (length(s)<3) do s:='0'+s;
					s2:=IntToStr(GetIntegerField('episode'));
					while (length(s2)<4) do s2:='0'+s2;
					sl[i-1]:='S'+s+'E'+s2+'='+sl[i-1];
					i:=i+1;
					GetNextRecord;
				end;
				sl.SaveToFile(jVideoFileFolder+'EpFilesList.txt');
			end;
		8:	begin
				sl.LoadFromFile(jVideoFileFolder+'EpFilesList.txt');
				i:=1;
				while (i<=sl.Count) do begin
					s:=copy(sl[i-1],1,15);
					j:=1;
					while (j>0) and (j<=10) do begin
						if (j>length(s))
						or (j=1)  and (s[j]<>'S')
						or (j>=2) and (j<=4) and (s[j]<'0')
						or (j>=2) and (j<=4) and (s[j]>'9')
						or (j=5)  and (s[j]<>'E')
						or (j>=6) and (j<=9) and (s[j]<'0')
						or (j>=6) and (j<=9) and (s[j]>'9')
						or (j=10) and (s[j]<>'=')
							then j:=0 
						else j:=j+1;
					end;
					if (j>0) then begin
						s2:='select editions where movie='+IntToStr(Moviecode)+' and season='
							+copy(s,2,3)+' and episode='+copy(s,6,4)+';';
						RecordCount:=ExecuteSQL(s2);
						if (RecordCount<=0) then begin
							s2:='insert into editions '
								+'(movie, sort_order, edition, season, episode, filename) '
								+'values('
								+IntToStr(Moviecode)+', '
								+copy(s,2,3)+copy(s,6,4)+', '
								+'1, '
								+copy(s,2,3)+', '
								+copy(s,6,4)+', '
								+'"'+sl.Values[sl.Names[i-1]]+'"'
								+');';
							RecordCount:=ExecuteSQL(s2);
						end
						else begin
							s2:='update editions set filename="'+sl.Values[sl.Names[i-1]]
								+'" where movie='+IntToStr(Moviecode)+' and season='
								+copy(s,2,3)+' and episode='+copy(s,6,4)+';';
							RecordCount:=ExecuteSQL(s2);
						end;
					end;
					i:=i+1;
				end;
			end;
	else 
	end;
	for i:=1 to 8 do begin
		s:=IntToStr(i);
		while (length(s)<5) do s:='0'+s;
		jTag[i]:='<a href="custom0220'+s+':'+IntToStr(MovieCode)+'"><img src="'+GetRscPath('Next.png')+'" border=0 align="absmiddle"></a>';
	end;	
	jTag[4]:='<a href="link:file://'+jEpRootDir+'FileList.bat"><img src="'+GetRscPath('Next.png')+'" border=0 align="absmiddle" alt="'+jEpRootDir+'FileList.bat"></a>';
	jTag[7]:='<a href="link:file://'+jEpRootDir+'EpFilesList.txt"><img src="'+GetRscPath('Next.png')+'" border=0 align="absmiddle" alt="'+jEpRootDir+'EpFilesList.txt"></a>';
	jTag[Step]:=ReplaceStr(jTag[Step],'Next.','Forward.');
	jPageTitle:=GetLangStr(1133);
	if MyFileExists(jOriginalThemePath+'EFLGen.html') then begin
		sl.LoadFromFile(jOriginalThemePath+'EFLGen.html');
		jPageContent:=sl.Text;
	end
	else if MyFileExists(jOriginalThemePath+'EFLGen-dft.html') then begin
		sl.LoadFromFile(jOriginalThemePath+'EFLGen-dft.html');
		sl.SaveToFile(jOriginalThemePath+'EFLGen.html');
		jPageContent:=sl.Text;
	end
	else jPageContent:='';
	jPageContent:=ReplaceStr(jPageContent,'<!--#MovieTitle -->',jMovieTitle);
	jPageContent:=ReplaceStr(jPageContent,'<!--#Tag1 -->',jTag[1]);
	jPageContent:=ReplaceStr(jPageContent,'<!--#RootDir -->',jEpRootDir);
	jPageContent:=ReplaceStr(jPageContent,'<!--#Tag2 -->',jTag[2]);
	jPageContent:=ReplaceStr(jPageContent,'<!--#Tag3 -->',jTag[3]);
	jPageContent:=ReplaceStr(jPageContent,'<!--#Tag4 -->',jTag[4]);
	jPageContent:=ReplaceStr(jPageContent,'<!--#Tag5 -->',jTag[5]);
	jPageContent:=ReplaceStr(jPageContent,'<!--#Tag6 -->',jTag[6]);
	jPageContent:=ReplaceStr(jPageContent,'<!--#Tag7 -->',jTag[7]);
	jPageContent:=ReplaceStr(jPageContent,'<!--#Tag8 -->',jTag[8]);
	sl.free;
	jLastPage:=BuildExtraPage(JPageTitle, jPageContent);
	result:=jLastPage;
end;

function FileRenamer: string;
var
	s: string;
	i,j,jAction: integer;
	f: TForm;
	bren,bclo,bcnt,blst: TButton;
	labTitle: TLabel;
	edSourcePath: TEdit;
	labSourcePath: TLabel;
	edTargetPath: TEdit;
	labTargetPath: TLabel;
	rbBegining: TRadioButton;
	rbEnding: TRadioButton;
	sl: TStringList;

procedure ButtonClick(Sender: TButton);
var
	zs: string;
	zn: integer;
	zerr: boolean;
begin
	zerr:=false;
	if (Sender.Name<>'btnClose') then begin
		if (edSourcePath.Text='') then begin
			showmessage(GetLangStr(1175));
			zerr:=true;
		end;
		if not zerr and (pos('%',edSourcePath.Text)>0) then begin
			showmessage(format(GetLangStr(1176),['''%''']));
			zerr:=true;
		end;
		if not zerr then begin
			if rbBegining.Checked then begin
				zs:=edSourcePath.Text+'%%';
				while edTargetPath.Text[1]=' ' do delete(edTargetPath.Text,1,1);
			end
			else begin
				zs:='%%'+edSourcePath.Text;
				while edTargetPath.Text[length(edTargetPath.Text)]=' ' 
					do delete(edTargetPath.Text,length(edTargetPath.Text),1);
			end;
			zs:='select count(*) from editions where filename like ''' + zs +'''';
			zn:=ExecuteSQL(zs);
			zn:=GetIntegerField('count(*)');
			if (zn=0) then begin
				showmessage(format(GetLangStr(1177),[zn]));
				zerr:=true;
			end;
		end;
		if not zerr then begin
			if (rbBegining.Checked<>GetBoolOption('FileRenBegining'))
			or (edSourcePath.Text>'') and (edSourcePath.Text<>GetStrOption('FileRenSrcPattern'))
			or (edTargetPath.Text>'') and (edTargetPath.Text<>GetStrOption('FileRenTgtPattern')) then begin
				SetStrOption('FileRenBegining',BoolToStr(rbBegining.Checked));
				if (edSourcePath.Text>'') and (edSourcePath.Text<>GetStrOption('FileRenSrcPattern')) 
					then SetStrOption('FileRenSrcPattern',edSourcePath.Text);
				if (edTargetPath.Text>'') and (edTargetPath.Text<>GetStrOption('FileRenTgtPattern'))
					then SetStrOption('FileRenTgtPattern',edTargetPath.Text);
			end;
			if (Sender.Name='btnRename') then begin
				jAction:=1;
				f.ModalResult := mrOk;
			end
			else if (Sender.Name='btnCount') then begin
				jAction:=2;
				showmessage(format(GetLangStr(1177),[zn]));
			end
			else if (Sender.Name='btnList') then begin
				jAction:=3;
				f.ModalResult := mrOk;
			end;
		end;
	end
	else begin
		jAction:=9;
		f.ModalResult := mrCancel;
	end;
end;

begin
	sl:=TStringList.Create();
	f := TForm.Create(nil);
	f.Caption := GetLangStr(1174);
	f.BorderStyle := bsDialog;
	f.Position := poScreenCenter;
	f.Width:=400;
	f.Height:=285;
	f.AutoSize:=false;

	labTitle := TLabel.Create(f);
	labTitle.Name := 'labTitle';
	labTitle.Parent := f;
	labTitle.SetBounds(10, 15, 110, 25);
	labTitle.Caption := GetLangStr(1178);

	rbBegining := tRadioButton.Create(f);
	rbBegining.Name := 'rbBegining';
	rbBegining.Parent := f;
	rbBegining.SetBounds(150, 40, 110, 25);
	rbBegining.Caption := GetLangStr(1179);
	rbBegining.Checked := GetBoolOption('FileRenBegining');

	rbEnding := tRadioButton.Create(f);
	rbEnding.Name := 'rbEnding';
	rbEnding.Parent := f;
	rbEnding.SetBounds(150, 65, 300, 25);
	rbEnding.Caption := GetLangStr(1180);
	rbEnding.Checked := not GetBoolOption('FileRenBegining');

	labSourcePath := TLabel.Create(f);
	labSourcePath.Name := 'labSourcePath';
	labSourcePath.Parent := f;
	labSourcePath.SetBounds(10, 95, 375, 25);
	labSourcePath.Caption := GetLangStr(1181);

	edSourcePath := TEdit.Create(f);
	edSourcePath.Name := 'edSourcePath';
	edSourcePath.Parent := f;
	edSourcePath.SetBounds(10, 115, 375, 25);
	edSourcePath.Text := GetStrOption('FileRenSrcPattern');
	if (edSourcePath.Text='%') then edSourcePath.Text:='';
	
	
	labTargetPath := TLabel.Create(f);
	labTargetPath.Name := 'labTargetPath';
	labTargetPath.Parent := f;
	labTargetPath.SetBounds(10, 150, 375, 25);
	labTargetPath.Caption := GetLangStr(1182);

	edTargetPath := TEdit.Create(f);
	edTargetPath.Name := 'edTargetPath';
	edTargetPath.Parent := f;
	edTargetPath.SetBounds(10, 170, 375, 25);
	edTargetPath.Text := GetStrOption('FileRenTgtPattern');
	if (edTargetPath.Text='%') then edTargetPath.Text:='';
	
	bren := TButton.Create(f);
	bren.Name := 'btnRename';
	bren.Parent := f;
	bren.SetBounds(10, 210, 90, 28);
	bren.Caption := GetLangStr(1183);
	bren.OnClick := @ButtonClick;

	bcnt := TButton.Create(f);
	bcnt.Name := 'btnCount';
	bcnt.Parent := f;
	bcnt.SetBounds(105, 210, 90, 28);
	bcnt.Caption := GetLangStr(1184);
	bcnt.OnClick := @ButtonClick;

	blst := TButton.Create(f);
	blst.Name := 'btnList';
	blst.Parent := f;
	blst.SetBounds(200, 210, 90, 28);
	blst.Caption := GetLangStr(1185);
	blst.OnClick := @ButtonClick;

	bclo := TButton.Create(f);
	bclo.Name := 'btnClose';
	bclo.Parent := f;
	bclo.SetBounds(295, 210, 90, 28);
	bclo.Caption := GetLangStr(1186);
	bclo.OnClick := @ButtonClick;

	f.ShowModal;
	
	if rbBegining.Checked
		then s:=edSourcePath.Text+'%%'
	else s:='%%'+edSourcePath.Text;
	if jAction=1 then begin
		if rbBegining.Checked
			then s:=format('update editions set filename=''%s'' || ',[edTargetPath.Text])
					+format('substr(filename,%d,length(filename)) ',[length(edSourcePath.Text)+1])
					+format('where filename like ''%s%%''',[edSourcePath.Text])
		else s:='update editions set filename='
				+format('substr(filename,1,length(filename) - %d) ',[length(edSourcePath.Text)])
				+format('|| ''%s''',[edTargetPath.Text])
				+format('where filename like ''%%%s''',[edSourcePath.Text]);
		i:=ExecuteSQL(s);
		showmessage(GetLangStr(1187));
	end
	else if jAction=3 then begin
		jHomePageCode:='';
		if rbBegining.Checked
			then s:='select filename from editions '
					+format('where filename like ''%s%%''',[edSourcePath.Text])
		else s:='select filename from editions '
				+format('where filename like ''%%%s''',[edSourcePath.Text]);
		j:=ExecuteSQL(s);
		sl.Clear;
		for i:=1 to j do begin
			s:=GetStringField('filename');
			if rbBegining.Checked 
				then s:=s+'<br>'+edTargetPath.Text+copy(s,length(edSourcePath.Text)+1,length(s))
			else s:=s+'<br>'+copy(s,1,length(s)-length(edSourcePath.Text))+edTargetPath.Text;
			sl.Add('<li>'+s+'<br>&nbsp;');
			GetNextRecord;
		end;
		sl.Text:='<br><ol>'+sl.Text;
		jLastPage:=BuildExtraPage(GetLangStr(98),sl.Text);
	end;

	f.Free;
	sl.Free;
	result:='';
end;

procedure ManualsRenamer(Mode: integer);
var
	jEdManualRef, jEdRef, jTargetType, jManualRef, jOldName, jNewName, jOldCode, jNewCode, jCounts, sql, s, s2: string;
	jOldMaxLen, jNewMaxLen, RecordCount, i, j, k: integer;
	jDeleteOld: boolean;
	jManuals, jFields, sl, sl2: TStringList;
begin
	sl:=TStringList.Create;
	sl2:=TStringList.Create;
	jManuals:=TStringList.Create;
	jFields:=TStringList.Create;
	jEdRef:='1,2,4,5,19,20,21';
	jEdManualRef:='6,7,10';
	jCounts:='';
	jOldMaxLen:=0;
	jNewMaxLen:=0;
	s:=ScriptsPath+'JeF_attributes_renamer.csv';
	if NOT MyFileExists(s) then begin
		showmessage(format(GetLangStr(1194),[s])+#13#10+GetLangStr(1195));
	end
	else begin
		s:=GetLangStr(201)+','+GetLangStr(168)+','+GetLangStr(206)+','+GetLangStr(202)+','
			+GetLangStr(203)+','+GetLangStr(204)+','+GetLangStr(205)+','+GetLangStr(255)+','
			+GetLangStr(256)+','+GetLangStr(257)+','+GetLangStr(383)+','+GetLangStr(493)+','
			+GetLangStr(540)+','+GetLangStr(541)+','+GetLangStr(542)+','+GetLangStr(543)+','
			+GetLangStr(544)+','+GetLangStr(545)+','+GetLangStr(573)+','+GetLangStr(1018)+','
			+GetLangStr(1254);
		jManuals.CommaText:='"'+ReplaceStr(s,',','","')+'"';
		jFields.CommaText:='1=video_standard,2=media_format,3=media_type,4=screen_ratio,5=resolution,'
							+'13=custom1,14=custom2,15=custom3,16=custom4,'
							+'19=video_codec,20=disc_label,21=edition';
		//load renaming chart
		sl.LoadFromFile(ScriptsPath+'JeF_attributes_renamer.csv');
		for i:=1 to sl.Count do begin
			if (copy(ClearExtraBlankCharacters(sl[i-1]),1,1)=';') then continue;
			s:=sl[i-1];
			j:=pos('"',s);
			while (j>0) do begin
				k:=MyPos('";',s,j+2);
				if (k=0) then k:=MyPos('"',s,j+2);
				if (k>0) 
					then s:=copy(s,1,j)+ReplaceStr(copy(s,j+1,k-j-1),';','¤')+copy(s,k,length(s));
				j:=MyPos(';"',s,j+1);
			end;
			sl[i-1]:=s;
		end;
		for i:=1 to sl.Count do begin
			if (copy(ClearExtraBlankCharacters(sl[i-1]),1,1)=';') then continue;
			s:='"'+ReplaceStr(sl[i-1],';','","')+'"';
			s:=ReplaceStr(s,'""','"');
			if (copy(s,length(s)-1,2)=',"') then s:=s+'"';
			sl2.CommaText:=ReplaceStr(s,'¤',';');
			jOldName:=sl2[1];
			jNewName:=sl2[2];
			if (length(jOldName)>jOldMaxLen) then jOldMaxLen:=length(jOldName);
			if (length(jNewName)>jNewMaxLen) then jNewMaxLen:=length(jNewName);
		end;
		//check names and count items to be processed
		for i:=1 to sl.Count do begin
			if (copy(ClearExtraBlankCharacters(sl[i-1]),1,1)=';') then continue;
			s:='"'+ReplaceStr(sl[i-1],';','","')+'"';
			s:=ReplaceStr(s,'""','"');
			if (copy(s,length(s)-1,2)=',"') then s:=s+'"';
			sl2.CommaText:=ReplaceStr(s,'¤',';');
			jManualRef:=IntToStr(StrToIntDef(sl2[0],0));
			if (jManualRef='0') then continue;
			if InList(jManualRef, jEdRef) or InList(jManualRef, jEdManualRef)
				then jTargetType:='edition'
			else jTargetType:='movie';
			jOldName:=sl2[1];
			jNewName:=sl2[2];
			jDeleteOld:=(UpperCase(sl2[3])='ZAP');
			jCounts:=jCounts+'<tr><td><nobr>&nbsp;';
			if (StrToIntDef(jManualRef,0)>0) and (StrToIntDef(jManualRef,0)<=jManuals.Count)
				then jCounts:=jCounts+jManuals[StrToIntDef(jManualRef,0)-1];
			jCounts:=jCounts+'&nbsp;</nobr></td><td><table width="100%"><tr><td width="'
							+IntToStr(jOldMaxLen*10)+'px"><nobr>&nbsp;'
							+ReplaceStr(jOldName,'&','&amp;')+'</nobr></td><td width="22px">';
			if jDeleteOld then jCounts:=jCounts+format('<img src="%s" align="absmiddle" width="18px" border="0">',[GetRscPath('Delete.png')]);
			jCounts:=jCounts+'</td><td width="22px">'+format('<img src="%s" align="absmiddle" width="18px" border="0">',[GetRscPath('Next.png')])
							+'</td><td width="'+IntToStr(jNewMaxLen*10)+'px"><nobr>'
							+ReplaceStr(jNewName,'&','&amp;')+s2+'</nobr></td></tr></table></td><td>&nbsp;';
			//Check old name
			sql:='select * from manuals where reference='+jManualRef
				+' and name='''+ReplaceStr(jOldName,'''','''''')+'''';
			RecordCount:=ExecuteSql(sql);
			if (RecordCount>0) 
				then jOldCode:=IntToStr(GetIntegerField('code'))
			else begin
				s:='"'+ReplaceStr(jOldName,'&','&amp;')+'"';
				jCounts:=jCounts+format(GetLangStr(1196),[s])+'</td></tr>';
				continue;
			end;
			//Check new name
			sql:='select * from manuals where reference='+jManualRef
				+' and name='''+ReplaceStr(jNewName,'''','''''')+'''';
			RecordCount:=ExecuteSql(sql);
			if (RecordCount>0) 
				then jNewCode:=IntToStr(GetIntegerField('code'))
			else begin
				s:='"'+ReplaceStr(jNewName,'&','&amp;')+'"';
				jCounts:=jCounts+format(GetLangStr(1196),[s])+'</td></tr>';
				continue;
			end;
			//count items to be processed
			if InList(jManualRef, jEdRef) or InList(jManualRef,'3,13,14,15,16') then begin
				sql:='select code from '+jTargetType+'s where '+jFields.Values[jManualRef]+'='+jOldCode;
			end
			else begin
				sql:='select code from '+jTargetType+'s_manuals where reference='+jManualRef
					+' and ref_code='+jOldCode;
			end;
			RecordCount:=ExecuteSql(sql);
			jCounts:=jCounts+IntTostr(RecordCount)+'&nbsp;</td></tr>';
			//process database updates
			if (Mode=1) then begin
				if InList(jManualRef, jEdRef) or InList(jManualRef,'3,13,14,15,16') then begin
					//Make all items pointing to Old value now point to New value (if not already pointing)
					sql:='update '+jTargetType+'s set '+jFields.Values[jManualRef]+'='+jNewCode
						+' where '+jFields.Values[jManualRef]+'='+jOldCode;
					RecordCount:=ExecuteSql(sql);
				end
				else begin
					//Make all items pointing to Old value now point to New value (if not already pointing)
					sql:='update '+jTargetType+'s_manuals set ref_code='+jNewCode
						+' where reference='+jManualRef+' and ref_code='+jOldCode
						+' and NOT '+jTargetType+' in (select '+jTargetType 
						+' from '+jTargetType+'s_manuals mm'
						+' where mm.reference='+jManualRef+' and mm.ref_code='+jNewCode+');';
					RecordCount:=ExecuteSql(sql);
					//Now delete all remaining links to old value (items that where already pointing to new value)
					sql:='delete from '+jTargetType+'s_manuals where reference='+jManualRef
						+' and ref_code='+jOldCode;
					RecordCount:=ExecuteSql(sql);
				end;
				//Now delete Old Manual definition if requested
				if jDeleteOld then begin
					sql:='delete from manuals where code='+jOldCode;
					RecordCount:=ExecuteSql(sql);
				end;
			end;
		end;
		jCounts:='<table align="center" border="1">'+jCounts+'</table>';
		if (Mode=1) 
			then jCounts:=jCounts+'<br><br><center><table border="1"><tr><td>&nbsp;'
								+GetLangStr(1187)+'&nbsp;</td></tr></table></center><br><br>&nbsp;';
		SetStrXFvar(213,'PgTitle',GetLangStr(1198));
		SetStrXFvar(213,'PgContent',jCounts);
		ExtraFeature(213,'00210000000000');
	end;
	jFields.Free;
	jManuals.Free;
	sl2.Free;
	sl.Free;
end;

function BuildFileList(RootDir, SaveDir: string; step: integer): integer;
var
	jFileExt, s, s2: string;
	i: integer;
	sl: TStringList;
begin
	if (copy(RootDir,length(RootDir),1)<>'\') then RootDir:=RootDir+'\';
	if (SaveDir='') then SaveDir:=RootDir;
	sl:=TStringList.Create;
	if (step=1) then begin
		sl.Text:='REM Write Test';
		sl.SaveToFile(SaveDir+'FileList.bat');
		if NOT MyFileExists(SaveDir+'FileList.bat') 
			then SaveDir:=ScriptsPath;
		sl.Text:='dir "'+RootDir+'" /S /A-D /B /O:GEN > "'+SaveDir+'FileList.txt"';
		sl.Text:=AnsiToAscii(sl.Text);
		sl.SaveToFile(SaveDir+'FileList.txt');
		result:=0;
	end
	else if (step=2) then begin
		jFileExt:=Uppercase(ClearExtraSDQuotes(GetStrOption('IgnoreFileExt')));
		if NOT MyFileExists(SaveDir+'FileList.txt')
			then SaveDir:=ScriptsPath;
		if MyFileExists(SaveDir+'FileList.txt') then begin
			sl.LoadFromFile(SaveDir+'FileList.txt');
			i:=1;
			while (i<=sl.count) do begin
				if (length(sl[i-1]) < 6)
					then s:=UpperCase(sl[i-1])
				else s:=UpperCase(copy(sl[i-1],length(sl[i-1])-5,6));
				if (pos('.',s)>0) then while (s[1]<>'.') and (s>'') do delete(s,1,1);
				if (InList(s,jFileExt))  	// '.TXT,.NFO,.ASX,.BAT,.DB' 
				or (pos('.',s)=0) then begin
					sl.Delete(i-1);
					continue;
				end;
				sl[i-1]:=AsciiToAnsi(sl[i-1]);
				i:=i+1;
			end;
			sl.Sort;
			sl.SaveToFile(SaveDir+'FileList.txt');
		end;
	end;
	sl.Free;
end;
  
function PromptForPath(Title, StartDir, Filename, Filter: string; FilterIdx, Mode: integer): string;
var
	PathDialog: TSaveDialog;
begin
	PathDialog:=TSaveDialog.Create(nil);
	if (Title>'') then PathDialog.Title:=Title;
	if (StartDir>'') then PathDialog.InitialDir:=StartDir;
	if (Filter>'') then PathDialog.Filter:=Filter;
	if (FilterIdx>0) then PathDialog.FilterIndex := FilterIdx;
	if (Mode=0) then PathDialog.FileName:='[...]'
	else if (Mode=1) then begin
		if (Filename>'') then PathDialog.FileName:=Filename
		else PathDialog.FileName:='*.*';
	end;
	if PathDialog.Execute then begin
		result:=PathDialog.FileName;
		if (mode=0) then begin
			while (length(result)>0) and (result[length(result)]<>'/') and (result[length(result)]<>'\') 
				do delete(result,length(result),1);
		end;
	end
	else result:='';
	PathDialog.Free;
end;

function AsciiToAnsi(AsciiStr: string): string;
var
	i, j: integer;
	s, s2: string;
	slAscii2Ansi: TStringList;
begin
    slAscii2Ansi:=TStringList.Create;
	slAscii2Ansi.CommaText:='132=228,148=246,129=252,225=223,142=196,153=214,154=220,128=199,'
		+'130=233,131=226,133=224,134=229,135=231,136=234,137=235,138=232,139=239,140=238,'
		+'143=197,144=201,147=244,150=251,151=249,20=182,145=230,146=198,155=162,156=163,'
		+'166=170,167=186,171=189,172=188,237=216,241=177,246=247,253=178,21=167,157=165,182=194';
	s:=AsciiStr;
	for i:=1 to length(s) do begin
		s2:=IntToStr(ord(s[i]));
		j:=slAscii2Ansi.IndexOfName(s2);
		if (j<>-1) then s[i]:=chr(StrToInt(slAscii2Ansi.Values[s2]));
	end;
	slAscii2Ansi.free;
	result:=s;
end;

function AnsiToAscii(AnsiStr: string): string;
var
	i, j: integer;
	s, s2: string;
	slAnsi2Ascii: TStringList;
begin
    slAnsi2Ascii:=TStringList.Create;
	slAnsi2Ascii.CommaText:='228=132,246=148,252=129,223=225,196=142,214=153,220=154,199=128,'
		+'233=130,226=131,224=133,229=134,231=135,234=136,235=137,232=138,239=139,238=140,'
		+'197=143,201=144,244=147,251=150,249=151,182=20,230=145,198=146,162=155,163=156,'
		+'170=166,186=167,189=171,188=172,216=237,177=241,247=246,178=253,167=21,165=157';
	s:=AnsiStr;
	for i:=1 to length(s) do begin
		s2:=IntToStr(ord(s[i]));
		j:=slAnsi2Ascii.IndexOfName(s2);
		if (j<>-1) then s[i]:=chr(StrToInt(slAnsi2Ascii.Values[s2]));
	end;
	slAnsi2Ascii.free;
	result:=s;
end;

procedure CopyTextFile(SrcPath, TgtPath: string);
var
	sl: TStringList;
begin
	sl:=TStringList.Create;
	sl.LoadFromFile(SrcPath);
	sl.SaveToFile(TgtPath);
	sl.Free;
end;

// Load Sql Strings
procedure LoadSqlStrings;
var
	sl: TStringList;
	i, j: integer;
	id, s: string;
begin
	sl:=TStringList.create;
	// Core Sql Strings
	with jSqlStrings do begin
        Clear;
		Add('C0051=select code, title, year, rating, filename from movies where date_add is not null and in_collection=1 order by date_add desc, code');
		Add('C0051D='+GetLangStr(98));
		Add('C0052=select code, title, year, rating, filename from movies where date_update is not null and in_collection=1 order by date_update desc, code');
		Add('C0052D='+GetLangStr(99));
		Add('C0053=select code, name, rating from persons where date_add is not null and in_collection=1 order by date_add desc, code');
		Add('C0053D='+GetLangStr(100));
		Add('C0054=select code, name, rating from persons where date_update is not null and in_collection=1 order by date_update desc, code');
		Add('C0054D='+GetLangStr(101));
		Add('C0055=select code, title, year, rating, filename from movies where date_add is not null and in_collection>=0 and wanted=1 order by date_add desc, code');
		Add('C0055D='+GetLangStr(1117));
		Add('C0056=select m.code, m.title, m.year, m.rating, e.code from movies m left outer join editions e on e.movie=m.code where e.disc_nom=''$1'' order by m.date_add desc, m.code');
		Add('C0056D='+GetLangStr(1117));
		Add('Z0057=select imdb_code from movies where imdb_code > '''' and in_collection=1 order by imdb_code');
		Add('Z0057D='+GetLangStr(1107));
		
		Add('M0081=select code, title, year, rating from movies where in_collection=1 and code not in (select distinct movie from editions where filename>"") order by date_add desc, code');
		Add('M0081D='+GetLangStr(1116));
		Add('M0082=select code, title, year, rating from movies where in_collection=1 and imdb_code="" order by date_add desc, code');
		Add('M0082D='+GetLangStr(1127));
		Add('M0083=select distinct m.code, m.title, m.year, m.rating from movies m inner join episodes e on e.movie=m.code where m.in_collection=1 order by m.date_add desc, m.code');
		Add('M0083D='+GetLangStr(1136));
		Add('M0084=select code, title, year from movies where code in (select distinct movie from editions where sort_order > 1) and code not in (select distinct movie from episodes)');
		Add('M0084D='+GetLangStr(1191));
		
		Add('P0094=select p.code from persons p where p.in_collection=1 and p.code not in (select distinct person from images) order by p.date_add desc, p.code');
		Add('P0094D='+GetLangStr(1138));

		Add('C0301=select code, title, year, rating, filename from movies where in_collection=1 order by date_add desc, code');
		Add('C0301-a=select code, title, year, rating, filename from movies where title like "%s%%" and in_collection=1 order by title, code');
		Add('C0301-g=select m.code, m.title, m.year, m.rating, m.filename from movies m inner join movies_manuals mm on mm.movie=m.code and mm.reference=8 inner join manuals mg on mg.code=mm.ref_code where mg.code=%s and m.in_collection=1 order by m.title');
		Add('C0302=select code, name from persons where in_collection=1 order by date_add desc, code');
		Add('C0302-a=select code, name from persons where (name like "%s%%" or name like "%% %s%%") and in_collection=1 order by name, date_add desc, code');
	end;
	// External Sql Strings
	if MyFileExists(ScriptsPath+ScriptName+'_program_sql.ini') then begin
		sl.LoadFromFile(ScriptsPath+ScriptName+'_program_sql.ini');
		for i:=0 to sl.Count-1 do begin
			if (copy(sl.Names[i],1,5)='P0084') then continue; // temp bug fix 
			if (jSqlStrings.IndexOfName(sl.Names[i])<>-1) 
				then jSqlStrings.Values[sl.Names[i]]:=sl.Values[sl.Names[i]]
			else jSqlStrings.Add(sl[i]);
		end;
	end;
	if (jSqlStrings.Count<>sl.Count) then jSqlStrings.SaveToFile(ScriptsPath+ScriptName+'_program_sql.ini');
	for i:=51 to 200 do begin  // Init Core and User Lists XFvar with corresponding sql string
		id:=IntToStr(i);
		while (length(id)<4) do id:='0'+id;
		if (jSqlStrings.IndexOfName('M'+id)<>-1) then s:='M'
		else if (jSqlStrings.IndexOfName('P'+id)<>-1) then s:='P'
		else if (jSqlStrings.IndexOfName('C'+id)<>-1) then s:='C'
		else if (jSqlStrings.IndexOfName('Z'+id)<>-1) then s:='Z'
		else s:='';
		if (s>'') then begin
			SetStrXFvar(i,'sql',jSqlStrings.Values[s+id]);
			if (jSqlStrings.IndexOfName(s+id+'D')<>-1)
				then SetStrXFvar(i,'sqldesc',jSqlStrings.Values[s+id+'D'])
			else SetStrXFvar(i,'sqldesc',s+id+' : '+GetLangStr(1109));
			SetIntXFvar(i,'CurPageNbr',1);
		end;
	end;
	for i:=301 to 302 do begin  // Init Core List XFvar with corresponding sql string
		id:=IntToStr(i);
		while (length(id)<4) do id:='0'+id;
		if (jSqlStrings.IndexOfName('C'+id)<>-1) then begin
			SetStrXFvar(i,'sql',jSqlStrings.Values['C'+id]);
			SetIntXFvar(i,'CurPageNbr',1);
		end;
	end;
	sl.free;
end;

function ExeCustomSql(sqlReq: string; XFid: integer): string;
var
	sql, sqlCaps, sqlsel, fields, s, s2: string;
	sqlMode, RecordCount, i, j: integer;
begin
	sql:=ClearExtraBlankCharacters(sqlReq);
	sql:=ReplaceStr(sql,'  ',' ');
	sqlCaps:=UpperCase(sql);
	if (pos('INSERT',sqlCaps)>0) then begin
		sqlMode:=1;
		sqlsel:='-1';
	end
	else if (pos('UPDATE',sqlCaps)>0) then begin
		sqlMode:=2;
		i:=pos('UPDATE',sqlCaps);
		j:=pos('OR',sqlCaps);
		if (j>0) then i:=MyPos(' ',sqlCaps,i);
		i:=MyPos(' ',sqlCaps,i+1);
		j:=MyPos(' ',sqlCaps,i+1);
		sqlsel:='select * from '+copy(sql,i,j-i);  //table
		i:=MyPos('WHERE',sqlCaps,i+1);
		sqlsel:=sqlsel+' '+copy(sql,i,length(sql));
	end
	else if (pos('DELETE',sqlCaps)>0) then begin
		sqlMode:=3;
		i:=pos('FROM',sqlCaps);
		i:=MyPos(' ',sqlCaps,i);
		j:=MyPos(' ',sqlCaps,i+1);
		sqlsel:='select * from '+copy(sql,i,length(sql));
	end
	else begin // select
		sqlMode:=4;
		i:=pos('FROM',sqlCaps);
		j:=pos('DISTINCT',copy(sqlCaps,1,i))+pos('ALL',copy(sqlCaps,1,i));
		if (j=0) then j:=1;
		i:=MyPos(' ',sqlCaps,i);
		j:=MyPos('FROM',sqlCaps,i+1);
		fields:=copy(sql,i,j-i);
		sqlsel:=sql;
	end;
	RecordCount:=ExecuteSQL(sqlsel);
	if (sqlMode<4) then begin
		if (RecordCount>=0) then s:=IntToStr(RecordCount) else s:=GetLangStr(1606);
		s2:=GetLangStr(1600+sqlMode)+#13#10+#13#10+format(GetLangStr(1605),[s]);
		i:=MessageDlg(s2,mtWarning,mbOk+mbCancel, 0);
		if (i=mrOk) then begin
			RecordCount:=ExecuteSQL(sqlReq);
			if (RecordCount>=0) then showmessage(GetLangStr(715));
		end;
		result:='';
	end
	else result:=BuildCustomList(sqlReq, XFid);
end;

function BuildCustomList(sqlReq: string; XFid: integer): string;
var
	sql, sqlCaps, s, s2: string;
	RecordCount, i, j: integer;
	sl, sl2: TStringList;
begin
	sl:=TStringList.Create;
	sl2:=TStringList.Create;
	sql:=ClearExtraBlankCharacters(sqlReq);
	sql:=ReplaceStr(sql,'  ',' ');
	sqlCaps:=UpperCase(sql);
		
	i:=pos('FROM',sqlCaps);
	j:=pos('DISTINCT',copy(sqlCaps,1,i))+pos('ALL',copy(sqlCaps,1,i));
	if (j=0) then j:=1;
	i:=MyPos(' ',sqlCaps,j);
	j:=MyPos('FROM',sqlCaps,i+1);
	sl.CommaText:=copy(sql,i,j-i);
	RecordCount:=ExecuteSQL(sql);
	if (sl.Count>0) then begin
		for i:=1 to RecordCount do begin
			s:='';
			for j:=1 to sl.Count do begin
				s2:=ClearExtraSDQuotes(GetStringField(sl[j-1]));
				if (StrToIntDef(s2,-999999)=-999999) then s2:='"'+s2+'"';
				s:=s+s2+';';
			end;
			sl2.Add(copy(s,1,length(s)-1));
			GetNextRecord;
		end;
		sl2.SaveToFile(ScriptsPath+'JeF_Sql_Result.csv');
		showmessage(format(GetLangStr(1607),['JeF_Sql_Result.csv']));
	end;
	sl.Free;
	sl2.Free;
	result:='';
end;

procedure ExportPage(Pg, Path:string);
var
	sl: TStringList;
begin
	if (Path='') then Path:=jThmPath+'ExportedPage.html';
	sl:=TStringList.create;
	sl.Text:=Pg;
	sl.Text:=ReplaceStr(sl.Text,'"'+ImagesPath,'"file:///'+ImagesPath);
	sl.Text:=ReplaceStr(sl.Text,'"'+PicturesPath,'"file:///'+PicturesPath);
	sl.Text:=ReplaceStr(sl.Text,'('+jThmPictPath,'(img/');
	sl.SaveToFile(Path);
	sl.free;
end;

// 20090912-JeF
function BuildExtraPage(PTitle, PContent: string): string;
var
	ThmPage, tag, info: string;
	i, j, k: integer;
begin
	ThmPage:=GetTemplate('list');
	if (ThmPage='') then ThmPage:='<h1><!--#title--></h1><br><!--#content-->';
	i:=pos('<!--#',ThmPage);
	while (i>0) do begin
		j:=MyPos('-->',ThmPage,i);
		tag:='';
		info:='';
		if (j>i) then begin
			tag:=copy(ThmPage,i+5,j-i-5);
			while (copy(tag,1,1)=' ') do tag:=copy(tag,2,length(tag)-1);
			while (copy(tag,length(tag),1)=' ') do tag:=copy(tag,1,length(tag)-1);
			k:=pos(' ',tag);
			if (k>0) then tag:=copy(tag,1,k-1);
			j:=j+3;
		end;
		if (tag='title')    			then begin
			info:='<a href="custom110100011:1"><img src="'+GetRscPath('IconsBarShow.png')
					+'" border="0" align="absmiddle" width="16"></a>&nbsp;';
			info:=BlockTag(info, 'TB0001+', 'tag')+PTitle;
			if (GetStrOption('NavBarState')='0') 
				then info:=BlockTag(info, 'TB0001+', 'show');
		end
		else if (tag='mainnavbar')  	then info:=jMainNavBar
		else if (tag='content')   		then info:=PContent;
		if (info<>'') then ThmPage:=copy(ThmPage,1,j-1) + info + copy(ThmPage,j,length(ThmPage)-j+1);
		i:=MyPos('<!--#',ThmPage,i+1);
	end;
	result:=ThmPage;
end;

function GetThumb(DbImgPath, ThumbsFolder, NoImgFile: string; ThumbWidth, ThumbHeight: integer; CutThumb: boolean): string;
var
	ImageFile, ThumbFile, NotFoundFile: string;
	i, j, k: integer;
  fl: boolean;
begin
  ImageFile := ImagesPath + DbImgPath; 
  ThumbFile := ImagesPath + ThumbsFolder + '\' + DbImgPath;
  if (NoImgFile = '') 
    then NoImgFile := 'no-cover.jpg';

  // Default Thumb Width and Height
  if (ThumbWidth <= 0) and (ThumbHeight <= 0) then begin
	  ThumbWidth := DefaultMultiCoverWidth;
	  ThumbHeight := DefaultMultiCoverHeight;
  end;
  
  // Force Thumb creation if older than Image
  if MyFileExists(ThumbFile) and MyFileExists(ThumbFile) then begin
    if GetFileDateTime(ThumbFile) < GetFileDateTime(ImageFile) 
      then DeleteFile(ThumbFile);
  end;
  
  // Thumb creation
  if NOT MyFileExists(ThumbFile) then begin
    // Try Image convertion
    if MyFileExists(ImageFile) 
      then ConvertThumb3(ImageFile, ThumbFile, ThumbsFolder, ThumbWidth, ThumbHeight, CutThumb);
    // Image conversion failed : get 'no-image' thumb 
    if NOT MyFileExists(ThumbFile) then begin 
      ImageFile := ImagesPath + NoImgFile; 
      ThumbFile := ImagesPath + ThumbsFolder + '\' + NoImgFile;
      // Create 'no-image' thumb if needed 
      if NOT MyFileExists(ThumbFile) then begin
        if MyFileExists(ImageFile) 
          then ConvertThumb3(ImageFile, ThumbFile, ThumbsFolder, ThumbWidth, ThumbHeight, CutThumb);
        // 'no-image' Thumb creation failed : point to 'no-image' image 
        if NOT MyFileExists(ThumbFile) 
          then ThumbFile := ImageFile;  
      end;
    end;
  end;
  
  result := ThumbFile;
end;

begin

end.