% Version 4
% This version allows for more declarative goals .. it converts them to
% the more compact form used in the previous versions.


% ANALYSE THE GOAL AND CONVERT IT THE COMPACT FORM FOR USE IN THE 
% 	MAIN ROUTINE

flow(Spec, Output) :-
	getinitial(Init),
	convert_list(Spec, Specd, [Nodes, Sources]), !,
	get_node_index(Output, Nodes, _, Oindex, no),
	analyse(Specd, Init, Oindex).

getinitial(Init) :-
	see(initial),
	read(Init),
	seen.

convert_list([S|Ss], Spec2, Info2) :-
	convert_list(Ss, Spec1, Info1),
	convert_arc(S, Spec1, Spec2, Info1, Info2). 

convert_list([], [], [[], Sources]) :-
	see(sources),
	read(Sources).  % first line of file gives order of sources 

convert_arc([Type, In, Out], Spec1, Spec4, Info1, Info3) :- 
	get_index(Type, In, Info1, Info2, Index1, Newnode_flag1),
	get_index(not_source, Out, Info2, Info3, Index2, Newnode_flag2),
	node_insert(Spec1, Spec2, Newnode_flag1),
	node_insert(Spec2, Spec3, Newnode_flag2),
	insert(Spec3, Spec4, Index2, [Type, Index1]).

get_index(source, N, [Nodes1, Sources], [Nodes1, Sources], Index, no) :-
	get_node_index(N, Sources, _, Index, no).
get_index(source, N, I1, I1, In, F) :-
	printf("Warning: source % does not exist \nIt will be treated as a normal graph node\n", [N]).
get_index(Type, Node, [Nodes1, Sources], [Nodes2, Sources], Index, Newnode_flag) :-
	get_node_index(Node, Nodes1, Nodes2, Index, Newnode_flag).

% finds an index to a node in the list, and if the node is not there, it
% creates the node at the end of the list.
% get_node_index(Node, Old_node_list, New_node_list, Index, Newnode_flag)
get_node_index(X, [X|Ns], [X|Ns], 1.0, no).
get_node_index(X, [Xd|Ns], [Xd|Nds], V + 1, Newnode_flag) :-
	get_node_index(X, Ns, Nds, V, Newnode_flag).
get_node_index(X, [], [X], 1, yes).

% sets up new lists on the spec (specification) list for new nodes
node_insert(S, S, no).
node_insert([S1|Ss1], [S1|Ss2], yes) :-
	node_insert(Ss1, Ss2, yes).
node_insert([], [[]], yes).

% inserts the arc in the new specification
insert([S|Ss], [S|Ts], Index, Arc) :- Index > 1,
	insert(Ss, Ts, Index-1, Arc).
insert([S|Ss], [[Arc|S]|Ss], 1, Arc).

% Setup and repeated calls to stepflow

analyse(Spec, Init, Output) :-
	getsources(Sources),
	sigflow(Sources, Init, Spec, Output),
	seen.

eof(?-end).

sigflow(X, _, _, _) :- eof(X).
sigflow(Sources, Old, Spec, Output) :-
	stepflow(Old, Sources, New, Spec, New),
	printnodes(New, Output), 
	getsources(NewSources), !,
	sigflow(NewSources, New, Spec, Output).

getsources(Ss) :- 
	read(Ss).


% stepflow(Oldnodes, Sources, Newnodes, Spec, Newnodes_left_to_process)
stepflow(Oldnodes, Sources, Newnodes, [S|Spec], [N|New]) :- 
	stepflow(Oldnodes, Sources, Newnodes, Spec, New),
	calcnode(Oldnodes, Sources, Newnodes, S, N).
	% The ordering of the recursive stepflow before the call to
	% calcnode ensures that the New list is constructed before it
	% is used.  This is not strictly necessary, but perhaps desirable.


stepflow(Oldnodes, Sources, Newnodes, [], []).

% calcnode(Oldnodes, Sources, Newnodes, Arcs, Newnode)
calcnode(Oldnodes, Sources, Newnodes, [Arc|Arcs], New) :-
	calcarc(Oldnodes, Sources, Newnodes, Arc, New1),
	calcnode(Oldnodes, Sources, Newnodes, Arcs, New2),
	New = New1 + New2.
calcnode(Oldnodes, Sources, Newnodes, [], 0).

% calcarc(Oldnodes, Sources, Newnodes, Arc, New)
calcarc(Oldnodes, Sources, Newnodes, [coeff(C), Arc], New) :-
	find_index(Value, Newnodes, Arc),
	New - C * Value = 0.

calcarc(Oldnodes, Sources, Newnodes, [delay, NIndex], New) :-
	find_index(Value, Oldnodes, NIndex),
	New - Value = 0.

calcarc(Oldnodes, Sources, Newnodes, [source, Name], New) :-
	find_index(Value, Sources, Name),
	New - Value = 0.

% find_index(item, list of items, place in list).
find_index(V, [V|Vs], 1). 
find_index(VV, [V|Vs], N) :-
	N > 0,
	find_index(VV, Vs, N - 1).


% PRINT ROUTINES

printnodes(N, 0) :- printall(N).
printnodes(N, S) :- S > 0,
	find_index(V, N, S),
	% fwrite("nsource", " % \n", [V]),
	%    this write statement writes out a numerical copy of
	%    the results in the file "nsource".
	graph(V, 3, -3, 80).

printall([N|Ns]) :- 
	printf("| % |", [N]),
	printall(Ns).

printall([]) :- printf("\n", []).

graph(N, Max, Min, Line) :-
	Quantiz = Line * (N-Min)/(Max-Min) -0.5,
	Spaces =  min(Quantiz, Line-1),
	spaces(Spaces),
	printf("*\n", []).

spaces(Q) :- Q >= 1, 
	print(" "),
	spaces(Q - 1).
spaces(Q) :- Q < 1.
 
