/* ================================= MANAGE COUNTERS ======================== */

:- module(
          counter, 
          [
            check_count_exists_value/1,
            check_count_exists_value/2,

            check_count_exists/0,
            check_count_exists/1,

            exists_count/0,
            exists_count/1,

            delete_count/0,
            delete_count/1,

            reset_count/0, 
            reset_count/1,

            reset_count_value/1,
            reset_count_value/2,

            read_count/1, 
            read_count/2, 

            get_count/1, 
            get_count/2, 

            count_down/0,
            count_down/1,

            incr_count/0,
		      incr_count/1,  

     	   n_times/1,
		   n_times/2
           ]
		 ).

/* ================================== MANAGE A COUNTER ====================== */

	/* check whether a counter exists, and create if it does not with a
      specific initial value */
check_count_exists_value(Value) :-
   \+ exists_count,
   !,
   reset_count_value(Value).

check_count_exists_value(_).

	/* check whether a counter exists, and create if it does not */
check_count_exists :-
   \+ exists_count,
   !,
   reset_count.

check_count_exists.


exists_count :-
   current_predicate(count/1).


delete_count :-
   retractall(count(_)).


reset_count :-
    delete_count,
    assert(count(0)),
    !.

	/* create a new cout with Initial_value as first value */
reset_count_value(Initial_value) :-
   delete_count,
   assert(count(Initial_value)),
   !.


read_count(X) :-
	count(X).


get_count(C) :-
    count(X),
    delete_count,
    C is X+1,
    assert(count(C)),
    !.


count_down :-
    count(X),
    delete_count,
    C is X-1,
    assert(count(C)),
    !.  
    

incr_count :-
    count(X),
    delete_count,
    C is X+1,
    assert(count(C)),
    !.          

/* ============================= COUNTER WITH A KEY ========================= */

	/* check whether a counter exists, and create if it does not with a
      specific initial value*/
check_count_exists_value(Key, Value) :-
   \+ exists_count(Key),
   !,
   reset_count_value(Key, Value).

check_count_exists_value(_, _).


	/* check whether a counter exists, and create if it does not */
check_count_exists(Key) :-
   \+ exists_count(Key),
   !,
   reset_count(Key).

check_count_exists(_).


exists_count(_Key) :-
   \+ current_predicate(count/2),
   !,
   false.

exists_count(Key) :-
   count(Key,_).


delete_count(Key) :-
   retractall(count(Key,_)).
   

reset_count(Key) :-
    delete_count(Key),
    assert(count(Key, 0)),
    !.

		/* create a new cout with Initial_value as first value */
reset_count_value(Key, Initial_value) :-
   delete_count(Key),
   assert(count(Key, Initial_value)),
   !.

read_count(Key,X) :-
	count(Key,X).

get_count(Key,C):-
    count(Key,X),
    delete_count(Key),
    C is X+1,
    assert(count(Key,C)),
    !.

count_down(Key):-
    count(Key,X),
    delete_count(Key),
    C is X-1,
    assert(count(Key,C)),
    !.       	
     
    
incr_count(Key) :-
    count(Key, X),
    delete_count(Key),
    C is X+1,
    assert(count(Key,C)),
    !.    
    
/* ====================== MANAGE A FIX NUMBER OF CHOICE POINTS =============== */   

n_times(0) :-
   !.
   
n_times(N) :-
   length(L, N),
   member(_, L).   


n_times(0, _Goal) :-
   !.

n_times(N, Goal) :-
   n_times(N),
   Goal,
   fail.
   
n_times(_, _).
   
   
/* ============================== END OF LISTING ============================ */    
    
