Quantcast
--[[
	Load each SimulationCraft profile and do the following things:

	1. Unparse the profile to verify the action list is being properly parsed.
	2. Emit the corresponding Ovale script to standard output.
--]]

-- Constants.
local profilesDirectory = "../../SimulationCraft/profiles/Tier17M"
local root = "../"
local separator = string.rep("-", 80)

local SIMC_CLASS = {
	deathknight = true,
	druid = true,
	hunter = true,
	mage = true,
	monk = true,
	paladin = true,
	priest = true,
	rogue = true,
	shaman = true,
	warlock = true,
	warrior = true,
}

local gmatch = string.gmatch
local gsub = string.gsub
local ipairs = ipairs
local strfind = string.find
local strlen = string.len
local strlower = string.lower
local strsub = string.sub
local strupper = string.upper
local tinsert = table.insert
local tremove = table.remove
local tsort = table.sort

-- Save original input and output handles.
local saveInput = io.input()
local saveOutput = io.output()

-- Get the valid profile names from the profiles directory.
local files = {}
do
	local dir = io.popen("dir /b " .. gsub(profilesDirectory, "/", "\\"))
	for name in dir:lines() do
		tinsert(files, name)
	end
	dir:close()

	-- Filter out invalid profile names.
	local filter = {}
	for _, name in ipairs(files) do
		local ok = true
		local lowername = strlower(name)

		-- Lexer for the profile filename.
		local tokenIterator = gmatch(lowername, "[^_.]+")

		-- Profile names always end in ".simc".
		ok = ok and strsub(lowername, -5, -1) == ".simc"

		local baseProfileName
		-- Profile names always start with a class name.
		if ok then
			-- The first token should be the class.
			local class = tokenIterator()
			-- SimulationCraft uses "death_knight" while WoW uses "deathknight".
			local wowClass = class
			if class == "death" then
				local token = tokenIterator()
				class = class .. "_" .. token
				wowClass = wowClass .. token
			end
			baseProfileName = class
			if not SIMC_CLASS[wowClass] then
				ok = false
			end
			-- Skip class driver profile that just forces other profiles to be run.
			if ok and strfind(lowername, class .. "_t%d+[a-z].simc") then
				ok = false
			end
		end

		-- The next token should be the required specialization.
		if ok then
			local specialization = tokenIterator()
			baseProfileName = baseProfileName .. "_" .. specialization
		end

		-- Filter out any profiles that are modifications of an existing base profile.
		if ok then
			-- Valid modifiers that can come before the tier designation that are part
			-- of the base profile name.
			local VALID_PRE_TIER_MODIFIER = {
				["1h"] = true,
				["2h"] = true,
			}
			local modifier = tokenIterator()
			while ok and modifier do
				if strfind(modifier, "t%d+[a-z]") then
					baseProfileName = baseProfileName .. "_" .. modifier
					break
				elseif VALID_PRE_TIER_MODIFIER[modifier] then
					baseProfileName = baseProfileName .. "_" .. modifier
				end
				modifier = tokenIterator()
			end
			baseProfileName = baseProfileName .. ".simc"
			if lowername ~= baseProfileName then
				for _, fileName in ipairs(files) do
					if baseProfileName == strlower(fileName) then
						ok = false
						break
					end
				end
			end
		end
		if not ok then
			filter[name] = true
		end
	end
	for k = #files, 1, -1 do
		if filter[files[k]] then
			tremove(files, k)
		end
	end
	tsort(files)
end

for _, name in ipairs(files) do
	local inputName =  profilesDirectory .. "/" .. name
	io.input(inputName)
	local simc = io.read("*all")
	-- Valid profiles never set "optimal_raid".
	if not strfind(simc, "optimal_raid=") then
		-- Find the class and specialization from the profile.
		local class, specialization
		for line in gmatch(simc, "[^\r\n]+") do
			if not class then
				for simcClass in pairs(SIMC_CLASS) do
					local length = strlen(simcClass)
					if strsub(line, 1, length + 1) == simcClass .. "=" then
						class = strupper(simcClass)
					end
				end
			end
			if not specialization then
				if strsub(line, 1, 5) == "spec=" then
					specialication = strsub(line, 6)
				end
			end
			if class and specialization then
				break
			end
		end
		-- Create WoWMock sandbox.
		dofile(root .. "WoWMock.lua")
		local config = {
			class = class,
			specialization = specialization,
		}
		local sandbox = WoWMock:NewSandbox(config)

		-- Load addon files into the sandbox.
		sandbox:LoadAddonFile("Ovale.toc", root)

		-- Fire events to simulate the addon-loading process.
		sandbox:Fire("ADDON_LOADED")
		sandbox:Fire("SPELLS_CHANGED")
		sandbox:Fire("PLAYER_LOGIN")
		sandbox:Fire("PLAYER_ENTERING_WORLD")

		-- Enter sandbox.
		setfenv(1, sandbox)

		local OvaleSimulationCraft = Ovale.OvaleSimulationCraft

		-- Parse SimulationCraft profile and emit the corresponding Ovale script.
		local profile = OvaleSimulationCraft:ParseProfile(simc)
		if profile then
			print(separator)
			print(">>>", name)
			print(OvaleSimulationCraft:Unparse(profile))
			print(separator)
			print(OvaleSimulationCraft:Emit(profile))
		end
	end
end

-- Restore original input and output handles.
io.input(saveInput)
io.output(saveOutput)