--- Module that provides a DSL for specifying states in the FSM DSL framework.
-- @module lqc.fsm.state
-- @alias make_state
--- Checks if object is callable (a function or a functable)
-- @param obj Object to check
-- @return true if obj is callable; otherwise false.
local function is_callable(obj)
    local type_obj = type(obj)
    return type_obj == 'function' or type_obj == 'table'
end

--- Checks if the state contains all the necessary info for a valid state specification
-- @param state table containing precondition, next_state and postcondition
-- @param state_name name of the state
-- @return nil; raises an error if state contains wrong or missing information
local function check_valid_state(state, state_name)
    if type(state_name) ~= 'string' then
        error 'Missing state name!'
    end
    if type(state) ~= 'table' then
        error 'State should be specified as a table!'
    end
    if not is_callable(state.precondition) then
        error('Need to provide a precondition function to state ' .. state_name .. '!')
    end
    if not is_callable(state.next_state) then
        error('Need to provide a next_state function to state ' .. state_name .. '!')
    end
    if not is_callable(state.postcondition) then
        error('Need to provide a postcondition function to state ' .. state_name .. '!')
    end
end

--- Helper function for specifying a state in the FSM
-- @param state_name Name to assign to the state
-- @param state_information Table containing precondition, next_state, postcondition functions
-- @return new table containing state information, ready to be added to the FSM
local function make_state(state_name, state_information)
    local function make_state_helper(state_info)
        check_valid_state(state_info, state_name)
        return {
            name = state_name,
            precondition = state_info.precondition,
            next_state = state_info.next_state,
            postcondition = state_info.postcondition,
        }
    end

    if state_information ~= nil then
        -- Called with normal syntax, directly return result
        return make_state_helper(state_information)
    end

    -- called with Lua DSL syntax, return closue which returns result
    return make_state_helper
end

return make_state

