module compare


//	**************************************************************************************************
//
//	A program in which two text files can be compared char by char.
//
//	The program has been written in Clean 1.3.1 and uses the Clean Standard Object I/O library 1.0.1
//	
//	**************************************************************************************************


import StdEnv, StdIO


::	Local
	=	{	name1	:: String
		,	name2	:: String
		}

noFilesSelected
	=	{ name1="", name2="" }


Start :: *World -> *World
Start world
	=	startIO noFilesSelected 0 [initIO] [] world

initIO :: (PSt Local .p) -> PSt Local .p
initIO ps
	#	(showid,ps)	= accPIO openId ps
	#	(_,ps)		= openMenu undef (file showid) ps
	=	ps
where
	file showid
		=	Menu "File"
				(	MenuItem "Compare..."		[MenuFunction (noLS compare),		MenuShortKey 'c']
				:+:	MenuItem "Compare again"	[MenuFunction (noLS again),			MenuShortKey 'a']
				:+:	MenuSeparator				[]
				:+:	MenuItem "Quit"				[MenuFunction (noLS closeProcess),	MenuShortKey 'q']
				)	[]
	where
		compare :: (PSt Local .p) -> PSt Local .p
		compare ps
			#	(maybeFirstFile,ps)			= selectInputFile ps
			|	isNothing maybeFirstFile
				=	{ps & ls=noFilesSelected}
			#	(maybeSecondFile,ps)		= selectInputFile ps
			|	isNothing maybeSecondFile
				=	{ps & ls=noFilesSelected}
			|	otherwise
				#	ps	= {ps & ls={name1=fromJust maybeFirstFile,name2=fromJust maybeSecondFile}}
				=	showdifference ps
		
		again :: (PSt Local .p) -> PSt Local .p
		again ps=:{ls={name1,name2}}
			|	name1=="" || name2==""
				=	compare ps
			|	otherwise
				=	showdifference ps
		
		showdifference :: (PSt Local .p) -> PSt Local .p
		showdifference ps=:{ls={name1,name2}}
			#	ps						= closeWindow showid ps
			#	(files,ps)				= accFiles (openfilepair (name1,name2)) ps
				(maybeDifference,files)	= comparefilepair 1 files
			#	ps						= appFiles (closefilepair files) ps
			|	isNothing maybeDifference
				=	appPIO beep ps
			#	(error,ps)				= openDialog undef (dialog (fromJust maybeDifference)) ps
			|	error<>NoError
				=	abort "Could not open dialog."
			|	otherwise
				=	ps
		where
			dialog (i,line1,line2)		= Dialog "Difference found"
											(	ListLS
											[	TextControl ("Difference at line "+++toString i) []
											,	TextControl line1 [ControlPos (Left,zero)]
											,	TextControl line2 [ControlPos (Left,zero)]
											])
											[	WindowId	showid
											,	WindowClose	(noLS (closeWindow showid))
											]

openfilepair :: (String,String) *Files -> ((*File,*File), *Files)
openfilepair (fname1,fname2) files
	#	(ok,f1,files)	= fopen fname1 FReadText files
	|	not ok
		=	abort ("Could not open "+++fname1)
	#	(ok,f2,files)	= fopen fname2 FReadText files
	|	not ok
		=	abort ("Could not open "+++fname2)
	|	otherwise
		=	((f1,f2),files)

closefilepair :: (*File,*File) *Files -> *Files
closefilepair (f1,f2) files
	#	(ok,files)	= fclose f1 files
	|	not ok
		=	abort "Could not close first file."
	#	(ok,files)	= fclose f2 files
	|	not ok
		=	abort "Could not close second file."
	|	otherwise
		=	files

comparefilepair :: Int (*File,*File) -> (Maybe (Int,String,String), (*File,*File))
comparefilepair i (f1,f2)
	|	sfend f1 && sfend f2
		=	(Nothing,(f1,f2))
	#	(line1,f1)	= freadline f1
	#	(line2,f2)	= freadline f2
	|	line1<>line2
		=	(Just (i,line1,line2),(f1,f2))
	|	otherwise
		=	comparefilepair (i+1) (f1,f2)
