/* -*- Mode: Prolog -*- */
/** @copyright
  
  This file is part of PrologDoc (http://prologdoc.sourceforge.net/).

  Copyright (C) 2004 by Salvador Fandino (sfandino@@yahoo.com)

  PrologDoc is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  PrologDoc is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with PrologDoc; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  
  @/copyright */

:- module(pd_util, [ line_feeds/3,
		     n_lines/2,
		     n_lines1/2,
		     at_line/3,
		     line/3,
		     atom_to_term/2,
		     report_syntax_error/4,
		     la_get/2,
		     las_get/2,
		     la_get/3,
		     la_check/2,
		     la_set/3,
		     la_reset/3,
		     las_reset/3,
		     la_select/3,
		     las_select/3,
		     ea_get/2,
		     eas_get/2,
		     ea_get/3,
		     ea_check/2,
		     ea_set/3,
		     ea_reset/3,
		     eas_reset/3,
		     ea_select/3,
		     ea_prepend/3,
		     ea_append/3,
		     la_push/3,
		     la_pop/3,
		     bind_vars/1,
		     unique_id/2 ]).

line_feeds([0'\n|L]) --> "\n", !, line_feeds(L).
line_feeds(L) --> [_], !, line_feeds(L).
line_feeds([]) --> [].

n_lines(T, L) :-
	line_feeds(LF, T, []),
	length(LF, L).
n_lines1(T, L) :-
	n_lines(T, L1),
	L is L1 + 1.

at_line(T, Where, L) :-
	append(Here, Where, T),
	n_lines1(Here, L).

line([]) --> "\n", !, [].
line([H|M]) --> [H], !, line(M).
line([]) --> [].

report_syntax_error(File, Text, Remains, Msg) :-
	at_line(Text, Remains, Line),
	line(Here1, Remains, _),
	atom_codes(Here, Here1),
	concat_atom(['syntax_error'|Msg], ': ', Error),
	format(user_error, '~p at ~p line ~p~nHERE -->>~p~n', [Error, File, Line, Here]),
	abort.

atom_to_term(A, T) :-
	atom_to_term(A, T, B),
	bind_vars(B).

bind_vars([]).
bind_vars([V=N|More]) :-
	V=N,
	bind_vars(More).

la_get(Args, Key=Value) :-
	member(Key=Value, Args),
	!.

ea_get(t(_, Args, _), KV) :-
	la_get(Args, KV).

las_get(_, []) :-
	!.
las_get(Args, [KV|More]) :-
	la_get(Args, KV),
	las_get(Args, More).

eas_get(t(_, Args,_), KVs) :-
	las_get(Args, KVs).

la_get(Args, Key=Value, Default) :-
	(   member(Key=Value, Args)
	->  true
	;   Value=Default ).

ea_get(t(_, Args, _), KV, Default) :-
	la_get(Args, KV, Default).

la_check(Args, KV) :-
	(   la_get(Args, KV)
	->  true
	;   throw(arg_missing(Args, KV)) ).

ea_check(E, KV) :-
	(   ea_get(E, KV)
	->  true
	;   throw(arg_missing(E,KV)) ).

la_set(Args, Key=Value, [Key=Value|Args]) :-
	(   member(Key=_, Args)
	->  throw(arg_already_exists(Args, Key=Value))
	;   true ).

ea_set(t(Name, Args, Childs), Key=Value, t(Name, [Key=Value|Args], Childs)) :-
	(   member(Key=_, Args)
	->  throw(arg_already_exists(t(Name, Args, Childs), Key=Value))
	;   true ).

la_reset(Args, Key=Value, [Key=Value|Args1]) :-
	delete(Args, Key=_, Args1).

ea_reset(t(N, Args, C), KV, t(N, Args1, C)) :-
	la_reset(Args, KV, Args1).

las_reset(Args, [], Args) :-
	!.
las_reset(Args, [KV|More], Args1) :-
	la_reset(Args, KV, Args2),
	las_reset(Args2, More, Args1).

eas_reset(t(N, A, C), KVs, t(N, A1, C)) :-
	las_reset(A, KVs, A1).

la_select(Args, K=V, Rest) :-
	select(K=V, Args, Rest).

las_select(Args, [], Args) :-
	!.
las_select(Args, [K=V|More], Rest) :-
	select(K=V, Args, Rest1),
	las_select(Rest1, More, Rest).
	
ea_select(t(N, Args, C), K=V, t(N, Rest, C)) :-
	select(K=V, Args, Rest).
	
ea_prepend(t(N, Args, C), KV, t(N, [KV|Args], C)).

ea_append(t(N, Args, C), KV, t(N, Args1, C)) :-
	append(Args, [KV], Args1).


la_push(A, K=V, [K=V|A]) :-
	(   select(K=O, A, R)
	->  la_push(R, 'S'(K)=O, A2)
	;   A2 = A ).

la_pop(A, K=V, A1) :-
	(   select(K=V, A, R)
	->  (   la_pop(R, 'S'(K)=O, R1)
	    ->	A1 = [K=O|R1]
	    ;	A1 = R ) ).

unique_id(Base, Id) :-
	term_to_atom(Base, S),
	unique_id(S, S, 1, Id).

:- dynamic used_id/1.

unique_id(Base, Try, I, Id) :-
	(   used_id(Try)
	->  I1 is I + 1,
	    concat_atom([Base, '-', I1], Try1),
	    unique_id(Base, Try1, I1, Id)
	;   Id = Try,
	    assert(used_id(Try)) ).

