--------------------------------------------------------------------------------
-- SimNetwork
-- 3D Models test scene
-- visualizer.lua
-- -----------------------------------------------------------------------------

if not SimNetwork_GLOBAL	then dofile("global.lua") end

scene3d = nil
camera3d = nil
light3d = nil
--------------------------------------------------------------------------------
-- input.lua
-- Global variables
-- ----------------
MouseX = 0		-- Absolute location of mouse pointer in coordinates of
MouseY = 0		-- Electro's window (and 2D scene)

SceneX = 0		-- Absolute location of mouse pointer in coordinates
SceneY = 0		-- of 3D scene

MouseLDown = false	-- Status of mouse buttons (false for up, true for down)
MouseRDown = false
MouseMDown = false

RotationX = 0		-- Current 3D scene rotation about X, Y, and Z
RotationY = 0
RotationZ = 0

counter=0          -- counter for animation
zoom = 1		-- Current zoom level
ZOOM_STEP = 3

scroll = {
	zoomIn = false,
	zoomOut = false,
	left = false,
	right = false,
	north = false,
	source = false,
}

--turn debuggin on/off
debug = false

-- Models: table of currently loaded models
Models = {}

function hide(entity) 
	--print("in hide()")
	E.set_entity_flags(entity,E.entity_flag_hidden,true)
end

function show(entity)
	--print("in show()")
	E.set_entity_flags(entity,E.entity_flag_hidden,false)
end

-- this functions loads the OBJ file specified by path and positions
-- it in x and z on the floor
function load(path, x, y, z)
	--print("in load()")
	e = E.create_object(path)
	if x ~= nil and y ~= nil and z ~= nil then
		E.set_entity_position(e, x, y, z)
	end
	
	table.insert(Models, e)
	E.parent_entity(e, scene3d)
end

-- Animate Router
function animateRouter(x, y, z)
	--print("in animateRouter()")
	e1 = E.create_object("data/routers/router_6/r1.obj")
      e2 = E.create_object("data/routers/router_6/r2.obj") 
	if x ~= nil and y ~= nilm and z ~= nil then
		E.set_entity_position(e1, x, y, z)
            E.set_entity_position(e2, x, y, z)
            hide(e2) 
	end

	counter=1

	table.insert(Models, e1)
      table.insert(Models, e2)
	
      E.parent_entity(e1, scene3d)
      E.parent_entity(e2,scene3d)
    
      end

-- Do Timer calls this fn to animate Router
  
-- e1 and e2 need to accessed from Models, this part of the code needs to be added
function ranimate()
	--print("in ranimate()")
  if counter==0
    then
         hide(e1)
		 show(e2)
         counter=1
  else
         hide(e2)
		 show(e1)
         counter=0
  end
 return
end

-- clears all loaded models
function clear()
	--print("in clear()")
	for key, model in Models do
		E.delete_entity(model)
	end
	
	Models = {}
end

-- -----------------------------------------------------------------------------
-- Function create_scene_3d()
-- Inputs: none
-- Returns: none
-- Description: loads 3D models, positions objects
-- and creats a perspective camera
-- -----------------------------------------------------------------------------
function create_scene_3d()
	--print("in create_scene_3d()")
	-- create entities
	scene3d = E.create_pivot()
	camera3d = E.create_camera(E.camera_type_perspective)
	
	light3d  = E.create_light(E.light_type_positional)
	E.set_entity_scale(scene3d, viewport.k, viewport.k, viewport.k)               
	zoom = viewport.k

	floor = E.create_object("data/floor.obj")
	
	-- Create SKY 
	sky = E.create_object("data/sky.obj")
	envmap = E.create_image("data/sky_nx.png",
                            "data/sky_px.png",
                            "data/sky_ny.png",
                            "data/sky_py.png",
                            "data/sky_nz.png",
                            "data/sky_pz.png")


	-- scale elments
	E.set_entity_scale(floor,1,1,1)
	E.set_entity_scale(sky, 200, 200, 200) 

	-- bind entities
	E.parent_entity(light3d, camera3d)
  	E.parent_entity(floor, scene3d)
	E.parent_entity(scene3d, light3d)
	E.parent_entity(sky, light3d)

	-- position elements               
	E.set_entity_position(camera3d, 0, 20, 100)
	E.set_entity_position(light3d, 0, 30, 30)
	E.set_entity_rotation(scene3d, RotationX, RotationY, 0)
	
	E.set_brush_image(E.get_mesh(sky, 0), envmap)
	E.set_brush_flags(E.get_mesh(sky, 0), E.brush_flag_unlit,     true)
	E.set_brush_flags(E.get_mesh(sky, 0), E.brush_flag_sky_map_0, true)
end

-- -----------------------------------------------------------------------------
-- Callbacks
-- Keyboard
function do_keyboard(k, s)
	--print("in do_keyboard()")
	if k == E.key_up then
		scroll.north = s
	elseif k == E.key_down then
		scroll.south = s
	elseif k == E.key_left then
		scroll.left = s
	elseif k == E.key_right then
		scroll.right = s
	elseif k == E.key_w then
		scroll.zoomIn = s
	elseif k == E.key_z then
		scroll.zoomOut = s
	end

end

function do_timer(dt)
	--print("in do_timer()")
    
	ranimate()

	--E.print_console("\n","MouseY:",MouseY)
	posX = MouseX;
	poxZ = MouseY;
	
	--this will enable collision detection
	posY = 0 
	
	local x0, y0, z0, x1, y1, z1 = E.get_entity_bound(floor)
	
	--if MouseX > x0 and MouseX < x1 and MouseY > z0 and MouseY < z1 then
	--	show(digTool)
		x, y, z = E.get_camera_vector(camera2d, MouseX, MouseY)

		--dprint("x:",x)
		--dprint("y:",y)
		--dprint("z:",z)
		--E.set_entity_position(digTool,x,1,z)
	--else
	--	hide(digTool)
	--end

	--store bounds of each of the sprites on the toolbar
		sDx0, sDy0, sDz0, sDx1, sDy1, sDz1 = E.get_entity_bound(spriteDemolish)
		
		-- get mouse position and check it against toolbar
		x2d, y2d, z2d = E.get_camera_vector(camera2d, MouseX, MouseY)

		--[[if x2d > sDx0*2 and x2d < sDx1*2 and y2d > sDy0*2 and y2d < sDy1*2 then
			
			if E.get_entity_flags(spriteDemolish,E.entity_flag_hidden) then
				hide(spriteDemolish)
				show(spriteDemolishHover)
			end
		else
			if E.get_entity_flags(spriteDemolish,E.entity_flag_hidden) then
				hide(spriteDemolishHover)
				show(spriteDemolish)
			end
		end]]
		
	return true
end

-- -----------------------------------------------------------------------------
-- Function: handle_3d_rotation
-- Inputs:	dx, dy (integer): relative pointer movement
-- Returns:	boolean: indicates whether screen needs refresh
-- Description: rotates 3D scene about X and Y, also restricts rotation
-- to (-360, 360) about Y, [0, 90] about X
-- -----------------------------------------------------------------------------
function handle_3d_rotation(dx, dy)
	--print("in handle_3d_rotation()")
	local refresh = false
	if dx ~= 0 then
		-- Rotate 3D scene about Y axis 
		RotationY = RotationY + dx
		
		if RotationY > 360 or RotationY < -360 then
			-- keep angle in (-360, 360)
			local discard = math.floor(RotationY/360)*360
			RotationY = RotationY - discard
		end
		
		refresh = true
		if debug then print("Turn about Y:", dx) end
	end
	
	if dy ~= 0 then
		-- Rotate 3D scene about X axis
		RotationX = RotationX + dy
		if RotationX > 89 then 
			RotationX = 89
		elseif RotationX < 10 then 
			RotationX = 10 
		end
		
		refresh = true
		if debug then print("Turn about X:", dy) end
	end
	
	if refresh then
		E.set_entity_rotation(scene3d, RotationX, RotationY, 0)
		if debug then print("Rotation: ", RotationX, RotationY, 0) end		
	end
	return refresh
end

-- -----------------------------------------------------------------------------
-- Function: handle_3d_zoom
-- Inputs:	dy (integer): relative pointer movement
-- Returns:	boolean: indicates whether screen needs refresh
-- Description: Zooms in/out
-- -----------------------------------------------------------------------------
function handle_3d_zoom(dy)
	--print("in handle_3d_zoom()")
	if dy ~= 0 then
		zoom = zoom + dy / 500
		if zoom > 0.125 then
			E.set_entity_scale(scene3d, zoom, zoom, zoom)
			return true
		end
	end
	return false
end

-- -----------------------------------------------------------------------------
-- Function: do_click() (callback)
-- Inputs:	b: button clicked
--		s: status; true for pressed, false for released
-- Description: called by Electro whenever a mouse button is clicked
-- -----------------------------------------------------------------------------

function do_click(b, s)
	--print("in do_click()")
	if b==1 then
		MouseLDown = s
	elseif b==3 then
		MouseRDown = s
	elseif b==4 then
		-- Mouse wheel down
	elseif b==5 then
		-- Mouse wheel up
	elseif b == 2 then
		MouseMDown = s
	end
	
	return false
	
end

-- -----------------------------------------------------------------------------
-- Function: do_point() (callback)
-- Inputs:	dx, dy: pointer movement, relative to last position
-- Description: Check whether Right/Middle button are down and perform
-- 3D rotation/zoom repspectively
-- -----------------------------------------------------------------------------
function do_point(dx, dy)
	--print("in do_point()")
	MouseX = MouseX + dx
	MouseY = MouseY + dy
	
	-- convert mouse coordinates into scene coordinates
	SceneX = 2 * viewport.k * MouseX - 1024
	SceneY = 2 * viewport.a * MouseY - 768
		
	local refresh = false
	
	if MouseLDown then
	
	end

	-- 3D rotation
	if MouseRDown then
		refresh = handle_3d_rotation(dx, dy)
	end	
	
	-- zoom in/out
	if MouseMDown then
		refresh = refresh or handle_3d_zoom(dy)
	end	

	return refresh
end

function do_timer(dt)
	--print("in do_timer()")
	if scroll.north then
		E.move_entity(camera3d, 0, 0, -2)
	elseif scroll.south then
		E.move_entity(camera3d, 0, 0, 2)
	elseif scroll.left then
		E.move_entity(camera3d, -2, 0, 0)
	elseif scroll.right then
		E.move_entity(camera3d, 2, 0, 0)
	elseif scroll.zoomIn then
		handle_3d_zoom(ZOOM_STEP)
	elseif scroll.zoomOut then
		handle_3d_zoom(-1 * ZOOM_STEP)
	end
end

init_viewport()
create_scene_3d()
E.enable_timer(true)
