% $Id: intarray.pl,v 1.1 2006/12/04 18:54:07 nunomorgadinho Exp $

:- initialization(init).

% include the pm2 interface lib
:- include('lib').

size(8).

determine(Size):-
  argument_counter(2),
  argument_list(Args),
  append([SizeString|_], [], Args),
  write_to_chars(Chars, SizeString),
  number_chars(Size, Chars).
  
determine(Size):-
  size(Size),
  write('Searching for '),write(Size),write('.'),nl.

start_prolog_workers(0):- !. % on master dont start
start_prolog_workers(VP):-
  % thread_create(+Goal, +VP, -Id)
  thread_create(_, VP, _),
  VP1 is VP - 1,
  start_prolog_workers(VP1).

stop_prolog_workers(0):- !. % on master dont stop
stop_prolog_workers(VP):-
  thread_send_message(vid(VP,0), unlock),
  VP1 is VP - 1,
  stop_prolog_workers(VP1).

test_prolog_workers(0):- !. % on master dont do it
test_prolog_workers(VP):-
  thread_send_message(vid(VP,0), teste),
  VP1 is VP - 1,
  test_prolog_workers(VP1).

read_test(0):- !. % on master dont do it
read_test(VP):-
  thread_get_message(X),
  VP1 is VP - 1,
  read_test(VP1).

% thread 0
init:-
  pm2_is_master,!,
  pm2_max_rank(MaxRank),
  
  determine(El),
    
  % Start_Prolog(0, 0) on each node
  start_prolog_workers(MaxRank),

  see('/home/nm/devel/tabard-0.1/input.txt'),
  read_chunk(El, 1000, MaxRank, NumberSentMessages),
  read_results(NumberSentMessages, Num),
  write(Num),nl, % number of total occurrences
  
%  test_prolog_workers(MaxRank),      %%% for t(0) uncomment
%  read_test(MaxRank),                %%% for t(0) uncomment

  stop_prolog_workers(MaxRank),
  
  finish_listeners.

% thread != 0
init:-
  spawn(sleep, ['1']),
  worker_work.

init.

% -------------------------------------------------------------------

worker_work:-
  pm2_self(Rank),
  thread_get_message(Termo),
  !, trick(Termo, X), !,
%  write('Worker '),write(Rank),write(' -> '),
%  write(Termo), write(','), write(X), nl,
  thread_send_message(vid(0,0), X),
  !, worker_work.

% -------------------------------------------------------------------

read_results(X, N):-
  read_results(X, 0, N).

read_results(0, N, N):-!.
read_results(X, Acc, N):-
        thread_get_message(Msg),
        Acc1 is Acc + Msg,
%        write('Master -> '),write(Msg),nl,
        X1 is X - 1,
        !, read_results(X1, Acc1, N).

% -----------------------------------------------------------------------

trick(unlock, ok).
trick(teste, ok).

trick(q(X,List), 0):-
  repeat(100, number_of_occurences(X, List, _)).

repeat(0):-!,fail.
repeat(_).
repeat(N):- N1 is N-1, repeat(N1).

repeat(N, G):-
  repeat(N), G, fail.
repeat(_, _).



number_of_occurences(X, L, N):-
  number_of_occurences(X, L, 0, N).

number_of_occurences(_, [], Acc, Acc):-!.                    
number_of_occurences(X, [Y|Ys], Acc, N):-
  X \= Y,
  number_of_occurences(X, Ys, Acc, N).
                     
number_of_occurences(X, [X|Xs], Acc, N):-
  Acc1 is Acc + 1,
  number_of_occurences(X, Xs, Acc1, N).


read_chunk(El, ChunkSize, Rank, N):-
  read_chunk(El, ChunkSize, Rank, 0, N).



read_chunk(El, ChunkSize, 0, Acc, N):-
  pm2_max_rank(MaxRank),
  !, read_chunk(El, ChunkSize, MaxRank, Acc, N).

% read_chunk(+ChunkSize) reads ChunkSize numbers from input to a list
read_chunk(El, ChunkSize, Rank, Acc, N):-
  read_lista(ChunkSize, ChunkList),
  length(ChunkList, ChunkSize),
  ChunkList \= [],
  thread_send_message(vid(Rank, 0), q(El, ChunkList)),  % envia a um worker
  NextRank is Rank - 1,
  Acc1 is Acc + 1,
  read_chunk(El, ChunkSize, NextRank, Acc1, N).

read_chunk(_, _, _, N, N).

% se for int mete numa lista
read_lista(N, [X|R]):-
  N > 0,
  read_token(X),
  integer(X),
  read_token(_), % le a virgula
  N1 is N - 1,
  read_lista(N1, R).
% otherwise nao
read_lista(_, []).
