--[[
This script is automatically run by Glu when it starts up.
Its purpose is to make it easy for users to run the scripts
supplied with Glu, or their scripts (the latter are in a
folder specified in the Preferences dialog).

Author: Andrew Trevorrow (andrew@trevorrow.com).
--]]

local glu = glu()
local cv = canvas()
-- require "gplus.strict"
local gp = require "gplus"
local cp = require "cplus"

local pathsep = glu.getdir("app"):sub(-1)
local supplieddir = glu.getdir("app").."Scripts"..pathsep
local yourdir = glu.getdir("scripts")

local suppliednames = {}    -- array of supplied script names (for button labels)
local yournames = {}        -- array of your script names (ditto)
local sbuttons = {}         -- buttons for supplied scripts
local ybuttons = {}         -- buttons for your scripts
local buttwd = 120          -- width of each button
local buttht = 22           -- height of each button
local buttgap = 15          -- vertical gap between buttons
local midgap = 20           -- horizontal space between button columns
local topgap = 20           -- vertical space above headings
local sclip = "s"           -- clip with heading for supplied scripts
local yclip = "y"           -- clip with heading for your scripts

local vr, vg, vb = glu.getcolor("viewport")

--------------------------------------------------------------------------------

function FindScripts(dir)
    local files = glu.getfiles(dir)
    if files == nil then return {} end    -- dir doesn't exist
    local names = {}
    for _, name in ipairs(files) do
        if name:sub(1,1) == "." then
            -- ignore hidden files (like .DS_Store on Mac)
        elseif name:sub(-1) == pathsep then
            -- name is a directory so see if it contains name.lua
            local fullpath = dir..name..name:sub(1,-2)..".lua"
            local f = io.open(fullpath, "r")
            if f then
                f:close()
                names[#names+1] = name:sub(1,-2)    -- strip off pathsep
            end
        end
    end
    if #names > 0 then table.sort(names) end
    return names
end

--------------------------------------------------------------------------------

function RunScript(filepath)
    local f = io.open(filepath, "r")
    if f then
        f:close()
    else
        glu.warn("Script file could not be opened:\n"..filepath)
        return
    end
    
    -- glu.run temporarily changes the current directory and creates a temporary canvas
    -- for the script; when the script ends it restores the Glu window size, title, etc
    -- and finally updates everything
    glu.run(filepath)
end

--------------------------------------------------------------------------------

function CreateButtons(names, dir)
    cp.buttonht = buttht
    cp.radius = 12
    cp.textshadowx = 2
    cp.textshadowy = 2

    local buttons = {}
    for i, name in ipairs(names) do
        local filepath = dir..name..pathsep..name..".lua"
        buttons[i] = cp.button(name, RunScript, {filepath})
        while buttons[i].wd > buttwd do
            name = name:sub(1,-5).."..."
            buttons[i].setlabel(name, true)
        end
        buttons[i].wd = buttwd
    end    
    return buttons
end

--------------------------------------------------------------------------------

function CreateColumnHeadings()
    cv.font("default-bold", 10)
    if (vr+vg+vb) // 3 < 128 then
        cv.rgba(cp.white) -- white text if viewport background is dark
    else
        cv.rgba(cp.black) -- black text if viewport background is light
    end
    local _, ht = cv.text(sclip, "GLU SCRIPTS")
    local _, ht = cv.text(yclip, "YOUR SCRIPTS")
    return ht
end

--------------------------------------------------------------------------------

function DrawColumnHeadings()
    local cvwd, _ = cv.getsize("")
    local swd, _ = cv.getsize(sclip)
    local ywd, _ = cv.getsize(yclip)
    if #suppliednames > 0 then
        if #yournames == 0 then
            -- only 1 column
            cv.paste(sclip, (cvwd-swd)//2, topgap)
        else
            -- put heading above left column
            cv.paste(sclip, (cvwd-midgap-buttwd-swd)//2, topgap)
        end
    end
    if #yournames > 0 then
        if #suppliednames == 0 then
            -- only 1 column
            cv.paste(yclip, (cvwd-ywd)//2, topgap)
        else
            -- put heading above right column
            cv.paste(yclip, (cvwd+midgap+buttwd-ywd)//2, topgap)
        end
    end
end

--------------------------------------------------------------------------------

function CreateCanvas()
    -- create canvas wide enough for 2 columns of buttons
    local maxwidth = buttwd * 2 + midgap
    cv.create(maxwidth, 1)
    cv.position("middletop")
    cv.blend(1)
    
    sbuttons = CreateButtons(suppliednames, supplieddir)
    ybuttons = CreateButtons(yournames, yourdir)
    local scount = #sbuttons
    local ycount = #ybuttons
    
    if scount + ycount == 0 then
        -- no buttons so viewport is empty
        glu.update()
        return
    end

    local textht = CreateColumnHeadings()
    
    -- resize canvas depending on text height and max number of buttons
    local maxcount = math.max(scount, ycount)
    if scount == 0 or ycount == 0 then
        -- only 1 column
        maxwidth = buttwd
    end
    cv.resize(maxwidth, topgap + textht + maxcount * (buttgap + buttht))
    
    DrawColumnHeadings()
    local x = 0
    local y = topgap - 5
    if scount > 0 then
        -- show buttons with supplied scripts
        if ycount == 0 then
            -- only 1 column of buttons
            x = (maxwidth - buttwd) // 2
        else
            -- 1st of 2 columns
            x = maxwidth//2 - (buttwd + midgap//2)
        end
        y = y + textht + buttgap
        for _, button in ipairs(sbuttons) do
            button.show(x, y)
            y = y + buttgap + buttht
        end
    end
    
    y = topgap - 5
    if ycount > 0 then
        -- show buttons with your scripts
        if scount == 0 then
            -- only 1 column of buttons
            x = (maxwidth - buttwd) // 2
        else
            -- 2nd of 2 columns
            x = maxwidth//2 + midgap//2
        end
        y = y + textht + buttgap
        for _, button in ipairs(ybuttons) do
            button.show(x, y)
            y = y + buttgap + buttht
        end
    end
    
    glu.update()
end

--------------------------------------------------------------------------------

function CheckViewportColor()
    -- if user changed viewport background via Prefs > Color then
    -- we might need to change text color
    if #suppliednames + #yournames == 0 then
        -- the viewport has no buttons, so no text
        return
    end
    local newr, newg, newb = glu.getcolor("viewport")
    if newr ~= vr or newg ~= vg or newb ~= vb then
        vr, vg, vb = newr, newg, newb
        CreateColumnHeadings()
        DrawColumnHeadings()
        glu.update()
    end
end

--------------------------------------------------------------------------------

function CheckScriptsFolder()
    -- if user changed their scripts folder via Prefs > File then
    -- we need to rebuild the buttons
    local newdir = glu.getdir("scripts")
    if newdir ~= yourdir then
        yourdir = newdir
        suppliednames = FindScripts(supplieddir)
        yournames = FindScripts(yourdir)
        -- hide & delete current buttons
        for _, button in ipairs(sbuttons) do button.hide() button = nil end
        for _, button in ipairs(ybuttons) do button.hide() button = nil end
        cv.delete()
        CreateCanvas()
    end
end

--------------------------------------------------------------------------------

function EventLoop()
    while true do
        local event = glu.getevent()
        if #event == 0 then
            glu.sleep(5)            -- don't hog the CPU when idle
            CheckViewportColor()    -- check if user changed viewport color
            CheckScriptsFolder()    -- check if user changed their scripts folder
        else
            event = cp.process(event)
            if #event == 0 then
                -- cp.process handled the given event (eg. button click)
            elseif event:find("^file") then
                -- can get this event if user drops .lua file onto Glu icon
                RunScript(event:sub(6))
            elseif event:find("^key") then
                glu.doevent(event)
            end
        end
    end
end

--------------------------------------------------------------------------------

function Main()
    suppliednames = FindScripts(supplieddir)
    yournames = FindScripts(yourdir)
    CreateCanvas()
    EventLoop()
end

--------------------------------------------------------------------------------

status, err = xpcall(Main, gp.trace)
if err then glu.continue(err) end
-- the following code is always executed
cv.delete()
