--[[
---------------------------------------------------------------------------
Remote Train Control Program for Windows

© Copyright 2020 by Mark DiVecchio

	This file is part of Remote Train Control.

	Remote Train Control is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	Remote Train Control is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with Remote Train Control.  If not, see <http://www.gnu.org/licenses/>.

 Home Page : http://www.silogic.com/trains/RTC_Running.html
---------------------------------------------------------------------------]]
-- Semicolons are not required in Lua code
title = "Run Graph End to End Test"
--
require([[defines]]);
require([[functions]]);
--

-- Original luagraph library Downloaded from
-- https://github.com/chen0040/lua-graph
--
-- Original Dijkstra algorithm described in
-- https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
--
--
local requiredVertices
local Layout4;	-- a set of data tables which define the layout
local Graph4;	-- an undirected weighted double vertex graph with requiredVertices nodes starting at 0
local MyTIUNo;

function setup(Engine, TIU)
	-- this function is called once when the [Run Script] button is pushed
	-- Engine : Engine number selected on the RTC Main window
	-- TIU : TIU number selected on the RTC Main window
	print("setup()");

	-- Instrumented Layout 4
	Layout4 = require([[Layout4]]);		-- All of the details about the Layout
	-- an undirected weighted double vertex graph
	
	-- create the undirected weighted double vertex graph and related tables
	Graph4 = require([[rtcgraphs.data.graph]]).create(0, true)	
	MyTIUNo = Layout4.MASTER_TIU;
	MyEngineNo = Engine;

	local requiredVertices = Layout4:CreateGraph(Graph4);	-- add all track vertices, edges and switches to Graph4;

	actualVertices = Graph4:vertexCount() 
	print("Vertices added : ", actualVertices) 
	print("Edges added : ", Graph4:edgeCount())
	if (actualVertices ~= requiredVertices) then
		return Stop("Run Graph End to End Test : Missing Vertices");		-- end the script
		end;
	
if (Debug() > 4) then	
	dumpadjacencylist()
	end

print("Shortest Paths (Based on Dijkstra) - Weighted");
-- https://github.com/chen0040/lua-graph#shortest-paths-dijkstra
-- https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm

-- this call to create() sets up the data structures used
local double_vertex = require('rtcgraphs.shortest_paths.Double_Vertex').create()

----------
-- re-weight an edge
-- internally its a directed graph so we can re-weight each direction separately
-- example code:
--[[
local ef = Graph4:findEdge(23,24)
if (ef) then
	ef:changeWeight(9)
	end
ef = Graph4:findEdge(24,23)
if (ef) then
	ef:changeWeight(15)
	end	
--]]

if (Debug() > 4) then	
	dumpadjacencylist()
	end


-- start of run
print("Set all Switches to Normal postion");
-- set all switches to NORMAL position
for k,v in pairs(Switches) do
	print("k = " .. k .. " TIU = " .. v[TIU_NUMBER] .. " AIU = " .. v[AIU_NUMBER] .. " Channel = " .. v[CHAN_NUMBER]);
	--Switch(NORMAL, v[CHAN_NUMBER], v[AIU_NUMBER], v[TIU_NUMBER], 0);
	--Sleep(0.5);
	end
-- set occupancy flags to 0
for x = 1, 14 do
	SetGlobalInt(x, 0);
	end;
---------
-- Eastbound train
local direction = EB;
local source = 2;		-- beginging vertex - the vertex just ahead of the engine
local destination = 34;	-- destination vertex - the vertex just ahead of where the engine should stop
local StartBlockNo = 2;
local EndBlockNo = 14;

-- Westbound train
--local direction = WB;
--local source = 53;		-- beginging vertex - the vertex just ahead of the engine
--local destination = 1;	-- destination vertex - the vertex just ahead of where the engine should stop
--local StartBlockNo = 13;
--local EndBlockNo = 2;
--[[-------------------------------------------------------------------]]
if (direction == EB) then
	print("Eastbound");
	else
	print("Westbound");
	end
-- mark block as occupied
SetGlobalInt(StartBlockNo, MyEngineNo);

-- this call to run() calculates the lowest cost to all vertices
double_vertex:run(Graph4, source) -- "source" is the id of the source vertex in the path search

--print("actualVertices = " .. dumpx(actualVertices));
--print("StationName = " .. dumpx(StationName));
--print("StationName = " .. Pretty(StationName));
--print("Switches = " .. dumpx(Switches));
--print("Switches = " ..  Pretty(Switches));

-- this chunk of code displays the shortest path from the souce vertex to a single destination vertex
local v = destination
    if v ~= source and double_vertex:hasPathTo(v) then
		if (double_vertex:getPathLength(v) ~= math.huge) then -- mcd
			print('path from ' .. source .. ' -> ' .. v .. ' ( cost: '  .. double_vertex:getPathLength(v) .. ' )')
			local path = double_vertex:getPathTo(v)
			print("path : " .. dumpx(path));
			for i = 0,path:size()-1 do
				local position, TIU, AIU, Channel, BlockNo;
				position, TIU, AIU, Channel, BlockNo = path:get(i):control();
				if (position == nil) then
					if (BlockNo == nil) then
						print('     # from ' .. path:get(i):from() .. ' -> ' .. path:get(i):to() .. ' ( cost: ' .. path:get(i).weight .. ' )');
						else
						print('     # from ' .. path:get(i):from() .. ' -> ' .. path:get(i):to() .. ' ( cost: ' .. path:get(i).weight .. ' )' ..
							' Block Number:' .. BlockNo);
						end
					else
					print('     # from ' .. path:get(i):from() .. ' -> ' .. path:get(i):to() .. ' ( cost: ' .. path:get(i).weight .. ' )' ..
						' switch:' .. (position and "NORMAL" or "REVERSE")  .. ' TIU = ' .. TIU .. ' AIU = ' .. AIU .. ' Channel = ' .. Channel);
					end
			end
		else
		print("no path from " .. source .. " -> " .. v .. " (getPathLength(v) == math.huge)")	-- mcd		
		end
    else
		print("no path from " .. source .. " -> " .. v .. " (hasPathTo(v) == false)")	-- mcd
    end


print(string.format("RunTime = %.2f seconds", RunTime()));
return Stop("End of Run Graph End to End Test");		-- end the script
end
--[[---------------------------------------------------------------------------------------]]
function dumpadjacencylist()	
-- code below prints the adjacency list 
	for k = 0, Graph4:vertexCount() - 1 do -- iterate through all vertices in g
		local v = Graph4:vertexAt(k)
		local adj_v = Graph4:adj(v) -- adjacency list for vertex v
		local text = ' Vertex ' .. v ;
		for i = 0, adj_v:size()-1 do
			local e = adj_v:get(i)
			text = text .. ', ' .. e:other(v) .. '(' .. e.weight .. ')' 
		end
		print(text);
		--print("adj(" .. v .. ") : " .. dumpx(adj_v));
	end
end

--[[---------------------------------------------------------------------------------------]]
function cleanup(Engine, TIU)
	-- this function is called once when the user presses the [STOP] button or the Stop() function is called
	print(string.format("cleanup() Complete at %.2f", RunTime()));
	return true;		-- false=cleanup failed, true=cleanup succeeded
	end
--[[---------------------------------------------------------------------------------------]]
--https://www.codegrepper.com/code-examples/lua/lua+dump+table
function dumpx(o)
   if type(o) == 'table' then
      local s = '{ '
      for k,v in pairs(o) do
         if type(k) ~= 'number' then k = '"'..k..'"' end
		 -- optional : print(k,v)
         s = s .. '['..k..'] = ' .. dumpx(v) .. ','
      end
      return s .. '} \n'
   else
      return tostring(o)
   end
end
--[[---------------------------------------------------------------------------------------]]