-- variables
local w,h=term.getSize()
local _key=""
local changelog_scroll=0
local color_selection=(math and math.random and math.random(1,4)) or 1
local count=0
local cursor=1
local cx
local download_url="https://drive.google.com/uc?id="
local first_step=true
local list_scroll=0
local menu_open=false
local menu_scroll=0
local menu_selection=1
local menu_width=0
local name="magiczockerOS Installer"
local offset=0
local requested=0
local root="/magiczockerOS/"
local running=true
local textline_width=15
local timer
local version="Ver. 1.1"
local view=0
-- tables
local _cursor={5,8,11}
local changelog={
    "(c) magiczocker",
    "",
    "Version 1.1",
    " Added CC-Tweaked support",
    " Updated to magiczockerOS 4.0 Preview 2",
    "",
    "Version 1.0",
    " First release"
}
local color_codes={
    {32768,32768,32768},
    {128,256,1},
    {64,1,16384}
}
local e={}
local file_success={}
local files={
    -- Startup
    {path="startup",link="1m84aKmusb5EA7-BbC36FWTR11PIOPoQK"},
    -- Core
    {path=root.."core.lua",link="1JBkZRBh-PVO8W9oXUlmdWO2aQa4J7oIB"},
    -- APIs
    {path=root.."apis/window.lua",link="15uBcrU_Yk1KGLSSSK9FEA6Txeg3p7ala"},
    -- Programs
    {path=root.."programs/desktop.lua",link="1Bn_G9AenQJhJabqA_vVw5SdoH25xrtkD"},
    {path=root.."programs/login.lua",link="1SJna9fCsEQkxPeMOilwEWQvv1YBeH2m7"},
    {path=root.."programs/settings.lua",link="1OSYw8FmIFFWBSOg1TbjcEiBmwe2qZ6mV"},
    {path=root.."programs/startmenu.lua",link="16Cug1805cg-kUUT90IrNst5Qp6x8SF-t"},
    {path=root.."programs/taskbar.lua",link="1NIfyFVSBzq2614lLZqybdpyGcb0wMPCo"}
}
local key_maps={}
local names={}
local textline_offset={}
local textline_cursor={}
local values={"","",""}
local menu={
    [0]={func=function() view=-1 end},
    [1]={txt="Close",func=function() running=false end}
}
local theme={top={128,2,2048,512},bottom={256,16,8,8}}
-- functions
local function _ceil(num)
    local _=num..""
    if _:find("%.") and #_:sub(_:find("%.")+1)>0 then
        return _+0>=0 and _:sub(1,_:find("%.")-1)+1 or _:sub(1,_:find("%.")-1)+0
    end
    return num
end
local function _floor(num)
    local _=num..""
    if _:find("%.") then
        return _+0>=0 and _:sub(1,_:find("%.")-1)+0 or _:sub(1,_:find("%.")-1)-1
    end
    return num
end
local function background_color(col,col_,col__)
    if term and term.isColor then
        term.setBackgroundColor((term.isColor() and col__) or (textutils and type(textutils.complete)=="function" and col_) or col)
    end
end
local function text_color(col,col_,col__)
    if term and term.isColor then
        term.setTextColor((term.isColor() and col__) or (textutils and type(textutils.complete)=="function" and col_) or col)
    end
end
local function write_text(txt,txt_,txt__,txt___)
    term.write((not term.isColor and txt) or (term.isColor() and txt___) or (textutils and type(textutils.complete)=="function" and txt__) or txt_)
end
local function draw_text_line(_)
    term.setCursorBlink(false)
    term.setCursorPos(cx+offset,_cursor[_])
    if _==cursor then
        background_color(32768,1,1)
        text_color(1,32768,32768)
    end
    term.write((values[_]..(((not term.isColor or not term.isColor()) and "_") or " "):rep(textline_width)):sub(1+textline_offset[_],textline_width+textline_offset[_]))
    if _==cursor then
        term.setCursorBlink(true)
        term.setCursorPos(cx+offset-1+textline_cursor[_]-textline_offset[_],_cursor[_])
    end
end
local function set_cursor()
    if textline_cursor[cursor]-1>#values[cursor] then
        textline_cursor[cursor]=#values[cursor]+1
    end
    if textline_cursor[cursor]<=textline_offset[cursor] then
        textline_offset[cursor]=textline_cursor[cursor]-1
    elseif textline_cursor[cursor]>textline_width+textline_offset[cursor] then
        textline_offset[cursor]=textline_cursor[cursor]-textline_width
    end
    if textline_offset[cursor]<0 then
        textline_offset[cursor]=0
    end
    draw_text_line(cursor)
end
local function draw_bottom()
    term.setCursorBlink(false)
    for i=4,h do
        text_color(1,1,1)
        background_color(1,128,theme.top[color_selection])
        term.setCursorPos(1+offset,i)
        if first_step and i<11 and (i-1)%3==0 then
            term.write((" "):rep(_floor(w*0.5-7.5)))
            term.write((((i==4 and "Username") or (i==7 and "Password") or "Repeat Password")..(" "):rep(15)):sub(1,15))
            term.write((" "):rep(_ceil(w*0.5-7.5)))
        elseif first_step and i<12 and (i-2)%3==0 then
            local _=(i==_cursor[cursor] and ">" or " ")
            term.write((" "):rep(_floor(w*0.5-8.5)))
            write_text(_,_," "," ")
            background_color(32768,256,theme.bottom[color_selection])
            if _==">" then
                term.write((" "):rep(15))
            else
                draw_text_line((i==5 and 1) or (i==8 and 2) or 3)
            end
            background_color(1,128,theme.top[color_selection])
            _=(i==_cursor[cursor] and "<" or " ")
            write_text(_,_," "," ")
            term.write((" "):rep(_ceil(w*0.5-8.5)))
        elseif first_step and i==13 then
            term.write((" "):rep(_floor(w*0.5-4.5)))
            background_color(32768,256,theme.bottom[color_selection])
            write_text(cursor==4 and ">" or " ",cursor==4 and ">" or " "," "," ")
            term.write("Install")
            write_text(cursor==4 and "<" or " ",cursor==4 and "<" or " "," "," ")
            background_color(1,128,theme.top[color_selection])
            term.write((" "):rep(_ceil(w*0.5-4.5)))
        elseif not first_step and i<h-2 and files[i-3+list_scroll] then
            term.write(" ")
            text_color(color_codes[1][file_success[i-3+list_scroll] or 1],color_codes[2][file_success[i-3+list_scroll] or 1],color_codes[3][file_success[i-3+list_scroll] or 1])
            term.write("o "..files[i-3+list_scroll].path)
            local _=w-({term.getCursorPos()})[1]
            if _>0 then
                term.write((" "):rep(_))
            end
        elseif not first_step and i==h-1 then
            background_color(32768,256,theme.bottom[color_selection])
            term.write((" "):rep(w*((#files-count-(#files-requested))/#files)))
            background_color(1,128,theme.top[color_selection])
            local _=w-({term.getCursorPos()})[1]+1
            if _>0 then
                term.write((" "):rep(_))
            end
        else
            term.write((" "):rep(w))
        end
    end
    if first_step and cursor<4 then
        set_cursor()
    end
end
local function draw_changelog()
    background_color(32768,256,theme.bottom[color_selection])
    text_color(1,1,1)
    term.setCursorPos(1+offset,4)
    term.write((" "):rep(w))
    for i=5,h-1 do
        term.setCursorPos(1+offset,i)
        term.write(changelog[i-4+changelog_scroll] and " "..changelog[i-4+changelog_scroll]..(" "):rep(w) or (" "):rep(w))
    end
    term.setCursorPos(1+offset,h)
    term.write((" "):rep(w))
end
local function draw_menu()
    if offset>0 then
        background_color(1,128,128)
        term.setCursorPos(1-menu_width+offset,1)
        term.write((" "):rep(menu_width))
        if h>3 or menu_selection~=0 then
            for i=2,h-3 do
                term.setCursorPos(1-menu_width+offset,i)
                if menu[i-1+menu_scroll] then
                    local _=(menu_width-#menu[i-1+menu_scroll].txt)*0.5
                    if i-1+menu_scroll==menu_selection then
                        text_color(32768,1,1)
                        write_text("-","-"," "," ")
                        term.write((" "):rep(_floor(_)-1)..menu[i-1+menu_scroll].txt..(" "):rep(_ceil(_)-1))
                        write_text("-","-"," "," ")
                    else
                        text_color(32768,256,1)
                        term.write((" "):rep(_floor(_))..menu[i-1+menu_scroll].txt..(" "):rep(_ceil(_)))
                    end
                else
                    term.write((" "):rep(menu_width))
                end
            end
        end
        if h>4 then
            term.setCursorPos(1-menu_width+offset,h-2)
            term.write((" "):rep(menu_width))
        end
        term.setCursorPos(1-menu_width+offset,h-1)
        if h>3 or menu_selection==0 then
            local _=(menu_width-#version)*0.5
            if menu_selection==0 then
                text_color(32768,1,1)
                write_text("-","-"," "," ")
                term.write((" "):rep(_floor(_)-1)..version..(" "):rep(_ceil(_)-1))
                write_text("-","-"," "," ")
            else
                text_color(32768,256,1)
                term.write((" "):rep(_floor(_))..version..(" "):rep(_ceil(_)))
            end
        end
        term.setCursorPos(1-menu_width+offset,h)
        term.write((" "):rep(menu_width))
    end
end
local function draw_top()
    background_color(1,128,theme.top[color_selection])
    text_color(32768,1,1)
    term.setCursorPos(1+offset,1)
    term.write((" "):rep(w))
    term.setCursorPos(1+offset,2)
    if view==-1 then
        term.write(" < "..name..(" "):rep(w))
    elseif view==0 then
        term.write(" = "..name..(" "):rep(w))
    end
    term.setCursorPos(1+offset,3)
    if view==0 then
        term.write((" "):rep(w))
    else
        write_text(("_"):rep(w),(" "):rep(w),(" "):rep(w),(" "):rep(w))
    end
end
local function set_menu_width()
    menu_width=0
    for i=1,#menu do
        if #menu[i].txt>menu_width then
            menu_width=#menu[i].txt
        end
    end
    if #version>menu_width then
        menu_width=#version
    end
    menu_width=menu_width+2
end
local function load_keys()
    if (_HOST or ""):find("1.13.2") then -- GLFW
        key_maps[257]="enter"
        key_maps[258]="tab"
        key_maps[259]="backspace"
        key_maps[261]="delete"
        key_maps[262]="right"
        key_maps[263]="left"
        key_maps[264]="down"
        key_maps[265]="up"
    else -- LWJGL
        key_maps[14]="backspace"
        key_maps[15]="tab"
        key_maps[28]="enter"
        key_maps[200]="up"
        key_maps[203]="left"
        key_maps[205]="right"
        key_maps[208]="down"
        key_maps[211]="delete"
    end
end
-- start
load_keys()
cx=_floor(w*0.5-6.5)
for i=1,#_cursor do
    textline_offset[i]=0
    textline_cursor[i]=1
end
set_menu_width()
draw_top()
draw_bottom()
timer=os.startTimer(0)
-- events
repeat
    e={coroutine.yield()}
    if e[1]=="http_success" then
        local file,err=fs.open(names[e[2]][2],"w")
        if file then
            file.write(e[3].readAll())
            file.close()
            e[3].close()
            file_success[names[e[2]][1]]=2
            count=count-1
        else
            file_success[names[e[2]][1]]=3
            count=count-1
        end
        draw_bottom()
    elseif e[1]=="http_failure" then
        file_success[names[e[2]][1]]=3
        count=count-1
        draw_bottom()
    elseif e[1]=="char" and not menu_open and view==0 and cursor<4 then
        values[cursor]=values[cursor]:sub(1,textline_cursor[cursor]-1)..e[2]..values[cursor]:sub(textline_cursor[cursor],#values[cursor])
        textline_cursor[cursor]=textline_cursor[cursor]+1
        set_cursor()
    elseif e[1]=="key" and key_maps[e[2]] and not menu_open and view==0 and cursor<4 and (
        key_maps[e[2]]=="backspace" or 
        key_maps[e[2]]=="left" or 
        key_maps[e[2]]=="right" or 
        key_maps[e[2]]=="delete"
    ) then
        _key=key_maps[e[2]]
        if _key=="backspace" and textline_cursor[cursor]>1 then
            textline_cursor[cursor]=textline_cursor[cursor]-1
            values[cursor]=values[cursor]:sub(1,textline_cursor[cursor]-1)..values[cursor]:sub(textline_cursor[cursor]+1,#values[cursor])
            set_cursor()
        elseif _key=="left" and textline_cursor[cursor]>1 then
            textline_cursor[cursor]=textline_cursor[cursor]-1
            set_cursor()
        elseif _key=="right" and textline_cursor[cursor]<=#values[cursor] then
            textline_cursor[cursor]=textline_cursor[cursor]+1
            set_cursor()
        elseif _key=="delete" and textline_cursor[cursor]<=#values[cursor] then
            values[cursor]=values[cursor]:sub(1,textline_cursor[cursor]-1)..values[cursor]:sub(textline_cursor[cursor]+1,#values[cursor])
            set_cursor()
        end
    elseif e[1]=="key" and key_maps[e[2]] and (not term.isColor or not term.isColor()) then
        _key=key_maps[e[2]]
        if _key=="backspace" and view==-1 then
            view=0
            draw_top()
            draw_bottom()
        elseif _key=="tab" and view==0 then
            menu_open=not menu_open
        elseif _key=="enter" then
            if menu_open then
                menu[menu_selection].func()
                menu_open=false
            elseif view==0 and first_step and values[2]==values[3] and cursor==4 then
                first_step=false
                draw_bottom()
            end
        elseif _key=="up" then
            if menu_open then
                menu_selection=menu_selection>0 and menu_selection-1 or #menu
                if menu_selection==#menu and #menu>h-4 then
                    menu_scroll=#menu-(h-4)
                elseif menu_selection>0 and menu_selection-menu_scroll==0 then
                    menu_scroll=menu_scroll-1
                end
                draw_menu()
            elseif view==-1 and changelog_scroll>0 then
                changelog_scroll=changelog_scroll-1
                draw_changelog()
            elseif view==0 and first_step and cursor>1 then
                cursor=cursor-1
                draw_bottom()
            elseif view==0 and not first_step and list_scroll>0 then
                list_scroll=list_scroll-1
                draw_bottom()
            end
        elseif _key=="down" then
            if menu_open then
                menu_selection=menu_selection<#menu and menu_selection+1 or 0
                if menu_selection==1 then
                    menu_scroll=0
                elseif menu_selection-menu_scroll==h-3 then
                    menu_scroll=menu_scroll+1
                end
                draw_menu()
            elseif view==-1 and #changelog-changelog_scroll>h-5 then
                changelog_scroll=changelog_scroll+1
                draw_changelog()
            elseif view==0 and first_step and cursor<4 then
                cursor=cursor+1
                draw_bottom()
            elseif view==0 and not first_step and #files-list_scroll>h-6 then
                list_scroll=list_scroll+1
                draw_bottom()
            end
        end
    elseif e[1]=="mouse_click" then
        e[3]=e[3]-offset
        if e[2]==1 then -- left click
            if e[3]==2 and e[4]==2 and not menu_open then -- open menu
                if view==-1 then
                    view=0
                    draw_top()
                    draw_bottom()
                elseif view==0 then
                    menu_open=true
                end
            elseif e[3]<1 and e[4]==h-1 and menu_open then -- changelog
                menu[0].func()
                menu_open=false
            elseif e[3]<1 and e[4]>1 and e[4]<h-2 and menu_open then -- menu entries
                if menu[e[4]-1+menu_scroll] then
                    menu[e[4]-1+menu_scroll].func()
                    menu_open=false
                end
            elseif e[3]>0 and menu_open then -- close menu
                menu_open=false
            elseif view==0 and first_step and values[2]==values[3] and e[4]==13 and e[3]>_floor(w*0.5-4.5) and e[3]<_floor(w*0.5-4.5)+10 then
                first_step=false
                draw_bottom()
            elseif view==0 and 
            first_step and 
            e[3]>_floor(w*0.5-7) and 
            e[3]<_floor(w*0.5-7)+15 and 
            e[4]>=_cursor[1] and 
            e[4]<=_cursor[#_cursor] then
                if e[4]==_cursor[cursor] then
                    if #values[cursor]:sub(e[3]-cx+1+textline_offset[cursor],e[3]-cx+1+textline_offset[cursor])>0 then
                        textline_cursor[cursor]=e[3]-cx+1+textline_offset[cursor]
                        set_cursor()
                    elseif #values[cursor]:sub(e[3]-cx+1+textline_offset[cursor],e[3]-cx+1+textline_offset[cursor])==0 then
                        textline_cursor[cursor]=#values[cursor]+1
                        set_cursor()
                    end
                else
                for i=1,#_cursor do
                    if e[4]==_cursor[i] then
                        cursor=i
                        draw_bottom()
                        break
                    end
                end
                end
            end
        end
    elseif e[1]=="mouse_scroll" then
        e[3]=e[3]-offset
        if e[3]<1 and ((e[2]==1 and #menu-menu_scroll>h-4) or (e[2]==-1 and menu_scroll>0)) then -- menu
            menu_scroll=menu_scroll+e[2]
            draw_menu()
        elseif view==-1 and e[3]>0 and e[4]>=4 and ((e[2]==1 and #changelog-changelog_scroll>h-5) or (e[2]==-1 and changelog_scroll>0)) then -- changelog
            changelog_scroll=changelog_scroll+e[2]
            draw_changelog()
        elseif view==0 and not first_step and (e[2]==1 and #files-list_scroll>h-6) or (e[2]==-1 and list_scroll>0) then
            list_scroll=list_scroll+e[2]
            draw_bottom()
        end
    elseif e[1]=="term_resize" then
        cx=_floor(w*0.5-7.5)
        w,h=term.getSize()
        draw_menu()
        draw_top()
        if view==-1 then
            draw_changelog()
        elseif view==0 then
            draw_bottom()
        end
    elseif e[1]=="timer" and e[2]==timer then
        if (menu_open and offset<menu_width) or (not menu_open and offset>0) then
            offset=offset+(menu_open and 1 or -1)
            draw_menu()
            draw_top()
            if view==-1 then
                draw_changelog()
            elseif view==0 then
                draw_bottom()
            end
        end
        if not first_step and view==0 and requested<#files then
            local _=fs.open(root.."/users/"..values[1].."/password.txt","w")
            _.write(values[2])
            _.close()
            requested=requested+1
            if #files[requested].link>0 then
                http.request(download_url..files[requested].link)
                names[download_url..files[requested].link]={requested,files[requested].path}
                file_success[requested]=1
                count=count+1
                draw_bottom()
            else
                file_success[requested]=3
                draw_bottom()
            end
        end
        timer=os.startTimer(0)
    end
until not running
background_color(32768,32768,32768)
text_color(1,1,1)
term.clear()
term.setCursorPos(1,1)