:- module(so_automaton, [match_list/3]).

:- use_module(library(clpfd)).
:- use_module('skip_pattern_compiler.pl').
:- use_module('event_types.pl').



/*
     This module describes automaton recognizing patterns on lists with output.
     The automaton is defined by the following predicates:
     initial(Id, I) : initial state I for automaton Id
     final(F) : final state F
     trans(S0, A, S1) : automaton can do transition after consuming A from state
     S0 to S1
     eps(S0, S1) : automaton can do ε - transition
     skip(S, A) : automaton can skip A when in a state S.
 */

state(T), [T] --> [T].
state(T0, T1), [T1] --> [T0].

eps_(S0, [], S1, [S1, S0])
   :- eps(S0, S1),
      dif(S0, S1). 

eps_(S0, [S0|Acc], S1, [S1, S0|Acc])
   :- eps(S0, S1),
      maplist(dif(S1), [S0|Acc]). 

match_list(Id, L, Out)
   :- initial(Id, I),
      phrase(matcher(L, Out), [a(I, [], 0)], [a(S, _, _)]),
      final(S).


zeroes([], []).
zeroes([_|As], [0|Out]) :- zeroes(As, Out).

matcher([], []) --> [].
matcher([A|L], [1 | Out])
   --> state(
         a(S0, _, T1), 
         a(S1, [], T2)
       ),
       {
          event_time(A, T2),
          T1 #< T2,
          trans(S0, A, S1)
       },
       matcher(L, Out).
matcher(L, Out)
   --> state(
         a(S0, Acc0, T), 
         a(S1, Acc1, T)
       ),
       {
          eps_(S0, Acc0, S1, Acc1)
       },
       matcher(L, Out).
matcher([A|L], [0|Out])
   --> state(
         a(S, _, T1), 
         a(S, [], T2)
       ),
       {
          event_time(A, T2),
          T1 #< T2,
          skip(S, A)
       },
       matcher(L, Out).
