implementation module ProjectWindowAux;

/* RWS: this module has several bugs, for example the
        out-of-date message are sometimes incorrect */

import StdClass,StdInt,StdBool,StdString;
import deltaDialog, deltaIOSystem, deltaFont, deltaControls, deltaIOState;
import EdProgramState, EdLists, EdTypes, EdProject, EdPath, EdParse, EdDialogs, EdDrawWindow, EdTextWindow;
											
	DCompEditOptionsID	:== 17;

	PSTitle1ID			:== 0;	
	PSAnaID				:== 1;
	PSDiagID			:== 2;
	PAnaID				:== 3;
		BProfileID		:== 301;
		BMemoryProfileID:== 302;
		BStrID			:== 303;
	PDiagID				:== 4;
	BWarID				:== 5;
	BVerID				:== 6;
	PTypID				:== 7;
		RNonID			:== 701;
		RInfID			:== 702;
		RSETID			:== 703;
		RAllID			:== 704;
	PAttrID				:== 8;
		BAttrID			:== 801;
	PCGID				:== 9;
	PGenID				:== 10;
		BGenID			:== 1001;
		BReuseUniqueNodes :== 1002;
	
	PSTitle2ID			:== 11;
	PFontID				:== 12;
	PSFontID			:== 13;
	PSizeID				:== 14;
	PSSizeID			:== 15;
	PFoxID				:== 16;
	PETabWID			:== 17;
	PSTabWID			:== 18;
	PSAutoID			:== 19;
	PBAutoID			:== 20;
	PUseAID				:== 21;
	
	IFontID				:== 2000;
	ISizeID				:== 4000;
	
	PUseDID				:== 200;
	PCancID				:== 210;
	POKID				:== 220;

::	Info	=	{	path	:: !Pathname,
                    abcpath :: !Pathname,
                    objpath :: !Pathname,

					dcldate	:: !DATE,
					icldate	:: !DATE,
					abcdate	:: !DATE,
					objdate	:: !DATE,
					imports	:: !Bool,
					
					version	:: !Int,
					sys		:: !Bool,
					stack	:: !Bool,
					abcOptions		:: !ABCOptions,
					
					modinfo	:: !ModInfo,
					tp		:: !Processor,
					src		:: !Bool,
					abc		:: !Bool };
					
//
//	Show Up to date Info
//

ExecUpToDate :: !DialogInfo !ProgState !IO -> ProgIO;
ExecUpToDate dstate prog=:{editor={Editor | project}} io
	| not (PR_ExecUpToDate project)
		# (_, prog, io) = OpenNotice noticedefa prog io;
		= (prog, io);
	// otherwise
		# (execdate,io)
			=	accFiles (FModified (MakeExecPathname (PR_GetRootPathName project))) io;
		# ((prog,scan,exec), io)
			=	accFiles (ModulesUpToDate execdate modnames project prog) io;
		# (_, prog, io) = OpenNotice (noticedefb scan exec) prog io;
		= (prog, io);
	where
	{
		noticedefa			= Notice [root +++ " is out of date"] (NoticeButton 1 "OK") [];
		noticedefb scan exec
					| scan	= Notice [root +++ " must be rescanned"] (NoticeButton 1 "OK") [];
					| exec	= Notice [root +++ " is out of date"] (NoticeButton 1 "OK") [];
							= Notice [root +++ " is up to date"] (NoticeButton 1 "OK") [];
		root				= PR_GetRootModuleName project;
		modnames			= PR_GetModulenames False IclMod project;
	};

ModulesUpToDate :: !DATE !(List Modulename) !Project !ProgState !Files -> ((!ProgState, !Bool, !Bool), Files);
ModulesUpToDate execdate Nil project prog files
	= ((prog, False, False), files);
ModulesUpToDate execdate (mn:!rest) project prog files
	| scan		= ((prog`, True, False), files`);
	| recompile	= ((prog`, False, True), files`);
				= ModulesUpToDate execdate rest project prog` files`;
	where {
	((prog`,info), files`)	= ReadInfo False mn project prog files;
	scan			= not info.modinfo.date.exists;
	recompile		= OutOfDate True info || OutOfDate False info || obj_outofdate;
	obj_outofdate	= not info.objdate.exists || not execdate.exists || Older_Date execdate info.objdate;
	};

//
// source/abc Out of date?
//
	
OutOfDate :: !Bool !Info -> Bool;
OutOfDate	source
		{	path,imports,dcldate,icldate,abcdate,objdate,version,sys,stack,abcOptions,src,abc,
			modinfo={compilerOptions} }
	| source	= src || old_version || imports || younger || not_exists || options || stackinfo;
				= abc || abc_outofdate;
	where {
	old_version						= (version <> Version) && abcdate.exists;
	younger							= dcl || icl;
	dcl								= dcldate.exists && Older_Date abc_obj_date dcldate;
	icl								= icldate.exists && Older_Date abc_obj_date icldate;
	not_exists						= not abcdate.exists && not objdate.exists;
	options							= abcdate.exists && NECompilerOptions abcOptions compilerOptions;
	stackinfo						= abcdate.exists && not stack && not sys;
	abc_obj_date | abcdate.exists	= abcdate;
									= objdate;
	abc_outofdate					= abcdate.exists && (	Older_Date objdate abcdate ||
															not objdate.exists ||
															abc );
	};
	
//
// Reanalyze dependencies
//
	
ReScan :: !Info -> Bool;
ReScan	{	dcldate,icldate,imports, modinfo={ModInfo | date} }
	=	not date.exists ||
		imports ||
		(dcldate.exists && Older_Date date dcldate) ||
		(icldate.exists && Older_Date date icldate);
			
//
//	Read file related to up to date info
//

ReadInfo :: !Bool !Modulename !Project !ProgState !Files -> ((!ProgState, !Info), Files);
ReadInfo readimports mod project prog=:{editor={defaults}} files
	= ((prog, info), files8)
	where {
	info	= {	path	= imppath,
				abcpath	= abcpath,
				objpath	= objpath,
	
				dcldate	= dcldate,
				icldate	= icldate,
				abcdate	= abcdate,
				objdate	= objdate,
				imports = imports,
				
				version	= version,
				sys		= sys,
				stack	= stack,
				abcOptions
						= abcOptions,
				modinfo	= modinfo,
				tp		= tp,
				src		= not (PR_SrcUpToDate mod project),
				abc		= not (PR_ABCUpToDate mod project) };
				
	defpath				= MakeDefPathname path;
	imppath				= MakeImpPathname path;
	(abcpath,files1)	= MakeABCSystemPathname path files;
	(objpath,files2)	= MakeObjSystemPathname tp path files1;
	(dcldate,files3)	= FModified defpath files2;
	(icldate,files4)	= FModified imppath files3;
	(abcdate,files5)	= FModified abcpath files4;
	(objdate,files6)	= FModified objpath files5;
	(imports,files7)	= imports_files7;
	imports_files7 | readimports
						= ReadImports mod abc_obj_date modinfo.deps project files6;
						= (False,files6);
	(files8,sys,stack,version,abcOptions)
						= GetABCCompiledInfo abcpath files7;
	abc_obj_date | abcdate.exists
						= abcdate;
						= objdate;
	path				= MakeFullPathname modinfo.ModInfo.dir mod;
	(_,modinfo)			= PR_GetModuleInfo mod project;
	tp					= (PR_GetCodeGenOptions project).CodeGenOptions.tp;
	};
	
ReadImports :: !Modulename !DATE !(List Modulename) !Project !*Files -> (!Bool, !*Files);
ReadImports mod abcdate Nil project files
	= (False, files);
ReadImports mod abcdate (imp:!rest) project files
	| not abcdate.exists			= (False, files);
	| mod == imp					= ReadImports mod abcdate rest project files;
	| not dcldate.exists			= ReadImports mod abcdate rest project files`;
	| Older_Date abcdate dcldate	= (True, files`);
									= ReadImports mod abcdate rest project files`;
	where {
	(dcldate,files`)= FModified defpath files;
	defpath			= MakeFullPathname modinfo.dir (MakeDefPathname imp);
	(_,modinfo)		= PR_GetModuleInfo imp project;
	};

NECompilerOptions :: !ABCOptions !CompilerOptions -> Bool;
NECompilerOptions abcOptions compilerOptions
	= abcOptions.abcMemoryProfile <> (not compilerOptions.neverMemoryProfile) || abcOptions.abcTimeProfile <> (not compilerOptions.neverTimeProfile) ||
				abcOptions.abcStrictnessAnalysis <> compilerOptions.sa || abcOptions.abcGenerateComments <> compilerOptions.gc;

