module compare


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


import StdEnv, StdIO


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

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


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

initIO :: (PSt Local) -> PSt Local
initIO pst
	# (showid,pst)	= accPIO openId pst
	# (_,pst)		= openDialog undef (dialog showid) pst
	= pst
where
	dialog showid
		= Dialog "Compare"
			(	ButtonControl "&Compare..."
					[	ControlFunction (noLS compare)
					,	ControlTip		"Compare two files"
					]
			:+:	ButtonControl "Compare &again"
					[	ControlFunction (noLS again)
					,	ControlTip		"Compare the files again"
					]
			:+:	ButtonControl "&Quit"
					[	ControlFunction (noLS closeProcess)
					,	ControlTip		"Quit compare"
					]
			)	[]
	where
		compare :: (PSt Local) -> PSt Local
		compare pst
			# (maybeFirstFile,pst)		= selectInputFile pst
			| isNothing maybeFirstFile
				= {pst & ls=noFilesSelected}
			# (maybeSecondFile,pst)		= selectInputFile pst
			| isNothing maybeSecondFile
				= {pst & ls=noFilesSelected}
			| otherwise
				# pst	= {pst & ls={name1=fromJust maybeFirstFile,name2=fromJust maybeSecondFile}}
				= showdifference pst
		
		again :: (PSt Local) -> PSt Local
		again pst=:{ls={name1,name2}}
			| name1=="" || name2==""	= compare pst
			| otherwise					= showdifference pst
		
		showdifference :: (PSt Local) -> PSt Local
		showdifference pst=:{ls={name1,name2}}
			# pst						= closeWindow showid pst
			# (files,pst)				= openfilepair (name1,name2) pst
			  (maybeDifference,files)	= comparefilepair 1 files
			# pst						= closefilepair files pst
			| isNothing maybeDifference
				= appPIO beep pst
			# (error,pst)				= openDialog undef (dialog (fromJust maybeDifference)) pst
			| error<>NoError
				= abort "Could not open dialog."
			| otherwise
				= pst
		where
			dialog (i,line1,line2)		= Dialog "Difference found"
											(	ListLS
											[	TextControl ("Difference at line "+++toString i) []
											,	TextControl line1 [ControlPos (Left,NoOffset)]
											,	TextControl line2 [ControlPos (Left,NoOffset)]
											])
											[	WindowId	showid
											,	WindowClose	(noLS (closeWindow showid))
											]

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

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

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)
