include("class.lua")
include("turretContrFRED.lua")
include("subsystem.lua")

TurretControlScript = class()

function TurretControlScript:init()
    self.ship = nil
    self.subsys = nil
    self.subsystem = nil

    self.mainCam = nil

    self.desiredOrientation = nil

    self.rotationTime = 2

    self.hookListeners = {}

    self.config = TurretControlConfig(self)

    self.fredInterface = TurretControlFRED(self)
end

function TurretControlScript:addListener(listener)
    table.insert(self.hookListeners, listener)
end

function TurretControlScript:fireHook(hookName, ...)
    for __, v in ipairs(self.hookListeners) do
        local func = v[hookName]

        if (type(func) == "function") then
            func(v, self, ...)
        end
    end
end

function TurretControlScript:getConfig()
    return self.config
end

function TurretControlScript:preMissionInit()
    self.mainCam = gr.createCamera("Turret Cam")

    self.nearOffset = ba.createVector(0, 10, -10)
    self.farOffset = ba.createVector(0, 15, -20)

    self.desiredOrientation = nil

    self.fireTurret = false

    self.isOkToFire = false

    self.zoomMode = false

    self:fireHook("onMissionInit")
end

function TurretControlScript:onMissionStart()
    self:preMissionInit()

    self.active = false

    self.inMission = true
end

function TurretControlScript:onMissionEnd()
    self:fireHook("onMissionEnd")

    self.inMission = false

    self.active = false
end

function TurretControlScript:onFrame()
    gr.drawString("", 300, 200)
    for i, v in pairs(Globals.HotKeyManager.pressTimes) do
        gr.drawString(string.format("%q: %.2f s ago", i, os.clock() - v))
    end

    if (not self:isValid()) then
        self:setActive(false)

        return
    end

    if (not self:isActive()) then
        return
    end

    self:update()
end

function TurretControlScript:update()
    self:handleInput()

    self:updateTurret()

    self:updateCamera()

    self:fireHook("onUpdate")
end

function TurretControlScript:handleInput()
    if (not self:isManual()) then
        return
    end

    local input = ba.getControlInfo()

    self.desiredOrientation.p = self.desiredOrientation.p + (((2 * math.pi) / self.rotationTime) * ba.getFrametime() * input.Pitch)
    self.desiredOrientation.h = self.desiredOrientation.h + (((2 * math.pi) / self.rotationTime) * ba.getFrametime() * input.Heading)

    self:checkOkToFire()

    if (input.PrimaryCount > 0) then
        self.fireTurret = self.isOkToFire
    else
        self.fireTurret = false
    end

    if (input.SecondaryCount > 0) then
        -- Enable zooming
    end
end

function TurretControlScript:checkOkToFire()
    local nextFirePos, dir = self.subsys:getNextFiringPosition()
    local vec = self.ship:checkRayCollision(nextFirePos,
        nextFirePos + dir * self.ship.Class.Model.Radius)

    if (vec) then
        self.isOkToFire = false
    else
        self.isOkToFire = true
    end
end

function TurretControlScript:updateTurret()
    if (not self:isManual()) then
        return
    end

    local targetPoint = self.ship.Orientation:unrotateVector(self.desiredOrientation:unrotateVector(ba.createVector(0, 0, 50))) + self.subsystem:getWorldPosition()

    self.subsys:rotateTurret(targetPoint)

    if (self.fireTurret) then
        self.subsys:fireWeapon()
    end
end

function TurretControlScript:updateCamera()
    local newOrient = self.subsys:getTurretHeading():getOrientation()
    newOrient.b = self.subsys:getTurretMatrix().b
    self.mainCam.Orientation = newOrient

    local pitch = -self.mainCam.Orientation.p

    if (pitch < 0) then
        pitch = 0
    end

    local perc = 1 - (pitch / (math.pi / 2))

    self.mainCam.Position = self.subsys.Orientation:unrotateVector(self.nearOffset + (self.farOffset - self.nearOffset) * perc)
end

function TurretControlScript:setManual(bool)
    if (not self:isActive()) then
        return
    end

    if (bool == nil) then
        bool = not self.manual
    end

    self.subsys:targetingOverride(bool)

    if (bool) then
        self.TurretResets = false
    else
        self.TurretResets = self.turretResets
    end

    self.manual = bool

    self:fireHook("onManualSet", self.manual)
end

function TurretControlScript:setTarget(ship, subsys)
    if (not self.inMission) then
        return false
    end

    if (ship == nil or not ship:isValid()) then
        return
    end

    if (subsys == nil or not subsys:isValid()) then
        return
    end

    if (not subsys:isTurret()) then
        return
    end

    self.ship = ship
    self.subsys = subsys
    self.subsystem = SubsystemContainer(self.ship, self.subsys)

    self.turretResets = self.subsys.TurretResets

    self.rotationTime = self.subsys.TurnRate

    self.desiredOrientation = self.subsys:getTurretHeading():getOrientation()
    self.desiredOrientation.b = self.subsys:getTurretMatrix().b

    self:fireHook("onTargetSet", self.ship, self.subsys)
end

function TurretControlScript:setActive(bool)
    if (bool) then
        if (not self:canBeActive()) then
            return
        end

        self.mainCam.SelfSubsystem = self.subsys

        gr.setCamera(self.mainCam)
    else
        gr.setCamera()
    end

    self.active = bool

    self:fireHook("onActiveSet", self.active)
end

function TurretControlScript:setNearOffset(vec)
    if (vec == nil) then
        return
    end

    self.nearOffset = vec
end

function TurretControlScript:setFarOffset(vec)
    if (vec == nil) then
        return
    end

    self.farOffset = vec
end

function TurretControlScript:setRotationTime(time)
    self.rotationTime = time
end

function TurretControlScript:getShip()
    if (not self:isActive()) then
        return nil
    end

    return self.ship
end

function TurretControlScript:getSubsystem()
    if (not self:isActive()) then
        return nil
    end

    return self.subsystem
end

function TurretControlScript:isManual()
    if (not self:isActive()) then
        return false
    end

    return self.manual
end

function TurretControlScript:canFireTurret()
    if (not self:isActive()) then
        return false
    end

    return self.isOkToFire
end

function TurretControlScript:canBeActive()
    if (not self:isValid()) then
        return false
    end

    if (not self.inMission) then
        return false
    end

    if (self.ship == nil or not self.ship:isValid()) then
        return false
    end

    if (self.subsys == nil or not self.subsys:isValid()) then
        return false
    end

    if (self.subsystem == nil) then
        return false
    end

    return true
end

function TurretControlScript:isActive()
    if (not self:canBeActive()) then
        return false
    end

    return self.active
end

function TurretControlScript:isValid()
    if (self.inMission) then
        if (self.mainCam == nil or not self.mainCam:isValid()) then
            return false
        end
    end

    return true
end

TurretControlConfig = class()

function TurretControlConfig:init(script)
    self.script = script

    self.currentWeaponBank = 1
end

function TurretControlConfig:getCurrentWeaponClass()
    local primBanks = self.script.subsys.PrimaryBanks

    if (self.currentWeaponBank > #primBanks) then
        local secBanks = self.script.subsys.SecondaryBanks

        if ((self.currentWeaponBank - #primBanks) > #secBanks) then
            return nil
        else
            return secBanks[self.currentWeaponBank - #primBanks].WeaponClass
        end
    else
        return primBanks[self.currentWeaponBank].WeaponClass
    end
end

function TurretControlConfig:getCurrentWeaponBank()
    return self.currentWeaponBank
end

function TurretControlConfig:setCurrentWeaponBank(bank)
    self.currentWeaponBank = bank
end

TurretHookListener = class()

function TurretHookListener:init()
end
