--***********************************************************
--**                    ROBERT JOHNSON                     **
--***********************************************************

require "TimedActions/ISBaseTimedAction"

ISReadABook = ISBaseTimedAction:derive("ISReadABook");


function ISReadABook:isValid()
    local vehicle = self.character:getVehicle()
    if vehicle and vehicle:isDriver(self.character) then
        return not vehicle:isEngineRunning() or vehicle:getSpeed2D() == 0
    end
    return self.character:getInventory():contains(self.item) and ((self.item:getNumberOfPages() > 0 and self.item:getAlreadyReadPages() <= self.item:getNumberOfPages()) or self.item:getNumberOfPages() < 0);
end

function ISReadABook:update()
    self.pageTimer = self.pageTimer + getGameTime():getMultiplier();
    self.item:setJobDelta(self:getJobDelta());

    if self.item:getNumberOfPages() > 0 then
        local pagesRead = math.floor(self.item:getNumberOfPages() * self:getJobDelta())
        self.item:setAlreadyReadPages(pagesRead);
        if self.item:getAlreadyReadPages() > self.item:getNumberOfPages() then
            self.item:setAlreadyReadPages(self.item:getNumberOfPages());
        end
        self.character:setAlreadyReadPages(self.item:getFullType(), self.item:getAlreadyReadPages())
    end
    if SkillBook[self.item:getSkillTrained()] then
        if self.item:getLvlSkillTrained() > self.character:getPerkLevel(SkillBook[self.item:getSkillTrained()].perk) + 1 or self.character:HasTrait("Illiterate") then
            if self.pageTimer >= 200 then
                self.pageTimer = 0;
                local txtRandom = ZombRand(3);
                if txtRandom == 0 then
                    self.character:Say(getText("IGUI_PlayerText_DontGet"));
                elseif txtRandom == 1 then
                    self.character:Say(getText("IGUI_PlayerText_TooComplicated"));
                else
                    self.character:Say(getText("IGUI_PlayerText_DontUnderstand"));
                end
                if self.item:getNumberOfPages() > 0 then
                    self.character:setAlreadyReadPages(self.item:getFullType(), 0)
                    self:forceStop()
                end
            end
        elseif self.item:getMaxLevelTrained() < self.character:getPerkLevel(SkillBook[self.item:getSkillTrained()].perk) + 1 then
            if self.pageTimer >= 200 then
                self.pageTimer = 0;
                local txtRandom = ZombRand(2);
                if txtRandom == 0 then
                    self.character:Say(getText("IGUI_PlayerText_KnowSkill"));
                else
                    self.character:Say(getText("IGUI_PlayerText_BookObsolete"));
                end
            end
        else
            ISReadABook.checkMultiplier(self);
        end
    end

    -- Playing with longer day length reduces the effectiveness of morale-boosting
    -- literature, like Comic Book.
    local bodyDamage = self.character:getBodyDamage()
    local stats = self.character:getStats()
    if self.stats and (self.item:getBoredomChange() < 0.0) then
        if bodyDamage:getBoredomLevel() > self.stats.boredom then
            bodyDamage:setBoredomLevel(self.stats.boredom)
        end
    end
    if self.stats and (self.item:getUnhappyChange() < 0.0) then
        if bodyDamage:getUnhappynessLevel() > self.stats.unhappyness then
            bodyDamage:setUnhappynessLevel(self.stats.unhappyness)
        end
    end
    if self.stats and (self.item:getStressChange() < 0.0) then
        if stats:getStress() > self.stats.stress then
            stats:setStress(self.stats.stress)
        end
    end
end

-- get how much % of the book we already read, then we apply a multiplier depending on the book read progress
ISReadABook.checkMultiplier = function(self)
-- get all our info in the map
    local trainedStuff = SkillBook[self.item:getSkillTrained()];
    if trainedStuff then
        -- every 10% we add 10% of the max multiplier
        local readPercent = (self.item:getAlreadyReadPages() / self.item:getNumberOfPages()) * 100;
        if readPercent > 100 then
            readPercent = 100;
        end
        -- apply the multiplier to the skill
        local multiplier = (math.floor(readPercent/10) * (self.maxMultiplier/10));
        if multiplier > self.character:getXp():getMultiplier(trainedStuff.perk) then
            self.character:getXp():addXpMultiplier(trainedStuff.perk, multiplier, self.item:getLvlSkillTrained(), self.item:getMaxLevelTrained());
        end
    end
end

function ISReadABook.checkLevel(character, item)
    if item:getNumberOfPages() <= 0 then
        return
    end
    local skillBook = SkillBook[item:getSkillTrained()]
    if not skillBook then
        return
    end
    local level = character:getPerkLevel(skillBook.perk)
    if (item:getLvlSkillTrained() > level + 1) or character:HasTrait("Illiterate") then
        item:setAlreadyReadPages(0)
        character:setAlreadyReadPages(item:getFullType(), 0)
    end
end

function ISReadABook:start()
    if self.startPage then
        self:setCurrentTime(self.maxTime * (self.startPage / self.item:getNumberOfPages()))
    end
    self.item:setJobType(getText("ContextMenu_Read") ..' '.. self.item:getName());
    self.item:setJobDelta(0.0);
    --self.character:SetPerformingAction(GameCharacterActions.Reading, nil, self.item)
    if (self.item:getType() == "Newspaper") then
        self:setAnimVariable("ReadType", "newspaper")
    else
        self:setAnimVariable("ReadType", "book")
    end
    self:setActionAnim(CharacterActionAnims.Read);
    self:setOverrideHandModels(nil, self.item);
    self.character:setReading(true)
    
    self.character:reportEvent("EventRead");

    if not SkillBook[self.item:getSkillTrained()] then
        self.stats = {}
        self.stats.boredom = self.character:getBodyDamage():getBoredomLevel()
        self.stats.unhappyness = self.character:getBodyDamage():getUnhappynessLevel()
        self.stats.stress = self.character:getStats():getStress()
    end

    if SkillBook[self.item:getSkillTrained()] then
        self.character:playSound("OpenBook")
    else
        self.character:playSound("OpenMagazine")
    end
end

function ISReadABook:stop()
    if self.item:getNumberOfPages() > 0 and self.item:getAlreadyReadPages() >= self.item:getNumberOfPages() then
        self.item:setAlreadyReadPages(self.item:getNumberOfPages());
    end
    self.character:setReading(false);
    self.item:setJobDelta(0.0);
    if SkillBook[self.item:getSkillTrained()] then
        self.character:playSound("CloseBook")
    else
        self.character:playSound("CloseMagazine")
    end
    ISBaseTimedAction.stop(self);
end

function ISReadABook:perform()
    self.character:setReading(false);
    self.item:getContainer():setDrawDirty(true);
    self.item:setJobDelta(0.0);
    if self.item:getTeachedRecipes() and not self.item:getTeachedRecipes():isEmpty() then
        self.character:getAlreadyReadBook():add(self.item:getFullType());
    end
    if not SkillBook[self.item:getSkillTrained()] then
        self.character:ReadLiterature(self.item);
    elseif self.item:getAlreadyReadPages() >= self.item:getNumberOfPages() then
--        self.character:ReadLiterature(self.item);
        self.item:setAlreadyReadPages(0);
    end
--    if self.item:getTeachedRecipes() and not self.item:getTeachedRecipes():isEmpty() then
--        for i=0, self.item:getTeachedRecipes():size() - 1 do
--           if not self.character:getKnownRecipes():contains(self.item:getTeachedRecipes():get(i)) then
--               self.character:getKnownRecipes():add(self.item:getTeachedRecipes():get(i));
--           else
--               self.character:Say(getText("IGUI_PlayerText_KnowSkill"));
--           end
--        end
--    end
    if SkillBook[self.item:getSkillTrained()] then
        self.character:playSound("CloseBook")
    else
        self.character:playSound("CloseMagazine")
    end
    -- needed to remove from queue / start next.
    ISBaseTimedAction.perform(self);
end

function ISReadABook:animEvent(event, parameter)
    if event == "PageFlip" then
        if getGameSpeed() ~= 1 then
            return
        end
        if SkillBook[self.item:getSkillTrained()] then
            self.character:playSound("PageFlipBook")
        else
            self.character:playSound("PageFlipMagazine")
        end
    end
end

function ISReadABook:new(character, item, time)
    local o = {}
    setmetatable(o, self)
    self.__index = self
    o.character = character;
    o.item = item;
    o.stopOnWalk = true;
    o.stopOnRun = true;

    local numPages
    if item:getNumberOfPages() > 0 then
        ISReadABook.checkLevel(character, item)
        item:setAlreadyReadPages(character:getAlreadyReadPages(item:getFullType()))
        o.startPage = item:getAlreadyReadPages()
        numPages = item:getNumberOfPages() -- item:getAlreadyReadPages()
    else
        numPages = 5
    end
    if isClient() then
        o.minutesPerPage = getServerOptions():getFloat("MinutesPerPage") or 1.0
        if o.minutesPerPage < 0.0 then o.minutesPerPage = 1.0 end
    else
        o.minutesPerPage = 2.0
    end
    local f = 1 / getGameTime():getMinutesPerDay() / 2
    time = numPages * o.minutesPerPage / f

    if(character:HasTrait("FastReader")) then
        time = time * 0.7;
    end
    if(character:HasTrait("SlowReader")) then
        time = time * 1.3;
    end

    if SkillBook[item:getSkillTrained()] then
        if item:getLvlSkillTrained() == 1 then
            o.maxMultiplier = SkillBook[item:getSkillTrained()].maxMultiplier1;
        elseif item:getLvlSkillTrained() == 3 then
            o.maxMultiplier = SkillBook[item:getSkillTrained()].maxMultiplier2;
        elseif item:getLvlSkillTrained() == 5 then
            o.maxMultiplier = SkillBook[item:getSkillTrained()].maxMultiplier3;
        elseif item:getLvlSkillTrained() == 7 then
            o.maxMultiplier = SkillBook[item:getSkillTrained()].maxMultiplier4;
        elseif item:getLvlSkillTrained() == 9 then
            o.maxMultiplier = SkillBook[item:getSkillTrained()].maxMultiplier5;
        else
            o.maxMultiplier = 1
            print('ERROR: book has unhandled skill level ' .. item:getLvlSkillTrained())
        end
    end
    o.ignoreHandsWounds = true;
    o.maxTime = time;
    o.caloriesModifier = 0.5;
    o.pageTimer = 0;
    o.forceProgressBar = true;
    if character:isTimedActionInstant() then
        o.maxTime = 1;
    end

    return o;
end
