io_prefixed_lines_defaults( Defs ) :-
	Defs = [
			starts_key(upper_case_n_codes_and_spaces_m(2,3)),
			starts_continuation(spaces_n(5))
			].

/** io_prefixed_lines( +Lines, -ParsedKVs, +Opts ).

Parse prefixed lines into KV pairs. 

Lines are nested code lists, that look like 

AA   Seom text
     more text for AA
BB   my own text

Which should be parsed to
	['AA'-[`Seom text`,`more text for AA`],'BB'-[`my own text`]]

Opts 
 * starts_key(StK=upper_case_n_codes_and_spaces_m(2,3))
   predicate for identifying keys
 * starts_continuation(StC=spaces_n(5)
   predicate for identifying continuation of a value line

@author nicos angelopoulos
@version  0.1 2015/10/06
@see maps_unip_seqs/0.

*/
io_prefixed_lines( [], [], _Args ) :- !.
io_prefixed_lines( Lines, KVs, Args ) :-
	Self = io_prefixed_lines,
	options_append( Self, Args, Opts ),
	options( [starts_key(KeyG),starts_continuation(CntG)], Opts ),
	Lines = [HLine|_], 
	atom_codes( Hatom, HLine ),
	debug( io_prefixed_lines, 'doing section starting with: ~w', [Hatom] ),
	io_prefixed_lines_goals( Lines, KeyG, CntG, '', [], KVs ).

io_prefixed_lines_goals( [], _KeyG, _CntG, Key, Acc, KVs ) :-
	( Acc == [] -> KVs = []; reverse( Acc, Val ), KVs = [Key-Val] ),
	!.
io_prefixed_lines_goals( [H|T], KeyG, CntG, Key, Acc, KVs ) :-
	io_prefixed_line( H, KeyG, CntG, Key, Acc, NxtKey, Cont, KVs, TKVs ),
	io_prefixed_lines_goals( T, KeyG, CntG, NxtKey, Cont, TKVs ).

io_prefixed_line( Line, KeyG, _CntG, Key, Acc, NxtKey, Cnt, KVs, TKVs ) :-
	call( KeyG, Line, NxtKey, Val ),
	!,
	( (Key=='',Acc==[]) -> 
		KVs = TKVs
		;
		reverse( Acc, Rev ),
		KVs = [Key-Rev|TKVs]
	),
	Cnt = [Val].
io_prefixed_line( Line, _KeyG, CntG, Key, Acc, NxtKey, Cnt, KVs, TKVs ) :-
	call( CntG, Line, Val ),
	!,
	Cnt = [Val|Acc],
	NxtKey = Key, 
	KVs = TKVs.
io_prefixed_line( Line, _KeyG, _CntG, _Key, _Acc, _NxtKey, _Cont, _KVs, _TKvs ) :-
	atom_codes( Atom, Line ),
	throw( cannot_parse(Atom) ).

upper_case_n_codes_and_spaces_m( N, M, Line, Key, ValCs ) :-
	length( KeyCs, N ),
	append( KeyCs, Rem1Cs, Line ),
	maplist( is_upper_case_code, KeyCs ),
	findall( Spc, (between(1,M,_),Spc=0' ), Spcs ),
	append( Spcs, ValCs, Rem1Cs ),
	atom_codes( Key, KeyCs ),
	!.
	
spaces_n( N, Line, ValCs ) :-
	findall( Spc, (between(1,N,_),Spc=0' ), Spcs ),
	append( Spcs, ValCs, Line ),
	!.

is_upper_case_code( Code ) :-
	0'A =< Code, Code =< 0'Z.