-- This Lua script sends Stimulations to the speller visualization box for a tactile p300-System with 6 stimulators
--
-- Author : Tobias Baumann
-- Date   : 2021-12-06
-- Revised: 2021-19-11

--This function lets the box sleep until a fixed moment
function wait_until(box, time)
	while box:get_current_time() < time do
		box:sleep()
	end
end

--This function lets the box wait for a fixed duration
function wait_for(box, duration)
	wait_until(box, box:get_current_time() + duration)
end

--this function checks, wether value already is an element of the given stim_matrix
function is_element(matrix, value)
	for i = 1, #matrix do
		if #matrix == 0 then
			return(false)
		elseif value == matrix[i] then
			return(true)
		end
	end
	return(false)
end
--this function creates a sequence of stimulations by shuffeling the values of the given stim_matrix
function create_sequence(matrix)
	math.randomseed(os.time())
	local stim_matrix = {}
	local stim_code = 0
	local i = 1
	while i <= #matrix do
		stim_code = matrix[math.random(1,#matrix)]	
		if is_element(stim_matrix, stim_code) == false then
			stim_matrix[i] = stim_code
			i = i + 1
		end
	end
	return(stim_matrix)
end

-- this function is called when the box is initialized
function initialize(box)
	--load stimulation codes
	dofile(box:get_config("${Path_Data}") .. "/plugins/stimulation/lua-stimulator-stim-codes.lua")
	
	--load box settings
	row_base = _G[box:get_setting(2)]
	col_base = _G[box:get_setting(3)] 
	n_rows = box:get_setting(4)
	n_repetitions = box:get_setting(5)
	flash_duration = box:get_setting(7)
	noflash_duration = box:get_setting(8)
	inter_repetition_delay = box:get_setting(9)
	inter_trial_delay = box:get_setting(10)
	send_toggle = _G[box:get_setting(11)]
	time_to_send = box:get_setting(13)
	
	if box:get_setting(12) == 'true' then
		free_spelling = true
		n_trials = 1
	else
		free_spelling = false
		n_trials = box:get_setting(6)
	end
	
	--Lua variables
	send = false
	experiment_end = false
	tactilo_stimcodes = {}
	for x = 1, n_rows do
		tactilo_stimcodes[x] = row_base + x - 1
	end
end

-- this function is called when the box is uninitialized
function uninitialize(box)

end

-- this function is called once by the box
function process(box)
	while box:keep_processing() do
	
		if send and not experiment_end then
			-- iterate over the number of trials
			for trial = 1, n_trials do
				box:send_stimulation(1, OVTK_StimulationId_RestStart, box:get_current_time() , 0)
				wait_for(box, inter_trial_delay)
				box:send_stimulation(1, OVTK_StimulationId_RestStop, box:get_current_time() , 0)
				box:send_stimulation(1, OVTK_StimulationId_TrialStart ,box:get_current_time() , 0)
				
				-- iterate over the number of repetitions
				for segment = 1, n_repetitions do
					tactilo_stimcodes = create_sequence(tactilo_stimcodes)
					box:send_stimulation(1, OVTK_StimulationId_SegmentStart ,box:get_current_time() , 0)
					
					-- iterate over the number of tactilos
					for i = 1, #tactilo_stimcodes do
						box:send_stimulation(1, tactilo_stimcodes[i] ,box:get_current_time() , 0)
						box:send_stimulation(1, OVTK_StimulationId_VisualStimulationStart ,box:get_current_time() , 0)
						wait_for(box, flash_duration)
						box:send_stimulation(1, OVTK_StimulationId_VisualStimulationStop ,box:get_current_time() , 0)
						wait_for(box, noflash_duration)
					end
					
					box:send_stimulation(1, OVTK_StimulationId_SegmentStop ,box:get_current_time() , 0)
					wait_for(box, inter_repetition_delay)
				end
				
				box:send_stimulation(1, OVTK_StimulationId_TrialStop ,box:get_current_time() , 0)
			
			end
			
			if not free_spelling then
				-- end experiment if set to copy spelling
				box:send_stimulation(1, OVTK_StimulationId_ExperimentStop ,box:get_current_time() , 0)
				send = false
				experiment_end = true
			end
			
		else if not send and not experiment_end then
			-- delay the start of the experiment by t = time_to_send
			wait_for(box, time_to_send)
			send = true
			box:send_stimulation(1, OVTK_StimulationId_ExperimentStart ,box:get_current_time() , 0)
		end
		
		end
		-- releases cpu
		box:sleep()
	end
	
end