assert(rb,"Run fbneo-training-mode.lua")

-- This file is meant to be run by scrolling-input-display.lua
-- user: Do not edit this file.

local recordpath = "framedump" --(relative to resourcepath)

--[[
print("Scrolling input display Lua script, " .. version)
print("Press " .. (input.registerhotkey and "Lua hotkey 1" or playerswitch) .. " to toggle players.")
print("Press " .. (input.registerhotkey and "Lua hotkey 2" or clearkey) .. " to clear the screen.")
print("Press " .. (input.registerhotkey and "Lua hotkey 3" or sizekey) .. " to resize the icons.")
print("Press " .. (input.registerhotkey and "Lua hotkey 4" or scalekey) .. " to toggle icon stretching.")
print("Press " .. (input.registerhotkey and "Lua hotkey 5" or recordkey) .. " to start/stop recording to '" .. recordpath .. "' folder")
print()
]]--

local minimum_tile_size, maximum_tile_size = 4, 16
local icon_size, image_icon_size = inputs.properties.scrollinginput.iconsize
local thisframe, lastframe, module, keyset, changed = {}, {}
local margin, rescale_icons, recording, display, start, effective_width = {}, true, false
local draw = { [1] = true, [2] = true }
local inp  = { [1] =   {}, [2] =   {} }
local idle = { [1] =    0, [2] =    0 }

local allinputcounters  = { [1] =   {}, [2] =   {} }
local nullinputcounters = { [1] = {[1] = 0}, [2] = {[1] = 0}}  -- counters for null input for player 1 and player 2
local activeinputcounters = { [1] = {[1] = 0}, [2] = {[1] = 0}}  -- counters for active inputs player 1 and player 2

local isplayernullinput = { [1] = true, [2] = true }
local frameskip_currval = 0
local frameskip_prevval = 0
local was_frameskip = false

for m, scheme in ipairs(gamekeys) do --Detect what set to use.
	if string.find(iconfile:lower(), scheme.set[1]:lower()) then
		module = scheme
		for k, emu in pairs(scheme.set) do --Detect what emulator this is.
			if k > 1 and emu then
				keyset = k
				break
			end
		end
		break
	end
end
if not module then error("There's no module available for " .. iconfile, 0) end
if not keyset then error("The '" .. module.set[1] .. "' module isn't prepared for this emulator.", 0) end

--hardcoded check corrects button mapping discrepancy between Tekken 1/2 and Tekken3/TTT
if mame and emu.sourcename() == "namcos11.c" then
	module[11][keyset],module[12][keyset],module[13][keyset] = nil,"Button 3","Button 4"
end

resourcepath = resourcepath .. "/"
recordpath = recordpath .. "/"
emu = emu or gens
----------------------------------------------------------------------------------------------------
-- image-string conversion functions

local function hexdump_to_string(hexdump)
	local str = ""
	for n = 1, hexdump:len(), 2 do
		str = str .. string.char("0x" .. hexdump:sub(n,n+1))
	end
	return str
end

local function string_to_hexdump(str)
	local hexdump = ""
	for n = 1, str:len() do
		hexdump = hexdump .. string.format("%02X",str:sub(n,n):byte())
	end
	return hexdump
end
--example usage:
--local image = gd.createFromPng("image.png")
--local str = image:pngStr()
--local hexdump = string_to_hexdump(str)

local blank_img_hexdump = 
"89504E470D0A1A0A0000000D49484452000000400000002001030000009853ECC700000003504C5445000000A77A3DDA00" ..
"00000174524E530040E6D8660000000D49444154189563601805F8000001200001BFC1B1A80000000049454E44AE426082"
local blank_img_string = hexdump_to_string(blank_img_hexdump)

----------------------------------------------------------------------------------------------------
-- display functions

local function text(x, y, row)
	gui.text(x, y, module[row][1])
end

local function image(x, y, row)
	gui.gdoverlay(x, y, module[row].img)
end

display = image
if not io.open(resourcepath .. iconfile, "rb") then
	print("Icon file " .. iconfile .. " not found.")
	print("Falling back on text mode.")
	display = text
end

local function readimages()
	local scaled_width = icon_size
	if rescale_icons and emu.screenwidth and emu.screenheight then
		scaled_width = icon_size * emu.screenwidth()/emu.screenheight() / (4/3)
	end
	if display == image then
		sourceimg = gd.createFromPng(resourcepath .. iconfile)
		image_icon_size = sourceimg:sizeX()/2;
		for n, key in ipairs(module) do
			key.img = gd.createFromPngStr(blank_img_string)
			gd.copyResampled(key.img, sourceimg, 0, 0, 0,(n-1)*image_icon_size, scaled_width, icon_size, image_icon_size, image_icon_size)
			collectgarbage()
			key.img = key.img:gdStr()
		end
	end
	effective_width = scaled_width
end
readimages()
----------------------------------------------------------------------------------------------------
-- update functions

local function filterinput(p, frame)
	isplayernullinput[p] = true
	for pressed, state in pairs(joypad.getdown(p)) do --Check current controller state >
		for row, name in pairs(module) do               --but ignore non-gameplay buttons.
			if pressed == name[keyset]
		--Arcade does not distinguish joypads, so inputs must be filtered by "P1" and "P2".
			or pressed == "P" .. p .. " " .. tostring(name[keyset])
		--MAME also has unusual names for the start buttons.
			or pressed == p .. (p == 1 and " Player " or " Players ") .. tostring(name[keyset]) then
				frame[row] = state
				isplayernullinput[p] = false
				break
			end
		end
	end
end

local function compositeinput(frame)          --Convert individual directions to diagonals.
	for _,dir in pairs({ {1,3,5}, {2,3,6}, {1,4,7}, {2,4,8} }) do --ul, ur, dl, dr
		if frame[dir[1]] and frame[dir[2]] then
			frame[dir[1]], frame[dir[2]], frame[dir[3]] = nil, nil, true
		end
	end
end

local function detectchanges(lastframe, thisframe)
	changed = false
	for key, state in pairs(thisframe) do       --If a key is pressed >
		if lastframe and not lastframe[key] then  --that wasn't pressed last frame >
			changed = true                          --then changes were made.
			break
		end
	end
	if lastframe then                               -- zass: add check for full state change
		for key, state in pairs(lastframe) do       -- also check that a key last frame
			if thisframe and not thisframe[key] then  --that wasn't pressed this frame >
				changed = true                          --then changes were made.
				break
			end
		end
	end
end

-- updated by zass to show counters
local function updaterecords(player, frame, nullinputcounters, activeinputcounters)
	max_input = 999    --how long to hold input counter for
	if allinputcounters == nil then
		allinputcounters = { [1] =   {}, [2] =   {} }
	else
		if allinputcounters[player] == nil then
			allinputcounters[player] = {}
		end
	end
	local input = allinputcounters[player]

	if changed then                         --If changes were made >
		for record = buffersize, 2, -1 do
			if input ~= nil then
				input[record] = input[record-1]   --then shift every old record by 1 >
			end
			nullinputcounters[record] = nullinputcounters[record-1]   --then shift every old record by 1 >
			activeinputcounters[record] = activeinputcounters[record-1]   --then shift every old record by 1 >
		end
		idle[player] = 0                      --Reset the idle count >
		input[1] = {}                         --and set current input as record 1 >
		if isplayernullinput[player] == true then
			nullinputcounters[1] = 1;
			activeinputcounters[1] = 0;
			if was_frameskip then
				nullinputcounters[1] = 2;
				activeinputcounters[1] = 0;
			end
		else
			nullinputcounters[1] = 0;
			activeinputcounters[1] = 1;
			if was_frameskip then
				nullinputcounters[1] = 0;
				activeinputcounters[1] = 2;
			end

		end
		local index = 1
		for row, name in ipairs(module) do    --but the order must not deviate from gamekeys.
			for key, state in pairs(frame) do
				if key == row then
					input[1][index] = row
					index = index+1
					break
				end
			end
		end
	else
		if idle[player] == nil then
			idle[player] = 0
		end
		idle[player] = idle[player]+1         --Increment the idle count if nothing changed.
		if isplayernullinput[player] == true then
			nullinputcounters[1] = nullinputcounters[1] + 1
			if nullinputcounters[1] > max_input then
				nullinputcounters[1] = max_input
			end
			if was_frameskip then             -- increment again if there was a frameskip
				nullinputcounters[1] = nullinputcounters[1] + 1
				if nullinputcounters[1] > max_input then
					nullinputcounters[1] = max_input
				end
			end
		else
			activeinputcounters[1] = activeinputcounters[1] + 1
			if activeinputcounters[1] > max_input then
				activeinputcounters[1] = max_input
			end
			if was_frameskip then
				activeinputcounters[1] = activeinputcounters[1] + 1
				if activeinputcounters[1] > max_input then
					activeinputcounters[1] = max_input
				end
			end
		end
	end
end

-- added by zass, increment counters if frameskip
local function checkframeskip()
	frameskip_address = 0xFF801D
	frameskip_prevval = frameskip_currval
	frameskip_currval = memory.readbyte(frameskip_address)
	local x = frameskip_currval - frameskip_prevval
	if x % 2 == 0 then
		was_frameskip = true
	else
		was_frameskip = false
	end
end

----------------------------------------------------------------------------------------------------
-- savestate functions

--[[if savestate.registersave and savestate.registerload then --registersave/registerload are unavailable in some emus
	savestate.registersave(function(slot)
		return draw, inp, idle
	end)

	savestate.registerload(function(slot)
		draw, inp, idle = savestate.loadscriptdata(slot)
		if type(draw) ~= "table" then draw = { [1] = true, [2] = true } end
		if type(inp)  ~= "table" then inp  = { [1] =   {}, [2] =   {} } end
		if type(idle) ~= "table" then idle = { [1] =    0, [2] =    0 } end
	end)
end
--]]
----------------------------------------------------------------------------------------------------
-- hotkey functions

function togglescrollinginputsplayer()
	draw[1] = inputs.properties.scrollinginput.scrollingstate[1]
	draw[2] = inputs.properties.scrollinginput.scrollingstate[2]
end

togglescrollinginputsplayer()

--[[
local function resize()
	if icon_size < maximum_tile_size then
		icon_size = icon_size + minimum_tile_size/4
	else
		icon_size = minimum_tile_size
	end
	emu.message("Icon size: " .. icon_size)
	readimages()
end

local function togglescaling()
	rescale_icons = not rescale_icons
	if emu.screenwidth and emu.screenheight then
		emu.message("Icon stretching " .. (rescale_icons and "on." or "off."))
		readimages()
	else
		emu.message("This emulator does not support icon scaling.")
	end
end

local function togglerecording()
	recording = not recording
	if recording then
		start = movie.framecount()
		print("Started recording.")
	else
		local stop = movie.framecount()
		print("Stopped recording. (" .. stop - start .. " frames)")
		if stop > start then
			print(string.format("'moviedump-%06d.png' to 'moviedump-%06d.png'", start, stop-1))
		end
		print()
		start = nil
	end
end
--]]

--[[
if input.registerhotkey then
	input.registerhotkey(1, function()
		toggleplayer()
	end)
	
	input.registerhotkey(2, function()
		clear()
	end)

	input.registerhotkey(3, function()
		resize()
	end)

	input.registerhotkey(4, function()
		togglescaling()
	end)

	input.registerhotkey(5, function()
		togglerecording()
	end)
	
end
]]--

--[[
local oldswitch, oldclearkey, oldsizekey, oldscalekey, oldrecordkey
emu.registerbefore( function()
	if not input.registerhotkey then --use input.get if registerhotkey is unavailable
		local nowswitch = input.get()[playerswitch]
		if nowswitch and not oldswitch then
				toggleplayer()
		end
		oldswitch = nowswitch

		local nowclearkey = input.get()[clearkey]
		if nowclearkey and not oldclearkey then
			clear()
		end
		oldclearkey = nowclearkey

		local nowsizekey = input.get()[sizekey]
		if nowsizekey and not oldsizekey then
			resize()
		end
		oldsizekey = nowsizekey

		local nowscalekey = input.get()[scalekey]
		if nowscalekey and not oldscalekey then
			togglescaling()
		end
		oldscalekey = nowscalekey

		local nowrecordkey = input.get()[recordkey]
		if nowrecordkey and not oldrecordkey then
			togglerecording()
		end
		oldrecordkey = nowrecordkey
	end
end)
--]]

function scrollingInputReg()

	for i = 1, 2 do
		if not inputs.properties.scrollinginput.scrollinginputxoffset[i] then
			inputs.properties.scrollinginput.scrollinginputxoffset[i] = margin[i] 
		end
	end
	
	for i = 1, 2 do
		if not inputs.properties.scrollinginput.scrollinginputyoffset[i] then
			inputs.properties.scrollinginput.scrollinginputyoffset[i] = margin[3] 
		end
	end

	for player = 1, 2 do
		local xoffset = inputs.properties.scrollinginput.scrollinginputxoffset[player]
		local yoffset = inputs.properties.scrollinginput.scrollinginputyoffset[player]
		if draw[player] then
			local i = 0
			local skip = 0
			for line in pairs(allinputcounters[player]) do
				if inputs.properties.scrollinginput.frames then
					i = i + 1
					if nullinputcounters[player][i] > 0 and i == 1 then
						gui.text(xoffset - 10 + effective_width, (line-1)*icon_size + yoffset, "" .. nullinputcounters[player][i], 0xAACCCCFF)
					elseif i == 1 then
						if nullinputcounters[player][i+1] and nullinputcounters[player][i+1] > 0 then
							gui.text(xoffset - 10 + effective_width, (line-1)*icon_size + yoffset, "" .. nullinputcounters[player][i+1], 0xAACCCCFF)
						end
						gui.text(xoffset + 5 + effective_width, (line-1)*icon_size + yoffset, "" .. activeinputcounters[player][i])
					-- if it's line 2 or higher
					elseif activeinputcounters[player][i] == 0 then
						skip = skip + 1 -- log a skip for an empty input
					else
						if nullinputcounters[player][i+1] and nullinputcounters[player][i+1] > 0 then
							gui.text(xoffset - 10 + effective_width, (line-1-skip)*icon_size + yoffset, "" .. nullinputcounters[player][i+1], 0xAACCCCFF)
						end
						gui.text(xoffset + 5 + effective_width, (line-1-skip)*icon_size + yoffset, "" .. activeinputcounters[player][i], "yellow")
					end

					-- display inputs, skipping a line for every empty input.
					for index,row in pairs(allinputcounters[player][line]) do
						display((index-1)*effective_width + xoffset + 30,  (line-1-skip)*icon_size + yoffset, row)
					end
				else
					for index,row in pairs(allinputcounters[player][line]) do
						display((index-1)*effective_width + xoffset, (line-1)*icon_size + yoffset, row)
					end
				end
			end
		end
	end
end

function scrollingInputRegAfter()
	if (interactivegui.movehud.enabled) then return end
	margin[1] = margin_left*effective_width
	margin[2] = (emu.screenwidth and emu.screenwidth() or screenwidth) - margin_right*effective_width
	margin[3] = margin_top*icon_size
	for player = 1, 2 do
		thisframe = {}
		if player == 1 and emu.romname() == "ssf2xjr1" then
			checkframeskip() -- only check frameskip once
		end
		filterinput(player, thisframe)
		compositeinput(thisframe)
		detectchanges(lastframe[player], thisframe)
		updaterecords(player, thisframe, nullinputcounters[player], activeinputcounters[player])
		lastframe[player] = thisframe
	end
	if recording then
		gd.createFromGdStr(gui.gdscreenshot()):png(resourcepath .. recordpath .. string.format("moviedump-%06d.png", movie.framecount()))
	end
end

function scrollingInputReload()
	toggleshowframes()
	icon_size, image_icon_size = inputs.properties.scrollinginput.iconsize
	readimages()
	togglescrollinginputsplayer()
end

function scrollingInputClear()
	idle = {[1] = 0, [2] = 0}
	allinputcounters  = {[1] = {}, [2] = {}}
end

function scrollingInputSetInput(allinput, nullinput, activeinput)
	if type(allinput)~="table" then return allinputcounters end
	if type(nullinput)~="table" then return nullinputcounters end
	if type(activeinput)~="table" then return activeinputcounters end
	allinputcounters = allinput
	nullinputcounters = nullinput
	activeinputcounters = activeinput
end

function scrollingInputSetSampleInput() -- for display to judge size of scrollinginputs
	local allinput, nullinput, activeinput
	allinput =  {
				{{1},{1},{1},{1},{1},{1},{1},{1},{1},{1},{1},{1},{1}},
				{{1},{1},{1},{1},{1},{1},{1},{1},{1},{1},{1},{1},{1}}
				}
	
	nullinput = {
				{1,1,1,1,1,1,1,1,1,1,1,1,1},
				{1,1,1,1,1,1,1,1,1,1,1,1,1}
				}
	
	activeinput={
				{1,1,1,1,1,1,1,1,1,1,1,1,1},
				{1,1,1,1,1,1,1,1,1,1,1,1,1}
				}
	scrollingInputSetInput(allinput, nullinput, activeinput)
end
