-module(regExprGen).
-export([manager/0,state/2,create/1]).

% Module for automata for regular languages on {a,b,c}.
%
% Each state is a process. Many strings can be parsed in parallel. 
%
% create : creates an automaton together with its manager. Returns the PID of the manager. 
%          An automaton is described by a list of quadruple, each quadruple describe the next state for, respectively,
%          a,b or c and whether the state is a final one (by means of the atoms final or notfinal).
%          In case of no next state for a character, the atom none is used. 
%          States in the list are denoted by integers form 0 to n, 0 denoting the initial state. 
%          Example: 
%          The automaton corresponding to the regular expression abc*+c(bb)*
%          has the following transition table.
%              a    b   c       Final States = q2, q3
%           0  1        3       < notfinal
%           1       2           < notfinal
%           2           2       < final
%           3       4           < final
%           4       3           < notfinal
%          
%           The list of quadruples representing the above table is the following one:
%
%           [{1,none,3,notfinal},{none,2,none,notfinal},{none,none,2,final},{none,4,none,final},{none,3,none,notfinal}]
%
%
%          
%          A parsing request can be sent to the manager by means of a triple {requestParsing,ID,List}
%          where ID is the PID of whom makes the request, and List is the string to be parsed.
%
%          For sake of simplicity a string is represented by a list of atoms that represents characters.
%
%          The manager sends the request to the initial state and receives the answer that is then
%          delivered to whom made the request. 
%          The original string to be parsed is kept through all the parsing process and sent back with the 
%          answer in order one can send onother request even before one gets the answer of the previous request. 
%
% manager : It is the function corresponding to the manager of the automaton.
%          Once spawned by the create function, the manager waits for the address of the initial state, 
%          that the create function itself sends to it (This procedures is a simple trick necessary since
%          the manager and the initial state need the PID of each other.)
%
% state   : It is the function corresponding to a state. Its arguments are the PID of the manager
%           and one atom (final or nofinal) representing whether the spawned state is final or not.
%           Once spawned by the create function, a state waits for a triple of PIDs
%           corresponding, respectively, to the states it has to be connected to for the characters a, b, or c.
%           In case a state is not connected to another state for a particular character (and hence the
%           string has to be rejected), the corresponding element in the triple is the atom none instead of a PID.
%           (As for the manager, this trick is needed in order to have automata with cliques.          
%
%           




% The lists:zip function is a predefined one in Erlang.
% We rewrite it here for sake of simplicity in case someone did not know it.

myzip([],[])   -> [];
myzip([H1|T1],[H2|T2]) -> [{H1,H2}|myzip(T1,T2)]. 



% The predefined function lists:nth(N,L) returns the N-th element of the list L 
% Here, in mynth, we need to take care that N could be the atom none and that we counts the states starting form 0.

mynth(N,L) -> if 
                 (N==none) -> none;
                 true      -> lists:nth(N+1,L)
             end.



create(List) ->          %%we create the manager and the (process-)states. The PID of manager is returned.

                      IDmanager = spawn(exprReg,manager,[]),
                      States    = [spawn(exprReg,state,[IDmanager,Final]) || {_,_,_,Final} <- List], 

                      %%we connect the manager to the initial state and the various states among themselves
                      %%according to the transition table

                      [QInit|_] = States,
                      IDmanager!QInit,
                      [IDQ!{mynth(NA,States),mynth(NB,States),mynth(NC,States)} || {IDQ,{NA,NB,NC,_}} <- myzip(States,List) ],
                      IDmanager.
                      


manager() -> receive
               IDinitial -> loopmanager(IDinitial)
             end.                       
                   

loopmanager(IDinitial) ->
             
               receive

                   {requestParsing,ID,List} -> IDinitial ! {List,ID,List};
                                               
                   {accepted,ID,List}       -> ID ! {accepted,List};

                   {rejected,ID,List}       -> ID ! {rejected,List}

               end,
             
               loopmanager(IDinitial).




                    


state(IDmanager,Final) -> receive
                             {IDA,IDB,IDC} -> loop(IDA,IDB,IDC,IDmanager,Final) 
                          end. 




 loop(IDA,IDB,IDC,IDmanager,Final) ->
           
         
         receive

              {[],ID,List}          ->    if 
                                             (Final == final)  -> IDmanager ! {accepted,ID,List};
                            
                                              true             -> IDmanager ! {rejected,ID,List}
                     
                                          end;

              {[ Char | Cs ],ID,List}  ->  Next = (if (Char == a) -> IDA; (Char == b) -> IDB; (Char == c) -> IDC end),
                                           
                                           if
                                              (Next == none)    ->  IDmanager ! {rejected,ID,List};

                                               true             -> Next ! {Cs,ID,List}
                                           end
          end,
             
         loop(IDA,IDB,IDC,IDmanager,Final).



                       


