module main

import datatypes
import gg
import gx
import os
import time
import math
import rand

const win_width = 1340
const win_height = 640
const timer_period = 40 * time.millisecond // defaulted at 25 fps

const font_small = gx.TextCfg{
	color: gx.black
	size: 20
}
const font_large = gx.TextCfg{
	color: gx.black
	size: 40
}

struct App {
mut:
	gg         &gg.Context
	qt         datatypes.Quadtree
	players    []datatypes.AABB
	particles  []Particle
	retrieveds []datatypes.AABB
	nodes      []datatypes.Quadtree
	width      f64 = 1340
	height     f64 = 640
}

struct Particle {
mut:
	pmt   datatypes.AABB
	speed f64
	angle f64
}

fn (mut p Particle) update() {
	p.pmt.x += p.speed * math.cos(p.angle * math.pi / 180)
	p.pmt.y += p.speed * math.sin(p.angle * math.pi / 180)

	if p.pmt.x < 0 {
		p.pmt.x = 0
		p.speed = -p.speed
		p.angle = -p.angle
	}
	if p.pmt.x > 1340 {
		p.pmt.x = 1340
		p.speed = -p.speed
		p.angle = -p.angle
	}
	if p.pmt.y < 0 {
		p.pmt.y = 0
		p.speed = -p.speed
		p.angle = 180 - p.angle
	}
	if p.pmt.y > 640 {
		p.pmt.y = 640
		p.speed = -p.speed
		p.angle = 180 - p.angle
	}
}

fn (mut app App) start() {
	app.players << datatypes.AABB{1200 * rand.f64(), 500 * rand.f64(), 20, 20}
	app.insert_particles()
	for mut particle in app.particles {
		particle.speed = 10 * rand.f64()
		particle.angle = 200 * rand.f64()
	}
	app.nodes << app.qt.get_nodes()
}

fn (mut app App) update() {
	app.qt.clear()
	app.nodes = []
	for mut particle in app.particles {
		particle.update()
		app.qt.insert(particle.pmt)
	}
	app.find_particles()
	app.nodes << app.qt.get_nodes()
}

fn (mut app App) insert_particles() {
	mut grid := 10.0
	mut gridh := app.qt.perimeter.width / grid
	mut gridv := app.qt.perimeter.height / grid
	num_particles := 100
	for _ in 0 .. num_particles {
		mut x := rand_minmax(0, gridh) * grid
		mut y := rand_minmax(0, gridv) * grid
		mut random_particle := datatypes.AABB{
			x: x
			y: y
			width: rand_minmax(1, 4) * grid
			height: rand_minmax(1, 4) * grid
		}
		app.particles << Particle{random_particle, 0.0, 0.0}
	}
}

fn (mut app App) find_particles() {
	app.retrieveds = []
	app.retrieveds << app.qt.retrieve(app.players[0])
}

fn main() {
	mut app := &App{
		gg: unsafe { nil }
	}
	app.gg = gg.new_context(
		bg_color: gx.white
		width: win_width
		height: win_height
		use_ortho: true
		create_window: true
		window_title: 'Quadtree Demo'
		frame_fn: frame
		event_fn: on_event
		user_data: app
		font_path: os.resource_abs_path('../assets/fonts/RobotoMono-Regular.ttf')
	)
	app.qt = app.qt.create(0, 0, 1340, 640, 8, 4, 0)
	app.start()
	spawn app.run()
	app.gg.run()
}

fn (mut app App) on_mouse_move(mouse_x f32, mouse_y f32) {
	for mut player in app.players {
		player.x = (mouse_x / gg.window_size_real_pixels().width) * 1340
		player.y = (mouse_y / gg.window_size_real_pixels().height) * 640
	}
}

fn on_event(mut e gg.Event, mut app App) {
	match e.typ {
		.mouse_move { app.on_mouse_move(e.mouse_x, e.mouse_y) }
		else {}
	}
}

fn (mut app App) run() {
	for {
		app.update()
		time.sleep(timer_period)
	}
}

fn frame(app &App) {
	app.gg.begin()
	app.draw()
	app.gg.end()
}

fn (app &App) display() {
	for player in app.players {
		app.gg.draw_rect_filled(f32(player.x), f32(player.y), f32(player.width), f32(player.height),
			gx.black)
	}
	for particle in app.particles {
		app.gg.draw_rect_empty(f32(particle.pmt.x), f32(particle.pmt.y), f32(particle.pmt.width),
			f32(particle.pmt.height), gx.blue)
	}
	for node in app.nodes {
		app.gg.draw_rect_empty(f32(node.perimeter.x), f32(node.perimeter.y), f32(node.perimeter.width),
			f32(node.perimeter.height), gx.red)
	}
	for retrieved in app.retrieveds {
		app.gg.draw_rect_filled(f32(retrieved.x + 1), f32(retrieved.y + 1), f32(retrieved.width - 2),
			f32(retrieved.height - 2), gx.green)
	}
	app.gg.draw_text(1200, 25, 'Nodes: ${app.nodes.len}', font_small)
	app.gg.draw_text(1200, 50, 'Particles: ${app.particles.len}', font_small)
}

fn (app &App) draw() {
	app.display()
}

fn rand_minmax(min f64, max f64) f64 {
	mut val := min + (rand.f64() * (max - min))
	return val
}
