implementation module ExtArray;

import StdDynamicDefaultElem;
import StdArray;
import SymbolTable;
import StdMaybe;

//1.3
from StdClass import ==, inc, +, one;
//3.1
/*2.0
import StdEnv;
0.2*/

mapASt f a s :== map_a_st 0 (size a) f a s
where {
	map_a_st i limit f a s
		| i == limit
			= s;
			= map_a_st (inc i) limit f a (f a.[i] s);
}; 

// S = for start
mapAiStS f a s start :== map_a_st start (size a) f a s
where {
	map_a_st i limit f a s
		| i == limit
			= s;
			= map_a_st (inc i) limit f a (f i a.[i] s);
}; 

// A = array, i = index, St = state
mapAiSt f a s :== map_a_st 0 (size a) f a s
where {
	map_a_st i limit f a s
		| i == limit
			= s;
			= map_a_st (inc i) limit f a (f i a.[i] s);
}; 

findAiSt p a s :== map_a_st 0 (size a) p a s
where {
	map_a_st i limit p a s
		| i == limit
			= s;
			
			# (ok,s)
				= (p i a.[i] s)
			| ok
				= s
				= map_a_st (inc i) limit p a s;
}; 

findAi p a :== map_a_st 0 (size a) p a
where {
	map_a_st i limit p a
		| i == limit
			= Nothing;
			
			# r
				= p i a.[i]
			| isNothing r
				= map_a_st (inc i) limit p a;
				= r

}; 
 
findAieu p a :== map_a_st2 p a
where {
	map_a_st2 p a
		#! (s_a,a)
			= usize a;
		= map_a_st 0 s_a p a;
	
	map_a_st i limit p a
		| i == limit
			= (Nothing,a);
			
			# (elem,a)
				= a![i];
			# r
				= p i elem
			| isNothing r
				= map_a_st (inc i) limit p a;
				= (r,a);
}; 

findAieuSE p start end a :== map_a_st2 p a
where {
	map_a_st2 p a
		= map_a_st start end p a;
	
	map_a_st i limit p a
		| i == limit
			= (Nothing,a);
			
			# (elem,a)
				= a![i];
			# r
				= p i elem
			| isNothing r
				= map_a_st (inc i) limit p a;
				= (r,a);
}; 

loopA f a s :== loop2 f s a
where
{
	loop2 f s a
		#! (s_a,a)
			= usize a;
		= loop 0 s_a a s f;
		 
	loop i limit a s f
		| i == limit
			= (a,s)
			
			#! (e,a)
				= a![i];
			#! s
				= f e s;
			= loop (inc i) limit a s f;
}

class ExtArrayDefaultElem .e
where
{
	ExtArrayDefaultElem :: !.e
};

//1.3
instance ExtArrayDefaultElem !(* /*S*/Xcoff)
//3.1
/*2.0
instance ExtArrayDefaultElem Xcoff
0.2*/
where {
	ExtArrayDefaultElem = empty_xcoff
};

//1.3
instance ExtArrayDefaultElem !Bool
//3.1
/*2.0
instance ExtArrayDefaultElem Bool
0.2*/
where {
	ExtArrayDefaultElem = False
};

//1.3
instance ExtArrayDefaultElem !Int
//3.1
/*2.0
instance ExtArrayDefaultElem Int
0.2*/
where {
	ExtArrayDefaultElem :: !.Int;
	ExtArrayDefaultElem = 0
};

//1.3
instance ExtArrayDefaultElem !Symbol
//3.1
/*2.0
instance ExtArrayDefaultElem Symbol
0.2*/
where {
	ExtArrayDefaultElem :: !.Symbol;
	ExtArrayDefaultElem = EmptySymbol
};

// class array uitbreiden met default element
loopAur f a s :== loop2 f s a
where {
	loop2 f s a
		#! (s_a,a)
			= usize a;
		= loopQ 0 s_a a s f;
	
	loopQ i limit a s f
		| i == limit
			= (a,s);
			
			#! (e,a)
				= replace a i ExtArrayDefaultElem;
			#! (e,s)
				= f e s;
			#! a
				= { a & [i] = e};
			= loopQ (inc i) limit a s f;
}

loopAfill f a s:== loop2 f a s
where {
	loop2 f a s
		#! (s_a,a)
			= usize a;
		= loop 0 s_a a s f;
		 
	loop i limit a s f
		| i == limit
			= (a,s)
			
			#! (a,s)
				= f i a s;
			= loop (inc i) limit a s f;
}	

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;
}

findAst f s limit :== loopAst 0 limit f s 
where {
	loopAst i limit f s
		| i == limit
			= (Nothing,s);
			
			#! (result,s)
				= f i s;
			| isNothing result
				= loopAst (inc i) limit f s;
				= (result,s);

}

// map
// A = on arrays
// e = f gets as first argument element at index i
// i = f gets as 2nd arg current array index
// a = f gets as 3rd arg the array
// u = assumes array unique but its elements not
mapAeiauSt f a s:== loop2 f a s
where {
	loop2 f a s
		#! (s_a,a)
			= usize a;
		= loop 0 s_a a s f;
		 
	loop i limit a s f
		| i == limit
			= (a,s)
			
			#! (element,a)
				= a![i];
			#! (a,s)
				= f element i a s;
			= loop (inc i) limit a s f;
}

// extend array with non-unique elements
//1.3
extend_array_nu :: !Int *(a b) -> (!Int,*(a b)) | ArrayElem, DefaultElem b & Array a;
//3.1
/*2.0
extend_array_nu :: .Int .(a b) -> (Int,.(c b)) | Array c b & Array a b & DefaultElem b;
0.2*/
extend_array_nu n_new_elements a 
	# (s_a,a)
		= usize a;
	# s_new_a
		= s_a + n_new_elements;
	# new_a
		= createArray s_new_a default_elem;
	# new_a
		= { new_a & [i] = a.[i]  \\ i <- [0..dec s_a] };
	= (dec s_new_a,new_a);
