--[[
---------------------------------------------------------------------------
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 = "Double Vertex Graph Test"
--
require([[defines]]);
require([[functions]]);
--
local SD = require([[Distances]]);		-- Measured stopping and starting distances in inches
--
-- Original luagraph library Downloaded from
-- https://github.com/chen0040/lua-graph
--
-- Original Dijkstra algorithm described in
-- https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
--
--
-- an undirected weighted double vertex graph with requiredVertices nodes starting at 0
local requiredVertices
-- create the graph and related tables
local Layout4 = require([[rtcgraphs.data.graph]]).create(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
	-- an undirected weighted double vertex graph
	local requiredVertices = 56
	MyTIUNo = TIU;

-- Youngstown Yard	
	-- Track 1
	Layout4:addDoubleVertex(0, 1) -- double vertex
	Layout4:addUndirectedEdge(1, 2, 5)
	Layout4:addDoubleVertex(2, 3) -- double vertex
	-- Track 2
	Layout4:addDoubleVertex(36, 37) -- double vertex
	Layout4:addUndirectedEdge(37, 38, 5)
	Layout4:addDoubleVertex(38, 39) -- double vertex
	-- switch track
	Layout4:addSwitchTrack(4, 3, 39, MyTIUNo, GATEWAY_YARD_AIU, GATEWAY_YARD_CHAN);	-- common vertex, normal vertex, reverse vertex, TIU, AIU, Channel
	Layout4:addDoubleVertex(4, 5) -- double vertex
--[[--------------Line between Youngstown Yard and Struthers------------------]]		
	Layout4:addUndirectedEdge(5, 6, 5)
--[[--------------Struthers------------------]]	
	Layout4:addDoubleVertex(6, 7) -- double vertex	
	Layout4:addSwitchTrack(7, 8, 40, MyTIUNo, STRUTHERS_WEST_AIU, STRUTHERS_WEST_CHAN);	-- common vertex, normal vertex, reverse vertex, TIU, AIU, Channel
	Layout4:addDoubleVertex(8, 9) -- double vertex
	Layout4:addDirectedEdge(9, 10, 15)	-- Struthers Through Track Eastward
	Layout4:addDirectedEdge(10, 9, 5)		-- Struthers Through Track Westward

-- Struthers Passing Track
	Layout4:addDoubleVertex(40, 41) -- double vertex
	Layout4:addDirectedEdge(41, 42, 7)	-- Eastward
	Layout4:addDirectedEdge(42, 41, 20)	-- Westward
	Layout4:addDoubleVertex(42, 43) -- double vertex
	
	Layout4:addDoubleVertex(10, 11) -- double vertex
	Layout4:addSwitchTrack(12, 11, 43, MyTIUNo, STRUTHERS_EAST_AIU, STRUTHERS_EAST_CHAN);	-- common vertex, normal vertex, reverse vertex, TIU, AIU, Channel	
	Layout4:addDoubleVertex(12, 13) -- double vertex

--[[--------------Line between Struthers and College------------------]]	
	Layout4:addUndirectedEdge(13, 14, 5)
--[[--------------College------------------]]	
	Layout4:addDoubleVertex(14, 15) -- double vertex
	Layout4:addSwitchTrack(15, 16, 44, MyTIUNo, COLLEGE_WEST_AIU, COLLEGE_WEST_CHAN);	-- common vertex, normal vertex, reverse vertex, TIU, AIU, Channel	
	
	Layout4:addDoubleVertex(16, 17) -- double vertex
	Layout4:addDirectedEdge(17, 18, 15)	-- College Through Track Eastward
	Layout4:addDirectedEdge(18, 17, 5)	-- College Through Track Westward
	
-- College Passing Track
	Layout4:addDoubleVertex(44, 45) -- double vertex
	Layout4:addDirectedEdge(45, 46, 7)	-- Eastward
	Layout4:addDirectedEdge(46, 45, 20)	-- Westward
	Layout4:addDoubleVertex(46, 47) -- double vertex
		
	Layout4:addDoubleVertex(18, 19) -- double vertex
	Layout4:addSwitchTrack(20, 19, 47, MyTIUNo, COLLEGE_EAST_AIU, COLLEGE_EAST_CHAN);	-- common vertex, normal vertex, reverse vertex, TIU, AIU, Channel	
	Layout4:addDoubleVertex(20, 21) -- double vertex
	
--[[--------------Line between College and Aliquippa------------------]]	
	Layout4:addUndirectedEdge(21, 22, 5)
--[[--------------Aliquppa------------------]]	
	Layout4:addDoubleVertex(22, 23) -- double vertex	

	Layout4:addSwitchTrack(23, 24, 48, MyTIUNo, ALIQUIPPA_WEST_AIU, ALIQUIPPA_WEST_CHAN);	-- common vertex, normal vertex, reverse vertex, TIU, AIU, Channel		
	Layout4:addDoubleVertex(24, 25) -- double vertex
	Layout4:addDirectedEdge(25, 26, 15)	-- Aliquippa Through Track Eastward
	Layout4:addDirectedEdge(26, 25, 5)	-- Aliquippa Through Track Westward	
	
-- Aliquippa Passing Track
	Layout4:addDoubleVertex(48, 49) -- double vertex
	Layout4:addDirectedEdge(49, 50, 7)	-- Eastward
	Layout4:addDirectedEdge(50, 49, 20)	-- Westward
	Layout4:addDoubleVertex(50, 51) -- double vertex	
	Layout4:addDoubleVertex(26, 27) -- double vertex	
	Layout4:addSwitchTrack(28, 27, 51, MyTIUNo, ALIQUIPPA_EAST_AIU, ALIQUIPPA_EAST_CHAN);	-- common vertex, normal vertex, reverse vertex, TIU, AIU, Channel		
	Layout4:addDoubleVertex(28, 29) -- double vertex	
--[[--------------Line between Aliquippa and McKees Rocks Yard------------------]]	
	Layout4:addUndirectedEdge(29, 30, 5)
--[[--------------McKees Rocks Yard------------------]]	
	Layout4:addDoubleVertex(30, 31) -- double vertex	
	Layout4:addSwitchTrack(31, 32, 52, MyTIUNo, MCKEES_ROCKS_REPAIR_SHOPS_YARD_AIU, MCKEES_ROCKS_REPAIR_SHOPS_YARD_CHAN);	-- (common vertex, normal vertex, reverse vertex, TIU, AIU, Channel)	
	-- Track 2
	Layout4:addDoubleVertex(52, 53) -- double vertex	
	Layout4:addUndirectedEdge(53, 54, 5)
	Layout4:addDoubleVertex(54, 55) -- double vertex
	-- Track 1
	Layout4:addDoubleVertex(32, 33) -- double vertex
	Layout4:addUndirectedEdge(33, 34, 5)
	Layout4:addDoubleVertex(34, 35) -- double vertex	
--
--	
-- templates:	
--	Layout4:adddirectedEdge(000, 000, 0)				-- (vertex1, vertex2, weight)
--	Layout4:addUndirectedEdge(000, 000, 0)			-- (vertex1, vertex2, weight)	
--	Layout4:addDoubleVertex(000, 000) -- double vertex
--	Layout4:addSwitchTrack(000, 000, 000, 000, 000, 000);	-- (common vertex, normal vertex, reverse vertex, TIU, AIU, Channel)	
--
	actualVertices = Layout4:vertexCount() 
	print("Vertices added : ", actualVertices) 
	print("Edges added : ", Layout4:edgeCount())
	if (actualVertices ~= requiredVertices) then
		return Stop("Graph Double Vertex 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
local source = 38	-- beginging vertex
-- 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
-- valid for Layout 3 only
--[[
local ef = Layout4:findEdge(23,24)
if (ef) then
	ef:changeWeight(9)
	end
ef = Layout4:findEdge(24,23)
if (ef) then
	ef:changeWeight(15)
	end	
--]]

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

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

--[=[
-- this chunk of code displays the shortest paths from the source vertex to all other vertices
for k = 0,Layout4:vertexCount() - 1 do
    local v = Layout4:vertexAt(k)
    if v ~= source and double_vertex:hasPathTo(v) then
        print('path from ' .. source .. ' -> ' .. v .. ' ( cost: '  .. double_vertex:getPathLength(v) .. ' )')
        local path = double_vertex:getPathTo(v)
        for i = 0,path:size()-1 do
            print('     # from ' .. path:get(i):from() .. ' -> ' .. path:get(i):to() .. ' ( cost: ' .. path:get(i).weight .. ' )')
        end
    else
		print("no path from " .. source .. " -> " .. v .. " (hasPathTo(v) == false)")
    end
end
--]=]
---[[
-- this chunk of code displays the shortest path from the souce vertex to a single destination vertex (k)
	k = 54	--destination vertex
    local v = k
    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;
				position, TIU, AIU, Channel = path:get(i):control();
				if (position == 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 .. ' )' ..
						' 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 Graph Double Vertex Test");		-- end the script
	end
--[[---------------------------------------------------------------------------------------]]
function dumpadjacencylist()	
-- code below prints the adjacency list 
	for k = 0, Layout4:vertexCount() - 1 do -- iterate through all vertices in g
		local v = Layout4:vertexAt(k)
		local adj_v = Layout4: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
	print(string.format("cleanup() Complete at %.2f", RunTime()));
	return true;		-- false=cleanup failed, true=cleanup succeeded
	end
--[[---------------------------------------------------------------------------------------]]
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
--[[---------------------------------------------------------------------------------------]]