local Root = CoolLevelUp;

Root["Arrow"] = { };

local Arrow = Root["Arrow"];

-- --------------------------------------------------------------------
-- ////////////////////////////////////////////////////////////////////
-- --                            GUI PART                            --
-- \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
-- --------------------------------------------------------------------

-- --------------------------------------------------------------------
-- **                             Locals                             **
-- --------------------------------------------------------------------

local DISPLAY_TIME = 0.200;
local REMOVE_TIME  = 0.500;

local UP_TEXTURE = Root.folder.."gfx\\ArrowUp";
local DOWN_TEXTURE = Root.folder.."gfx\\ArrowDown";

local BUMP_TIMER = 0.350;
local HOLD_TIMER = 0.700;

local JUMP_AMPLITUDE = 8;

-- --------------------------------------------------------------------
-- **                             Methods                            **
-- --------------------------------------------------------------------

-- ********************************************************************
-- * self:Display(direction, text[, uptime])                          *
-- ********************************************************************
-- * Arguments:                                                       *
-- * >> self: the arrow.                                              *
-- * >> direction: either "UP" or "DOWN".                             *
-- * >> text: text to display on the right of the arrow.              *
-- * >> uptime: if set, it defines the amount of time (in sec) the    *
-- * arrow will be up till disapparearing by itself.                  *
-- ********************************************************************
-- * Starts displaying an arrow.                                      *
-- ********************************************************************
local function Display(self, direction, text, uptime)
    if type(self) ~= "table" then return; end
    if ( self.status ~= "STANDBY" and self.status ~= "CLOSING" ) then return; end

    self.status = "OPENING";
    self.timer = DISPLAY_TIME;
    self.direction = direction;
    self.uptime = uptime;

    if ( direction == "DOWN" ) then
        self.texture:SetTexture(DOWN_TEXTURE);
  else
        self.texture:SetTexture(UP_TEXTURE);
    end
    self.texture:SetTexCoord(0, 1, 0, 1);

    self.text:SetText(text);

    self.jumpTimer = 0.000;
    self.jumpStatus = "HOLD_TIMER";

    self:Show();
    Arrow.OnUpdate(self, 0);
end

-- ********************************************************************
-- * self:Remove(atOnce)                                              *
-- ********************************************************************
-- * >> self: the arrow.                                              *
-- * >> atOnce: hide instantly the arrow?                             *
-- ********************************************************************
-- * Stops display of an arrow.                                       *
-- ********************************************************************
local function Remove(self, atOnce)
    if type(self) ~= "table" then return; end
    if ( self.status ~= "OPENING" and self.status ~= "RUNNING" and not atOnce ) then return; end

    if ( not atOnce ) then
        self.status = "CLOSING";
        self.timer = REMOVE_TIME;
  else
        self.status = "STANDBY";
        self.timer = 0;
        self:Hide();
    end
end

-- ********************************************************************
-- * self:ChangeOffset(offset)                                        *
-- ********************************************************************
-- * >> self: the arrow.                                              *
-- * >> offset: desired offset (16 by default).                       *
-- ********************************************************************
-- * Changes the offset of the arrow from the center of the hole.     *
-- ********************************************************************
local function ChangeOffset(self, offset)
    if type(self) ~= "table" then return; end

    self.offset = offset or 16;
end

-- --------------------------------------------------------------------
-- **                             Handlers                           **
-- --------------------------------------------------------------------

function Arrow.OnLoad(self)
    -- Children
    self.texture = self:CreateTexture(nil, "ARTWORK");
    self.texture:SetAllPoints(self); 
    self.texture:Show(); 
    self.text = self:CreateFontString(nil, "OVERLAY", "CoolLevelUp_ArrowTextTemplate");
    self.text:SetPoint("RIGHT", self, "LEFT", 2, 0);
    self.text:SetJustifyH("RIGHT");
    self.text:Show();

    -- Properties
    self.status = "STANDBY";
    self.timer = 0.000;
    self.direction = "UP";
    self.jumpTimer = 0.000;
    self.jumpStatus = "HOLDING";
    self.offset = 16;

    -- Methods
    self.Display = Display;
    self.Remove = Remove;
    self.ChangeOffset = ChangeOffset;
end

function Arrow.OnUpdate(self, elapsed)
    if type(self) ~= "table" then return; end

    if ( self.status == "STANDBY" ) then
        self:Hide();
        return;
    end

    local alpha = 1.00;

    if ( self.status == "OPENING" ) then
        self.timer = max(0, self.timer - elapsed);
        if ( self.timer == 0 ) then
            self.status = "RUNNING";
        end
        alpha = 1 - self.timer / DISPLAY_TIME;

elseif ( self.status == "RUNNING" ) then
        if type(self.uptime) == "number" then
            self.uptime = max(0, self.uptime - elapsed);
            if ( self.uptime == 0 ) then
                self:Remove();
            end
        end

elseif ( self.status == "CLOSING" ) then
        self.timer = max(0, self.timer - elapsed);
        if ( self.timer == 0 ) then self.status = "STANDBY" end
        alpha = self.timer / REMOVE_TIME;
    end

    local ofsY = 4;
    local maxY = JUMP_AMPLITUDE;
    if ( self.direction == "DOWN" ) then maxY = -maxY; end

    if ( self.jumpStatus == "HOLDING" ) then
        self.jumpTimer = max(0, self.jumpTimer - elapsed);
        if ( self.jumpTimer == 0 ) then
            self.jumpStatus = "BUMPING";
            self.jumpTimer = BUMP_TIMER;
        end
  else
        ofsY = 4 + maxY * (self.jumpTimer / BUMP_TIMER );
        self.jumpTimer = max(0, self.jumpTimer - elapsed);
        if ( self.jumpTimer == 0 ) then
            self.jumpStatus = "HOLDING";
            self.jumpTimer = HOLD_TIMER;
        end
    end

    self:SetAlpha(alpha);
    self:ClearAllPoints();
    self:SetPoint("CENTER", self:GetParent(), "CENTER", self.offset, ofsY);
end