implementation module DLState;


EXTEND_TYPE_INFO yes no :== no;

// StdEnv
import StdEnv;
import LibraryState;
// Linker
import State;
//import ReadLibrary;
import ProcessSerialNumber;
//import DebugUtilities;
F a b :== b;

// IDE 2.0 import
import PmProject;
import target;

// Ext
import ExtList;

import StdEnv, deltaEventIO, deltaMenu, deltaWindow, deltaTimer, deltaDialog;

import ClientWindow;
import DynamicLink;

import Directory;
/*2.0
from deltaIOState import class FileEnv, instance  FileEnv (IOState s) ;
0.2*/
//1.3
from deltaIOState import FileEnv;
//3.1

import ExtInt;

import dynamics; // internal constants for dynamics

import DynamicID;
import StdDynamicLowLevelInterface;
import typetable;
import MemoryState;
import LibraryInstance;
import type_io_equal_types;
import TypeImplementationTable;
import ToAndFromGraph;
import ToAndFromGraph;


:: *DLServerState
	= {
	// general data
		quit_server						:: !Bool
	,	application_path				:: !String
	,	static_application_as_client	:: !Bool
//	,	targets							:: [Target]
	
	// clients
	,	dl_client_states				:: *[*DLClientState]
	
	// client windows
	,	global_client_window			:: !GlobalClientWindow
	
	// conversions
	,	convert_functions				:: !ConvertFunctions
	
	// NEW TO HANDLE .LIB DEMANDS
	,	dlss_lib_mode					:: !Bool
	,	dlss_lib_command_line			:: !{{#Char}} //String
	};
	
DefaultDLServerState :: !*DLServerState;
DefaultDLServerState 
	= {
	// general data
		quit_server						= False
	,	application_path				= ""
	,	static_application_as_client	= False
//	,	targets							= []
	
	// clients
	,	dl_client_states				= []
	
	// client windows
	,	global_client_window			= DefaultGlobalClientWindow
	
	// conversions
	,	convert_functions				= default_convertfunctions

	// NEW TO HANDLE .LIB DEMANDS
	,	dlss_lib_mode					= False
	,	dlss_lib_command_line			= {}
	};	

AddToDLServerState :: *DLClientState *DLServerState -> *DLServerState; 	
AddToDLServerState dl_client_state dl_server_state=:{dl_client_states}
	#! dl_server_state 
		= { dl_server_state &
			dl_client_states = [dl_client_state:dl_client_states]
		};
	= dl_server_state;

/*
ClientExistsInDLServerState :: !Int !*DLServerState -> !(!Bool,!*DLServerState);	
ClientExistsInDLServerState client_id dl_server_state=:{dl_client_states}
	#! (l,r)
		= splitAtPred f dl_client_states [] [];
	#! (l_empty,l)
		= is_empty l;

	// restore dl_server_state
	#! dl_server_state 
		= { dl_server_state &
			dl_client_states 
				= case l_empty of {
					True
						-> r;
					False
						-> [hd l:r];
				}
		};
	= (not l_empty,dl_server_state);
where {
	f dl_client_state=:{id}
		= (id == client_id,dl_client_state);
};		
*/	
RemoveFromDLServerState :: !ProcessSerialNumber !*DLServerState -> (!Bool,!*DLClientState,!*DLServerState);
RemoveFromDLServerState client_id dl_server_state=:{dl_client_states}
	#! (l,r)
		= splitAtPred f dl_client_states [] [];
	#! (l_empty,l)
		=  is_empty l;
	| not l_empty
		#! dl_server_state
			= { dl_server_state &
				dl_client_states	= r
			};
		= (True,hd l,dl_server_state);
		
		= (False,DefaultDLClientState,{dl_server_state & dl_client_states = r});
where {
	f dl_client_state=:{id}
		= (id == client_id,dl_client_state);
};	
	
// [dl_client_states]
acc_dl_client_states :: ([*DLClientState] -> (.x,[*DLClientState])) !*DLServerState -> (.x,!*DLServerState);
acc_dl_client_states f dl_server_state=:{dl_client_states}
	#! (x,dl_client_states)
		= f dl_client_states;
	= (x, {dl_server_state & dl_client_states = dl_client_states} );
	
app_dl_client_states :: ([*DLClientState] -> [*DLClientState]) !*DLServerState -> !*DLServerState;
app_dl_client_states f dl_server_state=:{dl_client_states}
	= {dl_server_state & dl_client_states = f dl_client_states};

// dl_client_states
selacc_client_state :: !ProcessSerialNumber (*DLClientState -> (.x,*DLClientState)) !*DLServerState -> (.x,!*DLServerState);
selacc_client_state client_id g dl_server_state=:{dl_client_states}
	#! (l,r)
		= splitAtPred f dl_client_states [] [];
	#! (l_empty,l)
		=  is_empty l;
	| not l_empty
		#! (x,l)
			= g (hd l);
		#! dl_server_state 
			= { dl_server_state &
				dl_client_states = [l:r]
			};
		= (x,dl_server_state);
where {
	f dl_client_state=:{id}
		= (id == client_id,dl_client_state);
};




selacc_app_linker_state :: !ProcessSerialNumber !(*State -> *(.a,*State)) !*DLServerState -> *(.a,*DLServerState);
selacc_app_linker_state client_id f dl_server_state
	#! (x,dl_server_state)
		= selacc_client_state client_id w dl_server_state;
	= (x,dl_server_state);
where {
	w dl_client_state=:{app_linker_state}
		#! (x,app_linker_state)
			= f app_linker_state;
		= (x, {dl_client_state & app_linker_state = app_linker_state});
};

MainLibrary	:== 0;
			
:: *DLClientState
	= { 
	// client identification
		id						:: !ProcessSerialNumber
	,	target					:: !Target
	,	cgpath					:: !String
	,	initial_link			:: !Bool
		
	// project settings
	,	project 				:: !Project
	,	updated					:: !Bool
	,	project_name			:: !String
	
	// application linker state
	,	app_linker_state		:: !*State
	
	,	aux_linker_states		:: *{#*State}
	
	// client window
	,	client_window			:: !ClientWindow
	
	// support for block dynamics (only one
	,	dynamic_ids				:: !*DynamicID

/*
	,	stringtable				:: !StringTable
	,	descriptor_usage_table	:: !DescriptorUsageTable
	,	version					:: !Version
*/	
	,	lib_link				:: !Bool
	
	// Library implementation
	,	cs_main_library_name	:: !String
	,	cs_type_tables			:: !*{#TypeTable}
//	,	cs_memory_state			:: [MemoryState]
	
	,	cs_dynamic_info			:: !*{#DynamicInfo}
	
	,	cs_library_instances		:: !*LibraryInstances	// all info specific to a library instance
	,	cs_main_library_instance_i	:: !Maybe !Int
	
	,	cs_intra_type_equalities	:: !*EqTypesState
	
	,	cs_type_implementation_table	:: *TypeImplementationTable
	
	,	cs_to_and_from_graph	:: !ToAndFromGraphTable	
	
	,	cs_n_fixed_available_types	:: !Maybe !Int
	
	,	do_dump_dynamic			:: !Bool
	
	,	cs_n_lazy_dynamics		:: !Int						// first free dynamic
	
	,	cs_lazy_dynamic_index_to_dynamic_id	:: !*{!Maybe !Int}		// indexed by lazy_dynamic_index (rt) with No meaning not initialized, Yes is initialized and dynamic id is the integer

	,	cs_share_runtime_system	:: !Bool
	};
	
instance DynamicIDs DLClientState
where {
	new_dynamic_id dl_client_state=:{dynamic_ids}
		# (id,dynamic_ids)
			= new_dynamic_id dynamic_ids;
		= (id,{dl_client_state & dynamic_ids = dynamic_ids});
		
	free_dynamic_id id dl_client_state=:{dynamic_ids}
		# dynamic_ids
			= free_dynamic_id id dynamic_ids;
		= {dl_client_state & dynamic_ids = dynamic_ids};
		
	is_valid_id id dl_client_state=:{dynamic_ids}
		# dynamic_ids
			= is_valid_id id dynamic_ids;
		= {dl_client_state & dynamic_ids = dynamic_ids};

	is_valid_id2 id dl_client_state=:{dynamic_ids}
		# (ok,dynamic_ids)
			= is_valid_id2 id dynamic_ids;
		= (ok,{dl_client_state & dynamic_ids = dynamic_ids});

};

acc_dynamic_ids :: (!*DynamicID -> (.x,!*DynamicID)) !*DLClientState -> (.x,!*DLClientState);
acc_dynamic_ids f dl_client_state=:{dynamic_ids}
	# (x,dynamic_ids)
		= f dynamic_ids;
	= (x,{dl_client_state & dynamic_ids = dynamic_ids});
	
/*
app_state ::  (!*State -> !*State) !*DLClientState -> !*DLClientState;
app_state f dl_client_state=:{app_linker_state}
	= { dl_client_state & app_linker_state = f app_linker_state };

*/
DefaultDLClientState :: !*DLClientState;
DefaultDLClientState
	= { 
	// client identification
		id					= DefaultProcessSerialNumber
	,	target				= emptyTarget
	,	cgpath				= ""
	,	initial_link		= False
		
	// project settings
	,	project 			= PR_InitProject
	,	updated				= False
	,	project_name		= ""
	
	// application linker state
	,	app_linker_state	= EmptyState
//	,	main_library_state	= default_library_state
	
	,	aux_linker_states	= {}
//	,	aux_library_states	= {}
	
	
	/*
		,	main_library_state		:: !*LibraryState
	
	,	aux_linker_states		:: !*{#*State}
	,	aux_library_states		:: !*{#*LibraryState}

	
	*/
		
	// to be eliminated; platform dependent
//	,	static_libraries	= []
	
	// client window
	,	client_window		= DefaultClientWindow
	
	// support for block dynamics
	,	dynamic_ids			= default_dynamic_id

/*
	,	stringtable			= {}
	,	descriptor_usage_table	= {}
	,	version				= DefaultVersion
*/

	// main {code,type}-lib
//	,	main_code_type_lib	= {}
	,	lib_link			= False
	
	// Library implementation
	,	cs_main_library_name	= {}
	,	cs_type_tables			= {}
//	,	cs_memory_state			= []
	,	cs_dynamic_info			= {}
	,	cs_library_instances	= default_library_instances
	,	cs_main_library_instance_i	= Nothing

	,	cs_intra_type_equalities	= default_eq_types_state
	,	cs_type_implementation_table = default_type_implementation_table
	,	cs_to_and_from_graph		= default_elemU
	,	cs_n_fixed_available_types	= Nothing
	
	,	do_dump_dynamic			= False
	,	cs_n_lazy_dynamics		= INITIAL_LAZY_DYNAMIC_INDEX
	,	cs_lazy_dynamic_index_to_dynamic_id	= createArray INITIAL_LAZY_DYNAMIC_INDEX Nothing
	,	cs_share_runtime_system	= False
	};
	
// ADDED
instance AddMessage DLClientState
where {
	AddMessage linker_message dl_client_state=:{app_linker_state}
		#! app_linker_state
			= AddMessage linker_message app_linker_state;
		= {dl_client_state & app_linker_state = app_linker_state};
		
	IsErrorOccured dl_client_state=:{app_linker_state}
		#! (ok,app_linker_state)
			= IsErrorOccured app_linker_state;
		= (ok,{dl_client_state & app_linker_state = app_linker_state});
		
	GetLinkerMessages dl_client_state=:{app_linker_state}
		#! (messages,app_linker_state)
			= GetLinkerMessages app_linker_state;
		= (messages,{ dl_client_state & app_linker_state = app_linker_state });
		
	SetLinkerMessages messages dl_client_state=:{app_linker_state}
		#! app_linker_state
			= SetLinkerMessages messages app_linker_state;
		= {dl_client_state & app_linker_state = app_linker_state};
};

// ClientWindows
import expand_8_3_names_in_path;

// ids
timer_id 	:== 0;
free_id		:== timer_id + 1;

openClientWindow :: !String !ProcessSerialNumber !*DLServerState !(IOState !*DLServerState) -> !(!*DLServerState,!(IOState !*DLServerState));
openClientWindow client_name client_id s io
	/*
	** - multiple clients lazily linked from same project file probably need different names
	*/		
	// get dl_client_state for client_id
	#! (ok,dl_client_state,s)
		= RemoveFromDLServerState client_id s;
	| not ok
		= abort "openClientWindow (internal error)";
	#! (client_window,dl_client_state)
		= dl_client_state!client_window;
	#! ({visible_window_ids},s)
		= s!global_client_window;

	// generate unique id for client window
	#! (dl_client_states,s)
		= acc_dl_client_states (\dl_client_states -> (dl_client_states,[])) s;
	#! (dl_client_states,ids)
		= collect_ids dl_client_states [] visible_window_ids;
	#! window_id
		= find_out_unique_window_id (sort ids) free_id;
		
	#! dl_client_state
		= { dl_client_state &
			client_window	= { client_window & client_window_id = window_id }
		};
	#! s
		= { s &
			dl_client_states = [dl_client_state:dl_client_states]
		};
	#! io
		= DEBUG_MODE io (OpenWindows [window_def window_id] io);
		

		
	= (s,io);
where {
	collect_ids [] l ids
		= (l,ids);
	collect_ids [dl_client_state:dl_client_states] l ids
		#! ({visible_client_window,client_window_id},dl_client_state)
			= dl_client_state!client_window;
		| not visible_client_window
			= collect_ids dl_client_states [dl_client_state:l] ids;	
			= collect_ids dl_client_states [dl_client_state:l] [client_window_id:ids];
		
	find_out_unique_window_id :: [Int] !Int -> !Int;	
	find_out_unique_window_id [] cnt
		= cnt;
	find_out_unique_window_id [a:aa] cnt
		| a < free_id
			= find_out_unique_window_id aa cnt;
			
		| a == cnt	
			= find_out_unique_window_id aa (inc cnt);
			= cnt;
		
	// Client window specification
	window_def window_id
		= ScrollWindow window_id window_pos window_title
			(ScrollBar (Thumb 0) (Scroll 4)) 
			(ScrollBar (Thumb 0) (Scroll 4))
			picture_domain
			minimum_window_size
			initial_window_size
			update_function
			[GoAway (go_awayClientWindow window_id client_id)];
			
	where {
		go_awayClientWindow window_id client_id s=:{global_client_window={visible_window_ids}} io
			| isMember window_id visible_window_ids
				// client has already been killed
				#! (global_client_window=:{visible_window_ids},s)
					= s!global_client_window;
				#! visible_window_ids 
					= filter (\visible_window_id -> window_id <> window_id) visible_window_ids;
				#! io
					= CloseWindows [window_id] io;
				#! s
					= { s &
						global_client_window = {global_client_window & visible_window_ids = visible_window_ids}	
					};	
				= (s,io);
				
				#! io
					= KillClient2 client_id io;
				= (s,io);
					
		(ascent,descent,_,leading)
			= FontMetrics monaco_font;
		line_height 
			= ascent + descent + leading;
			
		window_pos
			= (100,100);
		window_title
			= expand_8_3_names_in_path client_name;
	
		window_width
			= 1000;
		window_height
			= 100;	
		picture_domain
			= ((0,0),(min_client_width,min_client_height));
		minimum_window_size
			= initial_window_size; 
		initial_window_size
			= (min_client_width,min_client_height);

		update_function _ s 
			= (s,[]);		
	}
}

// UpdateFunction

// Global settings for client windows
monaco_font
	# (ok,font)=SelectFont /*"Monaco"*/ "Courier" [] 9;
	| ok
		= font;
		
instance toString LinkerMessage
where {
	toString (LinkerError msg)
		= "Error: " +++ msg;
	toString (LinkerWarning msg)
		= "Warning: " +++ msg;
	toString (Verbose msg)
		= msg;
};

min_client_width	:== 250;
min_client_height	:== 250;

pl []
	= "";
pl [x:xs]
	= toString x +++ (pl xs);

updateClientWindow :: !*DLServerState !(IOState *DLServerState) -> (!*DLServerState,!(IOState *DLServerState));
updateClientWindow s io
	// collect messages
	#! (dl_client_states,s)
		= acc_dl_client_states (\dl_client_states -> (dl_client_states,[])) s;
	#! (dl_client_states,messages)
		= collect_messages dl_client_states [] [];
	#! io
		= case length messages of {
				0
					-> io;
				1
					#! io
						= foldl draw_client_window io messages;
					-> io;
				_
					-> abort "meedere messages";
		};
	#! (s,io)
		= foldl change_picture_domain (s,io) messages;	
	= ({s & dl_client_states = dl_client_states},io);
where {
	change_picture_domain (s,io) (id_client_window,messages)
		#! (ascent,descent,_,leading)
			= FontMetrics monaco_font;
		#! line_height
			= ascent + descent + leading;
			
		// compute new picture domain
		#! height_picture_domain
			= max (length messages * line_height) min_client_height;
		#! width_picture_domain
			= max (foldl (\max_width msg -> max max_width (FontStringWidth (toString msg) monaco_font) ) 0 messages) min_client_width;
		= ChangePictureDomain id_client_window ((0,0),(width_picture_domain,height_picture_domain)) s io;
	
	draw_client_window io (id_client_window,messages)
		#! draw_functions
			= [SetFont monaco_font,draw_linker_messages messages (leading + ascent) (ascent + descent + leading)];
		#! io
			= ChangeUpdateFunction id_client_window (\_ s -> (s,draw_functions)) io;
			
		// under macOS: enforce a redraw of the (entire) window
		#! io
			= sel_platform io (DrawInWindow id_client_window draw_functions io);
		= io;
	where {
		(ascent,descent,_,leading)
			= FontMetrics monaco_font;
			
		draw_linker_messages [] y line_height picture
			= picture;
		draw_linker_messages [msg:msgs] y line_height picture
			#! picture
				= MovePenTo (0,y) picture;
		
			#! picture
				= DrawString (toString msg) picture;
			= draw_linker_messages msgs (y + line_height) line_height picture;
	}
	
	// collect all messages for windows that need to be updated
	collect_messages :: !*[*DLClientState] !*[*DLClientState] [(!Int,!LinkerMessages)] -> *(*[*DLClientState],[(Int,[LinkerMessage])]);
	collect_messages [] dl_client_states messages
		= (dl_client_states,messages);
	collect_messages [dl_client_state:dl_client_states] new_dl_client_states messages
		#! (messages0,dl_client_state)
			= GetLinkerMessages dl_client_state;
			
		#! (client_window=:{n_messages,visible_client_window,client_window_id},dl_client_state)
			= dl_client_state!client_window;
		| n_messages == (length messages0) || not visible_client_window
			= collect_messages dl_client_states [dl_client_state:new_dl_client_states] messages;
		
			#! dl_client_state
				= { dl_client_state &
					client_window	= { client_window & n_messages = length messages0 }
				};				
			= collect_messages dl_client_states [dl_client_state:new_dl_client_states] [(client_window_id,messages0):messages];
}

/*
	removeClientWindow
	
	Task:
	It registers the window id as occupied of the client being closed. The window id *cannot* be released because
	it might contain error messages which the user may want to see first.
	
	If, however no errors have occured, the window is closed immediately	
*/
removeClientWindow :: !*DLClientState !*DLServerState !(IOState *DLServerState) -> (!*DLServerState,!(IOState !*DLServerState));
removeClientWindow dl_client_state=:{id,client_window={client_window_id,visible_client_window}} s io
	#! (ok,dl_client_state)
		= IsErrorOccured dl_client_state
	| ok
		// no errors; just close the window
		/*
			perhaps the user should be given the chance to close the window herself because she may want
			to read warnings. For debugging purposes its perhaps the way to go.
		*/
		= closeClientWindow dl_client_state s io;
		
		// errors; window remains visible
		#! s
			= case visible_client_window of {
				True
					#! (global_client_window,s)
						= s!global_client_window;
					#! s
						= { s &
							global_client_window = { global_client_window & visible_window_ids = [client_window_id:global_client_window.visible_window_ids]}
						};
					-> s;
				False
					-> s;
			}
		= (s,io);
where {
	closeClientWindow dl_client_state=:{client_window} s io
		#! (client_window_id,client_window)
			= client_window!client_window_id;
		#! io
			= CloseWindows [client_window_id] io;
		= (s,io);
} // removeClientWindow

Ps []
	= "";
Ps [d:ds]
	= toString d +++ ", " +++ (Ps ds);
		
// 
HandleRequestResult :: (!Bool,!ProcessSerialNumber,!*DLServerState,(IOState !*DLServerState)) -> (!*DLServerState,IOState !*DLServerState);
HandleRequestResult (remove_state,client_id,s,io)
	// platform independent ...; check for errors
	#! ((messages,ok),s)
		= selacc_app_linker_state client_id get_error_and_messages s;
		
	// update client windows
	
	// als window nog niet geopened, dan openen
	#! (s,io)
		= updateClientWindow s io;

	// remove client if necessary
	#! (s,io)
		= case remove_state of {
			True
				#! (_,removed_dl_client_state,s)
					= RemoveFromDLServerState client_id s;
				#! (s,io)
					= removeClientWindow removed_dl_client_state s io;
				-> (s,io);
					
			False
				-> (s,io);
		};
		
	// check for error fatal for client application
	| not ok
		# io
			= abort ("!kk"  +++ (pr_linker_message messages "")) //KillClient2 client_id io;
		= (s,io);
		
		= (s,io);
where {
	
	get_error_and_messages state 
		#! (messages,state)
			= GetLinkerMessages state;		
		#! (ok,state)
			= IsErrorOccured state;
		= ((messages,ok),state);
} // HandleRequestResult

pr_linker_message [] s
	= s;
pr_linker_message [LinkerError x:xs] s
	# new_s = "LinkerError:\t " +++ x +++ "\n";
	= pr_linker_message xs (s +++ new_s);
pr_linker_message [LinkerWarning x:xs] s
	# new_s = "LinkerWarning:\t " +++ x  +++ "\n";
	= pr_linker_message xs (s +++ new_s);
pr_linker_message [Verbose x:xs] s
	# new_s = "Verbose:\t " +++ x  +++ "\n";
	= pr_linker_message xs (s +++ new_s);


/*
instance toString [a] | toString a
where {
	toString _ = abort "aa"
};
*/


// NEW
app_state ::  (!*State -> !*State) !*DLClientState -> !*DLClientState;
app_state f dl_client_state=:{app_linker_state}
	= { dl_client_state & app_linker_state = f app_linker_state };
	

acc_state ::  (!*State -> (!.x,!*State)) !*DLClientState -> !(!.x,*DLClientState);
acc_state f dl_client_state=:{app_linker_state}
	# (x,app_linker_state)
		= f app_linker_state;
	= (x,{dl_client_state & app_linker_state = app_linker_state});
	
class AppPdState s
where {
	app_pd_state :: !(*PDState -> !*PDState) !*s -> !*s
};

instance AppPdState DLClientState
where {
	app_pd_state f dl_client_state
		= app_state (\s=:{pd_state} -> {s & pd_state = f pd_state}) dl_client_state
};

instance AppPdState State
where {
	app_pd_state f state=:{pd_state}
		= {state & pd_state = f pd_state};
};

class AccPdState s
where {
	acc_pd_state :: !(*PDState -> (!.x,!*PDState)) !*s -> (!.x,!*s)
};

instance AccPdState State
where {
	acc_pd_state f state=:{pd_state}
		#! (x,pd_state)
			= f pd_state;
		= (x,{ state & pd_state = pd_state});
};

instance AccPdState DLClientState
where {
	acc_pd_state f dl_client_state=:{app_linker_state}
		#! (x,app_linker_state)
			= acc_pd_state f app_linker_state;
		= (x,{dl_client_state & app_linker_state = app_linker_state});
};

// --------------------------------------------------------------------------------------------------------------------------
// VERSION MANAGEMENT OF CONVERSION FUNCTIONS

:: ConvertFunctions = {
		graph_to_string :: [Version]
	,	string_to_graph :: [Version]
	};
	
default_convertfunctions :: !ConvertFunctions;
default_convertfunctions 
	= { ConvertFunctions |
		graph_to_string = []
	,	string_to_graph = []
	};
		
/*
** Two situations at the moment, looking for
** - an appropriate graph_to_string function (write)
**   The highest major and minor version are being used to store dynamics. 
** - an appropriate string_to_graph function (read)
**   The expected and required major version numbers *must* match. Because
**   minor version number stand for non-structural bugfixes, the highest
**   minor version is taken.
**
** The situation is different when using unique and/or lazy read and written
** dynamics. An unique dynamic should probably always be saved using the 
** major version used during storing of the dynamic, the minor could be the 
** most recent. This is also valid for a lazily read or written dynamic.
**
** The major version number is mainly for (large) structural changes to the
** conversion functions e.g. the arity of each function is stored in five
** bits, hence an arity of maximal 31 is the limit. This can be improved by
** making the reasonable assumption that a partial arity of 30 should be
** enough. The full arity whatever it is can then be represented by zero. In
** this case zero is interpreted differently, so a major version change is
** necessary.
** An example for minor change is a check that the arity of the function is
** smaller than the 31-limit. This change is minor because it does not affect
** the interpretation of the dynamic.
**
** hex ASCII representation of the 4 byte version number:
** 0	(msb): reserved e.g. flags for endianess, without pointers/with pointers, uniqueness or not
** 1 		 : major, higher part
** 2 		 : major, lower part
** 3		 : minor 
*/	

eager_read_version :: !Version !*DLClientState !*DLServerState -> (!Bool,!Version,!*DLClientState,!*DLServerState);	
eager_read_version {major=major_required} dl_client_state dl_server_state=:{convert_functions={string_to_graph}} 
	#! minors
		= filter (\{major} -> major == major_required) string_to_graph;
	| isEmpty minors
		#! msg
			= "No string_to_graph function with major version " +++ toString major_required +++ " present"
		#! dl_client_state
			= AddMessage (LinkerError msg) dl_client_state;
		= (False,DefaultVersion,dl_client_state,dl_server_state);
		
	// at least one minor present
	= (True,last minors,dl_client_state,dl_server_state);
	
eager_write_version :: !*DLClientState !*DLServerState -> (!Bool,!Version,!*DLClientState,!*DLServerState);	
eager_write_version dl_client_state dl_server_state=:{convert_functions={graph_to_string=[]}}
	= abort "eager_write_version; there are no conversion functions";

eager_write_version dl_client_state dl_server_state=:{convert_functions={graph_to_string}}
	= (True,last graph_to_string,dl_client_state,dl_server_state); 
	
/*
:: Version = {
		major	:: !Int
	,	minor	:: !Int
	};
	
DefaultVersion :: !Version;
DefaultVersion 
	= { 
		major	= 0
	,	minor	= 0
	};
	
toVersion :: !Int -> !Version;
toVersion version
	#! version
		= { Version |
			major	= (version >> 8) bitand 0x0000ffff
		,	minor	= version bitand 0x000000ff
		};
	= version;
	
fromVersion :: !Version -> !Int;
fromVersion {major,minor}
	= (major << 8) bitor minor;
*/

import ExtString;
import directory_structure;

GetDynamicLinkerDirectory :: !*DLServerState -> (!String,!*DLServerState);
GetDynamicLinkerDirectory dl_server_state=:{application_path}
	= (application_path +++ "\\" +++ DS_CONVERSION_DIR,dl_server_state);
	


InitServerState :: !*DLServerState (IOState !*DLServerState) -> (!*DLServerState,(IOState !*DLServerState));
InitServerState dl_server_state=:{convert_functions} io
	#! (dlink_dir,dl_server_state)
		= GetDynamicLinkerDirectory dl_server_state;
	#! ((ok,dlink_path),io)
		= accFiles (pd_StringToPath dlink_dir) io
	| not ok
		= abort "InitServerState: internal error 1";
			
	#! ((dir_error,dir_entries),io)
		= accFiles (getDirectoryContents dlink_path) io
	| dir_error <> NoDirError
		= abort "InitServerState: internal error 2";

	#! (graph_to_string,string_to_graph)
		= build_conversions dir_entries [] [];
	#! convert_functions
		= { convert_functions &
			graph_to_string = sortBy less_version graph_to_string 
		,	string_to_graph = sortBy less_version string_to_graph
		};
	#! dl_server_state
		= { DLServerState | dl_server_state &
			convert_functions 	= convert_functions
		};
	= (dl_server_state,io);
where {
	// smallest major and minor at start of the version list
	less_version {major=major1,minor=minor1} {major=major2,minor=minor2}
		| major1 < major2
			= True;
			| major1 == major2
				= minor1 < minor2;
				= False;

// foldSt
	build_conversions [] graph_to_string string_to_graph
		= (graph_to_string,string_to_graph);
	build_conversions [{fileName}:ds] graph_to_string string_to_graph
		#! (found,s_prefix)
			= starts copy_graph_to_string_0x fileName;
		| not found
			#! (found,s_prefix)
				= starts copy_string_to_graph_0x fileName;
			| not found
				= build_conversions ds graph_to_string string_to_graph;
				
				// a string_to_graph function found
				#! version
					= from_base_i fileName 16 s_prefix 8;
				= F fileName build_conversions ds graph_to_string [toVersion version:string_to_graph];
					
			// a graph_to_string function
			#! version
				= from_base_i fileName 16 s_prefix 8;
			= F fileName build_conversions ds [toVersion version:graph_to_string] string_to_graph;

	copy_graph_to_string_0x
		=> copy_graph_to_string +++ "_0x";
		
	copy_string_to_graph_0x
		=> copy_string_to_graph +++ "_0x";
}

instance TypeTableOps DLClientState
where {
	AddReferenceToTypeTable type_table_reference dl_client_state
		# (cs_type_tables,dl_client_state)
			= get_type_tables dl_client_state;
		# (type_table_index,cs_type_tables)
			= AddReferenceToTypeTable type_table_reference cs_type_tables;
		# dl_client_state
			= { dl_client_state &
				cs_type_tables = cs_type_tables
			};
		= (type_table_index,dl_client_state);
		
	AddTypeTable type_table_index type_table dl_client_state
		# (cs_type_tables,dl_client_state)
			= get_type_tables dl_client_state;
		# cs_type_tables
			= AddTypeTable type_table_index type_table cs_type_tables;
		# dl_client_state
			= { dl_client_state &
				cs_type_tables = cs_type_tables
			};
		= dl_client_state;			
};

get_type_tables :: !*DLClientState -> *(*{#*TypeTable},*DLClientState);
get_type_tables dl_client_state=:{cs_type_tables}
	= (cs_type_tables,{dl_client_state & cs_type_tables = {}});
	
get_ets :: !*DLClientState -> *(!*EqTypesState,*DLClientState);
get_ets dl_client_state=:{cs_intra_type_equalities}
	= (cs_intra_type_equalities,{dl_client_state & cs_intra_type_equalities = default_eq_types_state});

get_type_implementation_table :: !*DLClientState -> (!*TypeImplementationTable,!*DLClientState);
get_type_implementation_table dl_client_state=:{cs_type_implementation_table}
	= (cs_type_implementation_table,{dl_client_state & cs_type_implementation_table = default_type_implementation_table});

instance DynamicInfoOps DLClientState
where {
	UpdateDynamicInfo dynamic_info_index dynamic_info dl_client_state
		# (cs_dynamic_info,dl_client_state)
			= get_dynamic_infos dl_client_state;
		# cs_dynamic_info
			= UpdateDynamicInfo dynamic_info_index dynamic_info cs_dynamic_info
		# dl_client_state
			= { dl_client_state &
				cs_dynamic_info = cs_dynamic_info
			};
		= dl_client_state;			
};

get_dynamic_infos dl_client_state=:{cs_dynamic_info}
	= (cs_dynamic_info,{dl_client_state & cs_dynamic_info = {}});
		
instance Library_Instances DLClientState
where {
	AddLibraryInstance dynamic_index library_name type_table_i dl_client_state=:{cs_library_instances}
		# (library_instance_i,cs_library_instances)
			= AddLibraryInstance dynamic_index library_name type_table_i cs_library_instances;
		= (library_instance_i,{dl_client_state & cs_library_instances = cs_library_instances});
};

import ExtArray;
from type_io_common import PredefinedModuleName;
from utilities import foldSt;

print_type_implementation_table :: !*DLClientState -> !*DLClientState;
print_type_implementation_table dl_client_state
	# (n_type_implementations,dl_client_state)
		= dl_client_state!cs_type_implementation_table.teit_n_type_implementations;
	# dl_client_state
		= AddMessage (Verbose "Type Implementation Table (format: module_name<type_table_i,library_instance_i>)") dl_client_state;
	= loopAst print_type_implementation dl_client_state n_type_implementations;
where {
	print_type_implementation type_implementation_ref dl_client_state
		// get implementation type to be printed
		# ({tei_type_implementations,tei_chosen_type_implementation},dl_client_state)
			= dl_client_state!cs_type_implementation_table.teit_type_implementations_a.[type_implementation_ref];
			
		// get names
		# ((type_name,_,_,_,_),dl_client_state)
			= get_info_library_instance_type_reference (hd tei_type_implementations) dl_client_state;
			
		// determine the type implementation used, if any
		# (used_implementation,dl_client_state)
			= case tei_chosen_type_implementation of {
				Nothing
					-> ("No",dl_client_state);
				Just chosen_type
					# (chosen_type,dl_client_state)
						= get_info_library_instance_type_reference chosen_type dl_client_state;
					-> (make_module_name chosen_type,dl_client_state);
			};
			
		// convert equivalences to string
		# (type_equivalences_as_string,dl_client_state)
			= foldSt f tei_type_implementations ("",dl_client_state);
			
		# msg
			= toString type_implementation_ref +++ " (" +++ type_name +++ ","+++ used_implementation +++ "):" +++ type_equivalences_as_string;
		# dl_client_state
			= AddMessage (Verbose msg) dl_client_state;
			
		= dl_client_state;
			
		
		
		
		// 0: Tree; module_name<library_instance_i,type_table_i>; chosen: none		
	where {
		make_module_name (type_name,module_name,type_table_i,library_instance_i,tio_type_ref)
			= module_name +++ "<" +++ toString type_table_i +++ "," +++ toString library_instance_i +++ (make_string tio_type_ref) +++ ">";
		where {
			make_string {tio_type_without_definition,tio_tr_module_n,tio_tr_type_def_n}
				#! s1
					= if (isNothing tio_type_without_definition) "Nothing" ("Just " +++ fromJust tio_type_without_definition);
				#! s2
					= toString tio_tr_module_n
				#! s3
					= toString tio_tr_type_def_n
				= EXTEND_TYPE_INFO (" ! " +++ s1 +++ " " +++ s2 +++ " " +++ s3) "";
			
			/*
			::  TIO_TypeReference
	= {
		tio_type_without_definition  :: !Maybe !String
	,   tio_tr_module_n    			 :: !Int
	,   tio_tr_type_def_n  			 :: !Int
	}
			*/
			// TIO_TypeReference
		
		};
			
		f library_instance_type_reference (s,dl_client_state)
			# (type_info,dl_client_state)
				= get_info_library_instance_type_reference library_instance_type_reference dl_client_state;
			= (s +++ " " +++  make_module_name type_info,dl_client_state);
			
			
			
			
	};
 


};

// DLClientState
get_info_library_instance_type_reference (LIT_TypeReference library_instance_i tio_type_ref) dl_client_state
	# (type_table_i,dl_client_state)
		= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_type_table_i;
	# (type_name,module_name,dl_client_state)
		= get_names tio_type_ref type_table_i dl_client_state;
	= ((type_name,module_name,type_table_i,library_instance_i,tio_type_ref),dl_client_state);
where {
	get_names {tio_type_without_definition=Just type_name} type_table_i dl_client_state
		= (type_name,PredefinedModuleName,dl_client_state);
		
	get_names {tio_type_without_definition=Nothing,tio_tr_module_n,tio_tr_type_def_n} type_table_i dl_client_state
	    #! (string_table,dl_client_state)
	        = dl_client_state!cs_type_tables.[type_table_i].tt_type_io_state.tis_string_table;

		// get type name
	    #! (tio_td_name,dl_client_state)
	        = dl_client_state!cs_type_tables.[type_table_i].tt_tio_common_defs.[tio_tr_module_n].tio_com_type_defs.[tio_tr_type_def_n].tio_td_name;
		# type_name
			= get_name_from_string_table tio_td_name string_table;
	        
	     // get module name
	    #! (tio_module,dl_client_state)
	        = dl_client_state!cs_type_tables.[type_table_i].tt_tio_common_defs.[tio_tr_module_n].tio_module;
		# module_name
			= get_name_from_string_table tio_module string_table;
	     
		= (type_name,module_name,dl_client_state);
// TIO_CommonDefs
// DLClientState
};
	
	
/*
get_type_name :: !TIO_TypeReference !String !*{#TIO_CommonDefs} -> (!String,!*{#TIO_CommonDefs});
get_type_name {tio_tr_module_n,tio_tr_type_def_n} tis_string_table tio_common_defs
    #! (tio_td_name,tio_common_defs)
        = tio_common_defs[tio_tr_module_n].tio_com_type_defs.[tio_tr_type_def_n].tio_td_name;
    #! (null_index_found,null_index)
        = CharIndex tis_string_table tio_td_name '\0';
    | not null_index_found
        = abort "get_type_name: internal error";
        
    # type_name
        = tis_string_table % (tio_td_name,dec null_index);
    = (type_name,tio_common_defs);
*/	
/*
:: TypeImplementation
	= {
		tei_type_implementations		:: [LibraryInstanceTypeReference]
	,	tei_chosen_type_implementation	:: Maybe LibraryInstanceTypeReference
	};

loopAst f s limit :== loopAst 0 limit f s 
where {
	loopAst i limit f s
		| i == limit
			= s;
			
			#! s
				= f i s;
			= loopAst (inc i) limit f s;
}
*/
	
get_from_graph_function_address2 :: (!Maybe !Version) !*DLClientState -> (ToAndFromGraphEntry,ToAndFromGraphEntryIndex,!*DLClientState);
get_from_graph_function_address2 maybe_version dl_client_state
	#! (cs_to_and_from_graph,dl_client_state)
		= get_cs_to_and_from_graph dl_client_state;
	#! (x1,x2,cs_to_and_from_graph)
		= get_from_graph_function_address maybe_version cs_to_and_from_graph;
	#! dl_client_state
		= { dl_client_state &
			cs_to_and_from_graph = cs_to_and_from_graph
		};
	= (x1,x2,dl_client_state);
	
	

get_cs_to_and_from_graph dl_client_state=:{cs_to_and_from_graph}
	= (cs_to_and_from_graph,{dl_client_state & cs_to_and_from_graph = default_elemU});


instance symbol_n_to_offset DLClientState
where {
	symbol_n_to_offset file_n symbol_n dl_client_state
		#! (symbol_index,dl_client_state)
			= acc_state (\state -> symbol_n_to_offset file_n symbol_n state) dl_client_state;
		= (symbol_index,dl_client_state);
};

check_whether_implementation_is_available :: !Int !String !*DLClientState -> (!Bool,!*DLClientState);
check_whether_implementation_is_available library_instance_i label_name dl_client_state
	#! (bool,_,dl_client_state)
		= check_whether_implementation_is_available2 library_instance_i label_name dl_client_state;
	= (bool,dl_client_state);


check_whether_implementation_is_available2 :: !Int !String !*DLClientState -> (!Bool,!Maybe !(!Int,!Int),!*DLClientState);
check_whether_implementation_is_available2 library_instance_i label_name dl_client_state
	#! (li_library_initialized,dl_client_state)
		= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_library_initialized;
	| not li_library_initialized
		#! dl_client_state
			= dl_client_state // <<- (label_name,False);

		= (False,Nothing,dl_client_state);
	#! (maybe_file_n_symbol_n,dl_client_state)
		= findLabel label_name library_instance_i dl_client_state;
	| isNothing maybe_file_n_symbol_n
		#! dl_client_state
			= dl_client_state // <<- (label_name,False);
		= (False,Nothing,dl_client_state);
		
	#! (file_n,symbol_n)
		= fromJust maybe_file_n_symbol_n;
	#! (maybe_address,dl_client_state)
		= isLabelImplemented file_n symbol_n dl_client_state;
		#! dl_client_state
			= dl_client_state // <<- (label_name,True,isJust maybe_address,maybe_address);

	= (isJust maybe_address,maybe_file_n_symbol_n,dl_client_state);

findLabel :: !String !Int !*DLClientState -> (!Maybe !(!Int,!Int),!*DLClientState);
findLabel label_name library_instance_i dl_client_state
	#! (names_table_element,dl_client_state)
		= find_symbol_in_symbol_table_new label_name (\index dl_client_state -> dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_names_table.[index]) dl_client_state;
	#! label_name_found
		= get names_table_element;
	= (label_name_found,dl_client_state);
where {
	get (NamesTableElement _ symbol_n file_n _)
		= Just (file_n,symbol_n);
	get _
		= Nothing;
};

isLabelImplemented :: !Int !Int !*DLClientState -> (!Maybe !Int,!*DLClientState);
isLabelImplemented file_n symbol_n dl_client_state
	#! (first_symbol_n,dl_client_state)
		= dl_client_state!app_linker_state.marked_offset_a.[file_n];
	#! (marked,dl_client_state)
		=  dl_client_state!app_linker_state.marked_bool_a.[first_symbol_n+symbol_n];
	| not marked
		= (Nothing,dl_client_state);
		
	#! (symbol_address,dl_client_state)
		= acc_state (address_of_label2 file_n symbol_n) dl_client_state;
	= (Just symbol_address,dl_client_state);

isTypeImplemented :: !LibraryInstanceTypeReference !*DLClientState -> (!Maybe !(!String,[String]),*DLClientState);
isTypeImplemented library_instance_type_reference dl_client_state
//	#! dl_client_state
//		= dl_client_state <<- "-------------";
//	= isTypeImplemented2 allSt library_instance_type_reference dl_client_state;
//NEW2
	= isTypeImplemented2 allSt library_instance_type_reference dl_client_state;

isAnyConstructorOfTypeImplemented :: !LibraryInstanceTypeReference !*DLClientState -> (!Maybe !(!String,[String]),*DLClientState);
isAnyConstructorOfTypeImplemented library_instance_type_reference dl_client_state
//	#! dl_client_state
//		= dl_client_state <<- "**************";

	= isTypeImplemented2 anySt library_instance_type_reference dl_client_state;

from type_io_common import UnderscoreSystemModule;
import predefined_types;

isTypeImplemented2 all_or_any (LIT_TypeReference library_instance_i tio_type_reference=:{tio_type_without_definition=Nothing}) dl_client_state
	#! (li_type_table_i,dl_client_state)
		= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_type_table_i;
	#! (type_name,labels_implementing_type,dl_client_state)
		= get_type_label_names tio_type_reference li_type_table_i  dl_client_state;
	#! dl_client_state
		= dl_client_state //<<- ("isTypeImplemented2",labels_implementing_type);
	#! (implementation_is_available,dl_client_state)
		= all_or_any (check_whether_implementation_is_available library_instance_i) labels_implementing_type dl_client_state;	
//		= anySt (check_whether_implementation_is_available library_instance_i) labels_implementing_type dl_client_state;
	| implementation_is_available // <<- ("isTypeImplemented", implementation_is_available, "any=", any_implementation_is_available, library_instance_i, labels_implementing_type)
		#! dl_client_state
			= dl_client_state <<- ("isTypeImplemented2",labels_implementing_type);

		= (Just (type_name,labels_implementing_type),dl_client_state);
		= (Nothing,dl_client_state);


isTypeImplemented2 _ (LIT_TypeReference library_instance_i tio_type_reference=:{tio_type_without_definition=Just type_name}) dl_client_state
	#! (li_type_table_i,dl_client_state)
		= dl_client_state!cs_library_instances.lis_library_instances.[library_instance_i].li_type_table_i;
	#! (type_name,labels_implementing_type,dl_client_state)
		= get_type_label_names tio_type_reference li_type_table_i  dl_client_state;
	= (Just (type_name,labels_implementing_type),dl_client_state);

get_type_label_names :: !TIO_TypeReference !Int !*DLClientState -> (!String,[String],!*DLClientState);
get_type_label_names {tio_type_without_definition=Just type_name} type_table_i dl_client_state
	#! list
		= filter (\{pt_type_name} -> type_name == pt_type_name) PredefinedTypes;
	| isEmpty list
		= abort ("get_type_label_names; internal error; unknown predefined type '" +++ type_name +++ "'");

	#! pt_constructor_names
		= map (\label_name -> gen_label_name True (label_name,UnderscoreSystemModule) '?') (hd list).pt_constructor_names;
	= (type_name,pt_constructor_names,dl_client_state);
	
get_type_label_names type_def=:{tio_tr_module_n,tio_tr_type_def_n} type_table_i dl_client_state
	#! (string_table_i,dl_client_state)
		= dl_client_state!cs_type_tables.[type_table_i].tt_type_io_state.tis_string_table;
	#! (tio_module,dl_client_state)
		= dl_client_state!cs_type_tables.[type_table_i].tt_tio_common_defs.[tio_tr_module_n].tio_module;
	#! module_name
		= get_name_from_string_table tio_module string_table_i;
		
	// list with constructor names
	#! ({tio_td_name,tio_td_rhs},dl_client_state)
		= dl_client_state!cs_type_tables.[type_table_i].tt_tio_common_defs.[tio_tr_module_n].tio_com_type_defs.[tio_tr_type_def_n];
	#! type_name
		= get_name_from_string_table tio_td_name string_table_i;
	#! (label_names,dl_client_state)
		= case tio_td_rhs of {
			(TIO_AlgType defined_symbols)
				-> foldSt (generate_algebraic_type_label_names module_name string_table_i) defined_symbols ([],dl_client_state);
			TIO_RecordType {tio_rt_fields}
				// Hoe kom ik erachter of het record type een index heeft
				-> generate_record_label module_name string_table_i type_name tio_rt_fields dl_client_state;
			TIO_SynType _
				| True <<- ("get_type_label_names; elimination of synonym types should still be done")
				-> ([],dl_client_state); //abort "syntype";
			s
				| True <<- (s,type_name)
				-> abort "lsdfklsfdksdk" <<- s;
		};
//	| True <<- ("labels", label_names)
	= (type_name,label_names,dl_client_state);
where {
	generate_record_label module_name string_table_i record_descriptor_name tio_rt_fields dl_client_state
//		#! record_descriptor_name
//			= get_name_from_string_table tio_td_name string_table_i;

		#! (is_strict_record,dl_client_state)
			= mapASt is_strict_field tio_rt_fields (False,dl_client_state);

		#! r_prefixed_label
			= gen_label_name True (record_descriptor_name,module_name) 'r';
		| is_strict_record // <<- (record_descriptor_name)
			// strict
			#! t_prefixed_label
				= gen_label_name True (record_descriptor_name,module_name) 't';
			#! c_prefixed_label
				= gen_label_name True (record_descriptor_name,module_name) 'c';
			= ([r_prefixed_label,t_prefixed_label,c_prefixed_label],dl_client_state);
			
			// non strict record
			= ([r_prefixed_label],dl_client_state);
	where {
		is_strict_field {tio_fs_index} s=:(True,dl_client_state)
			= s;
		is_strict_field {tio_fs_index} (is_strict_record,dl_client_state)
			#! ({tio_st_result={tio_at_annotation}},dl_client_state)
				= dl_client_state!cs_type_tables.[type_table_i].tt_tio_common_defs.[tio_tr_module_n].tio_com_selector_defs.[tio_fs_index].tio_sd_type;
			#! is_strict_field
				= case tio_at_annotation of {
					TIO_AN_Strict	-> True;
					_				-> False;
				};
			= (is_strict_record || is_strict_field,dl_client_state);
	};
	

// anySt :: (.a -> .(.b -> (.Bool,.b))) [.a] .b -> (.Bool,.b);

//		| True <<- tio_cons_type
//		= abort ("algtype " +++ constructor_name) <<- tio_cons_type;
	
/*
TIO_RecordType

::	TIO_RecordType =
	{
		tio_rt_fields			:: !{# TIO_FieldSymbol}
	}
	
::	TIO_FieldSymbol =
	{	tio_fs_name			:: !Int
	,	tio_fs_var			:: !Int				// ?
	,	tio_fs_index		:: !TIO_Index
	}
	
:: TIO_SelectorDef = 
	{ 
		tio_sd_type				:: !TIO_SymbolType
	}

::	TIO_SymbolType =
	{	tio_st_vars			:: [TIO_TypeVar]
	,	tio_st_args			:: [TIO_AType]
	,	tio_st_arity		:: !Int
	,	tio_st_result		:: !TIO_AType
	}
*/

	generate_algebraic_type_label_names module_name string_table_i {tio_ds_ident,tio_ds_index} (label_names,dl_client_state)
		#! constructor_name
			= get_name_from_string_table tio_ds_ident string_table_i;
	
		#! (tio_cons_type=:{tio_st_args},dl_client_state)
			= dl_client_state!cs_type_tables.[type_table_i].tt_tio_common_defs.[tio_tr_module_n].tio_com_cons_defs.[tio_ds_index].tio_cons_type;
		#! is_strict_constructor
			= any is_strict_constructor tio_st_args;
		#! d_prefixed_label
			= gen_label_name True (constructor_name,module_name) 'd';
		| is_strict_constructor // <<- constructor_name
			// strict
			#! k_prefixed_label
				= gen_label_name True (constructor_name,module_name) 'k';
			#! n_prefixed_label
				= gen_label_name True (constructor_name,module_name) 'n';
//			#! l_prefixed_label
//				= gen_label_name True (constructor_name,module_name) 'l';

			#! label_names
				= [k_prefixed_label,d_prefixed_label,n_prefixed_label/*,l_prefixed_label*/:label_names];
			=  (label_names,dl_client_state);

			// non-strict
			#! label_names
				= [d_prefixed_label:label_names];
			=  (label_names,dl_client_state);
	where {
		is_strict_constructor {tio_at_annotation=TIO_AN_Strict}
			= True;
		is_strict_constructor _
			= False;
	};

}

acc_library_instances :: .(*LibraryInstances -> *(.a,*LibraryInstances)) !*DLClientState -> *(.a,*DLClientState);
acc_library_instances f dl_client_state=:{cs_library_instances}
	# (x,cs_library_instances)
		= f cs_library_instances;
	= (x,{dl_client_state & cs_library_instances = cs_library_instances});
	
acc_lis_library_instances :: .(*{#*LibraryInstance} -> *(.a,*{#*LibraryInstance})) !*LibraryInstances -> *(.a,*LibraryInstances);
acc_lis_library_instances f cs_library_instances=:{lis_library_instances}
	# (x,lis_library_instances)
		= f lis_library_instances;
	= (x,{cs_library_instances & lis_library_instances = lis_library_instances} );
	
acc_library_instance :: .(*{!NamesTableElement} -> *(.a,*{!NamesTableElement})) !*LibraryInstance -> *(.a,*LibraryInstance);	
acc_library_instance f library_instance=:{li_names_table}
	# (x,li_names_table)
		= f li_names_table;
	= (x,{library_instance & li_names_table = li_names_table});

acc_names_table :: !Int !*DLClientState -> *(.{!NamesTableElement},*DLClientState);	
acc_names_table library_instance_i dl_client_state
	= acc_library_instances (\library_instances -> acc_lis_library_instances select_library_instance library_instances) dl_client_state;
where {
	select_library_instance library_instances 
		# (library_instance,library_instances)
			= replace library_instances library_instance_i default_library_instance;
			
		# (x,library_instance)
			= acc_library_instance (\nt -> (nt,{})) library_instance;
		# library_instances
			= { library_instances & [library_instance_i] = library_instance };
		= (x,library_instances); 
}

instance findImplementationType DLClientState
where {
	findImplementationType litr dl_client_state
		# (type_implementation_table,dl_client_state)
			= get_type_implementation_table dl_client_state;
		# (is_type_equation,type_implementation_ref,type_implementation_table)
			= findImplementationType litr type_implementation_table;
		# dl_client_state
			= { dl_client_state &
				cs_type_implementation_table	= type_implementation_table
			};
		= (is_type_equation,type_implementation_ref,dl_client_state);
};

print_type_table_reference :: !Int !TIO_TypeReference !{#*TypeTable} -> (!String,{#*TypeTable});
print_type_table_reference type_table_i {tio_tr_module_n,tio_tr_type_def_n,tio_type_without_definition=Nothing} type_tables
	#! (string_table_i,type_tables)
		= type_tables![type_table_i].tt_type_io_state.tis_string_table;
	#! (tio_td_name,type_tables)
		= type_tables![type_table_i].tt_tio_common_defs.[tio_tr_module_n].tio_com_type_defs.[tio_tr_type_def_n].tio_td_name;
	#! type_name
		= get_name_from_string_table tio_td_name string_table_i;
	= (type_name,type_tables);
print_type_table_reference type_table_i {tio_type_without_definition=Just type_name} type_tables
	= (type_name,type_tables);
	
get_lazy_dynamic_index_to_dynamic_id :: !*DLClientState -> *(!*{!Maybe !Int},!*DLClientState);
get_lazy_dynamic_index_to_dynamic_id dl_client_state=:{cs_lazy_dynamic_index_to_dynamic_id}
	= (cs_lazy_dynamic_index_to_dynamic_id,{dl_client_state & cs_lazy_dynamic_index_to_dynamic_id = {} });
