:- module(io,[
  io_read_int/1,io_read_double/1,
  io_read_ints/1,io_read_doubles/1,
  io_write_int/1,io_write_double/1,
  io_write_ints/1,io_write_doubles/1,
  io_read_chars/2,io_write_chars/2]).

ctype_num(C,N) :-
  ( C >= 48
  -> ( C =< 57
     -> N=1
     ; N=0
     )
     ; N=0
  ).

ctype_sign(C,N) :-
  ( C = 43
  -> N=1
  ; ( C = 45
    -> N=1
    ; N=0
    )
  ).

ctype_dot(C,N) :-
  ( C = 46
  -> N=1
  ; N=0
  ).

strchp_nums([],M,R,B) :- M=B, R=[].
strchp_nums([C|Cr],M,R,B) :- 
  ctype_num(C,N),
  ( N = 1
  -> strchp_nums(Cr,M,R,[C|B])
  ; M=B, R=[C|Cr]
  ).

strchp_sign([],M,R,B) :- M=B, R=[].
strchp_sign([C|Cr],M,R,B) :-
  ctype_sign(C,N),
  ( N = 1
  -> M=[C|B], R=Cr
  ; M=B, R=[C|Cr]
  ).

strchp_dot([],M,R,B) :- M=B, R=[].
strchp_dot([C|Cr],M,R,B) :-
  ctype_dot(C,N),
  ( N = 1
  -> M=[C|B], R=Cr
  ; M=B, R=[C|Cr]
  ).

strchp_int([],M,R,B) :- M=B, R=[].
strchp_int(C,M,R,B) :- strchp_sign(C,M1,R1,B), strchp_nums(R1,M,R,M1).

strchp_float([],M,R,B) :- M=B, R=[].
strchp_float(C,M,R,B) :- strchp_sign(C,M1,R1,B), strchp_nums(R1,M2,R2,M1), strchp_dot(R2,M3,R3,M2), strchp_nums(R3,M,R,M3).

io_read_int(I) :- read_line_to_codes(current_input,C), strchp_int(C,M,_,[]), reverse(M,Mr), number_codes(I,Mr).

build_ints([],L,A) :- L=A.
build_ints([_],L,A) :- L=A.
build_ints([_|R],L,A) :- strchp_int(R,M,Rr,[]),
  ( M = []
  -> build_ints(R,L,A)
  ; reverse(M,Mr), number_codes(I,Mr), build_ints(Rr,L,[I|A])
  ).

build_doubles([],L,A) :- L=A.
build_doubles([_],L,A) :- L=A.
build_doubles([_|R],L,A) :- strchp_float(R,M,Rr,[]),
  ( M = []
  -> build_doubles(R,L,A)
  ; reverse(M,Mr), number_codes(D,Mr), build_doubles(Rr,L,[D|A])
  ).

io_read_ints(L) :- read_line_to_codes(current_input,C), build_ints([0|C],Lr,[]), reverse(Lr,L).

io_read_double(D) :- read_line_to_codes(current_input,C), strchr_float(C,M,_,[]), reverse(M,Mr), number_codes(D,Mr).

io_read_doubles(L) :- read_line_to_codes(current_input,C), build_doubles([0|C],Lr,[]), reverse(Lr,L).

io_write_int(I) :- write(I), nl.

io_write_double(D) :- write(D), nl.

do_writes(_,[]).
do_writes(_,[E]) :- write(E).
do_writes(S,[E1,E2|L]) :- write(E1), write(S), do_writes(S,[E2|L]).

io_write_ints(L) :- do_writes(' ',L), nl.

io_write_doubles(L) :- do_writes(' ',L), nl.

char_code_list([],[]).
char_code_list([A|Ar],[B|Br]) :- 
  ( integer(A)
  -> B=A
  ; char_code(A,B)
  ), char_code_list(Ar,Br).

build_chars(_,[],R,C) :- R=C.
build_chars(A,[E|L],R,C) :- 
  ( nth0(I,A,E)
  -> build_chars(A,L,R,[I|C])
  ; build_chars(A,L,R,C)
  ).

io_read_chars(L,A) :- char_code_list(A,Ac), read_line_to_codes(current_input,C), build_chars(Ac,C,Lr,[]), reverse(Lr,L).

do_write_chars(_,[]).
do_write_chars(A,[E|L]) :- nth0(E,A,C), write(C), do_write_chars(E,L).

io_write_chars(L,A) :- do_write_chars(A,L), nl.
