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

#include <dos/stdio.h>
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/utility_protos.h>

#include "GUIC_Application.hpp"
#include "GUIC_OldButton.hpp"
#include "GUIC_Checkbox.hpp"
#include "GUIC_Cycle.hpp"
#include "GUIC_Date.hpp"
#include "GUIC_DirectoryExamine.hpp"
#include "GUIC_Error.hpp"
#include "GUIC_Event.hpp"
#include "GUIC_Exceptions.hpp"
#include "GUIC_File.hpp"
#include "GUIC_FileString.hpp"
#include "GUIC_FileExamine.hpp"
#include "GUIC_Fillbar.hpp"
#include "GUIC_Frame.hpp"
#include "GUIC_GGFXPicture.hpp"
#include "GUIC_OldListview.hpp"
#include "GUIC_PathString.hpp"
#include "GUIC_Screen.hpp"
#include "GUIC_SlidingInteger.hpp"
#include "GUIC_String.hpp"
#include "GUIC_StringType.hpp"
#include "GUIC_System.hpp"

#include "CompareWindow.hpp"
#include "PrefsWindow.hpp"

/*********************************************************************************************************/

class CompareWindowC_ListEntry : public GUIC_ObjectC
	{
	public:
		CompareWindowC_ListEntry	(GUIC_FileExamineC *file);
		~CompareWindowC_ListEntry	(VOID);
		STRPTR	getClass					(VOID);
		LONG		compare					(GUIC_ObjectC &o);
		VOID		print						(VOID);
		
		STRPTR 	fileName;
		LONG		fileSize;
		
	protected:	
		VOID		cleanUp					(VOID);
	};

CompareWindowC_ListEntry::CompareWindowC_ListEntry		(GUIC_FileExamineC *file)
{
	fileName	= 0;
	fileSize	= file->getSize();

	GUIC_SystemC::reallocString(&fileName, file->getName());
}
CompareWindowC_ListEntry::~CompareWindowC_ListEntry	(VOID)
{
	if (fileName)	delete [] fileName;
}
STRPTR 	CompareWindowC_ListEntry::getClass					(VOID)
{
	return "CompareWindowC_ListEntry";
}
VOID		CompareWindowC_ListEntry::cleanUp						(VOID)
{
}
LONG		CompareWindowC_ListEntry::compare					(GUIC_ObjectC &o)
{
	CompareWindowC_ListEntry *e = (CompareWindowC_ListEntry *)&o;
	
	if (fileSize > e->fileSize) return 1;
	if (fileSize < e->fileSize) return -1;
	
	return Stricmp(fileName, e->fileName);
}
VOID		CompareWindowC_ListEntry::print							(VOID)
{
	cout << "[" << getClass() << "," << this << ",Name=" << fileName << ",Size=" << fileSize << "]" << endl;
}

/*********************************************************************************************************/

CompareWindowC::CompareWindowC				(GUIC_ApplicationC &a, GUIC_ScreenC &s, PrefsWindowC &p) : GUIC_WindowC (42,30)
{
	app					= &a;
	screen			= &s;
	pWindow			= &p;
	
	ps_path			= new GUIC_PathStringC			( 1, 1,40, 2, "RAM:");
	lv_message	= new GUIC_OldListviewC			( 1, 4,40,20);
	bt_start			= new GUIC_OldButtonC			( 1,25, 8, 4, "_Start");
	fb_status		= new GUIC_FillbarC					(10,25,31, 4, 0);

	lv_message	-> setReadOnly(TRUE);
	
	add(ps_path);
	add(lv_message);
	add(bt_start);
	add(fb_status);

	app -> addPrefs("PathToCompare", ps_path);
	app -> addPrefs("CompareWindow", this);
	
	setTitle("Gallery - File Compare");
	setGuideContext("CompareWindow");

	activate();
}
CompareWindowC::~CompareWindowC			(VOID)
{
	cleanUp();
}

/*********************************************************************************************************/

STRPTR	CompareWindowC::getClass			(VOID)
{
	return "CompareWindowC";
}

BOOL		CompareWindowC::action				(GUIC_EventC &e)
{
	static LONG oldPriority;

	switch (e.id)
		{
		case GUIC_GadgetEvent:
			if (e.gadget == (GUIC_GadgetC *) bt_start)
				{
				GUIC_ListC fileList;

				// Set the status to 0
				fb_status->set(0);
				// Change the Task's priority
				if (pWindow->cb_priority->get()) oldPriority = SetTaskPri(FindTask(NULL), pWindow->si_priority->get() );

				try 
					{
					LONG equal; CHAR dummy[128];
					GUIC_DirectoryExamineC dir ( ps_path->get() );
				
					app->setBusy(TRUE);
					
					ps_path->setEnabled(FALSE);
					bt_start->set("Stop");
					lv_message->delAllItems();
					
					lv_message->addItem("Scanning directory.");
					setBusy(FALSE);
					scanDirectory(dir, fileList);
					setBusy(TRUE);
					lv_message->addItem("Directory scanned.");

					lv_message->addItem("Comparing files:");
					lv_message->addItem(" ");
					setBusy(FALSE);
					equal = compareFiles(fileList);
					setBusy(TRUE);
					lv_message->addItem(" ");
					lv_message->addItem("Files compared.");
					sprintf(dummy, "%ld equal files found.", equal);
					lv_message->addItem(dummy);
					lv_message->addItem("Logfile saved to T:Gallery.log.");
					
					}
				catch (GUIC_Exception &ex)
					{
					GUIC_ErrorC err ("Error", ex.getMessage() );
					err.request(this);
					}

				setBusy(TRUE);
				while (fileList.length()) delete (CompareWindowC_ListEntry *) fileList.remove(1);
				setBusy(FALSE);

				ps_path->setEnabled(TRUE);
				bt_start->set("_Start");
				
				// Change the priority again
				if (pWindow->cb_priority->get()) SetTaskPri(FindTask(NULL), oldPriority );

				app->setBusy(FALSE);
				}
			return TRUE;
			break;
		case GUIC_OpenWindow:
			return TRUE;
			break;
		case GUIC_CloseWindow:
			screen->remove(this);
			return TRUE;
			break;
		}
	
	return FALSE;
}

/*********************************************************************************************************/

VOID		CompareWindowC::scanDirectory	(GUIC_DirectoryExamineC &dir, GUIC_ListC &list)
{
	LONG result=0;
	CompareWindowC_ListEntry *entry;
	
	try
		{
		GUIC_FileExamineC *file = dir.examineNext();
		while (file)
			{
			if (file->isDirectory())
				{
				GUIC_DirectoryExamineC nextDir (file->getName());
				scanDirectory(nextDir, list); 
				}
			else 
				{
				entry = new CompareWindowC_ListEntry(file);
				list.addSorted(entry);
				result++;
				}
			
			GUIC_EventC *event = app->checkEvent();
			if (event && event->id == GUIC_GadgetEvent) throw GUIC_Exception("User Abort");
			
			file = dir.examineNext();
			}
		}
	catch (GUIC_Exception &) { throw; }
}
LONG		CompareWindowC::compareFiles	(GUIC_ListC &list)
{
	LONG found = 0, length = list.length(), oldLength=length;
	CompareWindowC_ListEntry *entry1, *entry2;
	GUIC_FileC file ("T:Gallery.log", GUIC_Write);
	
	while (length > 1)
		{

		/* Check for Stop gadget */
		GUIC_EventC *event = app->checkEvent();
		if (event && event->id == GUIC_GadgetEvent) throw GUIC_Exception("User Abort");

		entry1 = (CompareWindowC_ListEntry *) list.objectAt(1);
		entry2 = (CompareWindowC_ListEntry *) list.objectAt(2);
		
		if (entry1->fileSize == entry2->fileSize)
			{
			LONG i=2; 
			BOOL writeIt = FALSE;
			
			while (entry1->fileSize == entry2->fileSize)
				{
				if (areEqual(entry1->fileName, entry2->fileName))
					{
					writeIt = TRUE;
					file.writeLn(entry2->fileName);
					lv_message->addItem(entry2->fileName);
					delete (CompareWindowC_ListEntry *) list.remove(i); 		
					length--;
					if (length == 1 || i > length) break;
					entry2 = (CompareWindowC_ListEntry *) list.objectAt(i);
					}
				else 
					{
					i++;
					if (i > length) break;
					entry2 = (CompareWindowC_ListEntry *) list.objectAt(i);
					}
				fb_status->set( (100*(oldLength-length))/oldLength );
				}

			if (writeIt)
				{
				file.writeLn(entry1->fileName);
				file.writeLn("------------------------------");
				
				lv_message->addItem(entry1->fileName);
				lv_message->addItem("------------------------------");
				
				found++;
				}
			}

		delete (CompareWindowC_ListEntry *) list.remove(1); 
		length--;

		fb_status->set( (100*(oldLength-length))/oldLength );
		}
	
	return found;
}
BOOL		CompareWindowC::areEqual			(STRPTR file1, STRPTR file2)
{
	int read1, read2;
	GUIC_Exception *ex = 0;
	FILE *fp1, *fp2;
	
	fp1 = fopen(file1, "rb");
	if (fp1)
		{
		fp2 = fopen(file2, "rb");
		if (fp2)
			{
			FOREVER
				{
				read1 = fgetc(fp1);
				read2 = fgetc(fp2);

				if (read1 == EOF && read2 == EOF) break;
				
				if (read1 != read2 )
					{
					fclose(fp1);
					fclose(fp2);
					return FALSE;
					}
					
				}
			fclose(fp2);
			}
		else ex = new GUIC_Exception ("Can't find file ", file2);
		fclose(fp1);
		}
	else ex = new GUIC_Exception ("Can't find file ", file2);

	if (ex) throw ex;
	
	return TRUE;
}

/*********************************************************************************************************/

VOID		CompareWindowC::cleanUp				(VOID)
{
	delete ps_path;
	delete lv_message;
	delete bt_start;
	delete fb_status;
}

