include("class.lua")
include("hud.lua")
include("vec2d.lua")
include("util.lua")

MapGauge = class(HudGauge)

function MapGauge:init()
    self:move(0.7, 0)
    self:resize(gr.getScreenWidth() - self.x, 0.3)
    self:setColor(0, 255, 0, 128)

    self.margin = 0

    self.radius = gr.CurrentFont.Height / 2
    self.xOff = self.width / 2
    self.yOff = self.height / 2

    self.xMargin = self.xOff - self.radius
    self.yMargin = self.yOff - self.radius

    self:setClipping(true)
end

function MapGauge:getName()
    return "Map gauge"
end

function MapGauge:getDescription()
    return "A gauge that shows objects around the parent ship"
end

function MapGauge:mapScale()
    local defaultScale = self.script:getShip().Class.Model.Radius / (math.min(self.xOff, self.yOff) / 3)

    return defaultScale * self.hudScript:getConfig():getMapScale()
end

function MapGauge:getDisplayRadius(obj)
    return self:getObjectRadius(obj) / self:mapScale()
end

function MapGauge:getObjectRadius(obj)
    local name = obj:getBreedName()

    if (name == "Ship") then
        return obj.Class.Model.Radius
    elseif (name == "Weapon") then
        if (obj.Class:isMissile() and obj.Class.Model:isValid()) then
            return obj.Class.Model.Radius
        else
            return self.radius
        end
    else
        return self.radius
    end
end

function MapGauge:getVectorCoords(vec)
    local posDiff = self.script:getShip().Position - vec
    posDiff = self.script:getShip().Orientation:rotateVector(posDiff)

    local x = self.xOff - (posDiff.x / self:mapScale())
    local y = self.yOff + (posDiff.z / self:mapScale())

    if (math.abs(posDiff.x) <= self.maxXDiff and math.abs(posDiff.z) <= self.maxYDiff) then
        return x, y
    else
        return false, x, y
    end
end

function MapGauge:computeModelOrient(obj)
    local orient = obj.Orientation
    local other = self.script:getShip().Orientation

    local diff = other:getTranspose() * orient

    return ba.createOrientation((-math.pi / 2), 0, 0) * diff
end

function MapGauge:drawObject(obj, display, useTeamColor, alpha)
    if (obj:getBreedName() == "Ship") then
        if (obj.HiddenFromSensors or obj.Stealthed) then
            return nil
        end
    end

    local x, y, y2 = self:getVectorCoords(obj.Position)

    local visible = x ~= false

    if (not visible) then
        x = y
        y = y2
    end

    if (obj:getBreedName() == "Ship") then
        local r, g, b
        if (obj:isWarpingIn()) then
            r = 0
            g = 0
            b = 255
        else
            if (useTeamColor) then
                r, g, b = obj.Team:getColor()
            end
        end

        if (alpha) then
            gr.setColor(r, g, b, alpha)
        else
            gr.setColor(r, g, b)
        end
    end

    local xOff

    local objRadius = self:getDisplayRadius(obj)
    if (self:getObjectRadius(obj) < self:getObjectRadius(self.script:getShip()) * self.hudConfig:getModelFraction()
            or obj:getBreedName() ~= "Ship") then
        if (objRadius < 1) then
            objRadius = 2
        end

        self:drawCircle(x, y, objRadius)

        xOff = objRadius
    else
        local vec1 = obj.Position + obj.Orientation:unrotateVector(obj.Class.Model.BoundingBoxMax)
        local vec2 = obj.Position + obj.Orientation:unrotateVector(obj.Class.Model.BoundingBoxMin)

        local drawModel = true

        local x1, y1, y11 = self:getVectorCoords(vec1)
        local x2, y2, y21 = self:getVectorCoords(vec2)

        if (x1 == false) then
            drawModel = false
            x1 = y1
            y1 = y11
        end

        if (x2 == false) then
            drawModel = false
            x2 = y2
            y2 = y21
        end

        if (x1 > x2) then
            local temp = x2
            x2 = x1
            x1 = temp
        end
        if (y1 > y2) then
            local temp = y2
            y2 = y1
            y1 = temp
        end

        self:drawRectangle(x1, y1, x2, y2, false)

        local x1, y1 = self:__transform(x1, y1, true)
        local x2, y2 = self:__transform(x2, y2, true)

        if (drawModel) then
            obj.Class:renderTechModel2(x1, y1, x2, y2, self:computeModelOrient(obj))
        end

        self:setClip()

        xOff = x2
    end

    self:drawString(display:filterInvisible(), x + xOff * 1.1, y - gr.CurrentFont.Height / 2)

    return x, y
end

function MapGauge:drawShips()
    -- Draw parent ship first
    self:drawObject(self.script:getShip(), self.script:getShip().Name, true, 130)

    for i = 1, #mn.Ships do
        local ship = mn.Ships[i]
        if (ship ~= self.script:getShip()) then
            local dist = ship.Position:getDistance(self.script:getShip().Position)
            local a = dist * -0.04 + 255
            if (a < 10) then
                a = 10
            elseif (a > 255) then
                a = 255
            end

            self:drawObject(ship, ship.Name, true, a)
        end
    end
end

function MapGauge:drawBombs()
    gr.setColor(255, 255, 0, 230)
    for i = 1, #mn.Weapons do
        local bomb = mn.Weapons[i]
        if (bomb.Class.Bomb) then
            self:drawObject(bomb, bomb.Class.Name)
        end
    end
end

function MapGauge:drawSubsystem(parent, subsys, useTeamColor, alpha)
    local posDiff
    if (parent == self.script:getShip()) then
        posDiff = self.script:getShip().Position - (parent.Position + parent.Orientation:unrotateVector(subsys.Position))
        posDiff = self.script:getShip().Orientation:rotateVector(posDiff)
    else
        posDiff = subsys.Position
    end

    if (math.abs(posDiff.x) <= self.maxXDiff and math.abs(posDiff.z) <= self.maxYDiff) then
        if (useTeamColor) then
            local r, g, b = parent.Team:getColor()
            if (alpha) then
                gr.setColor(r, g, b, alpha)
            else
                gr.setColor(r, g, b)
            end
        end

        local x = self.xOff - (posDiff.x / self:mapScale())
        local y = self.yOff + (posDiff.z / self:mapScale())

        self:drawCircle(x, y, self.radius / self:mapScale())

        return x, y
    end
end

function MapGauge:drawParentSubsystem()
    local x, y = self:drawSubsystem(self.script:getShip(), self.script:getSubsystem():get())
end

function MapGauge:finalize()
    self:drawParentSubsystem()

    gr.setColor(0, 255, 0, 230)

    local xDiff = 70
    local str = string.format("%.0f m", self:mapScale() * xDiff)

    local startX = gr.CurrentFont.Height + 7
    local startY = self.height - gr.CurrentFont.Height - 7

    local endX = startX + xDiff
    local endY = startY

    self:drawLine(startX, startY, endX, endY)

    self:drawLine(startX, startY - 5, startX, startY + 5)
    self:drawLine(endX, endY - 5, endX, endY + 5)

    local stringX = startX + ((xDiff - gr.getStringWidth(str)) / 2)
    local stringY = startY + 4

    self:drawString(str, stringX, stringY)
end

function MapGauge:render()
    self:setupRendering()

    self.maxXDiff = self.xMargin * self:mapScale()
    self.maxYDiff = self.yMargin * self:mapScale()

    gr.setColor(255, 255, 255, 50)
    self:drawRectangle(0, 0, self.width, self.height, true)

    self:drawShips()

    self:drawBombs()

    self:finalize()

    self:doneRendering()
end

function MapGauge:shouldDraw()
    return not self.hudConfig:isShowingHelp()
end

return MapGauge
