% Convert internal format into dotty output
dotty(Machine, Name, FileName) :-
	open(FileName, write, File),
	format(File, "digraph ~s {~n node [shape = circle];~n rankdir=LR;~n", [Name]),
	dotty_transitions(File, Machine), 
	format(File, "}", []),
	close(File). 

dotty_transitions(_, []).
dotty_transitions(File, List) :-
	member(t(S,_I,_O,_D,NS), List), 
	deleteall(S, NS, List, Trans, NewList), 
	stringall(Trans, String), 
	outstate(S, OS), outstate(NS,ONS), 
	format(File, "~s -> ~s [label = ""~s"" ];~n", [OS,ONS,String]), 
	dotty_transitions(File, NewList). 

stringall([t(_S,I,O,D,_NS)], String) :-
	string(I,O,D,String). 
stringall([t(_S,I,O,D,_NS)|Rest], String) :-
	Rest \== [], 
	string(I,O,D,String1), append(String1, ",", Stringy), 
	stringall(Rest, String2),
	append(Stringy, String2, String). 

string(I, O, D, String) :-
	chars(I, Is), chars(O, Os), chars(D, Ds),
	append(Is, Os, T), append(T, Ds, String). 

% delete all transitions from S to NS from List, leaving NewList
deleteall(_S, _NS, [], [], []).
deleteall(S, NS, [t(S1,I,O,D,S2)|Rest], [t(S1,I,O,D,S2)|Trans], Other) :-
	S = S1, NS = S2, 
	deleteall(S, NS, Rest, Trans, Other). 

deleteall(S, NS, [t(S1,I,O,D,S2)|Rest], Trans, [t(S1,I,O,D,S2)|Other]) :-
	(S \== S1; NS \== S2), 
	 deleteall(S, NS, Rest, Trans, Other). 
	

chars(*, "*").
chars(b, "0").
chars(0, "0").
chars(1, "1").
chars(r, "R").
chars(l, "L").

outstate(1,"A"). 
outstate(2,"B"). 
outstate(3,"C"). 
outstate(4,"D"). 
outstate(5,"E"). 
outstate(6,"F"). 
outstate(a,"A"). 
outstate(b,"B"). 
outstate(c,"C"). 
outstate(d,"D"). 
outstate(e,"E"). 
outstate(f,"F"). 
outstate(h,"H"). 

% translate([b1r,c0l,a1l,a0r,d0l,z1r,e1r,d1l,f0l,e0l,f1r,b0l], List). 
translate(Marxen, Mine) :-
	smash(Marxen, List),
	parlist(List, Parity), 
	length(List, M), N is M/6, 
	trans(N, Parity, List, 1, 0, Mine).

smash([], []).
smash([T|Rest], Mine) :- 
	name(T, Name),
	Name = [One|Bit1], Bit1 = [Two|Bit2], Bit2 = [Three|_],
	name(First, [One]), 
	name(Second, [Two]), 
	name(Third, [Three]), 
	smash(Rest, Other),
	T2 = [Third|Other], T1 = [Second|T2], Mine = [First|T1].
	
trans(N, Parity, List, State, In, Trans) :-
	List = [S|Rest1], Rest1 = [O|Rest2], Rest2 = [D|Rest3], 
	transstate(S, NewState),
	transout(O, Out),
	transdir(Parity, D,Dir),
	increment(State, In, New, NewIn), 
	trans(N, Parity, Rest3, New, NewIn, Trans3),
	Trans = [t(State, In, Out, Dir, NewState)|Trans3].

trans(_N, _Parity, [], _State, _In, []).

transstate(a,1). 
transstate(b,2). 
transstate(c,3). 
transstate(d,4). 
transstate(e,5). 
transstate(f,6). 
transstate(z,h). 
transstate(h,h). 

transout(0,0).
transout(1,1).

transdir(right,r,r). 
transdir(right,l,l). 
transdir(left, l,r). transdir(left, r,l). 

parlist(List, Parity) :-
	List = [_NewState|Rest], Rest = [_Out|Rest1], Rest1 = [Dir|_], 
	parity(Dir, Parity).

parity(r,right).
parity(l,left).

%% Converts an n-state 2-symbol machine into a 2-state n-symbol one. 
n2to2n(M, NewM) :-
	dualise_transitions(M, NewM).

dualise_transitions([], []).
dualise_transitions([Trans|Rest], [NewTrans|Rest1]) :-
	dualise(Trans, NewTrans),
	dualise_transitions(Rest, Rest1).

dualise(t(State, In, Out, Dir, NewState), t(TState, TIn, TOut, Dir, TNewState)) :-
	NewState \== h, 
	state2symbol(State, TIn), 
	state2symbol(NewState, TOut), 
	symbol2state(In, TState), 
	symbol2state(Out, TNewState).

dualise(t(State, In, _Out, _Dir, h), t(TState, TIn, 1, r, h)) :-
	state2symbol(State, TIn), 
	symbol2state(In, TState).

state2symbol(a, 0).
state2symbol(b, 1).
state2symbol(c, 2).
state2symbol(d, 3).
state2symbol(e, 4).
state2symbol(f, 5).
state2symbol(1, 0). 	
state2symbol(2, 1). 	
state2symbol(3, 2). 	
state2symbol(4, 3). 	
state2symbol(5, 4). 	
state2symbol(6, 5). 	

symbol2state(0, a).
symbol2state(b, a).
symbol2state(1, b).
symbol2state(2, c).
symbol2state(3, d).
symbol2state(4, e).
symbol2state(5, f).

