#define __VERSION__ 	"39"
#define __REVISION__ 	"3"
#define __NAME__			"Gallery"
#define __AUTHOR__		"Markus Hillenbrand"

char *V = "$VER: " __NAME__ " " __VERSION__ "." __REVISION__ " (" __DATE__ ")";

#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#include <GUIC_Classes/GUIC_System.hpp>
#include <GUIC_Classes/GUIC_Date.hpp>
#include <GUIC_Classes/GUIC_Error.hpp>
#include <GUIC_Classes/GUIC_Frame.hpp>
#include <GUIC_Classes/GUIC_Application.hpp>
#include <GUIC_Classes/GUIC_Screen.hpp>
#include <GUIC_Classes/GUIC_Window.hpp>
#include <GUIC_Classes/GUIC_Error.hpp>
#include <GUIC_Classes/GUIC_Exceptions.hpp>
#include <GUIC_Classes/GUIC_DirectoryExamine.hpp>
#include <GUIC_Classes/GUIC_FileExamine.hpp>
#include <GUIC_Classes/GUIC_File.hpp>
#include <GUIC_Classes/GUIC_Key.hpp>
#include <GUIC_Classes/GUIC_List.hpp>
#include <GUIC_Classes/GUIC_Node.hpp>
#include <GUIC_Classes/GUIC_Exceptions.hpp>
#include <GUIC_Classes/GUIC_Button.hpp>
#include <GUIC_Classes/GUIC_Checkbox.hpp>
#include <GUIC_Classes/GUIC_String.hpp>
#include <GUIC_Classes/GUIC_Integer.hpp>
#include <GUIC_Classes/GUIC_Slider.hpp>
#include <GUIC_Classes/GUIC_Label.hpp>
#include <GUIC_Classes/GUIC_SlidingInteger.hpp>
#include <GUIC_Classes/GUIC_FileString.hpp>
#include <GUIC_Classes/GUIC_PathString.hpp>
#include <GUIC_Classes/GUIC_Message.hpp>
#include <GUIC_Classes/GUIC_FileRequester.hpp>
#include <GUIC_Classes/GUIC_ProgramArgs.hpp>

#define COPYRIGHT	"<SMALL> index file created with 'Gallery', (c) 1997 by <A HREF=\"http://www.student.uni-kl.de/~hillenbr\">Markus Hillenbrand</A> </SMALL>"
#define FILEFILTER 	"#?.(jpeg|jpg|gif|iff|ilbm|iff24|png|bmp|pcx|tiff)"

#define MINLINES					3
#define MINCOLUMNS			3	
#define MAXLINES					200
#define MAXCOLUMNS			200	
#define DEFAULTLINES			3
#define DEFAULTCOLUMNS	5

GUIC_ListC errorList;
int lastDay=0,lastMonth=0,lastYear=0;


class GalleryEntryC : public GUIC_ObjectC
	{
	public:
		GalleryEntryC		(STRPTR f, LONG s, int d, int m, int y) 	{ fileName=f; size=s; day=d; month=m; year=y; }
		int 		compare	(GUIC_ObjectC &o);
		void	print		(void) { cout << fileName << endl; }
		String fileName;
		int day,month,year;
		LONG size;
	protected:
		void cleanUp(void) {};
	};
	
int GalleryEntryC::compare(GUIC_ObjectC &o)
{ 
	// First we must convert the argument to what it really is:
	GalleryEntryC *g = (GalleryEntryC *)&o; 
	
	return strcmp(this->fileName, g->fileName); // Just compare the two file names	
}

String 	makeThumbnail	(GUIC_FileExamineC &file)
{
	String fileName = file.getName();

	int i = fileName.length();
	while (--i) if (fileName[i] == '.') break;

	String thumbName = fileName.left(i);
	thumbName+="_.jpg";

	try
		{
		GUIC_FileExamineC f(thumbName);
		if (f.newer(file)) return thumbName;
		}
	catch (GUIC_SystemX &e) { }

	String args = "<>NIL: \"" + fileName + "\" TO \"" + thumbName + "\" FORMAT JPEG QUALITY 90 BOXFIT 100 100";

	cout << " - creating thumbnail for file '" << fileName << "' ... " << flush;
	BOOL result = GUIC_SystemC::runProgram("GfxCon_68020", 100000, args);
	if (result) cout << "done." << endl; else cout << "error occured." << endl;

	return thumbName;
}
void 		createGallery		(GUIC_ListC &fileList, STRPTR pattern, LONG linesInTable, LONG columnsInTable, BOOL picClick)
{
	GalleryEntryC *key = (GalleryEntryC *)fileList.objectAt(1);
	GUIC_FileExamineC firstFile(key->fileName);
	String currentDir = firstFile.getPathPart();
	
	ldiv_t d = ldiv ( fileList.length(), columnsInTable );
	int lines = d.quot;
	if (d.rem) lines++;
	
	d = ldiv (lines, linesInTable);
	int galleries = d.quot;
	if (d.rem) galleries++;

	cout << "Creating " << galleries << " galleries in directory '" << currentDir << "' " << endl;
	
	fileList.sort();
	
	GUIC_FileExamineC directoryName(currentDir);

	// Create the index file with the frames
	
	GUIC_FileC gallery(currentDir, "index.html", GUIC_Write);
	gallery.write("<TITLE>Gallery '");
	gallery.write(directoryName.getFilePart());
	gallery.writeLn("'</TITLE>");
	gallery.writeLn("<FRAMESET COLS=150,*>");
	gallery.writeLn("<FRAME NAME=F1 SRC=\"galleries.html\" MarginHeight=0 MarginWidth=0 Scrolling=\"auto\" FrameBorder=0>");
	gallery.writeLn("<FRAME NAME=F2 SRC=\"index1.html\" MarginHeight=0 MarginWidth=0 Scrolling=\"auto\" FrameBorder=0>");
	gallery.writeLn("</FRAMESET>");
	
	// now create the overview over the galleries
	GUIC_FileC overview (currentDir, "galleries.html", GUIC_Write);
	overview.writeLn("<HTML>");
	overview.write("<H2>"); 
	overview.write(directoryName.getFilePart());
	overview.writeLn("</H2><BR>");
	for (int i=1; i<=galleries; i++)
		{
		overview.write("<A HREF=\"index");
		overview.write(i);
		overview.write(".html\" TARGET=F2>Gallery ");
		overview.write(i);
		overview.writeLn("</A> <BR>");
		}
		
	overview.writeLn("<BR> <BR> <IMG SRC=internal-gopher-menu> <A HREF=\"../index.html\" TARGET=_top> up </A>");
	overview.writeLn("</HTML>");

	// create each gallery
	int count = 0;
	for (i=1; i<=galleries; i++)
		{
		char filename[256];
		sprintf(filename, "index%ld.html", i);
		GUIC_FileC indexFile(currentDir, filename, GUIC_Write);

		// write head and title	
		indexFile.writeLn("<HTML>");
		indexFile.writeLn("<HEAD>");
	
		indexFile.write("<TITLE> "); indexFile.write(directoryName.getFilePart());	indexFile.writeLn(" </TITLE>");
		indexFile.writeLn("</HEAD>");
		indexFile.write("<BODY");
		if (pattern)
			{
			indexFile.write(" Background=\"");
			indexFile.write(pattern);
			indexFile.write("\"");
			}
		indexFile.writeLn(">");
		
		indexFile.write("<CENTER><H2>"); 
		indexFile.write(directoryName.getFilePart()); 
		indexFile.write("</H2> (Part ");
		indexFile.write(i);
		indexFile.write(" of ");
		indexFile.write(galleries);
		indexFile.writeLn(")<BR>");

		indexFile.writeLn("<HR>");
		indexFile.writeLn("<TABLE Border=1 CellSpacing=4 CellPadding=4>");
		
		int boundary = count + columnsInTable*linesInTable;
		if (boundary>fileList.length()) boundary = fileList.length();
		
		for (int j=count; j<boundary; j++)
			{
			key = (GalleryEntryC *)fileList.objectAt(j+1);
			GUIC_FileExamineC file(key->fileName);
			String thumbName = "";
			
			// Create the thumbnail now			
			try
				{
				thumbName = makeThumbnail(file);
				GUIC_FileExamineC thumb (thumbName);
				thumbName = thumb.getFilePart();
				}
			catch (GUIC_SystemX &e) { GalleryEntryC *s = new GalleryEntryC(key->fileName,0,0,0,0); errorList.addTail(*s); }

			// Check the date
			GUIC_DateC oldDate(lastDay,lastMonth,lastYear),*fileDate = file.getDate();;
			if (fileDate->greater(oldDate) )
				{
				lastDay   = fileDate->getDay();
				lastMonth = fileDate->getMonth();
				lastYear  = fileDate->getYear();
				}

			// Check if there are 5 entries per line in the table
			if (count++ % columnsInTable == 0) indexFile.write("<TR> ");

			// write the picture data
			indexFile.write("<TD> <CENTER>");
			
			if (picClick)
				{
				indexFile.write("<A HREF=\"");
				indexFile.write(file.getFilePart());
				indexFile.write("\"> <IMG SRC=\"");
				indexFile.write(thumbName);
				indexFile.write("\" ALT=Thumbnail> <BR>");
				}
			else
				{
				indexFile.write("<IMG SRC=\"");
				indexFile.write(thumbName);
				indexFile.write("\" ALT=Thumbnail> <BR>");
				indexFile.write("<A HREF=\"");
				indexFile.write(file.getFilePart());
				indexFile.write("\">");
				}
				
			indexFile.write(file.getFilePart());
			indexFile.write(" </A> <BR> Size: ");
			indexFile.write(key->size);
			indexFile.write(" <BR> Date: ");
			indexFile.write(key->day);
			indexFile.write(".");
			indexFile.write(key->month);
			indexFile.write(".");
			indexFile.write(key->year);
			indexFile.writeLn("</TD>");
			}
			
		indexFile.writeLn("</TABLE>");

		indexFile.writeLn("<HR>");
		indexFile.writeLn(COPYRIGHT);
		indexFile.writeLn("</BODY>");
		indexFile.writeLn("</HTML>");
		}
}
void 		createHTML		(GUIC_ListC &fileList, STRPTR pattern)
{
	GalleryEntryC *key = (GalleryEntryC *)fileList.objectAt(1);
	GUIC_FileExamineC firstFile(key->fileName);

	STRPTR currentDir = firstFile.getPathPart();
	GUIC_FileC indexFile(currentDir, "index.html", GUIC_Write);
	GUIC_FileExamineC directoryName(currentDir);

	String titleString = directoryName.getFilePart();
	if (titleString == String("") ) titleString = directoryName.getName();

	cout << "Creating file '" << indexFile.getName() << "'" << endl;

	indexFile.writeLn("<HTML>");
	indexFile.writeLn("<HEAD>");
	indexFile.write("<TITLE> "); indexFile.write(titleString); indexFile.writeLn(" </TITLE>");
	indexFile.writeLn("</HEAD>");
	indexFile.write("<BODY");
	if (pattern)
		{
		indexFile.write(" Background=\"");
		indexFile.write(pattern);
		indexFile.write("\"");
		}
	indexFile.writeLn(">");
	indexFile.write("<CENTER><H1>"); indexFile.write(titleString); indexFile.writeLn("</H1>");
	indexFile.writeLn("<HR><BR><BR>");
	
	// Create the table of galleries
	
	indexFile.writeLn("<TABLE Border=1 CellSpacing=4 CellPadding=4>");
	indexFile.writeLn("<TR> <TH> <CENTER> <H3> Gallery Name </H3> </TH> <TH> <CENTER> <H3> Entries </H3> </TH> <TH> <CENTER> <H3> Last Update </H3> </TH>");
	
	fileList.sort();
	
	for (int i=1; i<=fileList.length(); i++)
		{
		key = (GalleryEntryC *)fileList.objectAt(i);
		GUIC_FileExamineC file (key->fileName);

		indexFile.write("<TR> <TD> <CENTER> <A HREF=\"");
		indexFile.write(file.getFilePart());
		indexFile.write("/index.html\"");
		indexFile.write("> ");
		indexFile.write(file.getFilePart());
		indexFile.write(" </A> </TD> <TD> <CENTER> ");
		indexFile.write(key->size);
		indexFile.write(" </TD> <TD> <CENTER> ");

		if (key->day)
			{
			indexFile.write(key->day);
			indexFile.write(".");
			indexFile.write(key->month);
			indexFile.write(".");
			indexFile.write(key->year);
			}
		else indexFile.write("(Directory)");
		indexFile.writeLn(" </TD>");
		}

	indexFile.writeLn("</TABLE>");

	indexFile.writeLn("<BR> <IMG SRC=internal-gopher-menu> <A HREF=\"../index.html\" TARGET=_top> up </A> <BR>");

	indexFile.writeLn("<HR>");
	indexFile.writeLn(COPYRIGHT);
	indexFile.writeLn("</BODY>");
	indexFile.writeLn("</HTML>");
}
int 			scanDir				(STRPTR startDir, STRPTR pattern, LONG linesInTable, LONG columnsInTable, BOOL picClick)
{
	GUIC_ListC fileList,dirList;
	GalleryEntryC *key = 0;
	GUIC_FileExamineC *filex = 0;
	int entries = 0;

	GUIC_FileExamineC *examine = new GUIC_FileExamineC(startDir);
	if (!examine->isDirectory()) throw GUIC_SystemX("Error in function ScanDir (directory name expected).");
	String dirName = examine->getName();
	delete examine; examine=0;

	GUIC_DirectoryExamineC *direx= new GUIC_DirectoryExamineC(dirName);
	BOOL hasSubDirs = direx->hasSubdirectory();
	if (!hasSubDirs) direx->setFilter(FILEFILTER);

	try
		{
		while ( (filex = direx->examineNext()) )
			{
			String fileName  = filex->getName();
			GUIC_DateC *date = filex->getDate();

			if (filex->isDirectory())
				{
				String newPattern = String("../") + String(pattern);
				int entriesInDir  = scanDir(fileName, pattern ? (STRPTR) newPattern : 0, linesInTable, columnsInTable, picClick);
				if (entriesInDir)
					{
					key = new GalleryEntryC(fileName, entriesInDir, lastDay, lastMonth, lastYear);
					if (!key) throw GUIC_MemoryX("Can't allocate memory for key.");
					dirList.addTail(*key);
					entries+=entriesInDir;
					}
				lastDay=0; lastMonth=0; lastYear=0;
				}
			else if (! hasSubDirs && (fileName.right(5) != String("_.jpg") ) )
				{
				key = new GalleryEntryC(fileName, filex->getSize(), date->getDay(), date->getMonth(), date->getYear() );
				if (!key) throw GUIC_MemoryX("Can't allocate memory for key.");
				fileList.addTail(*key);
				entries++;
				}
			}
		}
	catch (GUIC_SystemX &e) { cerr << "Exception caught while processing directory '" << direx->getName() << "': " << e.getMessage() << endl; }
	delete direx;direx=0; /* Damit der lock auf das Verzeichnis freigegeben wird ! */

	if (dirList.length()) 	createHTML		(dirList,pattern);
	if (fileList.length())	createGallery		(fileList,pattern, linesInTable, columnsInTable, picClick);

	while (fileList.length()) delete (GalleryEntryC *)fileList.remove(1);
	while ( dirList.length()) delete (GalleryEntryC *) dirList.remove(1);

	return entries;
}


class GalleryWindowC : public GUIC_WindowC
	{
	public:
		GalleryWindowC	(GUIC_ApplicationC *app, GUIC_ScreenC *screen);
		~GalleryWindowC (void);
		BOOL action		(GUIC_EventC &);
	private:
		GUIC_ButtonC				*start, *quit;
		GUIC_FileStringC			*pattern;
		GUIC_PathStringC		*directory;
		GUIC_SlidingIntegerC 	*lines, *columns;
		GUIC_FrameC				*frame;
		GUIC_CheckboxC		*click;
		GUIC_LabelC				*dirLabel, *pattLabel, *linesLabel, *columnsLabel, *clickLabel;
	};
	
GalleryWindowC::GalleryWindowC	(GUIC_ApplicationC *app, GUIC_ScreenC *screen) : GUIC_WindowC (-1,-1,46,19)
{
	frame				= new GUIC_FrameC				(1,1,44,14,"Gallery");

	dirLabel			= new GUIC_LabelC				(3, 2,10,2,"_Directory:");
	pattLabel		= new GUIC_LabelC				(3, 4,10,2,"_Pattern:");
	linesLabel		= new GUIC_LabelC				(3, 7,10,2,"_Lines:");
	columnsLabel	= new GUIC_LabelC				(3, 9,10,2,"_Columns:");
	clickLabel		= new GUIC_LabelC				(3,12,30,2,"Use _thumbnail picture as link:");

	directory			= new GUIC_PathStringC		(13, 2,30,2,"");
	pattern			= new GUIC_FileStringC			(13, 4,30,2,"");
	lines				= new GUIC_SlidingIntegerC	(13, 7,30,2,MINLINES,MAXLINES,DEFAULTLINES);
	columns			= new GUIC_SlidingIntegerC	(13, 9,30,2,MINCOLUMNS,MAXCOLUMNS,DEFAULTCOLUMNS);	
	click				= new GUIC_CheckboxC			(40,12, 3,2,FALSE);
	
	start				= new GUIC_ButtonC				(1,16,15,2,"_Start");
	quit					= new GUIC_ButtonC				(30,16,15,2,"_Quit");
	
	directory	->setHelp("Directory for the first index file.");
	pattern	->setHelp("Background pattern in HTML pages.");
	lines		->setHelp("The number of lines per HTML table.");
	columns	->setHelp("The number of columns per HTML table.");
	click		->setHelp("Click on thumbnails to view picture?");
	start		->setHelp("Start the creation of the gallery.");
	quit			->setHelp("Quit the program.");
	
	directory	->setShortcut('d');
	pattern	->setShortcut('p');
	lines		->setShortcut('l');
	columns	->setShortcut('c');
	click		->setShortcut('t');
	start		->setShortcut('s');
	quit			->setShortcut('q');
	
	add(frame);
	add(dirLabel);
	add(directory);
	add(pattLabel);
	add(pattern);
	add(linesLabel);
	add(lines);
	add(columnsLabel);
	add(columns);
	add(clickLabel);
	add(click);
	add(start);
	add(quit);
	
	app->addPrefs("GalleryWindow"			, this);
	app->addPrefs("StartDirectory"			, directory);
	app->addPrefs("BackgroundPattern"	, pattern);
	app->addPrefs("NumberOfLines"			, lines);
	app->addPrefs("PictureAsLink"				, click);
	app->addPrefs("NumberOfColumns"		, columns);

	setTitle("Gallery - (c) by Markus Hillenbrand");
	setHelp(TRUE);
	activate();
}
GalleryWindowC::~GalleryWindowC	(void)
{
	delete frame;
	delete dirLabel;
	delete directory;
	delete pattLabel;
	delete pattern;
	delete linesLabel;
	delete lines;
	delete columnsLabel;
	delete columns;
	delete clickLabel;
	delete click;
	delete start;
	delete quit;
}

BOOL GalleryWindowC::action(GUIC_EventC &e)
{
	switch (e.id)
		{
		case GUIC_GadgetEvent:
			if (e.gadget == (GUIC_GadgetC *)start)
				{
				if (! strcmp(directory->get(), "") )
					{
					GUIC_ErrorC e("You must at least enter a directory name!");
					e.request(this);
					}
				else 
					{
					GUIC_SystemC::openConsole();
					sleep();
					activate();
					try 
						{
						scanDir (directory->get(), pattern->get(), lines->get(), columns->get(), click->get() );
						}
					catch (GUIC_Exception &x) { GUIC_ErrorC e("Exception caught:", x.getMessage() ); e.request(this); }
					waken();
					}
				}
			else if (e.gadget == (GUIC_GadgetC *)quit) 
				{
				dispose();
				}
			return TRUE;
			break;
		case GUIC_CloseWindow: 
			return TRUE;
			break;
		default:
			cerr << "Got an event: " << e.id << endl;
		}
	
	return FALSE;
}



void 		shell					(void)
{
	LONG result[] = { 0,0,0,0,0 };
	STRPTR templ = "STARTDIR/A,LINES/N,COLUMNS/N,BGPATTERN,PICCLICK/S";
	GUIC_ProgramArgsC args;
	if (! args.fit(templ, result))
		{
		cerr << "Usage: " << templ << endl;
		GUIC_SystemC::exit(GUIC_ExitError);
		}
	
	LONG lines = result[1] ? *(LONG *)result[1] : DEFAULTLINES;
	if (lines < MINLINES) 		lines=MINLINES;
	if (lines > MAXLINES)	lines=MAXLINES;
	
	LONG columns = result[2] ? *(LONG *)result[2] : DEFAULTCOLUMNS;
	if (columns < MINCOLUMNS) 	columns=MINCOLUMNS;
	if (columns > MAXCOLUMNS)	columns=MAXCOLUMNS;
	
	BOOL picclick = result[4];
	
	scanDir((STRPTR)result[0], (STRPTR)result[3], lines, columns, picclick); 

	if (errorList.length())
		{
		cerr << "The following files could not be converted to a thumbnail:" << endl;
		while (errorList.length())
			{
			GalleryEntryC *s = (GalleryEntryC *)errorList.remove(1);
			cerr << "- " << s->fileName << endl;
			delete s;
			}
		cerr << "Please check them and run 'Gallery' again." << endl;
		}
}
void		workbench			(void)
{
	GUIC_ApplicationC	app("Gallery");

	app.setAuthor		(__AUTHOR__);
	app.setVersion	(__VERSION__);
	app.setRevision	(__REVISION__);
	app.setDate		(__DATE__);
	app.setTime		(__TIME__);
	app.setInitializer	(TRUE);

	GUIC_ScreenC			screen;
	GalleryWindowC 	window(&app, &screen);
	
	screen.add(window);
	app.add(screen);

	app.start();

	BOOL running = TRUE;
	GUIC_EventC *event = 0;

	int count = 0;
	
	while (running && (event = app.wait()) )
		{
		// As we have only one window, it is not neccessary to check for the window id
		if (event->id == GUIC_CloseWindow) 
			{
			GUIC_MessageC	message	("Do you really want to quit ?", "Yes|No");
			if (1 == message.request(*event->window)) running = FALSE;
			}
		}

	app.stop();
}

void 		main					(int argc, char **argv)
{
	GUIC_SystemC::checkStackSize(50000);
	if (GUIC_SystemC::runFromShell() ) shell(); else workbench();
}

