#include "sys_interaction.h"
#include "system.h"
#include "sys_vr.h"
#include "sys_vr_passthru.h"
#include "sys_render.h"
#include "sys_undo.h"
#include "sys_tilestore.h"

static uint32_t tracked_id = 0xfffffffful;
static unsigned toolidx = 0;
static yrQuad* selected = NULL;
static vec4i beamdest;
static vec4f v_off[3];
static yrQuad preview;
static int touchdown;
static yrTexture tex_fill = NULL;
static yrTexture tpadbut_copy = NULL;
static yrTexture tpadbut_cancel = NULL;
static yrTexture tpadbut_copy_glow = NULL;
static yrTexture tpadbut_cancel_glow = NULL;

#define DIST_MIN 0.0f
#define DIST_MAX 64.0f

static void copy_shutdown(void);
static void copy_settrackedid(uint32_t, unsigned);
static void copy_tick(void);
static int  copy_canfreeze(void);
static void copy_forceidle(void);
static int	copy_getpokepos(vec4f* pos, vec4f* dir, float* len) {return 0;}

int tool_copy_init(func_tool_shutdown* st_sd,
				   func_tool_settrackedid* ft_sti,
				   func_tool_tick* ft_t,
				   func_tool_canfreeze* ft_cf,
				   func_tool_forceidle* ft_fi,
				   func_tool_getpokepos* ft_gpp,
				   func_tool_renderwindow* ft_rw,
				   func_tool_poke* ft_p)
{
	*st_sd	= copy_shutdown;
	*ft_sti	= copy_settrackedid;
	*ft_t	= copy_tick;
	*ft_cf	= copy_canfreeze;
	*ft_fi	= copy_forceidle;
	*ft_gpp = copy_getpokepos;
	*ft_rw	= nullfunc;
	*ft_p	= nullfunc;

	tracked_id = 0xfffffffful;
	toolidx = 0;
	selected = NULL;
	touchdown = 0;
	tex_fill			= yrTexture_loadfile("data/vr/empty.png");					if(!tex_fill) return -1;
	tpadbut_copy		= yrTexture_loadfile("data/vr/tpadbut_copy.png");			if(!tpadbut_copy) return -1;
	tpadbut_cancel		= yrTexture_loadfile("data/vr/tpadbut_cancel.png");		if(!tpadbut_cancel) return -1;
	tpadbut_copy_glow	= yrTexture_loadfile("data/vr/tpadbut_copy_glow.png");		if(!tpadbut_copy_glow) return -1;
	tpadbut_cancel_glow	= yrTexture_loadfile("data/vr/tpadbut_cancel_glow.png");	if(!tpadbut_cancel_glow) return -1;
	return 0;
}

static void copy_shutdown(void)
{
	yrTexture_unload(tex_fill);
	yrTexture_unload(tpadbut_copy);
	yrTexture_unload(tpadbut_cancel);
	yrTexture_unload(tpadbut_copy_glow);
	yrTexture_unload(tpadbut_cancel_glow);
	tex_fill = NULL;
	tpadbut_copy = NULL;
	tpadbut_cancel = NULL;
	tpadbut_copy_glow = NULL;
	tpadbut_cancel_glow = NULL;
}

static void copy_settrackedid(uint32_t tr_id, unsigned tool_idx)
{
	tracked_id = tr_id;
	toolidx = tool_idx;
}

static void copy_select(yrQuad* q, mat4f mat, vec4i off)
{
	yrQuadStore_editlock(q); //select quad
	yrTileStore_important(q->ext->tile_max_idx, (TileID*) q->ext->tiles);

	selected = q;
	beamdest = vec4i_add(q->v[1], q->v[2]);
	beamdest.m = _mm_srai_epi32(beamdest.m, 1); //divide by 2
	preview = *q;

	yrRenderOverlay_clear(OVERLAY_EDIT);
	yrRenderOverlay_draw(OVERLAY_EDIT, tex_fill, 0.0f, 0.0f, 8.0f, 8.0f, 0x80808080);
	
	vec4f oooi = {0.0f,0.0f,0.0f,1.0f};
	mat4f invmat = {mat.col[0],mat.col[1],mat.col[2],oooi};
	invmat = mat4f_invert(invmat);
	for(size_t i = 0; i < 3; ++i) {
		v_off[i] = vec4f_mul(1.0f/YR_ACCURACY, vec4f_from_vec4i(vec4i_sub(q->v[i], off)));
		v_off[i] = vec4f_sub(v_off[i], mat.col[3]);
		v_off[i].w = 1.0f;
		v_off[i] = mat4f_apply(invmat, v_off[i]);
	}
}

static void copy_copy(mat4f mat, vec4i off)
{
	YR_ASSERT(selected);
	yrQuad* newquad = yrQuadStore_add(&preview);
	if(!newquad) return;

	for(size_t t = 0; t < selected->ext->tile_max_idx; ++t)
	{
		GLuint devnull;
		if(selected->ext->tiles[t] == 0xFFFFFFFFul) continue;
		TileID tid = {selected->ext->tiles[t]};
		TileID ntid = yrTileStore_copy(tid, &devnull, &devnull);
		newquad->ext->tiles[t] = ntid.t;
		if(ntid.t != 0xFFFFFFFFul) yrTileStore_finishtile(ntid);
	}
	yrUndo_append(utAdd, NULL, newquad, NULL, newquad->ext->tiles);
}

static void copy_tick(void)
{
	VRControllerState_t cbuttons = {0};
	ovrSystem_GetControllerState(tracked_id, &cbuttons);
	mat4f mat = yrVR_world_from_tracked(tracked_id);
	vec4i off = yrVR_get_coord_offset();

	float touchx = cbuttons.rAxis[EVRButtonId_k_EButton_SteamVR_Touchpad - EVRButtonId_k_EButton_Axis0].x;
	float touchy = cbuttons.rAxis[EVRButtonId_k_EButton_SteamVR_Touchpad - EVRButtonId_k_EButton_Axis0].y;
	int touchd = 0!=(cbuttons.ulButtonPressed & (1ull << EVRButtonId_k_EButton_SteamVR_Touchpad));
	int toucht = (touchx != 0.0f && touchy != 0.0f);

	//draw buttons
	yrRenderTrackedOverlay_clear(toolidx);
	if(!selected) {
		if(touchd || touchx != 0.0f || touchy != 0.0f) {
			yrRenderTrackedOverlay_draw(toolidx, tpadbut_copy_glow, -0.5f, -0.5f, 0.5f, 0.5f, touchd ? 0xFFFF8010 : 0x80FF8010);
		}
		yrRenderTrackedOverlay_draw(toolidx, tpadbut_copy, -0.5f, -0.5f, 0.5f, 0.5f, 0xFFFFFFFF);
	} else {
		if(touchd || touchx != 0.0f || touchy != 0.0f) {
			float glowoff = (touchx < 0.0) ? -1.0f : 0.0f;
			yrTexture glowtex = (touchx < 0.0) ? tpadbut_copy_glow : tpadbut_cancel_glow;
			yrRenderTrackedOverlay_draw(toolidx, glowtex, glowoff, -0.5f, glowoff + 1.0f, 0.5f, touchd ? 0xFFFF8010 : 0x80FF8010);
		}
		yrRenderTrackedOverlay_draw(toolidx, tpadbut_copy, -1.0f, -0.5f, 0.0f, 0.5f, 0xFFFFFFFF);
		yrRenderTrackedOverlay_draw(toolidx, tpadbut_cancel, 0.0f, -0.5f, 1.0f, 0.5f, 0xFFFFFFFF);
	}
	yrRenderTrackedOverlay_render(toolidx);

	if(selected) {
		//draw beam
		vec4i o = vec4i_add(off, vec4i_from_vec4f(vec4f_mul(YR_ACCURACY, mat.col[3])));
		vec4f dir = vec4f_from_vec4i(vec4i_sub(beamdest, o));
		float dist = vec3f_length(dir);
		dir = vec4f_mul(1.0f/dist, dir);
		yrRender_beam(toolidx, mat.col[3], dir, selected->normal, dist / YR_ACCURACY, 0xFFFFFF80);
		//draw preview quad
		preview.v[0] = vec4i_add(off, vec4i_from_vec4f(vec4f_mul(YR_ACCURACY, mat4f_apply(mat, v_off[0]))));
		preview.v[1] = vec4i_add(off, vec4i_from_vec4f(vec4f_mul(YR_ACCURACY, mat4f_apply(mat, v_off[1]))));
		preview.v[2] = vec4i_add(off, vec4i_from_vec4f(vec4f_mul(YR_ACCURACY, mat4f_apply(mat, v_off[2]))));
		yrRenderOverlay_render(OVERLAY_EDIT, &preview, 0);
		//handle press
		if(!touchdown && touchd) {
			if(touchx > 0.0f) {
				yrQuadStore_editlock(NULL);
				selected = NULL; //cancel
			} else {
				copy_copy(mat, off); //make a copy
			}
		}
	} else {
		if(!yrQuadStore_editlocked() && toucht) {
			vec4i o = vec4i_add(off, vec4i_from_vec4f(vec4f_mul(YR_ACCURACY, mat.col[3])));
			tracehit h = yrInteraction_trace(o, vec4f_neg(mat.col[2]), DIST_MIN, DIST_MAX);
			vec4f n = h.q ? h.q->normal : mat.col[2];
			yrRender_beam(toolidx, mat.col[3], vec4f_neg(mat.col[2]), n, h.dist, 0xFF808040);
			if(!touchdown && touchd && h.q) {
				copy_select(h.q, mat, off);
			}
		}
	}
	touchdown = touchd;
}

static int copy_canfreeze(void)
{
	return selected == NULL;
}

static void	copy_forceidle(void)
{
	if(selected) {
		yrQuadStore_editlock(NULL);
		selected = NULL;
	}
}
