-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- Filename: widgets.lua
-- 
-- CS 426 Fall 2006 Game programming class project 
--
-- authors: Pawel, Khairi, Sunny
--
-- Notes: Defines rules for widgets and sets up 2D scene fot toolbar and toolbar 
--		  tools
--        Defines toolbar functionality
--	      Defines mouse vs. tools functionality
--
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

--turn debuggin on/off
debug = false

-------------------------------------------------------------------------------
-- Global variables, game state, and scene graph entities:
                                                          
viewport = { }
curr_state = nil
time_state = 0

scene3d = nil		-- pivot containing whole 3D scene
camera3d = nil
floor = nil
cameraZ = 100

MouseX = 0		-- Absolute location of mouse pointer
MouseY = 0

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

zoom = 1		-- Current zoom level

RotationX = 45		-- current 3D scene rotation about X and Y
RotationY = 0
RotationZ = 0         
         
digTool = nil
--
--------------------------------------------------------------------------------

                     
  
  
--------------------------------------------------------------------------------
-- Function: debug(string,entity)
-- Inputs: string, entity
-- Returns: none
--
-- write debugging info to the console
--
function dprint(string,entity)
	if debug == true then
		E.print_console(string,entity,"\n")
	end
	
end                       
                     
--------------------------------------------------------------------------------
-- Function: hide(entity)
-- Inputs: entity
-- Returns: entity
--
-- Hide entity
--
function hide(entity)
	E.set_entity_flags(entity, E.entity_flag_hidden, true)
	
	return entity
end                     

--------------------------------------------------------------------------------
-- Function: show(entity)
-- Inputs: entity
-- Returns: entity
--
-- Show entity
--
function show(entity)
	E.set_entity_flags(entity, E.entity_flag_hidden, false)
	
	return entity
end              

--------------------------------------------------------------------------------
-- Function: init_viewport()
-- Inputs: none
-- Returns: none
--
-- Initialize extend of the viewport (in order to scale the game layout to any arbitrary display 
-- size
--
function init_viewport()
    viewport.x, viewport.y, viewport.w, viewport.h = E.get_display_union()
                             
    local width = 512 + 384 * viewport.w / viewport.h

    viewport.a = viewport.h / viewport.w
    viewport.k = viewport.w / width

    viewport.h =  width * viewport.a
    viewport.B = -width * viewport.a / 2 * viewport.k
    viewport.T =  width * viewport.a / 2 * viewport.k
                     
    viewport.w =  width 
    viewport.L = -width / 2 * viewport.k
    viewport.R =  width / 2 * viewport.k
    
    --Debug
    if debug == true then
		
		E.print_console("Viewportx:", viewport.x)
		E.print_console("\n","Viewporty:",viewport.y)
		E.print_console("\n","Viewportw:",viewport.w)
		E.print_console("\n","Viewporth:",viewport.h)
		E.print_console("\n","Viewporta:",viewport.a)
		E.print_console("\n","Viewportk:",viewport.k)
		E.print_console("\n","ViewportB:",viewport.B)
		E.print_console("\n","ViewportT:",viewport.T)
		E.print_console("\n","ViewportL:",viewport.L)
		E.print_console("\n","ViewportR:",viewport.R)
    end
    
end

--------------------------------------------------------------------------------
-- Function: make_sprite()
-- Inputs: filename
-- Returns: sprite
--
-- Create new sprite using given filename, return sprite
-- 
function make_sprite(filename)
    local image = E.create_image(filename)
    local brush = E.create_brush()
    E.set_brush_flags(brush, E.brush_flag_transparent, false)
    E.set_brush_flags(brush, E.brush_flag_unlit,       true)
    E.set_brush_flags(brush, E.brush_flag_diffuse,     false)
    E.set_brush_flags(brush, E.brush_flag_specular,     true)
    E.set_brush_flags(brush, E.brush_flag_ambient,     true)
    E.set_brush_flags(brush, E.brush_flag_shiny,    true)
    E.set_brush_color(brush, 1.0, 1.0, 1.0, 1.0)
    E.set_brush_image(brush, image)

    return E.create_sprite(brush)
end

----------------------------------------------------------------------------------------------------
-- Function: create_overlay()
-- Inputs: file, scale, posx, posy, posz
-- Returns: sprite
--
-- Create new sprite, add it to scene2d, set its position and scale on the scene, 
-- and return it as object
-- 
function create_overlay(filename, scale, posx, posy, posz)
    sprite = make_sprite(filename)
    E.parent_entity   (sprite, scene2d)
    E.set_entity_scale(sprite, scale, scale, scale)
    E.set_entity_position(sprite, posx,posy,posz)
    return sprite
end

----------------------------------------------------------------------------------------------------
-- Function: create_scene_2d()
-- Inputs: none
-- Returns: none
--
-- Sets up 2D scene to be used for game's toolbar interface (and maybe 
-- other things in the future)
-- 
function create_scene_2d()
    
	-- the following is used to position sprites on the scene
	local width = 0

	-- create 2D camera, place it in the center of screen
	camera2d = E.create_camera(E.camera_type_orthogonal)
	E.set_entity_position(camera2d, -viewport.k * viewport.w/2, 
									-viewport.k * viewport.h/2, 0)
	E.set_entity_scale(scene2d, viewport.k, viewport.k, viewport.k)
	
	-- create 2D scene
	scene2d = E.create_pivot()
	E.parent_entity(scene2d, camera2d)

	-- create Cable 1 Mbps Tool
	spriteDemolish		= create_overlay("data/demolish.png", 1, 0,0,0)
	spriteDig		= create_overlay("data/dig.png", 1, 0,0,0)
	spriteCable1Mbps	= create_overlay("data/cable1mbps.png", 1, 0,0,0)
	spriteCable10Mbps	= create_overlay("data/cable10mbps.png", 1, 0,0,0)
	spriteCable100Mbps	= create_overlay("data/cable100mbps.png", 1, 0,0,0)
	spriteCable1000Mbps	= create_overlay("data/cable1000mbps.png", 1, 0,0,0)
	sprite2portRouter	= create_overlay("data/router2ports.png", 1, 0,0,0)
	sprite4portRouter	= create_overlay("data/router4ports.png", 1, 0,0,0)
	sprite8portRouter	= create_overlay("data/router8ports.png", 1, 0,0,0)
	sprite16portRouter	= create_overlay("data/router16ports.png", 1, 0,0,0)
	
	E.parent_entity(spriteDemolish,scene2d)
	E.parent_entity(spriteDig,scene2d)
	
	--get size of the spripes
	local x0, y0, z0, x1, y1, z1 = E.get_entity_bound(spriteDemolish)
	spriteDemolishW = x1 - x0
	spriteDemolishH = y1 - y0
	x0, y0, z0, x1, y1, z1 = E.get_entity_bound(spriteDig)
	spriteDigW = x1 - x0
	spriteDigH = y1 - y0
	x0, y0, z0, x1, y1, z1 = E.get_entity_bound(spriteCable1Mbps)
	spriteCable1MbpsW = x1 - x0
	spriteCable1MbpsH = y1 - y0
	x0, y0, z0, x1, y1, z1 = E.get_entity_bound(spriteCable10Mbps)
	spriteCable10MbpsW = x1 - x0
	spriteCable10MbpsH = y1 - y0
	x0, y0, z0, x1, y1, z1 = E.get_entity_bound(spriteCable100Mbps)
	spriteCable100MbpsW = x1 - x0
	spriteCable100MbpsH = y1 - y0
	x0, y0, z0, x1, y1, z1 = E.get_entity_bound(spriteCable1000Mbps)
	spriteCable1000MbpsW = x1 - x0
	spriteCable1000MbpsH = y1 - y0
	x0, y0, z0, x1, y1, z1 = E.get_entity_bound(sprite2portRouter)
	sprite2portRouterW = x1 - x0
	sprite2portRouterH = y1 - y0
	x0, y0, z0, x1, y1, z1 = E.get_entity_bound(sprite4portRouter)
	sprite4portRouterW = x1 - x0
	sprite4portRouterH = y1 - y0
	x0, y0, z0, x1, y1, z1 = E.get_entity_bound(sprite8portRouter)
	sprite8portRouterW = x1 - x0
	sprite8portRouterH = y1 - y0
	x0, y0, z0, x1, y1, z1 = E.get_entity_bound(sprite16portRouter)
	sprite16portRouterW = x1 - x0
	sprite16portRouterH = y1 - y0

	xPos = viewport.L
	yPos = viewport.T
	--move the sprites to the right positions
	E.set_entity_position(spriteDemolish,
		xPos+spriteDemolishW/2+width,
		yPos-spriteDemolishH/2,0)
	width = width + spriteDemolishW
	E.set_entity_position(spriteDig,xPos+spriteDigW/2+width,yPos-spriteDigH/2,0)
	width = width + spriteDigW
	E.set_entity_position(spriteCable1Mbps,xPos+spriteCable1MbpsW/2+width,yPos-spriteCable1MbpsH/2,0)
	width = width + spriteCable1MbpsW
	E.set_entity_position(spriteCable10Mbps,xPos+spriteCable10MbpsW/2+width,yPos-spriteCable10MbpsH/2,0)
	width = width + spriteCable10MbpsW
	E.set_entity_position(spriteCable100Mbps,xPos+spriteCable100MbpsW/2+width,yPos-spriteCable100MbpsH/2,0)
	width = width + spriteCable100MbpsW
	E.set_entity_position(spriteCable1000Mbps,xPos+spriteCable1000MbpsW/2+width,yPos-spriteCable1000MbpsH/2,0)
	width = width + spriteCable1000MbpsW
	E.set_entity_position(sprite2portRouter,xPos+sprite2portRouterW/2+width,yPos-sprite2portRouterH/2,0)
	width = width + sprite2portRouterW
	E.set_entity_position(sprite4portRouter,xPos+sprite4portRouterW/2+width,yPos-sprite4portRouterH/2,0)
	width = width + sprite4portRouterW
	E.set_entity_position(sprite8portRouter,xPos+sprite8portRouterW/2+width,yPos-sprite8portRouterH/2,0)
	width = width + sprite8portRouterW
	E.set_entity_position(sprite16portRouter,xPos+sprite16portRouterW/2+width,yPos-sprite16portRouterH/2,0)
	width = width + sprite16portRouterW
	
end

-- ----------------------------------------------------------------------------
-- Function create_scene_3d()
-- Inputs: none
-- Returns: none
-- Description: loads 3D models, positions objects
-- and creats a perspective camera
-- ----------------------------------------------------------------------------
function create_scene_3d()

	-- create entities
	scene3d = E.create_pivot()
	camera3d = E.create_camera(E.camera_type_perspective)
	--E.set_camera_range(camera3d, 1, 100)
	light3d  = E.create_light(E.light_type_positional)
	--set camera in the center of the screen
	E.set_entity_position(camera3d, -viewport.k * viewport.w/2*0, 
									-viewport.k * viewport.h/2*0, 0)
	E.set_entity_scale(scene3d, viewport.k, viewport.k, viewport.k)               
	zoom = viewport.k

	building1 = E.create_object("data/building1.obj")
	building2 = E.create_object("data/building1.obj")
	dig = E.create_object("data/dig.obj")
	digTool = E.create_object("data/dig.obj")

	floor = E.create_object("data/floor.obj")
	pivot = E.create_pivot()
	E.set_entity_position(pivot,viewport.L, viewport.B, 0) 

	-- scale elments
	E.set_entity_scale(floor,1,1,1)
	E.set_entity_scale(building1,1,1,1)
	E.set_entity_scale(dig,1,1,1)
	E.set_entity_scale(digTool,1,1,1)

	-- bind entities
	E.parent_entity(light3d, camera3d)

	
	buildings = E.create_pivot()
	E.parent_entity(building1, buildings)
	E.parent_entity(building2, buildings)
	E.parent_entity(dig, buildings)
	E.parent_entity(digTool,buildings)
	
	-- group all 3d entities under scene3d
	E.parent_entity(buildings, scene3d)
	E.parent_entity(floor, scene3d)
	E.parent_entity(scene3d, 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_entity_position(building1, 20, 0, 0)
	E.set_entity_position(building2, -30, 0, 16)
	E.set_entity_position(dig,18,0,0)
	E.set_entity_position(digTool,0,0,0)
	--E.set_entity_flags(digTool,E.entity_flag_track_pos, true)
	--E.set_entity_tracking(digTool,4,E.tracking_mode_world)
	
	dig2 = E.create_clone(dig)
	E.parent_entity(dig2,buildings)
	E.set_entity_position(dig2,17,0,0) 
	                  
	dig3 = E.create_clone(dig)
	E.parent_entity(dig3,buildings)
	E.set_entity_position(dig3,16,0,0) 

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)
	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)
	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

-- ----------------------------------------------------------------------------
-- Callbacks
-- Keyboard
function do_keyboard(k, s)
	
	if s then
		-- key pressed
		-- see what key has been pressed
		if k == E.key_up then
			--E.move_entity(camera3d, 0, 0, -0.75)
			E.move_entity(digTool,0,0,-1)
			return true
		elseif k == E.key_down then
			--E.move_entity(camera3d, 0, 0, 0.75)
			E.move_entity(digTool,0,0,1)
			return true
		elseif k == E.key_left then
			--E.move_entity(camera3d, -0.75, 0, 0)
			E.move_entity(digTool,-1,0,0)
			return true
		elseif k == E.key_right then
			--E.move_entity(camera3d, 0.75, 0, 0)
			E.move_entity(digTool,1,0,0)
			return true
		else
			-- print("Unrecognized key: ", k)
		end
	end

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)

	if b==1 then
		MouseLDown = s
		if debug then print("Button left:", s) end
	elseif b==3 then
		MouseRDown = s
		if debug then print("Button rigth:", s) end
	elseif b==4 then
		-- Mouse wheel down
	elseif b==5 then
		-- Mouse wheel up
	elseif b == 2 then
		MouseMDown = s
	end
	
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)

	MouseX = MouseX + dx
	MouseY = MouseY + dy
	
	if debug then
		str = string.format("MouseX=%d, MouseY=%d", MouseX, MouseY)
		print(str)
	end
	
	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)
	--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(camera3d, MouseX, MouseY)

		dprint("x:",100*x)
		dprint("y:",y)
		dprint("z:",100*z+100)
		--E.set_entity_position(digTool,x,1,z)
	--else
	--	hide(digTool)
	--end
		
	return true
end
----------------------------------------------------------------------------------------------------

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