--[[
/*******************************************************************************\
*                                                                               *
* Liberator.lua                                                                 *
*                                                                               *
*********************************************************************************
* Licensed under the MIT or X11 License                                         *
*                                                                               *
* Copyright (c) 2015 Eisbearg                                                   *
*                                                                               *
* Permission is hereby granted, free of charge, to any person obtaining a copy  *
* of this software and associated documentation files (the "Software"), to deal *
* in the Software without restriction, including without limitation the rights  *
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell     *
* copies of the Software, and to permit persons to whom the Software is         *
* furnished to do so, subject to the following conditions:                      *
*                                                                               *
* The above copyright notice and this permission notice shall be included in    *
* all copies or substantial portions of the Software.                           *
*                                                                               *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR    *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,      *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE   *
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER        *
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, *
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN     *
* THE SOFTWARE.                                                                 *
\*******************************************************************************/
--]]




Liberator = {};

Liberator._NAME            = "Liberator"
Liberator._COPYRIGHT    = "Copyright (C) 2015 Eisbearg"
Liberator._DESCRIPTION    = "Specialization to liberate vehicles that are stuck"
Liberator._VERSION        = "1.0.0"




source(Utils.getFilename("inspect.lua", g_currentModDirectory.."scripts/"))




function Liberator.prerequisitesPresent(specializations)
    return true;
end;


function Liberator:load(savegame)
    self.toggleLiberator = SpecializationUtil.callSpecializationsFunction("toggleLiberator");
    self.Liberator = {};

    self.isSelectable = true;

    local name = getXMLString(self.xmlFile, "vehicle.name");
    if name == nil then
        name = getXMLString(self.xmlFile, "vehicle.name.en");
    end;
    if name == nil then
        name = getXMLString(self.xmlFile, "vehicle.name.de");
    end;
    if name == nil then
        name = getXMLString(self.xmlFile, "vehicle.name.es");
    end;
    if name == nil then
        name = getXMLString(self.xmlFile, "vehicle.name.fr");
    end;
    if name == nil then
        name = getXMLString(self.xmlFile, "vehicle.name.pt");
    end;
    if name == nil then
        name = getXMLString(self.xmlFile, "vehicle.name.ru");
    end;
    if name == nil then
        name = "UnknownVehicle";
    end;
    print("--- inserting "..Liberator._NAME.." in vehicle "..name);

    self.Liberator.id = Liberator._NAME;
    self.Liberator.name = name;
    self.Liberator.move = false;
    self.Liberator.lastKey = {};
    self.Liberator.lastKey.symDown = 0;
    self.Liberator.lastKey.modDown = 0;
    self.Liberator.lastKey.symUp = 0;
    self.Liberator.lastKey.modUp = 0;
    self.Liberator.lastKey.scrolllActive = false;
    self.Liberator.lastKey.capsActive = false;
    self.Liberator.lastKey.x = 0;
    self.Liberator.lastKey.z = 0;
    self.Liberator.lastKey.rx = 0;
    self.Liberator.lastKey.rz = 0;
    self.Liberator.active = false;
    self.Liberator.swim = false;
end;


function Liberator:delete()
end;


function Liberator:mouseEvent(posX, posY, isDown, isUp, button)
end;


function Liberator:keyEvent(unicode, sym, modifier, isDown)
    if isDown then
        self.Liberator.lastKey.symDown = sym;
        self.Liberator.lastKey.modDown = modifier;
        
        if sym == 301 and bitAND(modifier, Input.MOD_CAPS) == 0 then
            self.Liberator.lastKey.capsActive = true;
        end;
        if sym == 301 and bitAND(modifier, Input.MOD_CAPS) > 0 then
            self.Liberator.lastKey.capsActive = false;
        end;
        
        if sym == Input.KEY_scrolllock then
            if self.Liberator.lastKey.scrolllActive == false then
                self.Liberator.lastKey.scrolllActive = true;
            else
                self.Liberator.lastKey.scrolllActive = false;
            end;
        end;
        
        if self.Liberator.lastKey.capsActive or self.Liberator.lastKey.scrolllActive then
            self.Liberator.active = true;
        else
            self.Liberator.active = false;
        end;
        
        if self.Liberator.active or self.Liberator.swim then
            if sym == Input.KEY_KP_8 then
                self.Liberator.lastKey.z = 3;
            end;
            if sym == Input.KEY_KP_2 then
                self.Liberator.lastKey.z = -3;
            end;
            if sym == Input.KEY_KP_4 then
                self.Liberator.lastKey.x = 3;
            end;
            if sym == Input.KEY_KP_6 then
                self.Liberator.lastKey.x = -3;
            end;
            if sym == Input.KEY_KP_divide then
                self.Liberator.lastKey.rx = 1;
            end;
            if sym == Input.KEY_KP_multiply then
                self.Liberator.lastKey.rx = -1;
            end;
            if sym == Input.KEY_KP_minus then
                self.Liberator.lastKey.rz = 1;
            end;
            if sym == Input.KEY_KP_plus then
                self.Liberator.lastKey.rz = -1;
            end;

            if sym == Input.KEY_KP_0 then
                print(inspect.inspect(self));
            end;
            if sym == Input.KEY_KP_5 then
                print(inspect.inspect(self));
                print(inspect.inspect(self.wheels));
                print(inspect.inspect(Input));
            end;
        end;
    end;
    if isDown == false then
        self.Liberator.lastKey.symUp = sym;
        self.Liberator.lastKey.modUp = modifier;
        
            if sym == Input.KEY_KP_8 then
                self.Liberator.lastKey.z = 0;
            end;
            if sym == Input.KEY_KP_2 then
                self.Liberator.lastKey.z = 0;
            end;
            if sym == Input.KEY_KP_4 then
                self.Liberator.lastKey.x = 0;
            end;
            if sym == Input.KEY_KP_6 then
                self.Liberator.lastKey.x = 0;
            end;
            if sym == Input.KEY_KP_divide then
                self.Liberator.lastKey.rx = 0;
            end;
            if sym == Input.KEY_KP_multiply then
                self.Liberator.lastKey.rx = 0;
            end;
            if sym == Input.KEY_KP_minus then
                self.Liberator.lastKey.rz = 0;
            end;
            if sym == Input.KEY_KP_plus then
                self.Liberator.lastKey.rz = 0;
            end;
    end;
end;


function Liberator:update(dt)
    if self:getIsActiveForInput(true) then
        local xt,yt,zt = getTranslation(self.components[1].node);
        local deltaWater = yt - g_currentMission.waterY + 2.5;
        self.Liberator.swim = deltaWater < 2;
        
        if self.Liberator.active or self.Liberator.swim then
            if self.Liberator.swim then
                velY = 0;
                if deltaWater < 1 then
                    velY = 1;
                end
                setLinearVelocity(self.components[1].node, self.Liberator.lastKey.x, velY, self.Liberator.lastKey.z);
            else
                setLinearVelocity(self.components[1].node, self.Liberator.lastKey.x, 1, self.Liberator.lastKey.z);
            end
            setAngularVelocity(self.components[1].node, self.Liberator.lastKey.rx, 0, self.Liberator.lastKey.rz);
        end;
    end;
end;


function Liberator:updateTick(dt)
end;


function Liberator:draw()
    if self:getIsActiveForInput(true) then
        g_currentMission:addHelpButtonText(g_i18n:getText(self.Liberator.id), InputBinding[self.Liberator.id]);

        if self.Liberator.active or self.Liberator.swim then
            setTextAlignment(RenderText.ALIGN_CENTER);
            setTextBold(true);
            setTextColor(1,1,1,1);

            renderText(0.50, 0.30, 0.016, "move: Keypad 2 8 and 4 6");
            renderText(0.50, 0.25, 0.016, "roll: Keypad / * and + -");

            setTextAlignment(RenderText.ALIGN_LEFT);
            setTextBold(false);
            setTextColor(1,1,1,1);
        end;
        
        --Liberator:printMotionDiag(self);
    end;
end;


function Liberator:toggleLiberator(state, nes)
end;


function Liberator:readStream(streamId, connection)
end;
        
    
function Liberator:writeStream(streamId, connection)
end;


function Liberator:printMotionDiag(steerableSelf)
    -- always be on the safe side of life -> set text-styling
    setTextAlignment(RenderText.ALIGN_LEFT);
    setTextBold(false);
    setTextColor(1,1,1,1);

    renderText(0.79, 0.89, 0.009, "Key(syn, mod):");
    renderText(0.84, 0.89, 0.009, tostring(steerableSelf.Liberator.lastKey.symDown));
    renderText(0.88, 0.89, 0.009, tostring(steerableSelf.Liberator.lastKey.modDown));
    renderText(0.92, 0.89, 0.009, tostring(steerableSelf.Liberator.lastKey.symUp));
    renderText(0.96, 0.89, 0.009, tostring(steerableSelf.Liberator.lastKey.modUp));

    local direction, dirX,dirY,dirZ = Liberator:getDirectionDegree(steerableSelf.rootNode)
    renderText(0.79, 0.87, 0.009, "direction:");
    renderText(0.84, 0.87, 0.009, string.format("%4.4f°", direction));
    renderText(0.88, 0.87, 0.009, string.format("(%4.4f | %4.4f | %4.4f)", dirX,dirY,dirZ));
    
    local velLinX,velLinY,velLinZ = getLinearVelocity(steerableSelf.rootNode);
    renderText(0.79, 0.85, 0.009, "vLinXYZ:");
    renderText(0.84, 0.85, 0.009, string.format("%4.4f°", velLinX));
    renderText(0.88, 0.85, 0.009, string.format("%4.4f°", velLinY));
    renderText(0.92, 0.85, 0.009, string.format("%4.4f°", velLinZ));
    
    local velAngX,velAngY,velAngZ = getAngularVelocity(steerableSelf.rootNode);
    renderText(0.79, 0.84, 0.009, "vAngXYZ:");
    renderText(0.84, 0.84, 0.009, string.format("%4.4f°", velAngX));
    renderText(0.88, 0.84, 0.009, string.format("%4.4f°", velAngY));
    renderText(0.92, 0.84, 0.009, string.format("%4.4f°", velAngZ));
    
    local altAboveGround, altAboveNN, terrainHeight = Liberator:getAltitude(steerableSelf.rootNode)
    renderText(0.79, 0.82, 0.009, "Alt:");
    renderText(0.84, 0.82, 0.009, string.format("%4.4fm", altAboveGround));
    renderText(0.88, 0.82, 0.009, string.format("(%4.4fm, %4.4fm)", altAboveNN, terrainHeight));
    
    local rotX,rotY,rotZ = getRotation(steerableSelf.rootNode);
    renderText(0.79, 0.80, 0.009, "rotXYZ:");
    renderText(0.84, 0.80, 0.009, string.format("%4.4f°", rotX));
    renderText(0.88, 0.80, 0.009, string.format("%4.4f°", rotY));
    renderText(0.92, 0.80, 0.009, string.format("%4.4f°", rotZ));
    
    local rotWorldX,rotWorldY,rotWorldZ = getWorldRotation(steerableSelf.rootNode);
    renderText(0.79, 0.79, 0.009, "rotWorldXYZ:");
    renderText(0.84, 0.79, 0.009, string.format("%4.4f°", rotWorldX));
    renderText(0.88, 0.79, 0.009, string.format("%4.4f°", rotWorldY));
    renderText(0.92, 0.79, 0.009, string.format("%4.4f°", rotWorldZ));
    
    local pitching, pitchingX,pitchingY,pitchingZ = Liberator:getPitchingDegree(steerableSelf.rootNode)
    renderText(0.79, 0.77, 0.009, "pitching:");
    renderText(0.84, 0.77, 0.009, string.format("%4.4f°", pitching));
    renderText(0.88, 0.77, 0.009, string.format("(%4.4f | %4.4f | %4.4f)", pitchingX,pitchingY,pitchingZ));
    
    local rolling, rollingX,rollingY,rollingZ = Liberator:getRollingDegree(steerableSelf.rootNode)
    renderText(0.79, 0.76, 0.009, "rolling:");
    renderText(0.84, 0.76, 0.009, string.format("%4.4f°", rolling));
    renderText(0.88, 0.76, 0.009, string.format("(%4.4f | %4.4f | %4.4f)", rollingX,rollingY,rollingZ));
end;


function Liberator:getDirectionDegree(rootNode)
    local dX,dY,dZ = localDirectionToWorld(rootNode, -1, 0, 0);
    local hyp = Utils.vector2Length(dX,dZ);

    if (hyp ~= 0.0) then
        local sinX = dX / hyp;
        local sinZ = dZ / hyp;
        local direction = math.deg(math.atan2(sinZ, sinX));
        if direction < 0 then
            direction = direction + 360
        end;
        --[[
        while (direction > 359.999999) do
            direction = direction - 360.0;
        end;
        while (direction < 0.0) do
            direction = direction + 360.0;
        end;
        --]]--

        return direction, dX,dY,dZ;
    end;  
    return 0, dX,dY,dZ;
end;


function Liberator:getPitchingDegree(rootNode)
    local lx,ly,lz = localDirectionToWorld(rootNode, 0, 1, 0);
    local x,y,z = localDirectionToWorld(rootNode, lx * -1,1,lz * -1);
    local length = Utils.vector2Length(x,y);

    if (length ~= 0.0) then
        local dX = x / length;
        local dY = y / length;
        local direction = math.deg(dX);

        return direction, x,y,z;
    end;  
    return 0, x,y,z;
end;


function Liberator:getRollingDegree(rootNode)
    local lx,ly,lz = localDirectionToWorld(rootNode, 0, 1, 0);
    local x,y,z = localDirectionToWorld(rootNode, lx * -1,1,lz * -1);
    local length = Utils.vector2Length(z,y);

    if (length ~= 0.0) then
        local dZ = z / length;
        local dY = y / length;
        local direction = math.deg(dZ);

        return direction, x,y,z;
    end;  
    return 0, x,y,z;
end;


function Liberator:getAltitude(rootNode)
    local terrainHeight = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, getWorldTranslation(rootNode));
    local x, altAboveNN = getWorldTranslation(rootNode);
    local altAboveGround = altAboveNN - terrainHeight;
    if altAboveGround < 0 then altAboveGround = 0.0 end;
    return altAboveGround, altAboveNN, terrainHeight;
end;
