--[[
  Copyright Tom Lukeywood 2018
    This file is part of ForestEngine

    ForestEngine is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    ForestEngine is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with ForestEngine.  If not, see <http://www.gnu.org/licenses/>.
]]--

GUI = {}
local DefaultFont = "./unifont-10.0.06.ttf"
local Pixelfile = "./Pixel.bmp" -- a blank transparent pixel

function GUI.NewWindow(Renderer, Rect, ColorRGB, Alpha, TitleBar)

    local self = {}

    self.WindowSurface, err = Image.load(Pixelfile) if not self.WindowSurface then print("No Pixel.bmp file found!\nPlease see the README file for more info.") error(err) end
    self.WindowTexture, err = Renderer:createTextureFromSurface(self.WindowSurface) if not self.WindowTexture then error(err) end
    self.type = "window"
    self.rect = Rect
    self.selected = false
    self.visible = true --if the window and its objects are to be rendered

    self.objects = {}

    if TitleBar then
        self.TitleBarSurface, err = Image.load(Pixelfile) if not self.TitleBarSurface then error(err) end
        self.TitleBarTexture, err = Renderer:createTextureFromSurface(self.TitleBarSurface) if not self.TitleBarTexture then error(err) end
        self.TitleBarText = GUI.CreateText(Renderer, DefaultFont, 32, TitleBar.text, "solid", TitleBar.textcolor)
    end

    function self:Add(Object)
        self.objects[#self.objects+1] = Object
    end

    function self:Render(EventHandler)
        if self.visible then
        --Draw Window
        self.WindowTexture:setBlendMode(SDL.blendMode.Blend)
        self.WindowTexture:setAlphaMod(Alpha)
        self.WindowTexture:setColorMod(ColorRGB)
        Renderer:copy(self.WindowTexture, nil, Rect)

        if TitleBar then
            self.TitleBarTexture:setBlendMode(SDL.blendMode.Blend)
            self.TitleBarTexture:setAlphaMod(TitleBar.alpha)
            self.TitleBarTexture:setColorMod(TitleBar.color)

            TitleBar.w = Rect.w; TitleBar.h = 32
            TitleBar.x = Rect.x; TitleBar.y = Rect.y - TitleBar.h
            Renderer:copy(self.TitleBarTexture, nil, TitleBar)

            --scale the text acording to its size
            local rect = { x=TitleBar.x, y=TitleBar.y, w = #TitleBar.text * 16, h = TitleBar.h - 14}
            if rect.w >= (TitleBar.w - 16) then rect.w = TitleBar.w end
            Renderer:copy(self.TitleBarText, nil, rect)

            --Window dragging (TESTING AT WORK!!!)
            local tmp1 = EventHandler.EventStatus[EVENT_MOUSEBUTTON_LEFT_PRESSED].Active -- keep these values safe
            local tmp2 = EventHandler.EventStatus[EVENT_MOUSEBUTTON_LEFT_CLICKED].Active
            if EventHandler then

                if (EventHandler.EventStatus[EVENT_MOUSEBUTTON_LEFT_PRESSED].Active
                or EventHandler.EventStatus[EVENT_MOUSEBUTTON_LEFT_CLICKED].Active)
                and self.selected then
                    self.selected = false
                    EventHandler.EventStatus[EVENT_MOUSEBUTTON_LEFT_PRESSED].Active = false -- will set these back later
                    EventHandler.EventStatus[EVENT_MOUSEBUTTON_LEFT_CLICKED].Active = false
                end

                if EventHandler.MouseX >= TitleBar.x
                and EventHandler.MouseX <= (TitleBar.x + TitleBar.w)
                and EventHandler.MouseY >= TitleBar.y
                and EventHandler.MouseY <= (TitleBar.y + TitleBar.h)
                and (EventHandler.EventStatus[EVENT_MOUSEBUTTON_LEFT_PRESSED].Active
                or EventHandler.EventStatus[EVENT_MOUSEBUTTON_LEFT_CLICKED].Active) then
                    if TitleBar.selectable then self.selected = true end
                end

                if self.selected then
                    self:Move( (EventHandler.MouseX - TitleBar.x - (self.rect.w / 2)), (EventHandler.MouseY - TitleBar.y) - (TitleBar.h / 2))
                end

                EventHandler.EventStatus[EVENT_MOUSEBUTTON_LEFT_PRESSED].Active = tmp1 -- restore original values
                EventHandler.EventStatus[EVENT_MOUSEBUTTON_LEFT_CLICKED].Active = tmp2

                --Hide window if right clicked on TitleBar
                if EventHandler.MouseX >= TitleBar.x
                and EventHandler.MouseX <= (TitleBar.x + TitleBar.w)
                and EventHandler.MouseY >= TitleBar.y
                and EventHandler.MouseY <= (TitleBar.y + TitleBar.h)
                and EventHandler.EventStatus[EVENT_MOUSEBUTTON_RIGHT_CLICKED].Active
                and not TitleBar.uncloseable then
                    self.visible = false
                end

            end
        end

        --Render objects
        for I = 1, #self.objects do
            if self.objects[I].type == "label" then
                Renderer:copy(self.objects[I].text, nil, self.objects[I].rect)
            elseif self.objects[I].type == "button" then
                local dc = Renderer:getDrawColor()
                Renderer:setDrawColor(self.objects[I].bgcolor)
                Renderer:fillRect(self.objects[I].rect)
                Renderer:setDrawColor(dc)
                Renderer:copy(self.objects[I].text, nil, self.objects[I].rect)

            elseif self.objects[I].type == "image" then
                Renderer:copy(self.objects[I].texture, nil, self.objects[I].rect)
            else io.write("Warning: invalid object type given to window\n")
            end
        end
        else return
        end
    end

    function self:Move(x,y)
        self.rect.x = Inc(self.rect.x, x)
        self.rect.y = Inc(self.rect.y, y)

        for I = 1, #self.objects do
            self.objects[I].rect.x = Inc(self.objects[I].rect.x, x)
            self.objects[I].rect.y = Inc(self.objects[I].rect.y, y)
        end

    end

    function self:Scale(w,h)
        if self.rect.w <= 128 or self.rect.h <= 64 then return
        elseif self.rect.w >= ForestEngine.WINDOW_WIDTH or self.rect.h >= ForestEngine.WINDOW_HEIGHT then return end

        self.rect.w = Inc(self.rect.w, w)
        self.rect.h = Inc(self.rect.w, h)

        for I = 1, #self.objects do
            self.objects[I].rect.w = Inc(self.objects[I].rect.w, w)
            self.objects[I].rect.h = Inc(self.objects[I].rect.h, h / 14)
        end
    end

    function self:Die()
      self = nil -- X_X
    end

    return self
end

function GUI.NewButton(Window, Renderer, Rect, Text, TextColor, BackgroundColor)
    local self = {}

    self.type = "button"

    if Window then
        if Rect.x < 0 or Rect.y < 0 or Rect.w < 0 or Rect.h < 0 then
        io.write("Warning: Rect used to create label contains value less than 0\n") end

        if Rect.x > Window.rect.w then io.write("Warning: X cordinate too large for window\n") Rect.x = Window.rect.w end
        if Rect.y > Window.rect.h then io.write("Warning: Y cordinate too large for window\n") Rect.y = Window.rect.h end
        if Rect.x >= Rect.w then Rect.x = (Rect.x + Window.rect.x) - Rect.w else Rect.x = (Rect.x + Window.rect.x) end
        if Rect.y >= Rect.h then Rect.y = (Rect.y + Window.rect.y) - Rect.h else Rect.y = (Rect.y + Window.rect.y) end
    end

    self.rect = Rect
    self.txtcolor = TextColor
    self.bgcolor = BackgroundColor
    self.text = GUI.CreateText(Renderer, DefaultFont, 24, Text, "solid", TextColor)
    self.clickable = true

    function self:Clicked(EventHandler)
    if self.clickable then
        if EventHandler.MouseX >= self.rect.x and EventHandler.MouseX <= (self.rect.x + self.rect.w)
        and EventHandler.MouseY >= self.rect.y and EventHandler.MouseY <= (self.rect.y + self.rect.h)
        and EventHandler.EventStatus[EVENT_MOUSEBUTTON_LEFT_CLICKED].Active then return true
        else return false end
    end end

    return self
end

function GUI.NewLabel(Window, Renderer, Rect, TTFfile, FontRes, Text, ColorRGB)
    local self = {}

    self.type = "label"

    if Window then
        if Rect.x < 0 or Rect.y < 0 or Rect.w < 0 or Rect.h < 0 then
        io.write("Warning: Rect used to create label contains value less than 0\n") end

        if Rect.x > Window.rect.w then io.write("Warning: X cordinate too large for window\n") Rect.x = Window.rect.w end
        if Rect.y > Window.rect.h then io.write("Warning: Y cordinate too large for window\n") Rect.y = Window.rect.h end
        if Rect.x >= Rect.w then Rect.x = (Rect.x + Window.rect.x) - Rect.w else Rect.x = (Rect.x + Window.rect.x) end
        if Rect.y >= Rect.h then Rect.y = (Rect.y + Window.rect.y) - Rect.h else Rect.y = (Rect.y + Window.rect.y) end
    end

    self.rect = Rect
    self.text = GUI.CreateText(Renderer, TTFfile, FontRes, Text, "solid", ColorRGB)

    return self
end

function GUI.NewMenu(Renderer, Buttons, Rect, Title, Txtcolor, BGcolor, BGalpha)

    local self = GUI.NewButton(nil, Renderer, Rect, Title, TxtColor, BGColor) --inherit from NewButton

    if Buttons then
    self.button_count = 0 for _ in pairs(Buttons) do self.button_count = Inc(self.button_count) end
    for I = 1, self.button_count do -- set rect's for Buttons
        Buttons[I].rect = {}
        Buttons[I].rect.y = Rect.y + (I * Rect.h)
        Buttons[I].rect.x = Rect.x
        Buttons[I].rect.w = Rect.w
        Buttons[I].rect.h = Rect.h
    end
    end

    self.type = "menu"
    self.rect = Rect
    self.title = GUI.CreateText(Renderer, DefaultFont, 24, Title, "solid", ColorRGB)
    self.show_items = false

    function self:Render(EventHandler)
        Renderer:copy(self.title, nil, self.rect)

        if self:Clicked(EventHandler) then
            if self.show_items then
                self.show_items = false
            else
                self.show_items = true
            end
        end -- work on expanding this to whole of menu

        if Buttons then
        if not self.show_items then
            for I = 1, self.button_count do
                Buttons[I].clickable = false
            end
        else
            for I = 1, self.button_count do
                Buttons[I].clickable = true
            end
        end

        if self.show_items then
            local save_y = self.rect.y
            for I = 1, self.button_count do
                self.rect.y = self.rect.y + self.rect.h
                Renderer:copy(Buttons[I].text, nil, self.rect)
            end
            self.rect.y = save_y
        end
    end
    end

    return self
end

function GUI.NewImage(Window, Renderer, Rect, IMGFile)
    local self = {}

    self.type = "image"
    if Window then
        if Rect.x < 0 or Rect.y < 0 or Rect.w < 0 or Rect.h < 0 then
        io.write("Warning: Rect used to create label contains value less than 0\n") end

        if Rect.x > Window.rect.w then io.write("Warning: X cordinate too large for window\n") Rect.x = Window.rect.w end
        if Rect.y > Window.rect.h then io.write("Warning: Y cordinate too large for window\n") Rect.y = Window.rect.h end
        if Rect.x >= Rect.w then Rect.x = (Rect.x + Window.rect.x) - Rect.w else Rect.x = (Rect.x + Window.rect.x) end
        if Rect.y >= Rect.h then Rect.y = (Rect.y + Window.rect.y) - Rect.h else Rect.y = (Rect.y + Window.rect.y) end
    end
    self.rect = Rect
    local surface, err = Image.load(IMGFile) if not surface then error(err) end
    self.texture, err = Renderer:createTextureFromSurface(surface) if not self.texture then error(err) end

    return self
end

function GUI.CreateText(Renderer, TTFfile, FontRes, Text, Style, FGColor, BGColor)
    if not TTFfile then
        TTFfile = DefaultFont -- Invalid .ttf file using default
    end
    local ret, err = TTF.init() if not ret then error(err) end
    local font, err = TTF.open(TTFfile, FontRes) if not font then error(err) end
    local s, err = font:renderUtf8(Text, Style, FGColor, BGColor) if not s then error(err) end
    return Renderer:createTextureFromSurface(s)
end

return GUI
