pattern={}

PATTERN_RANDOM = "random"
PATTERN_CHASE  = "chase"
PATTERN_AVOID  = "avoid"

function pattern.new()
    return {
        node = {},      -- array de punts ( node[1] = punt1,... node[n] = puntN )
        path = {},      -- array de camins entre nodes ( path[1] = { {target=2, actions={ {action="right", until="land"} ...} } ...} )
        path_idx = 0,   -- punter a path actiu (coincidix en el node)
        target_idx = 1, -- punter a target actiu, no al número de target si no a l'index dins del path
        action_idx = 1, -- punter a l'acció actual
        manual_target = {},
        manual_path = {},
        poi = {}, -- points of interest
        -- target_modes = { PATTERN_RANDOM, PATTERN_CHASE, PATTERN_AVOID },
        target_mode = PATTERN_RANDOM,
        next_action = pattern.next_action,
        next_target = pattern.next_target,
        in_target = pattern.in_target,
        target = pattern.target,
        target_node = pattern.target_node,
        action = pattern.action,
        event = pattern.event,
        actions = pattern.actions,
        -- recovery = pattern.noop,
        draw = pattern.draw,
        collision = pattern.collision,
        add_manual_target = pattern.add_manual_target,
        set_target_mode = pattern.set_target_mode,
    }
end

function pattern:set_target_mode ( mode, poi )
    self.poi = poi or {}
    self.target_mode = mode
end

function pattern:add_manual_target ( node, path )
    self.manual_target = self.node[node]
    self.manual_path = path
    self.target_idx = 1
    self.action_idx = 1
end

function pattern:noop()
    print("NO OP")
end

function pattern:draw()
    if true then return end
    local scr_x = 0
    local scr_y = 0
    local target = self:target()
    for k, v in pairs(self.node) do
        scr_x, scr_y = viewp:screen_coords( v.x, v.y )
        if self.path_idx==k or target==k then
            draw.rectf(scr_x, scr_y, 16, 16, 13)
        else
            draw.rectf(scr_x, scr_y, 16, 16, 16)
            draw.rect(scr_x, scr_y, 16, 16, k)
        end
        if target ~= nil and target==k then 
            draw.rectf(scr_x, scr_y, 16, 16, 15)
        end
        draw.text(k, scr_x+4, scr_y+4, k)
    end
end
-- Necessite saber quina estrategia aplicar abans de moure al següent target
-- ara aleatori

function pattern:origin()
print_dbg("")
    return self.node[self.path_idx]
end

function pattern:origin_num ()
print_dbg("")
    return self.path_idx
end

function pattern:set_path ( num )
print_dbg("")
    self.path_idx = num
end

function pattern:get_path ( num )
print_dbg("")
    return self.path[num]
end


-- [OK] Torna el id del target actual
-- function pattern:get_target ( )
    -- return self.path[self.path_idx][target_idx].target
-- end
function pattern:target()
    if not empty_table(self.manual_path) then
-- print_dbg("MANUAL => "..self.manual_path.target)
        return self.manual_path.target
    else
        if #self.path>0 then
-- print_dbg("PATH => "..self.path[self.path_idx][self.target_idx].target)
        return self.path[self.path_idx][self.target_idx].target
        end
    end
    return nil
end

-- [OK] Torna la llista d'accions actual
-- function pattern:get_actions ( )
    -- return self.path[self.path_idx][target_idx].actions
-- end
function pattern:actions()
print_dbg("")
    if not empty_table(self.manual_path) then
        return self.manual_path.actions
    else
        return self.path[self.path_idx][self.target_idx].actions
    end
end

-- [OK] Torna l'acció actual
-- function pattern:get_action ( )
    -- return self.path[self.path_idx][target_idx].actions[self.action_idx]
-- end
function pattern:action()
    if not empty_table(self.manual_path) then
-- print_dbg("MANUAL => "..self.manual_path.actions[self.action_idx].action)
        return self.manual_path.actions[self.action_idx].action
    else
-- print_dbg("PATH => "..self.path[self.path_idx][self.target_idx].actions[self.action_idx].action)
        return self.path[self.path_idx][self.target_idx].actions[self.action_idx].action
    end
end

-- [OK] Torna l'event actual
function pattern:event()
-- print_dbg("")
    if not empty_table(self.manual_path) then
        return self.manual_path.actions[self.action_idx].event
    else
        return self.path[self.path_idx][self.target_idx].actions[self.action_idx].event
    end
end

-- [OK] Obtindre la següent acció a fer
-- function pattern:next()
    -- self.action_idx = self.action_idx+1
    -- if self.action_idx>#self.path[self.path_idx][self.target_idx].actions then
        -- pattern:next_target() -- pasar per paràmetre o no
    -- end
    -- return pattern:action()
-- end
function pattern:next_action ( )
-- print_dbg("")
    local num_actions = 0
    -- index a la següent acció
    self.action_idx = self.action_idx+1
    -- comprovar si no queden accions disponibles
    if not empty_table(self.manual_path) then
        num_actions = #self.manual_path.actions
    else 
        num_actions = #self.path[self.path_idx][self.target_idx].actions
    end
    if self.action_idx>num_actions then
        -- avançar el target
        self:next_target() -- pasar per paràmetre o no
    end
    -- Tornar l'acció
    return self:action()
end

-- [OK] Canvia al següent target segons el path o al que se li pase
function pattern:next_target( target )
-- print_dbg("")
    target = target or self:target()
    -- Si hi ha una entrada manual eliminar-la
    if not empty_table(self.manual_path) then
        self.manual_path = {}
        self.manual_target = {}
    end
    
    -- target id
    self.path_idx = target

    -- tindre en compte l'estrategia per a triar el següent target des del path actual per ara aleatori
    if self.poi.x == nil or self.poi.y == nil then 
        self.target_mode = PATTERN_RANDOM
    end

    if #self.path[self.path_idx]==1 then
        self.target_idx = 1
    elseif self.target_mode == PATTERN_RANDOM then
        self.target_idx = math.random(#self.path[self.path_idx])
    else
        -- calcular distancies
        local next_target_min = 0
        local next_target_max = 0
        local min_distance = -1
        local max_distance = 0
        local d = 0
        for k, v in pairs(self.path[self.path_idx]) do
            d = distancia( self.node[v.target], self.poi )
            if d>max_distance then
                max_distance = d
                next_target_max = k
            end
            if min_distance==-1 and d>=0 then min_distance=d+1 end
            if d<min_distance and d>=0 then
                min_distance = d
                next_target_min = k
            end
        end
        -- asignar target segons el mode
        if self.target_mode==PATTERN_CHASE then
            self.target_idx = next_target_min
        elseif self.target_mode==PATTERN_AVOID then
            self.target_idx = next_target_max
        else
            self.target_idx = math.random(#self.path[self.path_idx])
        end
        
    end

    self.action_idx = 1
end

-- [OK] Torna el node del target actual
function pattern:target_node()
-- print_dbg(self.node[self:target()])
    return self.node[self:target()]
end

-- Comprova si point ha arribat al target (Afegir precissio per si volem que estiga nomes tocar, dins o abans d'eixir?)
function pattern:in_target( a )
--if collision( a, self:target_node() ) then
    -- print_dbg("COLLISION")
--else
    -- print_dbg("-")
--end
    return self:collision( a )
end

function pattern:collision( a )
    local b = self:target_node()
    return     (a.x+a.bb.x+a.bb.w >= b.x+b.bb.x) 
           and (a.x+a.bb.x <= b.x+b.bb.x+b.bb.w) 
           and (a.y+a.bb.y+a.bb.h >= b.y+b.bb.y) 
           and (a.y+a.bb.y+a.bb.h == b.y+b.bb.y+b.bb.h) -- part de baix dels dos
end