implementation module shared_buffer

import StdEnv

import memory_mapped_files

import memory

import StdDynamicLowLevelInterface
import DefaultElem

instance BinaryDynamicIO (!Int,!*StdDynamicSharedBufferInfo)
where
	bd_readi (ptr,mem)
		# (word,mem)
			= readWord1 ptr mem
		= (True,word,(ptr + 4,mem))

	bd_reads (ptr,mem) n_characters
		# string
			= createArray n_characters ' '
		# (ptr,string,mem)
			= bd_reads_loop 0 ptr string mem
		= (string,(ptr,mem))
	where
		// kan veel efficienter
		bd_reads_loop i ptr string mem
			| i == n_characters
				= (ptr,string,mem)
			# (c,mem)
				= readByte1 ptr mem
			= bd_reads_loop (inc i) (inc ptr) {string & [i] = toChar c} mem
			
	bd_seek (_,buffer=:{view}) offset FSeekSet
		= (True,(view + offset ,buffer))
		
	bd_delta_fp file
		= (0,file)
		
	bd_freadsubstring i n s (ptr,mem)
		#! (s_s,s)
			= usize s;
		#! (new_offset,s,mem)
			= bd_read_substring i s_s s ptr mem
		= (new_offset - ptr,s,(new_offset,mem));
	where
		bd_read_substring :: !Int !Int !*{#Char} !Int !*StdDynamicSharedBufferInfo -> (!Int,!*{#Char},!*StdDynamicSharedBufferInfo);
		bd_read_substring i s_s s offset mem
			| i >= s_s
				= (offset,s,mem);
		
			#! (c,mem)
				= readByte1 offset mem
			= bd_read_substring (inc i) s_s {s & [i] = toChar c} (inc offset) mem;

:: *StdDynamicSharedBufferInfo
	= {
		hfile	:: !HFILE
	,	hmap	:: !HANDLE
	,	view	:: !Int
	};
	
instance DefaultElemU StdDynamicSharedBufferInfo
where
	default_elemU
		= {
			hfile	= default_elem
		,	hmap	= default_elem
		,	view	= default_elem
		}

// ATTENTION:
// The first 2 words of a dynamic are overwritten by a pointer to the string descriptor and
// the length of the string. The header_size 
CreateSharedBufferFromFile2 :: !Int !String -> (Bool,(!Int,!*StdDynamicSharedBufferInfo),(!Int,!Int))
CreateSharedBufferFromFile2 dynamic_rts_process_handle file_name
	// open file
	# (file_handle,st)
		= CreateFile (file_name +++ "\0") GENERIC_READ FILE_SHARE_READ NULL OPEN_EXISTING  FILE_ATTRIBUTE_NORMAL 0 initialState
	| file_handle == INVALID_HANDLE_VALUE
		= abort "CreateSharedBuffer: CreateFile failed"

	# (file_size,st)
		= GetFileSize file_handle NULL st
	| file_size == 0xFFFFFFFF 
		= abort "CreateSharedBuffer: GetFileSize"	
	
	// create file mapping
	# (file_mapping_handle,st)
		= CreateFileMapping file_handle NULL PAGE_READONLY 0 0 NULL st
	| file_mapping_handle == 0
		= abort ("CreateSharedBuffer: CreateFileMapping failed" +++ toString GetLastError)		

	// map view of file
	# (view,st)
		= MapViewOfFile file_mapping_handle FILE_MAP_READ 0 0 0 st
	| view == 0
		= abort "CreateSharedBuffer: MapViewOfFile"	

	# (current_process_handle,st)
		= GetCurrentProcess st

	// duplicate handle to that string to dynamic rts
	# (a,st)
		= address_of_buffer st;
	# (bool,st)
		= DuplicateHandle current_process_handle file_mapping_handle dynamic_rts_process_handle (Ptr a) 0 0 DUPLICATE_SAME_ACCESS st
	| bool == 0
		= abort ("copy_to_dynamic_rts: failure of DuplicateHandle" +++ toString GetLastError)
	# (file_mapping_handle_in_server,st)
		= readWord1 a st;

	# stdDynamic_shared_buffer_info
		= {	hfile	= file_handle
		,	hmap	= file_mapping_handle
		,	view	= view
		};		
	# file
		= (0,stdDynamic_shared_buffer_info)
	| CloseST st
		= (True,file,(file_mapping_handle_in_server,file_size));
//	= (True,file,toString file_mapping_handle_in_server +++ "\n" +++ toString file_size)

CreateSharedBufferFromFile :: !Int !String -> (Bool,(!Int,!*StdDynamicSharedBufferInfo),!String)
CreateSharedBufferFromFile dynamic_rts_process_handle file_name
	#! (ok,file,(file_mapping_handle_in_server,file_size))
		= CreateSharedBufferFromFile2 dynamic_rts_process_handle file_name;
	= (True,file,toString file_mapping_handle_in_server +++ "\n" +++ toString file_size);

OpenExistingSharedBuffer2 :: (!Int,!Int) -> (Bool,(!Int,!*StdDynamicSharedBufferInfo))
OpenExistingSharedBuffer2 (file_mapping_handle,s_buffer)
	= OpenExistingSharedBuffer file_mapping_handle s_buffer;

OpenExistingSharedBuffer :: !Int !Int -> (Bool,(!Int,!*StdDynamicSharedBufferInfo))
OpenExistingSharedBuffer file_mapping_handle s_buffer
	# (view,st)
		= MapViewOfFile file_mapping_handle FILE_MAP_READ 0 0 s_buffer initialState
	| view == 0
		= abort ("OpenExistingSharedBuffer: MapViewOfFile failed" +++ toString GetLastError)
	# stdDynamic_shared_buffer_info
		= {	hfile	= 0
		,	hmap	= file_mapping_handle
		,	view	= view
		};
	# file = (0,stdDynamic_shared_buffer_info)
	= (True,file);

CloseExistingSharedBuffer :: !(!Int,!*StdDynamicSharedBufferInfo) -> Bool
CloseExistingSharedBuffer (_,{hmap,view})
	# st = initialState
	# (bool,st)
		= UnmapViewOfFile view st
	| bool == 0
		= abort ("get_tables_from_dynamic; could not close view" +++ toString GetLastError);	
	# (bool,st)
		= CloseHandle hmap st
	| bool == 0
		= abort "get_tables_from_dynamic; could not close view"
	= CloseST st

CloseSharedBufferFromFile :: (!Int,!*StdDynamicSharedBufferInfo) -> Bool
CloseSharedBufferFromFile (_,{hfile,hmap,view})
	#! (bool,st)
		= UnmapViewOfFile view initialState
	| bool == 0
		= abort "CloseSharedBufferFromFile; failure of CloseSharedBufferFromFile"

	# st = initialState		
	# (bool,st)
		= CloseHandle hmap st
	| bool == 0
		= abort "CloseSharedBufferFromFile; failure of CloseHandle (1)"
		
	# (bool,st)
		= CloseHandle hfile st
	| bool == 0
		= abort "CloseSharedBufferFromFile; failure of CloseHandle (2)"

	= CloseST st

CreateSharedBufferFromPageFile :: !Int !String -> (Bool,(!Int,!*StdDynamicSharedBufferInfo),!String)
CreateSharedBufferFromPageFile dynamic_rts_process_handle dynamic_as_string
	# file_size = size dynamic_as_string
	// create file mapping
	# (file_mapping_handle,st)
		= CreateFileMapping 0xFFFFFFFF NULL PAGE_READWRITE 0 file_size NULL initialState
	| file_mapping_handle == 0
		= abort ("CreateSharedBufferFromPageFile: CreateFileMapping failed" +++ toString GetLastError)		
	
	// map view of file
	# (view,st)
		= MapViewOfFile file_mapping_handle FILE_MAP_WRITE 0 0 file_size st
	| view == 0
		= abort "CreateSharedBufferFromPageFile: MapViewOfFile failed"

	# (current_process_handle,st)
		= GetCurrentProcess st

	// duplicate handle to that string to dynamic rts
	# (a,st)
		= address_of_buffer st;
	# (bool,st)
		= DuplicateHandle current_process_handle file_mapping_handle dynamic_rts_process_handle (Ptr a) 0 0 DUPLICATE_SAME_ACCESS st
	| bool == 0
		= abort "copy_to_dynamic_rts: failure of DuplicateHandle"
	# (file_mapping_handle_in_server,st)
		= readWord1 a st;
		
	# st
		= copy_string 0 file_size dynamic_as_string view st
	| CloseST st
//		= abort (toString (call_debugger view));

	# stdDynamic_shared_buffer_info
		= {	hfile	= 0
		,	hmap	= file_mapping_handle
		,	view	= view
		};		
	# file = (0,stdDynamic_shared_buffer_info)
//	| CloseST st
	= (True,file,toString file_mapping_handle_in_server +++ "\n" +++ toString file_size)		
where
	copy_string :: !Int !Int !String !Int !ST -> ST;
	copy_string i limit dynamic_as_string view st
		#! rest
			= limit rem 4
		#! st
			= copy_string_per_word i (limit - rest) dynamic_as_string view st
		#! st
			= copy_string_per_byte (limit-rest) limit dynamic_as_string view st
		= st		
	where
		copy_string_per_word :: !Int !Int !String !Int !ST -> ST;
		copy_string_per_word i limit dynamic_as_string view st
			| i >= limit
				= st 
			# v
				= FromStringToInt dynamic_as_string i
			= copy_string_per_word (i + 4) limit dynamic_as_string view (writeWord1 v (view + i) st)
			
			
		copy_string_per_byte :: !Int !Int !String !Int !ST -> ST;
		copy_string_per_byte i limit dynamic_as_string view st
			| i == limit
				= st
			= copy_string_per_byte (inc i) limit dynamic_as_string view  (writeByte1 dynamic_as_string.[i] (view + i) st)

CloseSharedBufferFromPageFile :: (!Int,!*StdDynamicSharedBufferInfo) -> Bool
CloseSharedBufferFromPageFile (_,{hmap,view})
	#! (bool,st)
		= UnmapViewOfFile view initialState
	| bool == 0
		= abort "CloseSharedBufferFromFile; failure of CloseSharedBufferFromFile"

	# st = initialState		
	# (bool,st)
		= CloseHandle hmap st
	| bool == 0
		= abort "CloseSharedBufferFromFile; failure of CloseHandle (1)"
		
	= CloseST st
	
FromStringToInt :: !String !Int -> Int
FromStringToInt array i
	= (toInt v0)+(toInt v1<<8)+(toInt v2<<16)+(toInt v3<<24)
where
	v0= array.[i]
	v1
		= array.[i+1]
	v2 
		= array.[i+2]
	v3  
		= array.[i+3]

/*
CreateSharedBufferFromPageFile :: !String -> (Bool,(!Int,!*{#Char}),!String,!*StdDynamicSharedBufferInfo)
CreateSharedBufferFromPageFile string
	# s_buffer
		= size string
		
	// create shared clean string
	# (file_mapping_handle,st)
		= CreateFileMapping 0xFFFFFFFF NULL PAGE_READWRITE 0 s_buffer (Ptr "zomaar\0") initialState
	| file_mapping_handle == 0
		= abort ("CreateSharedBufferFromPageFile: CreateFileMapping failed" +++ toString GetLastError)		


	# (view,st)
		= MapViewOfFile file_mapping_handle FILE_MAP_WRITE 0 0 s_buffer st
	| view == 0
		= abort "CreateSharedBufferFromPageFile: MapViewOfFile failed"
		
	# (buffer,st)
		= CreateSharedString view s_buffer st
		
	# (current_process_handle,st)
		= GetCurrentProcess st
	# (dynamic_rts_process_handle,st)
		= GetHandleToServer st

	// duplicate handle to that string to dynamic rts
	# (bool,st)
		= DuplicateHandle current_process_handle file_mapping_handle dynamic_rts_process_handle (Ptr (view + 8)) 0 0 DUPLICATE_SAME_ACCESS st
	| bool == 0
		= abort "copy_to_dynamic_rts: failure of DuplicateHandle"
	| CloseST st
	# (handle_to_shared_string_in_dynamic_rts,buffer)
		= FromStringToIntU buffer 0;
		
		
	# buffer 
		= copy_string 8 s_buffer string 0 buffer

/*		
	# (s_buffer,buffer)
		= usize buffer
	| s_buffer <> 0
	
	= abort (toString (call_debugger  view))
*/


	# stdDynamic_shared_buffer_info
		= {
			hfile	= 0
		,	hmap	= file_mapping_handle
		,	view	= view
		};
	= (True,(0,buffer),toString handle_to_shared_string_in_dynamic_rts +++ "\n" +++ toString s_buffer,stdDynamic_shared_buffer_info)
where 
	copy_string i limit src j dest
		| i == limit
			= dest
		= copy_string (inc i) limit src (inc j) {dest & [j] = src.[i] }
		
CloseSharedBufferFromPageFile :: !*StdDynamicSharedBufferInfo -> Bool
CloseSharedBufferFromPageFile {hmap,view}
/*
	#! (bool,st)
		= UnmapViewOfFile view initialState
	| bool == 0
		= abort "CloseSharedBufferFromFile; failure of CloseSharedBufferFromFile"
*/
	# st = initialState		
	# (bool,st)
		= CloseHandle hmap st
	| bool == 0
		= abort "CloseSharedBufferFromFile; failure of CloseHandle (1)"
	= CloseST st
*/	
call_debugger :: !Int -> Int
call_debugger _
	= code {
		instruction 204
	}

GetHandleToServer :: !ST -> (!HANDLE,!ST)
GetHandleToServer st
	= (GetHandleToServer2,st)

GetHandleToServer2 :: HANDLE;
GetHandleToServer2 
	= code {
		ccall GetHandleToServer ":I"
	}
		
FromStringToIntU :: !*{#Char} !Int -> (!Int,!*{#Char});
FromStringToIntU array i
	#! (v0,array)
		= array![i];
	#! (v1,array)
		= array![i+1];
	#! (v2,array)
		= array![i+2];
	#! (v3,array)
		= array![i+3];
	#! i
		= (toInt v0)+(toInt v1<<8)+(toInt v2<<16)+(toInt v3<<24);
	= (i,array);
	
WriteLong :: !*{#Char} !Int !Int -> *{#Char};
WriteLong array i v
	= { array & [i] 	= (toChar v)		,	[i+1] = (toChar (v>>8)),
				[i+2]	= (toChar (v>>16))  ,	[i+3] = (toChar (v>>24))};
