%           -*-Mode: prolog;-*-

:- dynamic edge/5.
:- dynamic count/1.

:- ensure_loaded(library(lists)).
:- ensure_loaded('~/Prolog/new_record').

:- multifile dcl/2.

dcl(edge, [org, dest, cat, needs]).

:- compile_declarations.

parse(Words, TopCat) :-
  ( Loop   <- edge, cat=TopCat, needs=Rhs, org=0, dest=0),
  ( Edge <- edge),
  retractall(Edge),
  retractall(count(_)),
  assert(count(0)),
  setof(Loop, rule(TopCat, Rhs), NewEdges),
  schedule(NewEdges, [], Agenda0),
  setof(Edge, lookup(Words, Edge), Edges),
  schedule(Edges, Agenda0, Agenda),
  parse(Agenda).

parse([Edge | _]) :-
  retract(count(I)),
  J is I+1,
  assert(count(J)),
  numbervars(Edge, 0, _),
%  format("~d.~5|Process  ~w~n", [I, Edge]),
  fail.
parse([Edge | Agenda0]) :-
  new_edge(Edge),
  step([Edge | Agenda0], Agenda1),
  new_loops(Edge, Agenda1, Agenda),
  parse(Agenda).
parse([]).

lookup(Words, Edge) :-
  ( Edge <- edge, cat=Cat, org=Org, dest=Dest, needs=[]),
  nth0(Org, Words, Word),
  Dest is Org+1,
  lex(Word, Cat).

step([Inactive | Agenda0], Agenda) :-
  ( Active, E <- edge, org=Org, dest=Mid, needs=[ICat | Needs]),
  ( Inactive  <- edge, org=Mid, dest=Dest, needs=[], cat=ICat),
  ( Result, E <- edge, org=Org, dest=Dest, needs=Needs),
  setof(Result, call(Active), Results),
  !,
  schedule(Results, Agenda0, Agenda).
step([Active | Agenda0], Agenda) :-
  ( Active, E <- edge, org=Org, dest=Mid, needs=[ICat | Needs]),
  ( Inactive  <- edge, org=Mid, dest=Dest, needs=[], cat=ICat),
  ( Result, E <- edge, org=Org, dest=Dest, needs=Needs),
  setof(Result, call(Inactive), Results),
  !,
  schedule(Results, Agenda0, Agenda).
step([_ | Agenda], Agenda).

new_loops(Active, Agenda0, Agenda) :-
  ( Active <- edge, dest=Mid, needs=[Cat | Needs]),
  ( Edge   <- edge, cat=Cat, needs=Rhs, org=Mid, dest=Mid),
%%%   \+ \+ ( numbervars(Cat, 0, _),
%%%           format("~7|~w~n", [Cat])
%%%         ),
  setof(Edge, rule(Cat, Rhs), NewEdges),
  !,
  schedule(NewEdges, Agenda0, Agenda).
new_loops(_, Agenda, Agenda).

new_edge(Edge) :-
  call(Edge),
  !.
new_edge(Edge) :-
%   \+ \+ ( numbervars(Edge, 0, _),
%           format("~5|New edge ~w~n", Edge)
%	 ),
  assert(Edge).

schedule([], Agenda, Agenda).
schedule([Task | Tasks], Agenda0, Agenda) :-
  schedule_task(Task, Agenda0, Agenda1),
  schedule(Tasks, Agenda1, Agenda).

schedule_task(Task, Agenda, Agenda) :-
  member(Task, Agenda),
  !.
schedule_task(Task, Agenda, Agenda) :-
  call(Task),
  !.
%schedule_task(Task, Agenda, [Task | Agenda]) :-
%  \+ \+ ( numbervars(Task, 0, _),
%          format("~5|Schedule ~w~n", [Task])
%        ).
schedule_task(Task, Agenda, [Task | Agenda]).

show_chart :-
  (E <- edge),
  call(E),
  print(E),
  nl,
  write('------------'),
  nl,
  fail.
show_chart.

show_chart(L) :-
  (E <- edge, org=0, dest=L),
  call(E),
  print(E),
  nl,
  write('------------'),
  nl,
  fail.
show_chart(_).
