require "Commodity_1";
require "Train_1";
require "Scheduler_3";
require "Speed_1";
P = require "Persistence_3";
require "Crossing_2";
require "Callback_1";

math.randomseed(os.time());

-- Anhalten oder Langsamfahren an Haltepunkt und Bahnübergang

function willStop(train, probability)
	if type(train) ~= "string" then
		probability = train;
		train = trainName;
	end;
	assertParam(1, false, "string");
	assertParam(2, false, "number");
	local info = P["Laufenselden.halt"];
	if info == nil then
		if math.random() <= probability and string.sub(Train.getRoute(train), 1, 1) == "P" then
			P["Laufenselden.halt"] = train;
			info = true;
		else
			P["Laufenselden.halt"] = false;
			info = false;
		end;
	end;
-- print(string.format("train %s will stop: %s", train, tostring(info)));
	return not not info;
end;

function changeSpeed(train, speed)
	if type(train) ~= "string" then
		speed = train;
		train = trainName;
	end;
	assertParam(1, false, "string");
	assertParam(2, false, "number");
	local curSpeed = Train.getSpeed(train);
-- print(string.format("changeSpeed of %s from %f to %f", train, curSpeed, speed));
	if curSpeed < 0.0 then
		Train.setSpeed(train, -speed);
	elseif curSpeed > 0.0 then
		Train.setSpeed(train, speed);
	else
		print(string.format("Laufenselden.changeSpeed(\"%s\", %f): no train or no speed (%s)", train, speed, curSpeed));
	end;
end;

function stopAndRestart(distance, delay, targetSpeed)
	assertParam(1, false, "number");
	assertParam(2, false, "number");
	assertParam(3, false, "number");
	local train = P["Laufenselden.halt"];
	if type(train) == "string" then
		Speed.change(train, 0, distance);
		local curSpeed = Train.getSpeed(train);
		if curSpeed < 0 then
			targetSpeed = -targetSpeed;
		end;
		Scheduler.executeAfter(delay, string.format("startAgain(%f)", targetSpeed));
	end;
end;

function startAgain(targetSpeed)
	local train = P["Laufenselden.halt"];
	if train then
		Train.setSpeed(train, targetSpeed);
	end;
end;

function clearStop()
	P["Laufenselden.halt"] = nil;
end;

-- Zufälliges Legen einer 2-Wege-Weiche, entweder als
-- doSwitch(<ID der Weiche>, <Wahrscheinlichkeit für Wechsel der Stellung>) oder als
-- doSwitch(<ID der Weiche>, <Stellung>, <Wahrscheinlichkeit für diese Stellung>)
function doSwitch(switchID, arg2, arg3)
	arg2 = arg2 or 0.5;
	if arg2 < 1.0 then
		if math.random() <= arg2 then
			local state = EEPGetSwitch(switchID);
			EEPSetSwitch(switchID, 3 - state);
		end;
	else
		local state = math.random() < arg3 and arg2 or 3 - arg2;
		EEPSetSwitch(switchID, state);
	end;
end;

-- Straßenabzweigung

Crossing.define("NS", 60, {}, 17, 10, 1);
Crossing.define("NW", 20, {}, 17, 10, 2);
Crossing.define("SN", 60, {}, 49, 9, 1);
Crossing.define("SW", 23, {"NS", "NW"}, 49, 9, 2);
Crossing.define("WS", 20, {"NS"}, 16, 7, 1);
Crossing.define("WN", 23, {"NS", "SN", "SW"}, 16, 7, 2);

-- Steuerung über das GBS

local function showTrainyard()
	EEPSetSignal(22, 1);
	local trainCount = EEPGetTrainyardItemsCount(1);
	clearlog();
	if trainCount == 0 then
		print("no trains in trainyard 1");
	else
		print("Nr | W | Zugname | Route | Wagen");
	end;
	for i = 1, trainCount do
		local trainName = EEPGetTrainyardItemName(1, i);
		local status, route = EEPGetTrainRoute(trainName);
		if not status then
			route = "unknown"
		end;
		local state = EEPGetTrainyardItemStatus(1, "", i) == 1 and "+" or "X";
		local content = Train.getTrainComposition(trainName, 120);
		print(string.format("%2d | %s | %s | %s | %s", i, state, trainName, route, content));
	end;
end;
Callback.registerSignal(22, showTrainyard, 2);

local function decrement23()
	EEPSetSignal(23, -1);
	EEPSetSignal(25, 2);
end;
Callback.registerSignal(25, decrement23, 1);

local function releaseTrain()
	local trainOnItsWay = nil;
	local trainCount = EEPGetTrainyardItemsCount(1);
	for i = 1, trainCount do
		if EEPGetTrainyardItemStatus(1, "", i) ~= 1 then
			trainOnItsWay = EEPGetTrainyardItemName(1, i);
			break;
		end;
	end;
	if trainOnItsWay then
		print("Zug " .. trainOnItsWay .. " ist bereits unterwegs.");
	else
		local trainNr = EEPGetSignal(23) - 1;
		if trainNr >= 1 and trainNr <= trainCount then
			if not EEPGetTrainFromTrainyard(1, "", trainNr) then
				print("Konnte Zug " .. tostring(trainNr) .. " nicht aus dem Depot entlassen");
			end;
		else
			print("Kein Zug mit Nummer " .. tostring(trainNr) .. " im Depot");
		end;
	end;
	EEPSetSignal(24, 2);
end;
Callback.registerSignal(24, releaseTrain, 1);