Shape = copy_table(BaseObject)

function Shape:init(def, view, skip_create_area)
    self.view = view
    self.enabled = true
    if def.disabled then
        self.enabled = false
    end
    self.hi_alpha = 0
    
    self.x = def.x
    self.y = def.y
    self.z = def.z
    self.angle = def.angle or 0
    self.extra = def.extra

    self.w = def.w
    self.h = def.h
    self.cx = def.cx or 0
    self.cy = def.cy or 0

    if def.mouse_click then
        self.call_mouse_click = view[def.mouse_click]
    end
    
    if not skip_create_area and self:area_needed() then
        self:create_area(def.area)
    end
end


function Shape:destroy()
end


function Shape:update(dt)
    self:highlight_update(dt)
end


function Shape:area_needed()
    return self.call_mouse_click or self.mouse_left_click or self.mouse_left_down
end


function Shape:create_area(def)
    self.area = {}

    if def then
        self.area.x0 = def.x0 or 0
        self.area.y0 = def.y0 or 0
        self.area.x1 = def.x1 or self.w - 1
        self.area.y1 = def.y1 or self.h - 1
    else
        self.area.x0 = 0
        self.area.y0 = 0
        self.area.x1 = self.w - 1
        self.area.y1 = self.h - 1
    end

    local dx = self.area.x1 - self.area.x0
    local dy = self.area.y1 - self.area.y0

    self.area.x0 = -1 * (self.cx - self.area.x0)
    self.area.y0 = -1 * (self.cy - self.area.y0)

    self.area.x1 = self.area.x0 + dx
    self.area.y1 = self.area.y0 + dy
    
    self.mouse_over = false
end


function Shape:render_area_box()
    gfx_render_box(self.x, self.y, self.area.x1 - self.area.x0 + 1, self.area.y1 - self.area.y0 + 1, 0.6, self.angle or 0, "ffffff", -self.area.x0, -self.area.y0)
end

function Shape:point_inside(px, py)
    px = px - self.x
    py = py - self.y

    if self.angle and self.angle ~= 0 then
        -- rotate vector to match area's rotation
        local cosa = math.cos(math.rad(-self.angle))
        local sina = math.sin(math.rad(-self.angle))
        px, py = px * cosa - py * sina, px * sina + py * cosa
        --debug_info = "angle "..self.angle..", px "..px..", py "..py
        --debug_info = debug_status..", area: "..self.area.x0.." "..self.area.y0.." "..self.area.x1.." "..self.area.y1
    end
    
    return px >= self.area.x0 and py >= self.area.y0 and px <= self.area.x1 and py <= self.area.y1
end


function shapes_overlap(shape1, shape2)
    -- Based on Oren Becker's algorithm: http://www.ragestorm.net/tutorial?id=22
    -- Caution: function assumes that objects' centers lie exactly
    -- in their physical centers, so you can't have i.e. object rotated around
    -- one of its vertices. For our case it's good enough though.

    local ax, ay, bx, by        -- vertices of the rotated shape2
    local cx, cy                -- center of shape2
    local blx, bly, trx, try    -- vertices of shape2 (bottom-left, top-right)
    
    local ang = shape1.angle - shape2.angle -- orientation of rotated shape1
    local cosa = math.cos(math.rad(ang))
    local sina = math.sin(math.rad(ang))

    local t, x, a       -- temporary variables for various uses
    local dx            -- deltaX for linear equations
    local ext1, ext2    -- min/max vertical values
    
    local w1 = math.floor((shape1.area.x1 - shape1.area.x0) / 2)
    local h1 = math.floor((shape1.area.y1 - shape1.area.y0) / 2)
    local w2 = math.floor((shape2.area.x1 - shape2.area.x0) / 2)
    local h2 = math.floor((shape2.area.y1 - shape2.area.y0) / 2)

    -- move shape2 to make shape1 cannonic
    cx = shape2.x - shape1.x
    cy = shape2.y - shape1.y

    -- rotate shape2 clockwise by shape2->angle to make shape2 axis-aligned
    local cos2 = math.cos(math.rad(-shape2.angle))
    local sin2 = math.sin(math.rad(-shape2.angle))
    cx, cy = cx * cos2 - cy * sin2, cx * sin2 + cy * cos2

    -- calculate vertices of (moved and axis-aligned := 'ma') shape2
    blx = cx - w2
    bly = cy - h2
    trx = cx + w2
    try = cy + h2

    -- calculate vertices of (rotated := 'r') shape1
    ax = w1 * cosa - h1 * sina
    ay = w1 * sina + h1 * cosa

    bx = -w1 * cosa - h1 * sina
    by = -w1 * sina + h1 * cosa

    t = sina * cosa
    
    -- verify that A is vertical min/max, B is horizontal min/max
    if t < 0 then
        ax, bx = bx, ax
        ay, by = by, ay
    end

    -- verify that B is horizontal minimum (leftest-vertex)
    if sina < 0 then
        bx = -bx
        by = -by
    end

    -- if shape2(ma) isn't in the horizontal range of
    -- colliding with shape1(r), collision is impossible
    if bx > trx or bx > -blx then
        return false
    end

    -- if shape1(r) is axis-aligned, vertical min/max are easy to get
    if t == 0 then
        ext1 = ay
        ext2 = -ext1
    else
        -- else, find vertical min/max in the range [BL.x, TR.x]
        x = blx - ax
        a = trx - ax
        ext1 = ay

        -- if the first vertical min/max isn't in (BL.x, TR.x), then
        -- find the vertical min/max on BL.x or on TR.x
        if a * x > 0 then
            dx = ax
            if x < 0 then
                dx = dx - bx
                ext1 = ext1 - by
                x = a
            else
                dx = dx + bx
                ext1 = ext1 + by
            end
            ext1 = ext1 * x
            ext1 = ext1 / dx
            ext1 = ext1 + ay
        end

        x = blx + ax
        a = trx + ax
        ext2 = -ay
        
        -- if the second vertical min/max isn't in (BL.x, TR.x), then
        -- find the local vertical min/max on BL.x or on TR.x
        if a * x > 0 then
            dx = -ax
            if x < 0 then
                dx = dx - bx
                ext2 = ext2 - by
                x = a
            else
                dx = dx + bx
                ext2 = ext2 + by
            end
            ext2 = ext2 * x
            ext2 = ext2 / dx
            ext2 = ext2 - ay
        end
    end

    -- check whether shape2(ma) is in the vertical range of colliding with shape1(r)
    -- (for the horizontal range of shape2)
    return not ((ext1 < bly and ext2 < bly) or (ext1 > try and ext2 > try))
end


function Shape:highlight_update(dt)
    if self.highlight_on and self.mouse_over then
        self.hi_alpha = self.hi_alpha + dt * 5
        if self.hi_alpha < 0.2 then self.hi_alpha = 0.2 end
        if self.hi_alpha > 1 then
            self.hi_alpha = 1
        end
    else
        self.hi_alpha = self.hi_alpha - dt * 5
        if self.hi_alpha < 0  then
            self.hi_alpha = 0
        end
    end
end
