data module Products
begin
    exports
    begin
	sorts
	    PRODUCT
	functions
	    A : -> PRODUCT
	    B : -> PRODUCT
    end
end Products

data module Stations
begin
    exports
    begin
	sorts
	    STATION
	functions
	    1 : -> STATION
	    2 : -> STATION
	    3 : -> STATION
	    4 : -> STATION
	    5 : -> STATION
	    6 : -> STATION
	    eq-stat : STATION # STATION -> BOOLEAN
	    next : STATION # PRODUCT -> STATION
    end
    imports
	Booleans, Products
    variables
	x : -> STATION
	y : -> STATION
	p : -> PRODUCT
    equations
    [1] eq-stat(x, x) = true
    [2] not(eq-stat(x, y)) = true
    [3] next(1, p) = 2
    [4] next(2, p) = 3
    [5] next(3, A) = 4
    [6] next(3, B) = 5
    [7] next(4, p) = 5
    [8] next(5, p) = 6
end Stations

process module Scheduler
begin
    exports
    begin
	atoms
	    send-request : STATION # PRODUCT
	    rec-request : STATION # PRODUCT
	    comm-request : STATION # PRODUCT
	    send-next : STATION # STATION
	    rec-next : STATION # STATION
	    comm-next : STATION # STATION
	    send-start : PRODUCT
	    rec-start : PRODUCT
	    comm-start : PRODUCT
	    send-end
	    rec-end
	    comm-end
	processes
	    Scheduler
	sets
	    of atoms
		HS = { send-request(s1, p), rec-request(s1, p),
		    send-next(s1, s2), rec-next(s1, s2),
		    send-start(p), rec-start(p), send-end, rec-end
		    | s1 in STATION, s2 in STATION, p in PRODUCT }
    end
    imports
	Stations
    processes
	Next : STATION # PRODUCT # STATION
	SubScheduler : STATION # PRODUCT
    communications
	send-request(s, p) | rec-request(s, p) = comm-request(s, p)
	    for s in STATION, p in PRODUCT
	send-next(s1, s2) | rec-next(s1, s2) = comm-next(s1, s2)
	    for s1 in STATION, s2 in STATION
	send-start(p) | rec-start(p) = comm-start(p)
	    for p in PRODUCT
	send-end | rec-end = comm-end
    variables
	s : -> STATION
	n : -> STATION
	p : -> PRODUCT
    definitions
	Scheduler =
		sum(p in PRODUCT,
		    rec-start(p) .
		    (
		        SubScheduler(1, p)
		    ||  Scheduler
		    )
		)
	SubScheduler(s, p) =
		    [not(eq-stat(s, 6)) = true] -> (
			rec-request(s, p) .
			Next(s, p, next(s, p))
		    )
		+   [s = 6] ->
			rec-end
	Next(s, p, n) =
		send-next(s, n) .
		SubScheduler(n, p)
end Scheduler

process module SchedFactory
begin
    imports
	Stations,
	Scheduler
    atoms
	input : PRODUCT
	output : PRODUCT
	read-input : PRODUCT
	send-input : PRODUCT
	comm-input : PRODUCT
	read-output : PRODUCT
	send-output : PRODUCT
	comm-output : PRODUCT
	to-belt : STATION # STATION # PRODUCT
	from-belt : STATION # PRODUCT
	comm-belt : STATION # STATION # PRODUCT
    processes
	Start
	Input
	Stations
	Station : STATION
	Output
    sets
	of PRODUCT
	    PRODUCT-set = { A, B }
	of STATION
	    STATION-set = { 1, 2, 3, 4, 5, 6 }
	of atoms
	    H = { send-input(p), read-input(p), send-output(p), read-output(p),
		    to-belt(x, y, p), from-belt(y, p)  | p in PRODUCT,
		    x in STATION, y in STATION }
    communications
	send-input(p) | read-input(p) = comm-input(p)
	    for p in PRODUCT
	send-output(p) | read-output(p) = comm-output(p)
	    for p in PRODUCT
	to-belt(s1, s2, p) | from-belt(s2, p) = comm-belt(s1, s2, p)
	    for s1 in STATION, s2 in STATION, p in PRODUCT
    variables
	s : -> STATION
    definitions
	Start = encaps(HS, Scheduler || encaps(H, Input || Stations || Output))
	Input =
	    sum(p in PRODUCT-set,
		input(p) .
		send-start(p) .
		send-input(p)
	    ) . Input
	Stations = merge(s in STATION-set, Station(s))
	Station(s) =
		[eq-stat(s, 1) = true] -> (
		    sum(p in PRODUCT,
			read-input(p) .
			send-request(s, p) .
			sum(n in STATION,
			    rec-next(s, n) .
			    to-belt(s, n, p)
			)
		    ) . Station(s)
		)
	    +   [eq-stat(s, 6) = true] -> (
		    sum(p in PRODUCT,
			from-belt(s, p) .
			send-output(p)
		    ) . Station(s)
		)
	    +   [and(not(eq-stat(s, 1)), not(eq-stat(s, 6))) = true] -> (
		    sum(p in PRODUCT,
			from-belt(s, p) .
			send-request(s, p) .
			sum(n in STATION,
			    rec-next(s, n) .
			    to-belt(s, n, p)
			)
		    ) . Station(s)
		)
	Output =
	    sum(p in PRODUCT,
		read-output(p) .
		send-end .
		output(p)
	    ) . Output
end SchedFactory
