------------------------------------------------------------------------------------------------
-- Please don't judge this code too heavily. It is a bit of a hack job but it works :)
------------------------------------------------------------------------------------------------


function uiDrawOptions()

    local w = UiWidth()
    local h = UiHeight()

    contW = w * 0.9
    contH = h * 0.9
    padH = 10
    padW = 10
    padW2 = padW * 2
    padH2 = padH * 2

    font_heading = 64
    font_normal = 28

    -- Base container.
    uiDrawBaseContainer()

    -- Title container.
    title_w = 128
    title_h = 128
    uiDrawTitleContainer()

    -- Options container.
    options_w = contW - (padW * 2)
    options_h = contH - title_h - (padH * 3)
    options_tabNames = {'World', 'Floor', 'Walls', 'Ceiling'}
    options_tabs = #options_tabNames
    options_tabH = 72
    options_tabW = (options_w - padW2)/options_tabs
    options_tabSelected = options_tabSelected or options_tabNames[1]
    uiDrawOptionsContainer()

end

function uiDrawBaseContainer()
    ui.padding.create(UiWidth() * 0.1/2, UiHeight() * 0.1/2)
    ui.container.create(contW, contH, ui.colors.g1, 1)
end

function uiDrawTitleContainer()

    -- Title container
    ui.padding.create(padW, padH)
    ui.container.create(contW - title_w, title_h, ui.colors.g2, 1)


    -- Text: Title
    do UiPush()

        -- Mod Preview Image
        local imgW = title_w - padW2
        local imgH = title_h - padH2
        ui.padding.create(padW, padH)
        UiColor(1,1,1, 1)
        UiRect(imgW, imgH)
        UiImageBox('MOD/img/world.png', imgW, imgH, 1,1, 1,1,1,1)

        -- Mod Title
        ui.padding.create(padW + imgW, 0)
        local textHeight = 64
        UiColor(1,1,1, 1)
        UiFont('bold.ttf', textHeight)
        UiAlign('top left')
        UiText('Infinite World Generator - '..regGetString('verison'))

        -- Mod Subtitle
        ui.padding.create(0, textHeight + padH/2)
        textHeight = 32
        UiFont('bold.ttf', textHeight)
        UiText('By: Geneosis')


    UiPop() end

    -- Button: Exit
    do UiPush()

        ui.padding.create(padW, 0)
        ui.padding.create(contW - title_w, 0)

        local btnW = 128 - (padW*3)
        local btnH = 128

        UiAlign('left top')

        -- Exit button
        UiColor(1,0,0,1)
        UiRect(btnW, btnH)

        UiButtonImageBox('ui/common/box-outline-6.png', 1,1, 0,0,0, a)
        if UiBlankButton(btnW, btnH) then
            if UI_GAME then
                UI_GAME = false
            elseif UI_OPTIONS then
                Menu()
            end
        end

        -- X text
        UiColor(1,1,1, 1)
        ui.padding.create(btnW/2, btnH/2)
        UiFont('bold.ttf', btnW/1.5)
        UiAlign('middle center')
        UiText('X')


    UiPop() end

    ui.padding.create(0, title_w)

end

function uiDrawOptionsContainer()

    -- Options container
    ui.padding.create(0, padH)
    ui.container.create(options_w, options_h, ui.colors.g2, 1)

    -- Text: Options
    ui.padding.create(padW, padH)
    do UiPush()
        UiColor(1,1,1, 1)
        UiFont('bold.ttf', font_heading)
        UiAlign('top left')
        UiText('Options')
    UiPop() end


    -- Button: Options reset
    do UiPush()
        ui.padding.create(contW - padW * 4, ((font_heading - font_normal * 1.5)/2))
        UiColor(1,1,1, 1)
        UiFont('bold.ttf', font_normal * 1.5)
        UiAlign('top right')

        local resetButton = UiTextButton('Reset Mod')
        if resetButton then
            modReset()
            beep()
        end

    UiPop() end

    -- Options tabs
    ui.padding.create(0, padH2 + font_heading)
    do UiPush()

        ui.tabView.tab.create("World")

        ui.padding.create(options_tabW + (padW/(options_tabs-1)), 0)
        ui.tabView.tab.create("Floor")

        ui.padding.create(options_tabW + (padW/(options_tabs-1)), 0)
        ui.tabView.tab.create("Walls")

        ui.padding.create(options_tabW + (padW/(options_tabs-1)), 0)
        ui.tabView.tab.create("Ceiling")

    UiPop() end


    -- Options tab content container
    local tabContentH = contH - title_h - options_tabH - options_tabH - padH * 6.5
    ui.padding.create(0, options_tabH)
    ui.container.create(contW - padW*4, tabContentH, ui.colors.g3, 1)


    -- Tab content
    ui.padding.create(padW, padH2)
    ui.container.create(contW - padW*6, tabContentH - padH*3, ui.colors.g1, 1)
    ui.padding.create(padW2*2, padH2*2)
    do UiPush()

        if options_tabSelected == 'World' then

            options_tabs_render.World()

        elseif options_tabSelected == 'Floor' then

            options_tabs_render.Floor()

        elseif options_tabSelected == 'Walls' then

            options_tabs_render.Walls()

        elseif options_tabSelected == 'Ceiling' then

            options_tabs_render.Ceiling()

        end

    UiPop() end

end

materials = {"glass", "grass", "rock", "dirt", "wood", "plaster", "concrete", "brick", "metal", "masonry", "foliage", "plastic", "heavymetal", "asmuth", "unphysical", "hardmetal"}

textures = {"none", "ground", "road", "grass", "stains", "scorched", "cracked", "muddy", "rusted", "sand", "concrete", "planks", "puddles", "cement", "water", "flat", "painted", "ragged", "soaked", "marshy", "gravel", "asphalt", "impacts"}

options_tabs_render = {

    World = function()

        do UiPush()

            ui.padding.create(0, 20)

            do UiPush()

                ui.slider.create('Chunk size', 'world.chunkSize', 'Voxels', 10, 512, nil, nil, nil, nil, true)
                ui.padding.create(0, 90)

                ui.slider.create('Render distance', 'world.renderDistance', 'Chunks', 1, 100, nil, nil, nil, nil, true)
                ui.padding.create(0, 90)

                ui.checkBox.create('Despwan chunks out of render distance', 'world.despawnChunks')
                ui.padding.create(0, 90)

                ui.slider.create('Generate', 'world.generate', '', nil, nil, nil, nil, nil, nil, nil, {"floor", "floor + walls", "floor + walls + ceiling"})
                ui.padding.create(0, 90)

            UiPop() end

            do UiPush()

                ui.padding.create(800, 0)

                ui.checkBox.create('Debug Mode', 'world.debugMode')
                ui.padding.create(0, 90)

                UiFont('regular.ttf', font_normal)
                UiColor(1, 1, 1, 1)
                UiAlign('left middle')
                UiText("This mod builds upon Thompson937's Minecraft Superflat World")
                ui.padding.create(0, 30)
                UiText("and adds the ability to generate walls and ceiling")
                ui.padding.create(0, 30)
                UiText("as well as fully customizable materials and textures.")
                ui.padding.create(0, 40)
                UiText("Although there is no actual procedural work here (only random walls) this mod is")
                ui.padding.create(0, 30)
                UiText("built as a framework to simplify the implementation of actual procedural tiles,")
                ui.padding.create(0, 30)
                UiText("as well as a way to easily test various chunk configurations.")
                ui.padding.create(0, 40)
                UiText("Feel free to reuse and build upon it, leaving a mention to this mod ;)")
                ui.padding.create(0, 40)

            UiPop() end

        UiPop() end

    end,

    Floor = function()

        do UiPush()

            ui.slider.create('Material (physics and sound)', 'floor.material', '', nil, nil, nil, nil, nil, nil, nil, materials)
            ui.padding.create(0, 50)

            ui.colorPicker.create('Color', 'floor.color', nil, nil, nil, false)
            ui.padding.create(0, 50)

            ui.slider.create('Texture (visual and sound)', 'floor.texture', '', nil, nil, nil, nil, nil, nil, nil, textures)
            ui.padding.create(0, 50)

            ui.slider.create('Texture opacity', 'floor.textureOpacity', '%', 0, 100, nil, nil, nil, nil, true)
            ui.padding.create(0, 50)

            ui.slider.create('Metallic (blur)', 'floor.metallic', '%', 0, 100, nil, nil, nil, nil, true)
            ui.padding.create(0, 50)

            ui.slider.create('Roughness (reflection)', 'floor.roughness', '%', 0, 100, nil, nil, nil, nil, true)
            ui.padding.create(0, 50)

            ui.slider.create('Emissive (glow)', 'floor.emissive', '%', 0, 100, nil, nil, nil, nil, true)
            ui.padding.create(0, 50)

        UiPop() end

        do UiPush()

            ui.padding.create(800, 0)

            ui.checkBox.create('Unbreakable', 'floor.unbreakable')
            ui.padding.create(0, 70)

            ui.slider.create('Thickness', 'floor.thickness', 'Voxels', 1, 100, nil, nil, nil, nil, true)
            ui.padding.create(0, 50)
           
        UiPop() end
        
    end,

    Walls = function()

        do UiPush()

            ui.slider.create('Material (physics and sound)', 'walls.material', '', nil, nil, nil, nil, nil, nil, nil, materials)
            ui.padding.create(0, 50)

            ui.colorPicker.create('Color', 'walls.color', nil, nil, nil, false)
            ui.padding.create(0, 50)

            ui.slider.create('Texture (visual and sound)', 'walls.texture', '', nil, nil, nil, nil, nil, nil, nil, textures)
            ui.padding.create(0, 50)

            ui.slider.create('Texture opacity', 'walls.textureOpacity', '%', 0, 100, nil, nil, nil, nil, true)
            ui.padding.create(0, 50)

            ui.slider.create('Metallic (blur)', 'walls.metallic', '%', 0, 100, nil, nil, nil, nil, true)
            ui.padding.create(0, 50)

            ui.slider.create('Roughness (reflection)', 'walls.roughness', '%', 0, 100, nil, nil, nil, nil, true)
            ui.padding.create(0, 50)

            ui.slider.create('Emissive (glow)', 'walls.emissive', '%', 0, 100, nil, nil, nil, nil, true)
            ui.padding.create(0, 50)

        UiPop() end

        do UiPush()

            ui.padding.create(800, 0)

            ui.checkBox.create('Unbreakable', 'walls.unbreakable')
            ui.padding.create(0, 70)

            ui.slider.create('Thickness', 'walls.thickness', 'Voxels', 1, 10, nil, nil, nil, nil, true)
            ui.padding.create(0, 50)

            ui.slider.create('Height', 'walls.height', 'Voxels', 1, 100, nil, nil, nil, nil, true)
            ui.padding.create(0, 50)

            ui.slider.create('Count per chunk', 'walls.count', 'Walls', 1, 4, nil, nil, nil, nil, true)
            ui.padding.create(0, 50)

            ui.slider.create('Probability to generate', 'walls.proba', '%', 1, 100, nil, nil, nil, nil, true)
            ui.padding.create(0, 50)

        UiPop() end
        
    end,

    Ceiling = function()

        do UiPush()

            ui.slider.create('Material (physics and sound)', 'ceiling.material', '', nil, nil, nil, nil, nil, nil, nil, materials)
            ui.padding.create(0, 50)

            ui.colorPicker.create('Color', 'ceiling.color', nil, nil, nil, false)
            ui.padding.create(0, 50)

            ui.slider.create('Texture (visual and sound)', 'ceiling.texture', '', nil, nil, nil, nil, nil, nil, nil, textures)
            ui.padding.create(0, 50)

            ui.slider.create('Texture opacity', 'ceiling.textureOpacity', '%', 0, 100, nil, nil, nil, nil, true)
            ui.padding.create(0, 50)

            ui.slider.create('Metallic (blur)', 'ceiling.metallic', '%', 0, 100, nil, nil, nil, nil, true)
            ui.padding.create(0, 50)

            ui.slider.create('Roughness (reflection)', 'ceiling.roughness', '%', 0, 100, nil, nil, nil, nil, true)
            ui.padding.create(0, 50)

            ui.slider.create('Emissive (glow)', 'ceiling.emissive', '%', 0, 100, nil, nil, nil, nil, true)
            ui.padding.create(0, 50)

        UiPop() end

        do UiPush()

            ui.padding.create(800, 0)

            ui.checkBox.create('Unbreakable', 'ceiling.unbreakable')
            ui.padding.create(0, 70)

            ui.slider.create('Thickness', 'ceiling.thickness', 'Voxels', 1, 100, nil, nil, nil, nil, true)
            ui.padding.create(0, 50)
           
        UiPop() end
        
    end,

}


ui = {}

ui.colors = {
    white = Vec(1,1,1),
    g3 = Vec(0.5,0.5,0.5),
    g2 = Vec(0.35,0.35,0.35),
    g1 = Vec(0.2,0.2,0.2),
    black = Vec(0,0,0),
}



ui.container = {}

function ui.container.create(w, h, c, a)
    if not c then c = Vec(0.5,0.5,0.5) end
    UiColor(c[1], c[2], c[3], a or 0.5)
    UiRect(w, h)
end



ui.padding = {}

function ui.padding.create(w, h)
    UiTranslate(w or 10, h or 10)
end



ui.tabView = {}

ui.tabView.tab = {}

function ui.tabView.tab.create(text)

    do UiPush()

        UiAlign('top left')

        ui.container.create(options_tabW - padW, options_tabH, ui.colors.g1, 1)

        if options_tabSelected == text then
            ui.container.create(options_tabW - padW, options_tabH, ui.colors.g3, 1)
        end

        UiButtonImageBox('ui/common/box-outline-6.png', 1,1, 0,0,0, a)
        if UiBlankButton(options_tabW, options_tabH) then
            if options_tabSelected ~= text then
                PlaySound(LoadSound('clickdown.ogg'), GetCameraTransform().pos, 1)
            end
            options_tabSelected = text
        end

        ui.padding.create(options_tabW/2, options_tabH/2)

        UiColor(1,1,1, 1)
        UiFont('bold.ttf', font_normal*1.25)
        UiAlign('center middle')
        UiText(text)

    UiPop() end

end



ui.slider = {}

function ui.slider.create(title, registryPath, valueText, min, max, w, h, fontSize, inline, intSlider, stringChoices)

    local hasTitle = not(title == nil or title == '')
    local strSlider = stringChoices and #stringChoices > 0 
    local intSlider = intSlider or false
    local value = regGetFloat(registryPath)
    if intSlider then value = regGetInt(registryPath) end

    min = min or 0
    max = max or 300
    inline = inline or false

    local strIndex = {}
    if strSlider then
        min = 1
        max = #stringChoices
        for k,v in pairs(stringChoices) do
            strIndex[v]=k
        end
        local strVal = regGetString(registryPath)
        value = strIndex[strVal]
    end

    UiAlign('left middle')

    -- Text header
    UiColor(1,1,1, 1)
    UiFont('regular.ttf', fontSize or font_normal)
    if hasTitle then
        titleW, titleH = UiText(title)
        if inline then
            UiPush()
            ui.padding.create(titleW + padW2, 0)
        else
            ui.padding.create(0, fontSize or font_normal)
        end
    end

    -- Slider BG
    UiColor(0.4,0.4,0.4, 1)
    local slW = w or 400
    if hasTitle and inline then slW = slW - (titleW + padW2) end
    UiRect(slW, h or 10)

    -- Convert to slider scale.
    value = ((value-min) / (max-min)) * slW

    -- Slider dot
    UiColor(1,1,1, 1)
    UiAlign('center middle')
    value, done = UiSlider("ui/common/dot.png", "x", value, 0, slW)
    local val = (value/slW) * (max-min) + min -- Convert to true scale.
    if intSlider then val = floatToInt(val) end
    if strSlider then val = stringChoices[floatToInt(val)] end
    if done then
        if strSlider then
            regSetString(registryPath, val)
        elseif intSlider then
            regSetInt(registryPath, val)
        else
            regSetFloat(registryPath, val)
        end
    end

    -- Slider value
    do UiPush()
        UiAlign('left middle')
        ui.padding.create(slW + padW2, 0)
        if strSlider then
            UiText(val .. ' ' .. (valueText or ''))
        else
            local decimals = ternary(val < 100, 3, 1)
            if intSlider then decimals = 0 end
            UiText(sfn(val, decimals) .. ' ' .. (valueText or ''))
        end
    UiPop() end

    if hasTitle and inline then UiPop() end

end


ui.checkBox = {}

function ui.checkBox.create(title, registryPath)

    local value = regGetBool(registryPath)

    UiAlign('left middle')

    -- Text header
    UiColor(1,1,1, 1)
    UiFont('regular.ttf', fontSize or font_normal)
    UiText(title)
    ui.padding.create(0, fontSize or font_normal)

    -- Toggle BG
    UiAlign('left top')
    UiColor(0.4,0.4,0.4, 1)
    local tglW = w or 140
    local tglH = h or 40
    UiRect(tglW, h or tglH)

    -- Render toggle
    do UiPush()

        local toggleText = 'ON'

        if value then
            ui.padding.create(tglW/2, 0)
            UiColor(0,0.8,0, 1)
        else
            toggleText = 'OFF'
            UiColor(0.8,0,0, 1)
        end

        UiRect(tglW/2, tglH)

        do UiPush()
            ui.padding.create(tglW/4, tglH/2)
            UiColor(1,1,1, 1)
            UiFont('bold.ttf', font_normal)
            UiAlign('center middle')
            UiText(toggleText)
        UiPop() end

    UiPop() end

    UiButtonImageBox('ui/common/box-outline-6.png', 10,10, 0,0,0, a)
    if UiBlankButton(tglW, tglH) then
        regSetBool(registryPath, not value)
        PlaySound(LoadSound('clickdown.ogg'), GetCameraTransform().pos, 1)
    end

end

ui.colorPicker = {}

function ui.colorPicker.create(title, registryPath, w, h, fontSize, useAlpha)

    w = w or 400
    h = h or 10
    useAlpha = useAlpha or false
    
    UiAlign('left middle')

    -- Text header + color preview
    UiColor(1,1,1, 1)
    UiFont('regular.ttf', fontSize or font_normal)
    local titleW, titleH = UiText(title)
    do UiPush()
        UiAlign('left bottom')
        ui.padding.create(titleW + padW2)
        local r = regGetInt(registryPath..'.r')/255
        local g = regGetInt(registryPath..'.g')/255
        local b = regGetInt(registryPath..'.b')/255
        local a = 1
        if useAlpha then a = regGetInt(registryPath..'.a')/255 end
        UiColor(r, g, b, a)
        UiRect(70, 40)
    UiPop() end
    ui.padding.create(0, fontSize or font_normal)

    -- Red/Green/Blue/Alpha sliders
    ui.slider.create('', registryPath..'.r', 'Red', 0, 255, w, h, fontSize, true, true)
    ui.padding.create(0, fontSize or font_normal)
    ui.slider.create('', registryPath..'.g', 'Green', 0, 255, w, h, fontSize, true, true)
    ui.padding.create(0, fontSize or font_normal)
    ui.slider.create('', registryPath..'.b', 'Blue', 0, 255, w, h, fontSize, true, true)
    if useAlpha then
        ui.padding.create(0, fontSize or font_normal)
        ui.slider.create('', registryPath..'.a', 'Alpha', 0, 255, w, h, fontSize, true, true)
    end

end

ui.button = {}

function ui.button.create(text, textColor, borderColor, bgColor, border, w, h)
    local button = nil
    do UiPush()
        textColor = textColor or {r=0, g=0, b=0, a=1}
        borderColor = borderColor or {r=0, g=0, b=0, a=1}
        bgColor = bgColor or {r=ui.colors.g2[1], g=ui.colors.g2[2], b=ui.colors.g2[3], a=1}
        border = border or 2
        UiFont('bold.ttf', font_normal * 1.5)
        local textW, textH = UiGetTextSize(text)
        local spacing = 2
        w = w or (textW + (2 * spacing) + (2 * border))
        h = h or (textH + (2 * spacing) + (2 * border))
        UiAlign('left middle')
        UiColor(borderColor.r,borderColor.g,borderColor.b,borderColor.a)
        UiRect(w, h)
        ui.padding.create((textW / 2) + spacing + border, 0)
        UiAlign('center middle')
        UiColor(bgColor.r,bgColor.g,bgColor.b,bgColor.a)
        UiRect(w- (border * 2), h - (border * 2))
        UiColor(textColor.r,textColor.g,textColor.b,textColor.a)
        button = UiTextButton(text)
    UiPop() end
    return button
end


ui.keyBinding = {}

function ui.keyBinding.create(title, registryPath)

    local value = regGetString(registryPath)

    UiAlign('left middle')

    -- Text header
    UiColor(1,1,1, 1)
    UiFont('regular.ttf', fontSize or font_normal)
    UiText(title)
    ui.padding.create(0, fontSize or font_normal)

    -- Binding BG
    UiAlign('left top')
    local tglW = w or 160
    local tglH = h or 40

    local editing = (value == "-")
    local text = ""
    if editing then
        text = "Press a key..."
        UiColor(0.6,0.6,0.6, 1)
        local keyPressed = InputLastPressedKey()
        if keyPressed ~= "" then
            regSetString(registryPath, keyPressed)
        end
    else
        text = string.upper(value)
        UiColor(0.4,0.4,0.4, 1)
    end

    UiRect(tglW, h or tglH)

    -- Render key
    do UiPush()

        ui.padding.create(tglW/2, tglH/2)
        UiColor(1,1,1, 1)
        UiFont('bold.ttf', font_normal)
        UiAlign('center middle')
        UiText(text)

    UiPop() end

    UiButtonImageBox('ui/common/box-outline-6.png', 10,10, 0,0,0, a)
    if UiBlankButton(tglW, tglH) then
        if editing then
            regSetString(registryPath, "")
        else
            regSetString(registryPath, "-")
        end
        PlaySound(LoadSound('clickdown.ogg'), GetCameraTransform().pos, 1)
    end

end