--[[
  Copyright Tom Lukeywood 2018
    This file is part of the Forest2D world editor

    the Forest2D world editor 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.

    the Forest2D world editor 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 the Forest2D world editor.  If not, see <http://www.gnu.org/licenses/>.
]]--

-- load Forest2D from the directory above
local tmp=package.cpath
package.cpath="../Data.so;"..package.path
package.path="../?.lua;"..package.path
local Forest2D = require "Forest2D"
package.cpath=tmp

Forest2D:Init()

Forest2D.WINDOW_WIDTH = 640
Forest2D.WINDOW_HEIGHT = 480
local FULLSCREEN = false

--Command Line Parameters
if (arg[1] == "FULLSCREEN") then FULLSCREEN = true end

window = Forest2D:CreateSDLWindow("Forest2D WorldEditor", "../../Assets/Graphics/Textures/Soil.bmp")

if FULLSCREEN == true then
ret, error = window:setFullscreen(SDL.window.Fullscreen)
if not ret then error(error) end
end
Renderer = Forest2D:CreateSDLRenderer(window)

local EventHandler = Forest2D.EventHandler.New(2) --2 milisecond delay between events

local TileAnimationset = Forest2D.World.TileAnimationset.New(Renderer, "./SavedWorld/Animationset.bmp", "./SavedWorld/Animationset.cfg")
local Tileset = Forest2D.World.Tileset.New(Renderer, "./SavedWorld/Tileset.bmp")
local GameWorld = Forest2D.World.New (Renderer, Tileset, TileAnimationset, 32, 1, 6, 48, 64)

--UI Widgets
local HelpWindow = Forest2D.GUI.NewWindow (Renderer, {x = 150, y = 128, w = 320, h = 200}, 0x111111, 96,
{color = 0xFF0000, alpha = 210, text = "Help", textcolor = 0x000000, selectable = true, uncloseable = true})

local HelpWindowLabel1 = Forest2D.GUI.NewLabel(HelpWindow, Renderer, {x = 0, y = 0, w = 320, h = 25}, "./unifont-10.0.06.ttf", 26, "LSHIFT + LMouseClick to place an object", 0xFF0000)
local HelpWindowLabel2 = Forest2D.GUI.NewLabel(HelpWindow, Renderer, {x = 0, y = 48, w = 320, h = 25}, "./unifont-10.0.06.ttf", 26, "LSHIFT + RMouseClick to place blank tile", 0xFF0000)
local HelpWindowLabel3 = Forest2D.GUI.NewLabel(HelpWindow, Renderer, {x = 0, y = 73, w = 320, h = 25}, "./unifont-10.0.06.ttf", 26, "Scroll wheel to change current object", 0xFF0000)
local HelpWindowLabel4 = Forest2D.GUI.NewLabel(HelpWindow, Renderer, {x = 0, y = 98, w = 320, h = 25}, "./unifont-10.0.06.ttf", 26, "Keys 1-6 to change current tilemap Layer", 0xFF0000)
local HelpWindowLabel5 = Forest2D.GUI.NewLabel(HelpWindow, Renderer, {x = 0, y = 121, w = 320, h = 25}, "./unifont-10.0.06.ttf", 26, "E for edit mode, R to render scene", 0xFF0000)

HelpWindow:Add(HelpWindowLabel1)
HelpWindow:Add(HelpWindowLabel2)
HelpWindow:Add(HelpWindowLabel3)
HelpWindow:Add(HelpWindowLabel4)
HelpWindow:Add(HelpWindowLabel5)

local New_item = Forest2D.GUI.NewButton(nil, Renderer, nil, "New ", 0x000000, 0xFFFFFF)
local Save_item = Forest2D.GUI.NewButton(nil, Renderer, nil, "Save", 0x000000, 0xFFFFFF)
local Load_item = Forest2D.GUI.NewButton(nil, Renderer, nil, "Load", 0x000000, 0xFFFFFF)
local Quit_item = Forest2D.GUI.NewButton(nil, Renderer, nil, "Quit", 0x000000, 0xFFFFFF)
local File_menu = Forest2D.GUI.NewMenu(Renderer, {New_item, Save_item, Load_item, Quit_item}, {x = 0, y = 0, w = 64, h = 24}, "File", 0x000000, 0xFFFFFF, 255)

local Tileset_item = Forest2D.GUI.NewButton(nil, Renderer, nil, "Tileset", {x = 80, y = 0, w = 80, h = 24}, 0x000000, 0xFFFFFF, 255)
local Animationset_item = Forest2D.GUI.NewButton(nil, Renderer, nil, "Animationset", {x = 80, y = 0, w = 80, h = 24}, 0x000000, 0xFFFFFF, 255)
local Select_menu = Forest2D.GUI.NewMenu(Renderer, {Tileset_item, Animationset_item}, {x = 80, y = 0, w = 80, h = 24}, "Select", 0x000000, 0xFFFFFF, 255)

-- UI variables
local ShowHelpWindow = false
local CurrentLayer = 6

-- Aliases for indexing ObjectType
local OBJ_TYPE_TILESET = 1
local OBJ_TYPE_ANIMATIONSET = 2

local ObjectType = {"tileset", "animationset"} -- The type of game object the user is currently working with.
local ObjectTypeIndex = 1
local TilesetIndex = 1
local TileAnimationsetIndex = 1

-- modes "edit", "view"
local EditorMode = "edit"

Renderer:setDrawColor(0xFFFFFF)
while true do

    if FULLSCREEN == true then
        ret, err = window:setFullscreen(SDL.window.Fullscreen)
            if not ret then
                error(er)
            end
    else
        ret, err = window:setFullscreen(SDL.window.OpenGL)
            if not ret then
                error(err)
            end
    end

    --Manage Events
    if EventHandler.EventStatus[EVENT_SDLQUIT].Active or EventHandler.EventStatus[EVENT_ESCKEY_PRESSED].Active then print "Exiting..." goto QUIT end
    if EventHandler.EventStatus[EVENT_FKEY_PRESSED].Active then if FULLSCREEN == false then FULLSCREEN = true else FULLSCREEN = false end EventHandler.DisableEvent(EVENT_FKEY_PRESSED, 500) end

    if EventHandler.EventStatus[EVENT_UPKEY_PRESSED].Active then GameWorld.Camera.PosY = GameWorld.Camera.PosY - 4 end
    if EventHandler.EventStatus[EVENT_DOWNKEY_PRESSED].Active then GameWorld.Camera.PosY = GameWorld.Camera.PosY + 4 end
    if EventHandler.EventStatus[EVENT_LEFTKEY_PRESSED].Active then GameWorld.Camera.PosX = GameWorld.Camera.PosX - 4 end
    if EventHandler.EventStatus[EVENT_RIGHTKEY_PRESSED].Active then GameWorld.Camera.PosX = GameWorld.Camera.PosX + 4 end

    EventHandler.GetActiveEvents()

  -- Set CurrentLayer
    if EventHandler.EventStatus[EVENT_1KEY_PRESSED].Active then
      CurrentLayer = 1
    end
    if EventHandler.EventStatus[EVENT_2KEY_PRESSED].Active then
      CurrentLayer = 2
    end
    if EventHandler.EventStatus[EVENT_3KEY_PRESSED].Active then
      CurrentLayer = 3
    end
    if EventHandler.EventStatus[EVENT_4KEY_PRESSED].Active then
      CurrentLayer = 4
    end
    if EventHandler.EventStatus[EVENT_5KEY_PRESSED].Active then
      CurrentLayer = 5
    end
    if EventHandler.EventStatus[EVENT_6KEY_PRESSED].Active then
      CurrentLayer = 6
    end

  -- Allows user to place objects in world when LShift key held down
    if (EventHandler.EventStatus[EVENT_MOUSEBUTTON_LEFT_PRESSED].Active
    or EventHandler.EventStatus[EVENT_MOUSEBUTTON_LEFT_CLICKED].Active)
    and EventHandler.EventStatus[EVENT_LSHIFTKEY_PRESSED].Active then

        local my, mx = GetCurrentMouseTile(EventHandler.MouseY, EventHandler.MouseX, GameWorld.Camera.PosY, GameWorld.Camera.PosX)
        --FIXME: Because mtiley and mtilex are rounded to nearest integer they are sometimes slightly off few pixels
        --not critical bug
        mtiley = (my + Round(GameWorld.Camera.PosY / GameWorld.SizeOfTile))
        mtilex = (mx + Round(GameWorld.Camera.PosX / GameWorld.SizeOfTile))

        if mtilex > 0 and mtilex < GameWorld.SizeX
        and mtiley > 0 and mtiley < GameWorld.SizeY then

          if ObjectType[ObjectTypeIndex] == "tileset" then
            GameWorld:SetTile(1, CurrentLayer, mtiley, mtilex, false,"animated")
            GameWorld:SetTile(1, CurrentLayer, mtiley, mtilex, TilesetIndex,"tile_id")
          elseif ObjectType[ObjectTypeIndex] == "animationset" then
            GameWorld:SetTile(1, CurrentLayer, mtiley, mtilex, true, "animated")
            GameWorld:SetTile(1, CurrentLayer, mtiley, mtilex, TileAnimationsetIndex, "animation_id")
          end

        end
    --TODO: find a more general purpose method of erasing objects
    -- Place Tile at index 1 when right clicked
    elseif (EventHandler.EventStatus[EVENT_MOUSEBUTTON_RIGHT_PRESSED].Active
    or EventHandler.EventStatus[EVENT_MOUSEBUTTON_RIGHT_CLICKED].Active)
    and EventHandler.EventStatus[EVENT_LSHIFTKEY_PRESSED].Active then
       local my, mx = GetCurrentMouseTile(EventHandler.MouseY, EventHandler.MouseX, GameWorld.Camera.PosY, GameWorld.Camera.PosX)

        mtiley = (my + Round(GameWorld.Camera.PosY / GameWorld.SizeOfTile))
        mtilex = (mx + Round(GameWorld.Camera.PosX / GameWorld.SizeOfTile))

        if mtilex > 0 and mtilex < GameWorld.SizeX
        and mtiley > 0 and mtiley < GameWorld.SizeY then
            GameWorld:SetTile(1, CurrentLayer, mtiley, mtilex, false,"animated")
            GameWorld:SetTile(1, CurrentLayer, mtiley, mtilex, 1,"tile_id")
        end
    end

    -- Scroll through diffrent object types with mouse wheel
    if EventHandler.EventStatus[EVENT_MOUSEWHEEL_UP].Active then
      if TilesetIndex < #Tileset then
        TilesetIndex = Inc(TilesetIndex)
      end
      if TileAnimationsetIndex < #TileAnimationset then
        TileAnimationsetIndex = Inc(TileAnimationsetIndex)
      end
    end
    if EventHandler.EventStatus[EVENT_MOUSEWHEEL_DOWN].Active then
      if TilesetIndex > 1 then
        TilesetIndex = Dec(TilesetIndex)
      end
      if TileAnimationsetIndex > 1 then
        TileAnimationsetIndex = Dec(TileAnimationsetIndex)
      end
    end

   -- Next implement the UI!

    if New_item:Clicked(EventHandler) then
        GameWorld:Free()
        GameWorld:Init() print "World cleared"
    elseif Save_item:Clicked(EventHandler) or EventHandler.EventStatus[EVENT_SKEY_PRESSED].Active then
        GameWorld:Save("./SavedWorld/tilemap") print "Saved World" EventHandler.DisableEvent(EVENT_SKEY_PRESSED, 500)
    elseif Load_item:Clicked(EventHandler) or EventHandler.EventStatus[EVENT_LKEY_PRESSED].Active then
        GameWorld:Load("./SavedWorld/tilemap") print "Loaded World" EventHandler.DisableEvent(EVENT_LKEY_PRESSED, 500)
    elseif Quit_item:Clicked(EventHandler) then
        goto QUIT
    elseif Tileset_item:Clicked(EventHandler) then
        print("Selected " .. ObjectType[OBJ_TYPE_TILESET])
        ObjectTypeIndex = OBJ_TYPE_TILESET
    elseif Animationset_item:Clicked(EventHandler) then
        print("Selected " .. ObjectType[OBJ_TYPE_ANIMATIONSET])
        ObjectTypeIndex = OBJ_TYPE_ANIMATIONSET
    end

    if EventHandler.EventStatus[EVENT_RKEY_PRESSED].Active then
      EditorMode = "view"
    elseif EventHandler.EventStatus[EVENT_EKEY_PRESSED].Active then
      EditorMode = "edit"
    end
    if EditorMode == "edit" then -- render current layer
      GameWorld:Render(1, CurrentLayer)
    elseif EditorMode == "view" then -- render full scene
      for I=1, GameWorld.SizeZ do GameWorld:Render(1,I) end
    end

    --Show currently selected object

    if ObjectType[ObjectTypeIndex] == "tileset" then
      Tileset[TilesetIndex]:setAlphaMod(200)
      Renderer:copy(Tileset[TilesetIndex], nil, {w = 64, h = 64, x = Forest2D.WINDOW_WIDTH - 64, y = (Forest2D.WINDOW_HEIGHT - 64)})
      Tileset[TilesetIndex]:setAlphaMod(255)
    elseif ObjectType[ObjectTypeIndex] == "animationset" then
      TileAnimationset[TileAnimationsetIndex].AnimationTexture:setAlphaMod(150)
      Renderer:copy(TileAnimationset[TileAnimationsetIndex].AnimationTexture, nil, {w = 256, h = 96, x = Forest2D.WINDOW_WIDTH - 256, y = (Forest2D.WINDOW_HEIGHT - 32)})
      TileAnimationset[TileAnimationsetIndex].AnimationTexture:setAlphaMod(255)
    end


    -- Show and hide the help window with F1
    if EventHandler.EventStatus[EVENT_F1KEY_PRESSED].Active and not ShowHelpWindow then
      ShowHelpWindow = true
      HelpWindow.visible = true
      EventHandler.DisableEvent(EVENT_F1KEY_PRESSED, 400)
    elseif EventHandler.EventStatus[EVENT_F1KEY_PRESSED].Active and ShowHelpWindow then
      ShowHelpWindow = false
      EventHandler.DisableEvent(EVENT_F1KEY_PRESSED, 400)
    end
    if ShowHelpWindow then
      HelpWindow:Render(EventHandler)
    end

    File_menu:Render(EventHandler)
    Select_menu:Render(EventHandler)

    -- Display info
    Forest2D.Text.PrintText(Renderer, "Layer" .. tostring(CurrentLayer), 522, 0, 20, 14)
    Forest2D.Text.PrintText(Renderer, "Editor mode: " .. EditorMode, 280, 460, 20, 14)

    Renderer:present()
    Renderer:clear()

end

::QUIT::

GameWorld:Free()
Forest2D:Quit()
