import "kapps/conutil.ort"
import "mbdata.ort"
import "kapps/raycaster/raycaster.ort"
import "kapps/drawbmp.ort"
import "kapps/snake/rng.ort"
import "kapps/snake/snake.ort"

type KConsoleCommandRunner is a function->void
type KConsoleCommand is
cstr name
cstr desc
KConsoleCommandRunner command
KConsoleCommand _next

function(cstr name, cstr desc, KConsoleCommandRunner command) KConsoleCommand::new -> KConsoleCommand does
KConsoleCommand new = malloc(@sizeof(KConsoleCommand)@)|KConsoleCommand
new.name=name
new.desc=desc
new.command=command
new._next=0|ptr|KConsoleCommand
return new

function(KConsoleCommand c, cstr args) KConsoleCommand:run -> void does
c.command(args)
return
endtype

function() console_disp_line -> void does
kterm:print("\nk>")
return

function(int scancode, bool down) consolehandler -> void does
console_buf:handleevent(scancode, down)
return

function(cstr command) console_submit -> void does
cstr name
cstr args
if command:index(char(" "))==-1 do
name=command
args=""
else do
int idx=command:index(char(" "))
name=malloc(idx+1)
memcpy(command|ptr, name|ptr, idx)
name[idx]=0|byte
args=(command|ptr):offset(idx+1)|cstr
done
KConsoleCommand cmd = get_command(kcommand_head, name)
if cmd|ptr|int!=0 do
command_to_run=cmd
command_args=args
else do
kterm:print("Invalid Command")
console_disp_line()
done

return

function(KConsoleCommand head, cstr name) get_command -> KConsoleCommand does
KConsoleCommand cur = head
while cur|ptr|int!=0 do
if cur.name==name do
return cur
done
cur=cur._next
done
return 0|ptr|KConsoleCommand

function(cstr args) kc_help -> void does
kterm:printl("Commands: ")
KConsoleCommand cur = kcommand_head
while cur|ptr|int!=0 do
kterm:print(" - ")
kterm:print(cur.name)
kterm:print(": ")
kterm:print(cur.desc)
kterm:print("\n")
cur=cur._next
done
return

function(cstr args) kc_dumpargs -> void does
kterm:print("Args: ")
kterm:printl(args)
return

function(cstr args) kc_mem -> void does
kterm:print("mm_head: ")
kterm:dumphexi(mm_head|int)
kterm:print(" mm_pos: ")
kterm:dumphexi(mm_pos|int)
kterm:print("\nUsed: ")
kterm:printi((mm_pos|int)-(mm_head|int))
kterm:print("\n")
return

function(cstr args) kc_dump_multiboot -> void does
(multiboot_data_physaddr:offset(base_vma)|RawMultibootInfo):print()
return

function(cstr args) kc_dump_parseed_multiboot -> void does
if mbinfo.valid do
kterm:print("cmdline=")
kterm:printl(mbinfo.cmdline)
kterm:print("bootloader=")
kterm:printl(mbinfo.bootloader)
kterm:print("boot_device=")
kterm:dumphex(mbinfo.boot_device, 2)
kterm:print("\nmodule count=")
kterm:printi(mbinfo.module_count)
kterm:printl("")
if mbinfo.text_mode do
kterm:printl("Text Mode")
else do
kterm:printl("Video Mode")
done
kterm:print("addr=")
kterm:dumphexi(mbinfo.fb_raw_addr)
kterm:print("\n w=")
kterm:printi(mbinfo.screen_w)
kterm:print("\n h=")
kterm:printi(mbinfo.screen_h)
kterm:print("\n d=")
kterm:printi(mbinfo.screen_depth)
kterm:print("\n p=")
kterm:printi(mbinfo.screen_pitch)
kterm:printl("")
else do
kterm:printl("mbinfo reports invalid")
done
return

function(cstr args) kc_fault -> void does
if args=="dbz" do
int a = 1/0
elif args=="pw" do
(0xDEADBEEF|ptr)[0]=0|byte
elif args=="pr" do
byte a = (0xDEADBEEF|ptr)[0]
else do
kterm:printl("Pass dbz, pw or pr")
done
return

function(cstr args) kc_echo -> void does
kterm:printl(args)
return

function(cstr args) kc_addhex -> void does
kterm:dumphex(hex_char_to_num(args:idxi(0))+hex_char_to_num(args:idxi(2)), 2)
return

function(cstr args) kc_clear -> void does
if mbinfo.text_mode==0|bool do
console_emulator:clear()
done
kterm:blank()
kterm.cursor_x=0
kterm.cursor_y=-1

return

function(cstr args) kc_hexnum -> void does
kterm:print("Read: ")
kterm:printi(hex_char_to_num(args:idxi(0)))
return

@declare_func("__kwritepw", "void", "(i32, i32)")@
function(cstr args) kc_shutdown -> void does
kterm:print("Shutting Down...")
__kwritepw(0xB004, 0x2000)
return

function(cstr args) kc_getpicticks -> void does
kterm:print("Ticks: ")
kterm:printlong(pic_ticks)
kterm:print("\nSeconds ~:")
kterm:printlong(pic_ticks/18|long)
kterm:print("\n")
return

function(cstr args) kc_picsleep -> void does
if args:len()!=1 do
kterm:printl("Pass 1 hex digit for seconds to sleep")
return
done
long initial=pic_ticks
int t=hex_char_to_num(args:idxi(0))
kc_getpicticks("")
while (pic_ticks-initial)<((19*t)|long) do
0
done
kc_getpicticks("")
return

function(cstr args) kc_color -> void does
if args:len()==2 do
kterm.attributes=((hex_char_to_num(args:idxi(0))*16)+hex_char_to_num(args:idxi(1)))|byte
kterm:print("Set\n")
else do
kterm.attributes=0x0F|byte
done
return

function(cstr args) kc_colorama -> void does
int y=0
int x
while y<16 do
x=0
while x<16 do
kterm:printa((y<<4)+x, "X")
x+=1
done
kterm:print("\n")
y+=1
done
return

function(cstr args) kc_snowcrash_code -> void does
int idx
while 1==1 do
idx=0
while idx<0x300000 do
memcpy((base_vma+idx)|ptr, mbinfo.fb_addr, mbinfo.screen_h*mbinfo.screen_pitch)
idx+=20
done
done
return

import framebuffer

function(cstr args) kc_drawstuff -> void does
Framebuffer f = Framebuffer::from_mbinfo(mbinfo)
f:fill(64,64,64)
f:setpx(10,10,255,0,0)
f:fillrect(20, 40, 35, 25, 0, 255, 128)
f:fillrect(25, 45, 35, 25, 255, 255, 128)
f:drawchar(40, 20, 8, "A":ord(), 0, 0, 255)

int i=50
while i<200 do
f:setpx(i,i,50+i,0,0)
f:setpx(200-i,i,0,50+i,0)
i+=1
done
return

function(cstr args) kc_drawcolors -> void does
Framebuffer f = Framebuffer::from_mbinfo(mbinfo)
int r=0
int g
int b
long ticks
while r<=256 do
g=0
while g<=256 do
b=0
while b<=256 do
f:fill(r,g,b)
ticks=pic_ticks
while pic_ticks==ticks do
0
done
b+=64
done
g+=64
done
r+=64
done
return

function(cstr args) kc_chararama -> void does
int high=0
int low
kterm:printl(" 0123456789ABCDEF (Low Byte)")
kterm:printl("")
while high<16 do
if high<10 do
kterm:putchar((48+high)|byte)
else do
kterm:putchar((65+high-10)|byte)
done
kterm:print(" ")
low=0
while low<16 do
kterm:putchar(((16*high)+low)|byte)
low+=1
done
kterm:printl("")
high+=1
done
return

function(cstr args) kc_fail -> void does
orth::fail(args)
return

function(cstr args) kc_prof -> void does
if args:len()==0 do
kterm:print("Pass `on` to turn on, `off` to turn off, and `show` to show stats\n")
done

if args=="on" do
orth::internal::profile::install_profiler()
elif args=="off" do
orth::internal::profile::disable_profiler()
elif args=="show" do
orth::internal::profile::display_profiling_data()
done
return

function(cstr name, cstr desc, KConsoleCommandRunner cmd) add_cmd -> void does
KConsoleCommand cur = kcommand_head
while cur._next|ptr|int!=0 do
cur=cur._next
done
cur._next=KConsoleCommand::new(name, desc, cmd)
return

KeyboardBuf console_buf
KConsoleCommand command_to_run
cstr command_args
KConsoleCommand kcommand_head
function() kconsole_run -> void does
kcommand_head=KConsoleCommand::new("help", "Display Help", kc_help|KConsoleCommandRunner)
add_cmd("dumpargs", "Show the passed arguments", kc_dumpargs|KConsoleCommandRunner)
add_cmd("mem", "Show memory statistics", kc_mem|KConsoleCommandRunner)
add_cmd("fault", "Cause a fault. Types are dbz, pw, pr", kc_fault|KConsoleCommandRunner)
add_cmd("echo", "Repeat args", kc_echo|KConsoleCommandRunner)
add_cmd("add2h", "Add two (hex) digits", kc_addhex|KConsoleCommandRunner)
add_cmd("clear", "Clear Screen", kc_clear|KConsoleCommandRunner)
add_cmd("hexnum", "Parse a hex digit", kc_hexnum|KConsoleCommandRunner)
add_cmd("dmpmbd", "View Multiboot info structure", kc_dump_multiboot|KConsoleCommandRunner)
add_cmd("dmppmbd", "View Parsed Multiboot info structure", kc_dump_parseed_multiboot|KConsoleCommandRunner)
add_cmd("pict", "View PIC interrupt count", kc_getpicticks|KConsoleCommandRunner)
add_cmd("pics", "Sleep for n secs. Pass 1 hex digit", kc_picsleep|KConsoleCommandRunner)
add_cmd("shutdown", "Try to shut down", kc_shutdown|KConsoleCommandRunner)
add_cmd("color", "Set terminal color mode. Pass 2 hex digits, or no args to reset", kc_color|KConsoleCommandRunner)
add_cmd("colorama", "Demo availible colors", kc_colorama|KConsoleCommandRunner)
add_cmd("chararama", "Demo availible chars", kc_chararama|KConsoleCommandRunner)
add_cmd("snowcrash", "Dump kernel code into vram. *no getting out*", kc_snowcrash_code|KConsoleCommandRunner)
add_cmd("draw", "Draw some stuff", kc_drawstuff|KConsoleCommandRunner)
add_cmd("drawcolors", "Draw some colors", kc_drawcolors|KConsoleCommandRunner)
add_cmd("rcmtest", "Test some trig", rc_mtest|KConsoleCommandRunner)
add_cmd("rc", "Raycaster", rc_run|KConsoleCommandRunner)
add_cmd("drawbmp", "Draw a BMP that was loaded as a kernel module", kc_draw_bmp|KConsoleCommandRunner)
add_cmd("rng", "Emit some (bad) random numbers", s_rngtest|KConsoleCommandRunner)
add_cmd("snake", "Play Snake!", snake_run|KConsoleCommandRunner)
add_cmd("fail", "Call orth::fail with args as message", kc_fail|KConsoleCommandRunner)
add_cmd("prof", "Control profiling", kc_prof|KConsoleCommandRunner)

console_buf=KeyboardBuf::new(1024, kterm, console_submit|SubmitCallback)
command_to_run=0|ptr|KConsoleCommand
system_kbdstate:set_handler(consolehandler|KeyboardConsumerCallback)
console_disp_line()
while 1|bool do
if command_to_run|ptr|int!=0 do
command_to_run:run(command_args)
system_kbdstate:set_handler(consolehandler|KeyboardConsumerCallback)
console_disp_line()
command_to_run=0|ptr|KConsoleCommand
done
done
return