implementation module ddState;

// the executable may *never* be in the same folder as its project is because
// otherwise its project is taken to be proper project.
import StdEnv;

import read_dynamic, dynamics, compute_graph, write_dynamic, memory, ddState;
import code from library "StaticClientChannel_library";
import ExtString;
import ArgEnv;

import StdEnv;
import memory;
import expand_8_3_names_in_path;

import MarkUpText;

import DebugUtilities;

:: *DDState = {
		file_name					:: !String				// filename of dynamic
	,	project_name				:: !String				// filename of application using that dynamic
	,	first_time					:: !Bool				// first time
	,	mem							:: *Mem
	
	//
	,	int_descP					:: !Int
	,	char_descP					:: !Int
	,	bool_descP					:: !Int
	,	real_descP					:: !Int
	,	string_descP				:: !Int
	,	array_descP					:: !Int
	,	e__StdDynamic__rDynamicTemp	:: !Int
	,	build_block_label			:: !Int
	,	build_lazy_block_label		:: !Int
	
	,	background_colour			:: !Colour
	};
	
DefaultDDState :: !*Mem -> !*DDState;
DefaultDDState mem
	= { DDState |
		file_name		= ""
	,	project_name	= ""
	,	first_time		= True
	
	,	mem				= mem
	,	int_descP		= 0
	,	char_descP		= 0
	,	bool_descP		= 0
	,	real_descP		= 0
	,	string_descP	= 0
	,	array_descP		= 0
	,	e__StdDynamic__rDynamicTemp	= 0
	,	build_block_label			= 0
	,	build_lazy_block_label		= 0
	
	,	background_colour	= Yellow

	};
	
InitialDDState :: !*Mem !Colour -> (!Bool,!String,!*DDState);
InitialDDState mem colour
	#! (quit,msg,ddState)
		= process_options 1 (size commandline) (DefaultDDState mem);	
		/*
// temp ...
	#! ddState
		= { DDState | ddState &
			file_name	= "C:\\WINDOWS\\DESKTOP\\Clean\\Dynamics\\Examples\\WriteDynamic\\test"
		,	project_name = "C:\\WINDOWS\\DESKTOP\\Clean\\Dynamics\\Examples\\WriteDynamic\\WriteDynamic.prj"
		};
	#! quit
		= False;
// ... temp
*/
		
	#! (file_name,ddState)
		= ddState!DDState.file_name;
	#! (project_name,ddState)
		= ddState!DDState.project_name;
	#! (quit,msg,ddState)
		= case (file_name == "" && project_name <> "") || (file_name <> "" && project_name == "")of {
			True
				-> (True,"No dynamic or project specified\n",ddState);
			False
				-> (quit,msg,ddState);
		};
	= (quit,msg,{ ddState & background_colour = colour});
where {
	process_options _ 1 ddState
		= (True,"",ddState);
	process_options _ 3 ddState
		# is_project_at_index_1
			= (ends commandline.[1] ".prj") || (ends commandline.[1] ".PRJ");
		| is_project_at_index_1
			# ddState
				= snd (dynamic_file 0 ddState);
			# ddState
				= snd (project_file 1 ddState);
//			= abort (ddState.file_name +++ " - " +++ ddState.project_name);
			= (False,"",ddState);
		
		# is_project_at_index_2
			= (ends commandline.[2]) ".prj" || (ends commandline.[2] ".PRJ");
		| is_project_at_index_2
			# ddState
				= snd (project_file 1 ddState);
			# ddState
				= snd (dynamic_file 0 ddState);
//			= abort (ddState.file_name +++ " - " +++ ddState.project_name); //
			= (False,"",ddState);
			
			= (True,"Invalid option\n",ddState);
		
	process_options_from_prompt i limit ddState
		| F ("   " +++ toString limit) i == limit
			= if (limit == 1) (do_help ddState) (False,"",ddState);
		| i + 1 >= limit
			= (True,"Invalid option\n",ddState);
		#! (delta,ddState)
			= case commandline.[i] of {
				// specification of dynamic file
				"-f"
					-> dynamic_file i ddState;	
				"-file"
					-> dynamic_file i ddState;
				"-p"
					-> project_file i ddState;
				"-project"
					-> project_file i ddState;
			};
		= process_options_from_prompt (i + delta) limit ddState;

	
	dynamic_file i ddState
		#! ddState
				= { DDState | ddState &
					file_name = expand_8_3_names_in_path commandline.[inc i]
				};
		= (2,ddState);	
		
	project_file i ddState
		#! ddState
				= { DDState | ddState &
					project_name = commandline.[inc i]
				};
		= (2,ddState);	
		
	do_help ddState
		#! l
			= [ 	"dumpDynamic version 0.0"
				,	""
				,	"Commandline options:"
				,	"-file (or -f) 		the dynamic to be dumped"
				,	"-project (or -p)	project using the dynamic"
			];
		= (True,to_string l,ddState);
			
	where {
		to_string []
			= "";
		to_string [x:xs]
			#! s1
				= to_string xs;
			= x +++ "\n" +++ (to_string xs);
	}
		
	commandline
		= getCommandLine;
}
	
/*
Start :: !*World -> (!*File,!*World);	
Start world
	//
	# (file,world)
		= stdio world;
	#! (mem,world)
		= getMemory world;
		
	// init
	#! (quit,msg,ddState)
		= InitialDDState mem;
	| quit
		#! file
			= fwrites msg file
		= (file,world);
		
	// do dynamic
	#! (file,world)
		= do_dynamic ddState file world;
	= (file,world);
*/

do_dynamic :: !*DDState !*File !*a -> *(!BinaryDynamic,!*DDState,!*File,*a,[MarkUpCommand {#Char}]) | FileEnv a;
do_dynamic ddState file files
	#! (file_name,ddState)
		= ddState!DDState.file_name;
		
	// read dynamic
	#! ((ok,dynamic_info),files)
		= accFiles (read_dynamic file_name) files;
	| not ok
		= abort "error"
			
	// dump type&value; the first arg is ignored
	#! (nodes,desc_table,file,ddState,markup_commands,files)
		= do_look dynamic_info file  ddState files;	
		
	// dump value
//	#! (_,_,file,ddState)
//		= do_look Value dynamic_info file  ddState;
	= (dynamic_info,ddState,file,files,markup_commands);
where {
//	do_look :: !BinaryDynamic !*File *DDState -> *(*Nodes NodeKind,*DescriptorAddressTable,!*File,*DDState,_);
	do_look :: !BinaryDynamic !*File !*DDState !*f -> *(*Nodes NodeKind,*DescriptorAddressTable,!*File,*DDState,[MarkUpCommand {#Char}],!*f) | FileEnv f;
	do_look dynamic_info file ddState files
		#! file
			= WriteHeader  dynamic_info file;
					
		// internal computation
		#! (max_desc_name,max_mod_name,desc_table)
			= BuildDescriptorAddressTable  dynamic_info;
		#! (nodes,desc_table,ddState)
			= compute_nodes  desc_table dynamic_info ddState;
			
		#! file
			= fwritec '\n' file;
		#! (nodes,file,desc_table,ddState,markup_commands)
			= WriteGraph  desc_table dynamic_info nodes file ddState;

		#! file
			= fwritec '\n' file;
		#! file
			= WriteStringTable  dynamic_info file;
	
		#! file
			= fwritec '\n' file;
		#! (file,desc_table)
			= WriteDescriptorAddressTable max_desc_name max_mod_name dynamic_info desc_table file;

		#! file
			= fwritec '\n' file;
		#! file
			= WriteBlockTable dynamic_info file;

	
//		#! file
//			= fwritec '\n' file;
			
		# x = (WriteDynamicInfo dynamic_info.bd_dynamic_info file)
		# (file,files)
			= accFiles x files;

		= (nodes,desc_table,file,ddState,markup_commands,files);
}

replace_command_line :: !String -> !Bool;
replace_command_line _
	= code {
		ccall replace_command_line "S-I"
	};
