-- -----------------------------------------------------------------------------
-- scene.lua
-- SimNetwork
-- 3D scene
-- -----------------------------------------------------------------------------

SimNetwork_SCENE = true
if not SimNetwork_GLOBAL	then dofile("global.lua") 		end
if not SimNetwork_DATA		then dofile("data.lua") 		end
if not SimNetwork_TOOLBAR	then dofile("toolbar.lua") 		end
if not SimNetwork_ANIMATE	then dofile("animate.lua")		end
debugModels = {}

ANIM_FRAME_RATE = 1/60		-- 60 animation frames per second
collisions = {}			-- registered collisions

MODEL = {
	
}

OBJECTS = {	-- Contains all 3D Models and defines their offset and bounds
	floor = {
		e = nil,
		bounds = {200, 1, 200},
		offset = {0, 0, 0},
		model = "data/floor.obj"
	},
	
	router4 = {
		e = nil,
		bounds = {3*2, 1*2, 2*2},
		offset = {0, 1, 0},
		model = "data/routers/router_4.obj",
		eNotFit = "data/routers/router_4_notfit.obj"
	},
	
	router6 = {
		e = nil,
		bounds = {3*2, 1*2, 2*2},
		offset = {0, 1, 0},
		model = "data/routers/router6/r1.obj",
		eNotFit = "data/routers/router_4_notfit.obj"
	},
	
	router8 = {
		e = nil,
		bounds = {3*2, 1*2, 2*2},
		offset = {0, 1, 0},
		model = "data/routers/router8/r2.obj",
		eNotFit = "data/routers/router_4_notfit.obj"
	},
	
	cable0 = {
		e = nil,
		bounds = {0.4, 0.4, 1},
		offset = {0, 0.1, 0},
		model = "data/cables/cable0.obj",
	},

	cable1 = {
		e = nil,
		bounds = {0.4, 0.4, 1},
		offset = {0, 0.1, 0},
		model = "data/cables/cable1.obj"
	},
	
	cable10 = {
		e = nil,
		bounds = {0.2*4, 0.2*4, 1},
		offset = {0, 0.2, 0},
		model = "data/cables/cable10.obj"
	},
	
	cable100 = {
		e = nil,
		bounds = {0.3*4, 0.3*4, 1},
		offset = {0, 0.3, 0},
		model = "data/cables/cable100.obj"
	},
	
	offices = {
		e = nil,
		bounds = {1.6*2, 2.7*2, 1.0*2},
		offset = {0, 2.7, 0},
		model = "data/customers/offices/building1.obj"
	},
	
	community = {
		e = nil,
		model = "data/customers/community_hall/cm.obj",
		offset = {0, 3.9, 0},
		bounds = {4.47*2, 3.8*2, 3.68*2},
	},
    
	corporate = {
		e = nil,
		model = "data/customers/corporate/corporate.obj",
		offset = {0,7.5,0},
		bounds ={7.70*2, 10.65*2, 3.41*2},
	},     

	factory1 = {
		e = nil,
		model = "data/customers/factory1/factory1.obj",
		offset = {0, 2.8, 0},
		bounds = {7.6*2, 3*2, 8.17 * 2},

	},

	factory2 = {
		e = nil,
		model = "data/customers/factory2/factory2.obj",
		offset = {0, 2.5, 0},
		bounds = {6.6*2, 2.6*2, 7*2},
	},
    
	lab = {
		e = nil,
		model = "data/customers/lab/lab.obj",
		offset = {0, 2.8, 0},
		bounds = {5.66*2 ,2.84*2, 6.01*2},
	},
    
	library = {
		e = nil,
		model = "data/customers/library/lib.obj",
		offset = {0, 3.9,0},
		bounds = {4.5*2,3.88*2,3.4*2},
	},

	residential = {
		e = nil,
		model = "data/customers/residential/residential.obj",
		offset = {0, 2.5, 0},
		bounds = { 8.46*2, 2.52*2, 8.67*2},
	},

	university = {
		e = nil,
		model = "data/customers/university/university.obj",
		offset = {0, 2.5, 0},
		bounds = {9.9*2, 2.69*2 ,8.10*2},
	},
    
	church = {
		e = nil,
		model = "data/customers/church/church.obj",
		offset = {0,3.4, 0},
		bounds = { 1.92*2, 3.46*2,1.34*2 },
           
	},
	
	art_college = {
		e = nil,
		model = "data/customers/arts/art.obj",
		offset = {0, 1.85, 0},
		bounds = {10.75, 3.09, 10.45}
	},
	
	selectionBox = {
		e = nil,
		bounds = {5, 5, 5},
		offset = {0, 3, 0},
		model = "data/selectionbox.obj"
	},
	
	peerBox = {
		e = nil,
		bounds = {5, 5, 5},
		offset = {0, 3, 0},
		model = "data/peerbox.obj"
	},
	
	statusBar100 = {
		e = nil,
		bounds = {1, 5, 1},
		offset = {0, 5, 0},
		model = "data/statusbar/statusbar100.obj",
	},
	
	statusBar75 = {
		e = nil,
		bounds = {1, 5, 1},
		offset = {0, 5, 0},
		model = "data/statusbar/statusbar75.obj",
	},
	
	statusBar50 = {
		e = nil,
		bounds = {1, 5, 1},
		offset = {0, 5, 0},
		model = "data/statusbar/statusbar50.obj",
	},

	statusBar25 = {
		e = nil,
		bounds = {1, 5, 1},
		offset = {0, 5, 0},
		model = "data/statusbar/statusbar25.obj",
	},
	
	statusBar0 = {
		e = nil,
		bounds = {1, 5, 1},
		offset = {0, 5, 0},
		model = "data/statusbar/statusbar0.obj",
	},
	
	arrow_head = {
		e = nil,
		model = "data/arrow_head.obj"
	},
	
	arrow_body = {
		e = nil,
		model = "data/arrow_body.obj"
	}

}


enterFeeButton = nil
enterFeeButtonHover = nil

WIDGETS = {	-- Contains all widgets
	customer = nil, -- 
	router = nil, -- 
	cable = nil, -- 
}

-- Define state if scenes
SCENE_STATE = {
	normal			= 0,	-- initial, nothing selected
	cable_draw		= 2,
	router_drop		= 4,
	demolish		= 8,
}

-- Defines types of messages
MESSAGE = {
	restriction = 1
}

CATEGORY_SELECTABLE = 1
CATEGORY_FLOOR = 2
CATEGORY_MOUSERAY = CATEGORY_SELECTABLE + CATEGORY_FLOOR
CATEGORY_NEWELEMENT = CATEGORY_SELECTABLE

Scene = {}
sceneMt = {__index = Scene}

-- -----------------------------------------------------------------------------
-- Function: Scene:init()
-- Inputs: none
-- Returns: newScene - pointer to the scene
-- Initializes the main scene
-- -----------------------------------------------------------------------------
function Scene:init()
	--print("in Scene:init()")
	newScene = {
		
		map = {
			mouseRay = nil,		-- Mouse ray: used for mouse picking	
			
			scene3d = nil,		-- pivot for whole 3D scene
			headLight = nil,
			
			camera3d = nil,		-- root camera
			cameraLocation = {},	-- current camera coordinates
			cameraRotation = {},	-- current camera rotation
		
			floor = nil,		-- ground
			
			-- GObjects are here!
			cables = {},
			routers = {},
			customers = {},
			customerSelectionBox = {},
			statusBar = {},
			
			selected = nil,		-- currently selected GObject,
			selectionBox = nil,	-- current selection box
			statusBar = nil,	-- current status bar
			tempCableSegments = {},-- holds temporary points while	
						-- cable being drawn
			tempRouter = nil,	-- routers being dropped
			
			element1st = nil,	-- pointers to GObjects elements
			element2nd = nil,	-- between which current cable is
						-- being drawn
			
			newElementFit = nil,	-- indicates whether the element
						-- being dropped/drawn can fit
						-- in its current position or not
			peerBoxes = nil,
			
			trafficArrows = {},
		},
		
		gui = {
			scene2d = nil,		-- pivot for 2D scene (toolbar and widgets)
	 		camera2d = nil,
			widgets = {},		-- 2D widgets
			
			widgetsCamera = nil,
			activeWidget = nil,	-- only one widget can be displayed
						-- at a time
		},

			
		-- last time Scene:animate was called
		lastAnimCall = nil,
		
		-- current state of scene
		state = SCENE_STATE.normal,
		toolType = nil			-- tool currently being applied to
						-- scene
	}
	
	-- load all objects
	for x, object in OBJECTS do
		if object.e == nil then
			object.e = E.create_object(object.model)
			--hide objects (otherwise they are cramped into the lower right of the screen)
			hide(object.e)
			if object.eNotFit ~= nil then
				object.eNotFit = E.create_object(object.eNotFit)
				hide(object.eNotFit)
			end
		end
	end
	
	-- load animation models
	loadAnimationModels()
	
	setmetatable(newScene, sceneMt)
	return newScene
end

function Scene:printMessage(msg, color)
	--print("in Scene:printMessage()")
	--E.print_console(msg)
	--E.print_console("\n")
	setMessage(msg, color)
end

-- ------------------------------------------------------------------------------
-- Function:	Scene:display()
-- Inputs:	Electro entity
-- Assigns the electro entity to the 3D scene (i.e. displays it)\
function Scene:display(entity)
	--print("in Scene:display()")
	E.parent_entity(entity, self.map.headLight)
end

function Scene:getTestCollisionResult()	

	local res = self.map.colResult
	self.map.colResult = nil
	
	return res
end
	
function Scene:testCollision(bounds, coordinates)
	
	--print("Collision test")
	-- create pivot and bound it to 3D scene
	self.map.colTest = E.create_pivot()
	E.set_entity_position(self.map.colTest, unpack(coordinates))
	self:display(self.map.colTest)
	
	self.map.colResult = false
	
	-- enable collision detection on new temp router
	self:addSceneGeom(self.map.colTest, E.geom_type_box, 
		bounds,
		0)
	E.set_entity_geom_attr(self.map.colTest, E.geom_attr_callback, CATEGORY_SELECTABLE)
	
end

function Scene:endTestCollision()
	if self.map.colTest ~= nil then
		--print("Ending test collision")
		E.set_entity_geom_attr(self.map.colTest, E.geom_attr_callback, 0)
		E.delete_entity(self.map.colTest)
		self.map.colTest = nil
	end
end
-- ------------------------------------------------------------------------------
-- Function Scene:retrieveObject()
-- Inputs:	eEntity: an Electro entity
-- Returns:	instance of the entity's game logic object or nil
-- This function is useful for retreiving the actual game logic object given
-- an Electro entity. It is used in mouse picking where do_contact() returns
-- the Electro entity and we want to map it to the actual object
-- ------------------------------------------------------------------------------
function Scene:retrieveObject(eEntity)
	--print("in Scene:retrieveObject()")
	if eEntity == nil then
		E.print_console("retrieveObject(nil) attempted!")
		return
	end
	
	-- search in customers
	for index, object in self.map.customers do
		if object.e == eEntity then
			return object
		end
	end
	
	-- search in routers
	for index, object in self.map.routers do
		if object.e == eEntity then
			return object
		end
	end
	
	-- search in cables
	for index, cable in self.map.cables do
		-- search segment of cable
		for x, segment in cable.e do
			if segment == eEntity then
				return cable
			end
		end
	end
	
	print("WARNING: couldn't retrieve object!")
	-- not found
	return nil
end

-- -----------------------------------------------------------------------------
-- Function: Scene:hiLight()
-- Inputs: entity
-- Returns: none
-- Change visual appearance of an object (used when selecting objects)
-- -----------------------------------------------------------------------------
function Scene:hiLight(entity)
	--print("in Scene:hiLight()")
	E.set_entity_alpha(entity, 0.1)
end

-- -----------------------------------------------------------------------------
-- Function: Scene:deLight()
-- Inputs: entity
-- Returns: none
-- Change visual appearance of an object (used when de-selecting objects)
-- -----------------------------------------------------------------------------
function Scene:deLight(entity)
	--print("in Scene:deLight()")
	E.set_entity_alpha(entity, 1.0)
end

-- -----------------------------------------------------------------------------
-- Function: Scene:select()
-- Inputs: entity
-- Returns: none
-- Hanle object selection
-- -----------------------------------------------------------------------------
function Scene:select(entity)
	--print("in Scene:select()")
	local newSelect = self:retrieveObject(entity)
	
	if	self.map.selected == newSelect and 
		self.map.selected ~= nil
	then
		E.play_sound(toolHoverSound)	
		-- same element reselected, toggle widget
		gameScene:toggleWidget()
		
	elseif	self.map.selected ~= newSelect 
	then
		E.play_sound(toolHoverSound)	
		self:deselect()
		self.map.selected = newSelect	
		
		--  selected element
		--print("Selected element: ", self.map.selected.o:getElementType())
		
		-- See if element is a cable
		if self.map.selected ~= nil and self.map.selected.o:getElementType() == "cable" then
			-- selected element is a cable, 
			-- high light all segments of cable
			for x, segment in self.map.selected.e do
				self:hiLight(segment)
			end
	
		elseif self.map.selected ~= nil and self.map.selected.o:getElementType() == "customer" then
			
			-- highlight the customer
			--self:hiLight(self.map.selected.e)
		
			-- display selection box
			self:showSelectionBox(self.map.selected.e)
			
			-- display peer boxes
			self:showPeerBoxes(self.map.selected.o)
		
			-- show customer satisfaction bar using status bar			
			self:showStatusBar(self.map.selected.e)
			
			-- show traffic flow arrows
			self:drawFlowArrows(self.map.selected.o)
			
		elseif self.map.selected ~= nil and self.map.selected.o:getElementType() == "router" then
			
			-- highlight the router
			--self:hiLight(self.map.selected.e)
			
			-- show selection box
			self:showSelectionBox(self.map.selected.e)
			
			--show router utilization bar
			self:showStatusBar(self.map.selected.e)
		end		
	end
end

-- -----------------------------------------------------------------------------
-- Function: Scene:deselect()
-- Inputs: none
-- Returns: none
-- Hanle object de-selection
-- -----------------------------------------------------------------------------
function Scene:deselect()
	--print("in Scene:deselect()")
	if self.map.selected == nil then
		return
	end
	
	if self:isWidgetShown() then
		self:toggleWidget()
	end
	
	-- Is previously selected element a cable?
	if self.map.selected.o:getElementType() == "cable" then
		-- de high light all segments of cable
		for x, segment in self.map.selected.e do
			self:deLight(segment)
		end
	else
		-- just a single entitied element
		self:deLight(self.map.selected.e)
		self:hideSelectionBox()
		if self.map.selected.o:getElementType() == "customer" then
			self:hidePeerBoxes()
			inputEntry = false
			inputString = ""
		end
		
		self:hideStatusBar()
		self:removeFlowArrows()
	end
	
	self.map.selected = nil
	self.state = SCENE_STATE.normal
	E.play_sound(toolDeselectSound)	
end

-- -----------------------------------------------------------------------------
-- Function: Scene:getSelected()
-- Inputs: none
-- Returns: selected object
--
-- -----------------------------------------------------------------------------
function Scene:getSelected()
	--print("in Scene:getSelected()")
	return self.map.selected
end

-- -----------------------------------------------------------------------------
-- Function: Scene:getMouseRay()
-- Inputs: none
-- Returns: mouse ray pointer
--
-- -----------------------------------------------------------------------------
function Scene:getMouseRay()
	--print("in Scene:getMouseRay()")
	return self.map.mouseRay
end

function Scene:tempRouterFit(status)
	--print("in Scene:tempRouterFit()")
	local template = nil
	if status ~= nil and status then
		template = OBJECTS[self.toolType].e
	else
		template = OBJECTS[self.toolType].eNotFit
	end
	
	if self.map.tempRouter ~= nil then
	
	if self.map.newElementFit ~= nil and self.map.newElementFit ~= status then
		local x, y, z = E.get_entity_position(self.map.tempRouter)
		E.delete_entity(self.map.tempRouter)
		self.map.tempRouter = E.create_clone(template)
		E.parent_entity(self.map.tempRouter, self.map.headLight)
		E.set_entity_position(self.map.tempRouter, x, y, z)

		self.map.newElementFit = status
	end
	
	end
	
	if not status then
		E.set_entity_alpha(self.map.tempRouter, 0.7)
	end
	
	--hide(self.map.tempRouter)
end

--------------------------------------------------------------------------------
-- Function:	Scene:moveTempRouter()
-- Inputs:	p: point to move temp router to
function Scene:moveTempRouter(p)
	--print("in Scene:moveTempRouter()")
	if p ~= nil then

		-- move temp router
		E.set_entity_position(self.map.tempRouter, unpack(p))
		
		-- set new status to fit and show it
		self:tempRouterFit(true)
		show(self.map.tempRouter)
		
		-- update collision detection state: if router collides
		-- with any other object, collision is immediately reported
		-- and its state is changed to NOT fit
		--[[
		self:removeSceneGeom(self.map.tempRouter)
		self:addSceneGeom(self.map.tempRouter, E.geom_type_box, 
			OBJECTS[self.toolType].bounds,
			CATEGORY_NEWELEMENT)
		--]]
	else
		E.print_console("WARNING: moveTempRouter(nil)!\n")
	end
end

--------------------------------------------------------------------------------
-- Function:	Scene:prepareTempRouter()
-- Inputs:	p: point at which to display temp router, if no point is provided
--		router is hidden until the next mouse hover
function Scene:prepareTempRouter(p)
	--print("in Scene:prepareTempRouter()")
	self.map.tempRouter = E.create_clone(OBJECTS[self.toolType].e)
	self.map.newElementFit = true
	
	-- assign it under headLight, and hide it at first
	E.parent_entity(self.map.tempRouter, self.map.headLight)
	if p == nil then
		hide(self.map.tempRouter)
	else
		E.set_entity_position(self.map.tempRouter, unpack(p))
	end
	
	-- enable collision detection on new temp router
	--[[
	self:addSceneGeom(self.map.tempRouter, E.geom_type_box, 
		OBJECTS[self.toolType].bounds,
		CATEGORY_NEWELEMENT)
	--]]

end

function Scene:cancelRouterDropping()
	--print("in Scene:cancelRouterDropping()")
	if self.map.tempRouter ~= nil then
		E.delete_entity(self.map.tempRouter)
		self.map.tempRouter = nil
	end
end

function Scene:resetPreviousTool(newTool)
	--print("in Scene:resetPreviousTool()")
	if newTool == self.toolType or self.toolType == nil then
		return
	
	elseif isCable(self.toolType) then
		self:cancelCableDrawing()
	
	elseif isRouter(self.toolType) then
		-- cancel router dropping
		self:cancelRouterDropping()
	end
end

-- ------------------------------------------------------------------------------
-- Function: Scene:toolSelection(newTool)
-- Inputs:	newTool: newly selected tool
-- Returns:	none
-- Called whenever currently selected tool changes
-- ------------------------------------------------------------------------------
function Scene:toolSelection(newTool)
	--print("in Scene:toolSelection()")
	self:resetPreviousTool(newTool)
	self.toolType = newTool
	
	if isCable(newTool) then
		self.state = SCENE_STATE.cable_draw
	
	elseif isRouter(newTool) then
		self:prepareTempRouter()
		self.state = SCENE_STATE.router_drop

		
	elseif isDemolish(newTool) then
		-- set scene state to demolish
		self.state = SCENE_STATE.demolish	
	
	elseif newTool == nil then
		self.state = SCENE_STATE.normal
	end
	
end

-- ------------------------------------------------------------------------------
-- Function: Scene:mouseTrack()
-- Inputs:	none
-- Returns:	none
-- Called whenever mouse coordinates change within scene
-- ------------------------------------------------------------------------------
function Scene:mouseTrack()
	--print("in Scene:mouseTrack()")
	if self.state == SCENE_STATE.cable_draw then
		-- if we're drawing a cable, then we need to adjust cable
		-- segment being drawn
		self:enableMouseRay(CATEGORY_MOUSERAY)
	
	elseif self.state == SCENE_STATE.router_drop then
		-- we're dropping a router, then we need to adjust the temporary
		-- router location
		self:enableMouseRay(CATEGORY_MOUSERAY)
	end
end

function Scene:handleElementsCollision()
	--print("in Scene:handleElementsCollision()")
	if isRouter(self.toolType) then
		self:tempRouterFit(false)
	end
end

-- ------------------------------------------------------------------------------
-- Function: Scene:mouseSceneHover(a, p)
-- Inputs:	a: Electro entity being hovered, p: Point of hovering
-- Returns: none
-- Called by Electro's do_contact() to report mouse hover over the scene
-- -----------------------------------------------------------------------------
function Scene:mouseSceneHover(a, p)
	--print("in Scene:mouseSceneHover()")
	-- use retreiveObject(a)
	
	if self.state == SCENE_STATE.cable_draw then
		if table.getn(self.map.tempCableSegments) > 0 then
			-- we're currently drawing a cable segment
			-- adjust the current cable segment being drawn
			
			local cableSegment = self.map.tempCableSegments[
				table.getn(self.map.tempCableSegments)]
			
			local layout = calcSegmentLayout(cableSegment.point, p)
			
			E.set_entity_position(cableSegment.e, unpack(layout.midPoint))
			E.set_entity_rotation(cableSegment.e, unpack(layout.rotation))
			E.set_entity_scale(cableSegment.e, unpack(layout.scale))
			cableSegment.angle = layout.rotation[2]
			
		end
	
	elseif self.state == SCENE_STATE.router_drop then
		local dropPoint = v_add(p, OBJECTS[self.toolType].offset)
		self:moveTempRouter(dropPoint)
	end
end

-- ------------------------------------------------------------------------------
-- Function: Scene:mouseClick()
-- Inputs:	button: "left", or "right"
-- Returns:	none
--
-- -----------------------------------------------------------------------------
function Scene:mouseClick(button)
	--print("in Scene:mouseClick()")
	if button == "right" then
	
		
		if	self.state == SCENE_STATE.cable_draw then
			-- cancel cable drawing
			unselectTool()
		elseif	self.state == SCENE_STATE.router_drop then
			unselectTool()
		elseif	self.state == SCENE_STATE.demolish then
			unselectTool()	
		else
			-- deselect current entity
			self:deselect()
		end
	
	elseif button == "left" then
		self:enableMouseRay(CATEGORY_MOUSERAY)
	end
end
	
-- ------------------------------------------------------------------------------
-- Function: Scene:mousePick()
-- Inputs:	a, picked entity
--		p: point of picking
-- Returns: none
-- Called by Electro's do_contact() call back to report mouse picking event to
-- handle entity selection in 3D scene
-- -----------------------------------------------------------------------------
function Scene:mousePick(a, p)
	--print("in Scene:mousePick()")
	if a == self.map.floor then
		-- **** Floor collision ****
		if self.state == SCENE_STATE.normal then
			if self.map.selected ~= nil and self:isWidgetShown() then
				-- floor is clicked and we have a widget shown,
				-- hide widget
				self:toggleWidget()
			end

		-- ** Purchase cable **
		elseif self.state == SCENE_STATE.cable_draw then
			
			-- is this the first segment?
			if table.getn(self.map.tempCableSegments) == 0 then
				-- reject, first segment has to start at 
				self:printMessage("Cable laying must begin at a customer or router!", MESSAGE.restriction)  
				return
			else
				-- draw temp cable segment
				p[2] = 0
				self:newCableSegment(p)
			end
		
		-- ** Purchase router **
		elseif self.state == SCENE_STATE.router_drop then
			-- do we have enough money?
			if not gameSim:canPurchase(gameSim:getUnitCost(self.toolType)) then
				self:printMessage("You do not have enough money to purchase this router.", MESSAGE.restriction)
				return
			end
			
			if p == nil then
				E.print_console("p == nil!")
			end
			
			if self.toolType == nil then
				E.print_console("self.toolType == nil!")
			end
			
			-- create a new router
			local router = self:createElement(self.toolType, p)
			
			if self.map.tempRouter ~= nil then
			-- delete temporary router
			E.delete_entity(self.map.tempRouter)
			end
			self.map.tempRouter = nil
			
			-- purchase the element
			gameSim:purchase(router.o:getCost())
			
			-- prepare another have another temp router
			local dropPoint = v_add(p, OBJECTS[self.toolType].offset)
			self:prepareTempRouter(dropPoint)
		end
		
		
	else
		-- **** Collision with some element (other than floor) ****
		local gObject = self:retrieveObject(a)
		
		if self.state == SCENE_STATE.cable_draw then
			
			if gObject.o:getElementType() == "cable" then
				-- can not draw cable over a cable
				self:printMessage("You can not lay cables over other cables.", MESSAGE.restriction)
				return
			elseif not gObject.o:canAddNewConnection() then
				-- no more room for new cable
				self:printMessage("Element can not accommodate a new cable.", MESSAGE.restriction)
				return
			end
			
			-- got logic permission
			local x, y, z = E.get_entity_position(a)
			y = 0
			if table.getn(self.map.tempCableSegments) == 0 then
				-- first segment, start cable drawing!
				-- see if element can accommodate new cable
				self.map.element1st = gObject
				self:newCableSegment({x, y, z})
				
			else
				-- last segment, end cable drawing
				self.map.element2nd = gObject
				if self.map.element1st == self.map.element2nd then
					self:printMessage("Cable must connect two distinct elements.", MESSAGE.restriction)
					return
				end
				
				local len = calcCableLength(self.map.tempCableSegments)
				local cable = Cable:new(self.toolType, len, {})
				
				-- Do we have enough money to purchase the cable?
				if not gameSim:canPurchase(cable:getCost()) then
					-- no
					self:printMessage("You do not have enough money to purchase the cable.", MESSAGE.restriction)
					return
				end
				
				-- see if logic allows adding the cables between the two elements
				local res = self.map.element1st.o:addConnection(self.map.element2nd.o, cable)
				if res == "link_max" then
					self:printMessage("Element can not accomodate a new cable.", MESSAGE.restriction)
					return
				elseif res == "already_linked" then
					self:printMessage("There is already a connection linking the two elements.", MESSAGE.restriction)
					return
				end
				
				-- deduct cost of cable from balance
				gameSim:purchase(cable:getCost())
				
				-- cable has been added to logic!
				local segments, len, angles = self:drawCable({x, y, z})
				cable:setSegments(segments)
				cable:setLength(len)
				cable:setAngles(angles)
				
				table.insert(self.map.cables, {e = segments, o = cable})
				
				-- delete temporarty segments
				self.map.tempCableSegments = {}
				self.map.element1st = nil
				self.map.element2nd = nil
			end
			
		elseif self.state == SCENE_STATE.demolish then
			-- remove the selected object as long as it is a cable or router
			
			if gObject.o:getElementType() == "cable" then
			
				-- Do we have enough money to delete the cable?
				if not gameSim:canPurchase(Demolish:getCost()) then
					self:printMessage("You do not have enough balance to demolish.", MESSAGE.restriction)
					return
				end
								
			elseif gObject.o:getElementType() == "router" then	
				-- A router
				-- make sure router has no connections, otherwise
				-- reject demolishing it
				if not gObject.o:canDemolish() then
					self:printMessage("You need to remove all cables connected to this router first.", MESSAGE.restriction)
					return
				end
				
			elseif gObject.o:getElementType() == "customer" then
				self:printMessage("You can not demolish a customer.", MESSAGE.restriction)
				return
			end
			
			-- delete element
			Scene:deleteElement(gObject)
			
			--play the demolish sound
			E.play_sound(demolishSound)
			
			-- deduct demolish cost from player's balance
			gameSim:purchase(Demolish:getCost())
			
		elseif self.state == SCENE_STATE.router_drop then
			-- can not drop router on top of other objects
			self:printMessage("You can not place a router over other routers, cables, or customers.", MESSAGE.restriction)
			return
			
		else	-- ** NORMAL state
			--normal state
			self:select(a)
		end
	end
	
end

-- -----------------------------------------------------------------------------
-- Function: Scene:cancelCableDrawing()
-- Inputs: none
-- Returns: none
-- cleans up cable that is being drawn when player decided to cancel cable drawing
-- -----------------------------------------------------------------------------
function Scene:cancelCableDrawing()
	--print("in Scene:cancelCableDrawing()")
	-- remove temporary cable elements
	if self.map.tempCableSegments ~= nil and table.getn(self.map.tempCableSegments) > 0 then
		for key, value in self.map.tempCableSegments do
			if value.e ~= nil then
				E.delete_entity(value.e)
			end
		end
	end
	
	self.map.tempCableSegments = {}
end


function Scene:showPeerBoxes(customer)
	--print("in Scene:showPeerBoxes()")
	local peers = customer:getPeers()
	
	self.map.peerBoxes = {}
	
	for i, peer in peers do
		local bounds = OBJECTS[peer:getSubtype()].bounds
		
		e = peer:getE()
		self.map.peerBoxes[i] = E.create_clone(OBJECTS.peerBox.e)
		
		E.set_entity_flags(self.map.peerBoxes[i],E.entity_flag_billboard,true)
		E.set_entity_alpha(self.map.peerBoxes[i], 0.4)
		E.set_entity_scale(self.map.peerBoxes[i], bounds[1]/2+1, bounds[2]/2+0, bounds[3]/2+1)
		E.set_entity_position(self.map.peerBoxes[i], E.get_entity_position(e))
		
		self:display(self.map.peerBoxes[i])
	end
end
	
function Scene:hidePeerBoxes()
	--print("in Scene:hidePeerBoxes()")
	for i, box in self.map.peerBoxes do
		E.delete_entity(box)
	end
	self.map.peerBoxes = {}
end

-- -----------------------------------------------------------------------------
-- Function: Scene:showSelectionBox()
-- Inputs: entity
-- Returns: none
-- Shows selection box around the entity
-- -----------------------------------------------------------------------------
function Scene:showSelectionBox(entity)
	--print("in Scene:showSelectionBox()")
	local bounds = OBJECTS[self.map.selected.o:getSubtype()].bounds
	x, y, z = E.get_entity_position(entity)
	E.set_entity_flags(self.map.selectionBox,E.entity_flag_billboard,true)
	E.set_entity_scale(self.map.selectionBox, bounds[1]/2+3, bounds[2]/2+2, bounds[3]/2+3)
	E.set_entity_position(self.map.selectionBox,x,y,z)
	show(self.map.selectionBox)
end

-- -----------------------------------------------------------------------------
-- Function: Scene:hideSelectionBox()
-- Inputs: entity
-- Returns: none
-- Hide selection box
-- -----------------------------------------------------------------------------
function Scene:hideSelectionBox()
	--print("in Scene:hideSelectionBox()")
	hide(self.map.selectionBox)
end

-- -----------------------------------------------------------------------------
-- Function: Scene:showStatusBar()
-- Inputs: entity
-- Returns: none
-- Shows status bar of the entity
-- -----------------------------------------------------------------------------
function Scene:showStatusBar(entity)
	--print("in Scene:showStatusBar()")
	local bounds = OBJECTS[self.map.selected.o:getSubtype()].bounds
	x, y, z = E.get_entity_position(entity)
	
	-- create status bar based on the utilization or in case of customer, based on satisfaction
	
	if self.map.selected.o:getElementType() == "customer" then
		local percentage = self.map.selected.o:getStatusBar()

		--get satisfaction of the customer and based on that, set status bar
		if percentage > 85 then
			self.map.statusBar = E.create_clone(OBJECTS.statusBar100.e)
		elseif percentage > 60 then
			self.map.statusBar = E.create_clone(OBJECTS.statusBar75.e)
		elseif percentage > 35 then
			self.map.statusBar = E.create_clone(OBJECTS.statusBar50.e)
		elseif percentage > 10 then
			self.map.statusBar = E.create_clone(OBJECTS.statusBar25.e)
		else
			self.map.statusBar = E.create_clone(OBJECTS.statusBar0.e)
		end
	elseif self.map.selected.o:getElementType() == "router" then
		--get load of the router and based on that, set status bar
		if self.map.selected.o.currentLoad > 85 then
			self.map.statusBar = E.create_clone(OBJECTS.statusBar100.e)
		elseif self.map.selected.o.currentLoad > 60 then
			self.map.statusBar = E.create_clone(OBJECTS.statusBar75.e)
		elseif self.map.selected.o.currentLoad > 35 then
			self.map.statusBar = E.create_clone(OBJECTS.statusBar50.e)
		elseif self.map.selected.o.currentLoad > 10 then
			self.map.statusBar = E.create_clone(OBJECTS.statusBar25.e)
		else
			self.map.statusBar = E.create_clone(OBJECTS.statusBar0.e)
		end
	end 
	
	E.parent_entity(self.map.statusBar, self.map.headLight)
	E.set_entity_flags(self.map.statusBar,E.entity_flag_billboard,true)
	E.set_entity_scale(self.map.statusBar, 1, 1, 1)
	E.set_entity_position(self.map.statusBar,x, y+10, z)

	show(self.map.statusBar)
end

-- -----------------------------------------------------------------------------
-- Function: Scene:hideSelectionBox()
-- Inputs: entity
-- Returns: none
-- Hide selection box
-- -----------------------------------------------------------------------------
function Scene:hideStatusBar()
	--print("in Scene:hideStatusBar()")
	if self.map.statusBar ~= nil then
		E.delete_entity(self.map.statusBar)
		self.map.statusBar = nil
	end
end

function Scene:updateStatusBar(entity)
	self:hideStatusBar()
	self:showStatusBar(entity)
end

--------------------------------------------------------------------------------
-- Function:	Scene:createElement()
-- Inputs:	elementType (string): detailed type of element (e.g.: "offices", 
--		"router2".
--		coordinates (tables):	x, y, z coordinates of intended 
--		element's position
-- Returns:	GObject of the created element
-- Creates a new GObject entity initializing it in game logic and on the scene
-- -----------------------------------------------------------------------------
function Scene:createElement(elementType, coordinates)
	--print("in Scene:createElement()")
	local gObject = GObject:new()

	-- clone and position electro entity
	gObject.e = E.create_clone(OBJECTS[elementType].e)		
	
	E.set_entity_position(gObject.e, coordinates[1], 0, coordinates[3])
	-- apply initial offset (normally to raise objects above floor level)
	if OBJECTS[elementType].offset ~= nil then
		E.move_entity(gObject.e, unpack(OBJECTS[elementType].offset))
	end
	
	E.parent_entity(gObject.e, self.map.headLight)
	
	-- set bounds for mouse picking
	if OBJECTS[elementType].bounds ~= nil then
		self:addSceneGeom(gObject.e, E.geom_type_box, 
			OBJECTS[elementType].bounds,
			CATEGORY_SELECTABLE)
	end
	
	-- DEBUG: geometry visible
	--E.set_entity_flags(gObject.e, E.entity_flag_visible_geom, true)
	
	if	elementType == "university"	or	
		elementType == "lab"		or
		elementType == "offices"	or
		elementType == "corporate"	or
		elementType == "community"	or
		elementType == "factory1"	or
		elementType == "factory2"	or
		elementType == "residential"	or
		elementType == "library"	or
		elementType == "church"	or
		elementType == "art_college"	then
		
		gObject.o = Customer:new(elementType, "Customer " .. (table.getn(self.map.customers)+1), gObject.e)
		-- create customer animation object
		gObject.anim = CustomerAnim:new(gObject)
		
		table.insert(self.map.customers, gObject)
		
	elseif	elementType == "cable1"	or
		elementType == "cable10"	or
		elementType == "cable100"	then
		gObject.o = Cable:new(elementType, gObject.e)
		table.insert(self.map.cables, gObject)
		
	elseif	elementType == "router4"	or
		elementType == "router6"	or
		elementType == "router8"	then
		gObject.o = Router:new(elementType, "Router " .. (table.getn(self.map.routers)+1), gObject.e)
		table.insert(self.map.routers, gObject)
	end
	
	-- notify simulation engine of changes
	gameSim:modified()
	
	return gObject
end

--------------------------------------------------------------------------------
-- Function: Scene:deleteElement()
-- Inputs:	gObject of element to be deleted
-- Returns:	none
-- Deletes the element from scene, and reports entity removal to simulation
-- engine. This makes sure that if a cable is removed, for example, both ends
-- connected to the cable are updated.
-- -----------------------------------------------------------------------------
function Scene:deleteElement(gObject)
	--print("in Scene:deleteElement()")
	local o = gObject.o
	
	-- delete Electro entity from scene
	if gObject.o:getElementType() == "cable" then
		-- element is a cable: remove all segments of cable
		for key, value in gObject.e do
			E.delete_entity(value)
			value = nil
		end
	else
		E.delete_entity(gObject.e)
		e = nil
	end
	
	-- notify simulation engine ot removal
	gameSim:modified()
	gameSim:removeElement(gObject.o)
end

--------------------------------------------------------------------------------
-- Function:	Scene:calcSegmentLayout()
-- Inputs:	pointA, pointB: ends of cable
-- Return:	layout: a table describing the layout of a cable segment on scene
-- Given the two ends of the cable, function calculates midPoint, rotation,
-- and scale of a cable segment so that the caller can position and scale
-- it correctly on the screen
-- -----------------------------------------------------------------------------
function calcSegmentLayout(pointA, pointB)
	--print("in Scene:calcSegmentLayout()")
	
	if pointA == nil then
		print("pointA == nil!")
	end
	
	if pointB == nil then
		print("pointB == nil!")
	end
	
	local layout = {}
	pointA[2] = 1
	pointB[2] = 1
	layout.midPoint = {
		(pointA[1] + pointB[1]) / 2,
		1,
		(pointA[3] + pointB[3]) / 2,
	}
	
	local scaleZ = distance(pointA, pointB)
	layout.scale = {1, 1, scaleZ}
	
	layout.rotation = {
		0, 
		(-1 * math.deg(math.atan((pointA[3] - pointB[3]) / (pointA[1] - pointB[1])))) - 90,
		0
	}
	
	return layout
end

-- -----------------------------------------------------------------------------
-- Function:	Scene:calcCableLength()
-- Inputs:	array of cable segments
-- Returns:	integer, the length of the cable (sum of segment lengths)
-- -----------------------------------------------------------------------------
function calcCableLength(segments)
	--print("in calcCableLength()")
	local length = 0
	for x, segment in segments do
		local Sx, Sy, Sz = E.get_entity_scale(segment.e)
		length = length + Sz
	end
	
	return math.floor(length)
end


-- -----------------------------------------------------------------------------
-- Function:	Scene:newCableSegment()
-- Inputs:	p: point at which the segment start
-- Returns:	none
-- Draws a new temporary cable segment and inserts it into map.tempCableSegments
-- -----------------------------------------------------------------------------
function Scene:newCableSegment(p)
	--print("in Scene:newCableSegment()")
	local newSegment = E.create_clone(OBJECTS.cable0.e)
	E.set_entity_position(newSegment, unpack(p))
	if OBJECTS.cable0.offset ~= nil then
		E.move_entity(newSegment, unpack(OBJECTS.cable0.offset))
	end
	
	E.parent_entity(newSegment, self.map.headLight)
	table.insert(self.map.tempCableSegments, {e = newSegment, point = p, angle = 0})
end

--------------------------------------------------------------------------------
-- Function: 	Scene:drawCable()
-- Inputs:	lastPoint: optional (could be nil): indicates end point
--		of last segment of not nil
-- Returns:	1) array of Electro entities representing segments of cable
--		2) total length of cable (sum of segments' length) 
-- -----------------------------------------------------------------------------
function Scene:drawCable(lastPoint)
	--print("in Scene:drawCable()")
	local pointA = nil
	local pointB = nil
	local cableSegments = {}
	local angles = {}
	local totalLen = 0
	
	-- loop through temporary segments
	for i = 1, table.getn(self.map.tempCableSegments) do
		local tempSegment = self.map.tempCableSegments[i]
		local midX, midY, midZ = E.get_entity_position(tempSegment.e)
		local sX, sY, sZ = E.get_entity_scale(tempSegment.e)
		
		-- replace temporary segments with permanent ones
		local segment = E.create_object(OBJECTS[self.toolType].model)
		
		-- did the caller pass a lastPoint?
		if i == table.getn(self.map.tempCableSegments) and lastPoint ~= nil then
			-- recalculate layout of last segment, since caller wants
			-- it different from temporary segment
			local layout = calcSegmentLayout(
				tempSegment.point, 
				lastPoint)
			sX = layout.scale[1]
			sY = layout.scale[2]
			sZ = layout.scale[3]
			midX = layout.midPoint[1]
			midY = layout.midPoint[2]
			midZ = layout.midPoint[3]
			tempSegment.angle = layout.rotation[2]
		end
		totalLen = totalLen + sZ
			
		E.set_entity_scale(segment, sX, sY, sZ)
		E.set_entity_position(segment, midX, midY, midZ)
		if OBJECTS[self.toolType].offset ~= nil then
			E.move_entity(segment, unpack(OBJECTS[self.toolType].offset))
		end
		
		E.set_entity_rotation(segment, 0, tempSegment.angle, 0)
		
		-- enable geometry on segment
		local bounds = OBJECTS[self.toolType].bounds
		self:addSceneGeom(segment, E.geom_type_box, {
			bounds[1] * sX,
			bounds[2] * sY,
			bounds[3] * sZ}, CATEGORY_SELECTABLE)
		
		-- delete temp segment
		E.delete_entity(tempSegment.e)
		
		-- replace with new segment
		E.parent_entity(segment, self.map.headLight)
		table.insert(cableSegments, segment)
		table.insert(angles, tempSegment.angle)
	end

	-- notify simulation engine
	gameSim:modified()
	
	return cableSegments, totalLen, angles
end

-- -----------------------------------------------------------------------------
-- Function: Scene:moveCamera()
-- Inputs: transV - vector in 3d space
-- Returns: none
-- Moves camera into new position specified by the 3d vector
-- -----------------------------------------------------------------------------
function Scene:moveCamera(transV)
	--print("in Scene:moveCamera()")
	-- Rotate camera
	self.map.cameraRotation[2] = self.map.cameraRotation[2] + transV[4]
	E.set_entity_rotation(self.map.camera3d, unpack(self.map.cameraRotation))

	-- Reset camera position according to current scroll vector and rotation.
	local s = math.sin(math.rad(self.map.cameraRotation[2]))
	local c = math.cos(math.rad(self.map.cameraRotation[2]))
	local x, y, z = unpack(self.map.cameraLocation)
	
	x = x + transV[1]*c + transV[2]*s
	z = z + transV[1]*(-s) + transV[2]*c
	y = y + transV[3]
	
	if (x>=-200 and x <=200 and z >= -200 and z <=200 and y>=20 and y <=160) then
		self.map.cameraLocation = {x, y, z}
		E.set_entity_position(self.map.camera3d, x + s*y, y, z + c*y)
	end
	-- E.set_entity_position(self.map.headLight, 0, 0, 0)
	
end

-- -----------------------------------------------------------------------------
-- Function: Scene:addSceneGeom()
-- Inputs: theEntity, geomType, geomData, geomCategory
-- Returns: none
-- used with collisions, sets up necessary geoms and structures
-- -----------------------------------------------------------------------------
function Scene:addSceneGeom(theEntity, geomType, geomData, geomCategory)
	--print("in Scene:addScemeGeom()")
	-- disable floor geometry
	self:disableFloorCollision()
	
	E.set_entity_geom_type(theEntity, geomType, unpack(geomData))       
	E.set_entity_geom_attr(theEntity, E.geom_attr_category, geomCategory)

	-- DEBUG: enable visibility
	--E.set_entity_flags(theEntity, E.entity_flag_visible_geom, true)
	
	-- re-renable floor geomtry
	self:enableFloorCollision()
end

-- -----------------------------------------------------------------------------
-- Function: Scene:removeSceneGeom()
-- Inputs: theEntity
-- Returns: none
-- Turns off collision for the entity
-- -----------------------------------------------------------------------------
function Scene:removeSceneGeom(theEntity)
	--print("in Scene:removeSceneGeom()")
	E.set_entity_geom_type(theEntity, E.geom_type_none)
end

--------------------------------------------------------------------------------
-- Function: Scene:enableMouseRay()
-- Inputs:	category: geometry category to assign to mouse ray
-- Returns:	none
-- Enables mouse ray, this function is called whenever we want to detect
-- collision between mouse pointer and any other entity in 3D scene. Note that
-- collisions are reported to Scene:mousePick
-- -----------------------------------------------------------------------------
function Scene:enableMouseRay(category)
	--print("in Scene:enableMouseRay()")
	if category == nil or self.map.mouseRay == nil then
		E.print_console(" category == nil or self.map.mouseRay == nil")
		return
	else

	local mouseV = {E.get_camera_vector(self.map.camera3d, input.MouseX, input.MouseY)}
	local cameraP = {E.get_entity_position(self.map.camera3d)}
					
	-- Enable collision on floor
	--self:enableFloorCollision()
		
	-- Enable the mouse ray.
	E.set_entity_geom_type(
		self.map.mouseRay, 
		E.geom_type_ray, 
		cameraP[1], cameraP[2], cameraP[3],
		unpack(v_mult(mouseV, 100)))
				
	-- enable mouse ray collision
	E.set_entity_geom_attr(self.map.mouseRay, E.geom_attr_callback, category)
	end
end

-- -----------------------------------------------------------------------------
-- Function: Scene:disableMouseRay()
-- Inputs: none
-- Returns: none
-- disables the mouse ray
-- -----------------------------------------------------------------------------
function Scene:disableMouseRay()
	--print("in Scene:disableMouseRay()")
	if self.map.mouseRay == nil then
		E.print_console("self.map.mouseRay == nil")
		print("self.map.mouseRay == nil")
		return
	else
	
	-- Disable mouse ray
	E.set_entity_geom_attr(self.map.mouseRay, E.geom_attr_callback, 0)
	E.set_entity_geom_type(
		self.map.mouseRay,
		E.geom_type_ray,
		0, 0, 0, 0, 0, 0)
		
	-- Disable collision on floor
	--self:disableFloorCollision()
	end
end

-- -----------------------------------------------------------------------------
-- Function: Scene:enableFloorCollision()
-- Inputs: none
-- Returns: none
-- enables collision between floor and other elements
-- -----------------------------------------------------------------------------
function Scene:enableFloorCollision()
	--print("in Scene:enableFloorCollision()")
	E.set_entity_geom_type(self.map.floor, E.geom_type_box, unpack(OBJECTS.floor.bounds))
	E.set_entity_geom_attr(self.map.floor, E.geom_attr_category, CATEGORY_FLOOR)
	
end

-- -----------------------------------------------------------------------------
-- Function: Scene:disableFloorCollision()
-- Inputs: none
-- Returns: none
-- disables collision between floor and other elements
-- -----------------------------------------------------------------------------
function Scene:disableFloorCollision()
	--print("in Scene:disableFloorCollision()")
	if self.map.floor == nil then
		print("self.map.floor == nil")
	end
	self:removeSceneGeom(self.map.floor)
end

-- -----------------------------------------------------------------------------
-- Function: Scene:isWidgetShown()
-- Inputs: none
-- Returns: true or false
-- returns true if there is widget shown on the 2d screen, otherwise returns false
-- -----------------------------------------------------------------------------
function Scene:isWidgetShown()
	--print("in Scene:isWidgetShown()")
	if self.gui.activeWidget ~= nil then
		return true
	else
		return false
	end
end


function Scene:toggleHelp()
	
	if inGameHelp ~= nil then
		--E.print_console("Destroy widget")
		-- destroy active widget
		E.delete_entity(inGameHelp)
		inGameHelp = nil
	else
		local pivot = E.create_pivot()
			
		local background = make_sprite("data/widgets/help.png")
		E.set_entity_alpha(background, 0.9)
		
		-- create brush to be used for strings
		local brush = E.create_brush()
		E.set_brush_color(brush,0,0,0,1)
		
		--create string for customer name
		local helpString1 = E.create_string("HELP")
		E.set_string_fill(helpString1, blackBrush)
		E.set_entity_position(helpString1, 0, 120, 0)
		E.set_entity_scale(helpString1, 16,16,1)
		
		local helpString2 = E.create_string("Keys:")
		E.set_string_fill(helpString2, blackBrush)
		E.set_entity_position(helpString2, -280, 100, 0)
		E.set_entity_scale(helpString2, 13,13,1)
		
		local helpString3 = E.create_string("W or Arrow Up - Move Camera Forward")
		E.set_string_fill(helpString3, blackBrush)
		E.set_entity_position(helpString3, -300, 80, 0)
		E.set_entity_scale(helpString3, 13,13,1)
		
		local helpString4 = E.create_string("S or Arrow Down - Move Camera Backwards")
		E.set_string_fill(helpString4, blackBrush)
		E.set_entity_position(helpString4, -300, 60, 0)
		E.set_entity_scale(helpString4, 13,13,1)
		
		local helpString5 = E.create_string("A or Arrow Left - Move Camera Left")
		E.set_string_fill(helpString5, blackBrush)
		E.set_entity_position(helpString5, -300, 40, 0)
		E.set_entity_scale(helpString5, 13,13,1)
		
		local helpString6 = E.create_string("D or Arrow Right- Move Camera Right")
		E.set_string_fill(helpString6, blackBrush)
		E.set_entity_position(helpString6, -300, 20, 0)
		E.set_entity_scale(helpString6, 13,13,1)
		
		local helpString7 = E.create_string("Q - Rotate Scene Left")
		E.set_string_fill(helpString7, blackBrush)
		E.set_entity_position(helpString7, -300, 0, 0)
		E.set_entity_scale(helpString7, 13,13,1)
		
		local helpString8 = E.create_string("E - Rotate Scene Right")
		E.set_string_fill(helpString8, blackBrush)
		E.set_entity_position(helpString8, -300, -20, 0)
		E.set_entity_scale(helpString8, 13,13,1)
		
		local helpString9 = E.create_string("Z - Zoom In")
		E.set_string_fill(helpString9, blackBrush)
		E.set_entity_position(helpString9, -300, -40, 0)
		E.set_entity_scale(helpString9, 13,13,1)
		
		local helpString10 = E.create_string("X - Zoom Out")
		E.set_string_fill(helpString10, blackBrush)
		E.set_entity_position(helpString10, -300, -60, 0)
		E.set_entity_scale(helpString10, 13,13,1)
		
		local helpString11 = E.create_string("H - Toggle Help Screen")
		E.set_string_fill(helpString11, blackBrush)
		E.set_entity_position(helpString11, -300, -80, 0)
		E.set_entity_scale(helpString11, 13,13,1)
		
		local helpString12 = E.create_string("F10 - Pause/Quit the Game")
		E.set_string_fill(helpString12, blackBrush)
		E.set_entity_position(helpString12, -300, -100, 0)
		E.set_entity_scale(helpString12, 13,13,1)
		
		local helpString13 = E.create_string("Mouse:")
		E.set_string_fill(helpString13, blackBrush)
		E.set_entity_position(helpString13, -280, -140, 0)
		E.set_entity_scale(helpString13, 13,13,1)
		
		local helpString14 = E.create_string("Mouse Wheel Up/Down - Zoom")
		E.set_string_fill(helpString14, blackBrush)
		E.set_entity_position(helpString14, -300, -160, 0)
		E.set_entity_scale(helpString14, 13,13,1)
		
		local helpString15 = E.create_string("When No Tool Is Selected:")
		E.set_string_fill(helpString15, blackBrush)
		E.set_entity_position(helpString15, -300, -200, 0)
		E.set_entity_scale(helpString15, 13,13,1)
		
		local helpString16 = E.create_string("Single Left Click On Entity - Show Status Bar And Highligh Object")
		E.set_string_fill(helpString16, blackBrush)
		E.set_entity_position(helpString16, -300, -220, 0)
		E.set_entity_scale(helpString16, 13,13,1)
		
		local helpString18 = E.create_string("(For Customers, Highlight The Peers)")
		E.set_string_fill(helpString18, blackBrush)
		E.set_entity_position(helpString18, -280, -240, 0)
		E.set_entity_scale(helpString18, 13,13,1)
		
		local helpString20 = E.create_string("Right Click - Deselect Widget And/Or Current Tool")
		E.set_string_fill(helpString20, blackBrush)
		E.set_entity_position(helpString20, -300, -280, 0)
		E.set_entity_scale(helpString20, 13,13,1)
		
		local helpString21 = E.create_string("Left Click On Status Bar Selects Tool")
		E.set_string_fill(helpString21, blackBrush)
		E.set_entity_position(helpString21, -300, -320, 0)
		E.set_entity_scale(helpString21, 13,13,1)
		
		E.parent_entity(helpString1, pivot)
		E.parent_entity(helpString2, pivot)
		E.parent_entity(helpString3, pivot)
		E.parent_entity(helpString4, pivot)
		E.parent_entity(helpString5, pivot)
		E.parent_entity(helpString6, pivot)
		E.parent_entity(helpString7, pivot)
		E.parent_entity(helpString8, pivot)
		E.parent_entity(helpString9, pivot)
		E.parent_entity(helpString10, pivot)
		E.parent_entity(helpString11, pivot)
		E.parent_entity(helpString12, pivot)
		E.parent_entity(helpString13, pivot)
		E.parent_entity(helpString14, pivot)
		E.parent_entity(helpString15, pivot)
		E.parent_entity(helpString16, pivot)
		E.parent_entity(helpString18, pivot)
		E.parent_entity(helpString20, pivot)
		E.parent_entity(helpString21, pivot)
		E.parent_entity(background, pivot)
			
		inGameHelp = pivot
		
		-- position widget in left top corner underneath the toolbar
		E.set_entity_position(inGameHelp, 0+400, 0-200, 0)
		
		-- add it to scene2d hierarchy
		E.parent_entity(inGameHelp, self.gui.widgetsCamera)
		
		
		--[[
		
		
		
		
		
		
		
		]]
	end
end

function Scene:createNegotiateWidget()
	local pivot = E.create_pivot()
			
				local background = make_sprite("data/widgets/customer.png")
				E.set_entity_alpha(background, 0.9)
				
				-- create brush to be used for strings
				local brush = E.create_brush()
				E.set_brush_color(brush,0,0,0,1)
				
				--create string for customer name
				local customerNameString = E.create_string("Customer Name:")
				E.set_string_fill(customerNameString, blackBrush)
				E.set_entity_position(customerNameString, -150, 40, 0)
				E.set_entity_scale(customerNameString, 13,13,1)
				
				local customerName = E.create_string(self.map.selected.o.name)
			
				E.set_string_fill(customerName, brush)
				E.set_entity_position(customerName, 10, 40, 0)
				E.set_entity_scale(customerName, 13,13,1)
				
				--create string for initial Fee
				local initialFeeString = E.create_string("Demand Fee:")
				E.set_string_fill(initialFeeString, brush)
				E.set_entity_position(initialFeeString, -150, 20, 0)
				E.set_entity_scale(initialFeeString, 13,13,1)
				
				local initialFee= E.create_string("$" .. self.map.selected.o:getInitialFee())
			
				E.set_string_fill(initialFee, brush)
				E.set_entity_position(initialFee, 10, 20, 0)
				E.set_entity_scale(initialFee, 13,13,1)
				
				--create string for supplied Fee
				local suppliedFeeString = E.create_string("Supply Fee:")
				E.set_string_fill(suppliedFeeString, brush)
				E.set_entity_position(suppliedFeeString, -150, 0, 0)
				E.set_entity_scale(suppliedFeeString, 13,13,1)
				
				-- create enter fee button
				enterFeeButton = make_sprite("data/widgets/enterbutton.png")
				E.set_entity_position(enterFeeButton, 43, 5, 0)
				enterFeeButtonHover = make_sprite("data/widgets/enterbuttonhover.png")
				E.set_entity_position(enterFeeButtonHover, 43, 5, 0)
				enterFeeButtonInsert = make_sprite("data/widgets/enterbuttoninsert.png")
				E.set_entity_position(enterFeeButtonInsert, 43, 3, 0)
				E.set_entity_alpha(enterFeeButtonInsert, 0.9)
				
				-- create $ string
				local dollarString = E.create_string("$")
				E.set_string_fill(dollarString, brush)
				E.set_entity_scale(dollarString, 13,13,1)
				E.set_entity_position(dollarString, 10, 0, 0)
				
				-- create fee input string
				feeInputString = E.create_string(inputString)
				E.set_string_fill(feeInputString, brush)
				E.set_entity_scale(feeInputString, 13,13,1)
				E.set_entity_position(feeInputString, 20, 0, 0)
				
				--hide(feeInputString)
				
				--hide the things that should not show yet
				hide(enterFeeButtonHover)
				hide(enterFeeButtonInsert)
				
				--create string for initial bandwidth
				local initialBandwidthString = E.create_string("Demand Bandwidth:")
				E.set_string_fill(initialBandwidthString, brush)
				E.set_entity_position(initialBandwidthString,-150,-20, 0)
				E.set_entity_scale(initialBandwidthString, 13,13,1)
				
				local initialBandwidth = E.create_string(self.map.selected.o.initialBandwidth .. " Mbps")
			
				E.set_string_fill(initialBandwidth, brush)
				E.set_entity_position(initialBandwidth, 10, -20, 0)
				E.set_entity_scale(initialBandwidth, 13,13,1)
				
				--create string for supplied bandwidth
				local suppliedBandwidthString = E.create_string("Supplied Bandwidth:")
				E.set_string_fill(suppliedBandwidthString, brush)
				E.set_entity_position(suppliedBandwidthString,-150,-40, 0)
				E.set_entity_scale(suppliedBandwidthString, 13,13,1)
				
				local temp = ""
				if self.map.selected.o:getLink() ~= nil then
					temp = self.map.selected.o:getLink().cable:getBandwidth()
				else
					temp = "None"
				end
				
				suppliedBandwidth = E.create_string(temp .. " Mbps")
			
				E.set_string_fill(suppliedBandwidth, brush)
				E.set_entity_position(suppliedBandwidth, 10, -40, 0)
				E.set_entity_scale(suppliedBandwidth, 13,13,1)
				
				--create negotiate button
				negotiateButton = make_sprite("data/widgets/negotiateButton.png")
				E.set_entity_position(negotiateButton, -80, -70, 0)
				
				--create string for customer name and hide it. it is displayed if player does not enter negotiate fee
				enterFeeString = E.create_string("Enter supply fee!")
				E.set_string_fill(enterFeeString, redBrush)
				E.set_entity_position(enterFeeString, -157, -105, 0)
				E.set_entity_scale(enterFeeString, 13,13,1)
				E.parent_entity(enterFeeString, pivot)
				hide(enterFeeString)

				negotiationFailedString = E.create_string("Negotiation Failed! Lower monthly cost")
				E.set_string_fill(negotiationFailedString, redBrush)
				E.set_entity_position(negotiationFailedString, -157, -105, 0)
				E.set_entity_scale(negotiationFailedString, 12,12,1)
				hide(negotiationFailedString)
				
				negotiationFailedString2 = E.create_string("and/or connect customer")
				E.set_string_fill(negotiationFailedString2, redBrush)
				E.set_entity_position(negotiationFailedString2, -157, -125, 0)
				E.set_entity_scale(negotiationFailedString2, 12,12,1)
				hide(negotiationFailedString2)

				negotiationPassedString = E.create_string("Negotiation Passed! Right click")
				E.set_string_fill(negotiationPassedString, blueBrush)
				E.set_entity_position(negotiationPassedString, -150, -70, 0)
				E.set_entity_scale(negotiationPassedString, 12,12,1)
				hide(negotiationPassedString)
				
				negotiationPassedString2 = E.create_string("to hide the widget. Next connect")
				E.set_string_fill(negotiationPassedString2, blueBrush)
				E.set_entity_position(negotiationPassedString2, -150, -90, 0)
				E.set_entity_scale(negotiationPassedString2, 12,12,1)
				hide(negotiationPassedString2)
				
				negotiationPassedString3 = E.create_string("the remaining peers!")
				E.set_string_fill(negotiationPassedString3, blueBrush)
				E.set_entity_position(negotiationPassedString3, -150, -110, 0)
				E.set_entity_scale(negotiationPassedString3, 12,12,1)
				hide(negotiationPassedString3)
				
				-- add entities
				E.parent_entity(negotiationPassedString, pivot)
				E.parent_entity(negotiationPassedString2, pivot)
				E.parent_entity(negotiationPassedString3, pivot)
				E.parent_entity(negotiationFailedString, pivot)
				E.parent_entity(negotiationFailedString2, pivot)
				E.parent_entity(customerNameString, pivot)
				E.parent_entity(customerName, pivot)
				E.parent_entity(initialFeeString, pivot)
				E.parent_entity(initialFee, pivot)
				E.parent_entity(suppliedFeeString, pivot)
				E.parent_entity(initialBandwidthString, pivot)
				E.parent_entity(initialBandwidth, pivot)
				E.parent_entity(suppliedBandwidthString, pivot)
				E.parent_entity(suppliedBandwidth, pivot)
				E.parent_entity(dollarString, pivot)
				E.parent_entity(negotiateButton, pivot)
				E.parent_entity(feeInputString, pivot)
				E.parent_entity(enterFeeButton, pivot)
				E.parent_entity(enterFeeButtonHover, pivot)
				E.parent_entity(enterFeeButtonInsert, pivot)
				E.parent_entity(background, pivot)


	return pivot
end

function Scene:createCustomerWidget()
local pivot = E.create_pivot()
			
				local background = make_sprite("data/widgets/customer.png")
				E.set_entity_alpha(background, 0.9)
				
				-- create brush to be used for strings
				local brush = E.create_brush()
				E.set_brush_color(brush,0,0,0,1)
				E.set_typeface("data/Coprgtb.TTF")
				
				--create string for customer name
				local customerNameString = E.create_string("Customer Name:")
				E.set_string_fill(customerNameString, brush)
				E.set_entity_position(customerNameString, -150, 40, 0)
				E.set_entity_scale(customerNameString, 13,13,1)
				
				local customerName = E.create_string(self.map.selected.o.name)
				E.set_string_fill(customerName, brush)
				E.set_entity_position(customerName, 10, 40, 0)
				E.set_entity_scale(customerName, 13,13,1)
				
				--create string for supplied Fee
				local suppliedFeeString = E.create_string("Supply Fee:")
				E.set_string_fill(suppliedFeeString, brush)
				E.set_entity_position(suppliedFeeString, -150, 20, 0)
				E.set_entity_scale(suppliedFeeString, 13,13,1)
				
				--create string for supplied Fee
				local suppliedFee = E.create_string("$" .. self.map.selected.o:getMonthlyFee())
				E.set_string_fill(suppliedFee, brush)
				E.set_entity_position(suppliedFee, 10, 20, 0)
				E.set_entity_scale(suppliedFee, 13,13,1)
				
				--create string for customer satisfaction
				local satisfactionString = E.create_string("Satisfaction:")
				E.set_string_fill(satisfactionString, brush)
				E.set_entity_position(satisfactionString, -150, 0, 0)
				E.set_entity_scale(satisfactionString, 13,13,1)
				
				--create string for customer satisfaction
				local percentage = self.map.selected.o:getSatisfactionRate()
				custSatisfaction = E.create_string(percentage .. " %")
				E.set_string_fill(custSatisfaction, brush)
				E.set_entity_position(custSatisfaction, 10, 0, 0)
				E.set_entity_scale(custSatisfaction, 13,13,1)
				
				--create string for supplied Fee
				local currentLoadString = E.create_string("Required Bandwidth:")
				E.set_string_fill(currentLoadString, brush)
				E.set_entity_position(currentLoadString, -150, -20, 0)
				E.set_entity_scale(currentLoadString, 13,13,1)
				
				--create string for supplied Fee
				customerWidget.currentLoadS = E.create_string(self.map.selected.o:getCurrentBandwidth() .. " Mbps")
				E.set_string_fill(customerWidget.currentLoadS, brush)
				E.set_entity_position(customerWidget.currentLoadS, 10, -20, 0)
				E.set_entity_scale(customerWidget.currentLoadS, 13,13,1)
				
				--create string for supplied bandwidth
				local availableBandwidthString = E.create_string("Available Bandwidth:")
				E.set_string_fill(availableBandwidthString, brush)
				E.set_entity_position(availableBandwidthString,-150,-60, 0)
				E.set_entity_scale(availableBandwidthString, 13,13,1)
				
				local temp = ""
				if self.map.selected.o:getLink() ~= nil then
					temp = self.map.selected.o:getLink().cable:getBandwidth()
				else
					temp = "None"
				end
				
				local availableBandwidth = E.create_string(temp .. " Mbps")
				E.set_string_fill(availableBandwidth, brush)
				E.set_entity_position(availableBandwidth, 10, -60, 0)
				E.set_entity_scale(availableBandwidth, 13,13,1)
				
				--create string for supplied Bandwidth
				local suppliedBandwidthString = E.create_string("Supplied Bandwidth:")
				E.set_string_fill(suppliedBandwidthString, brush)
				E.set_entity_position(suppliedBandwidthString, -150, -40, 0)
				E.set_entity_scale(suppliedBandwidthString, 13,13,1)
				
				--create string for supplied Bandwidth
				suppliedBandwidth = E.create_string(self.map.selected.o.suppliedBandwidth .. " Mbps")
				E.set_string_fill(suppliedBandwidth, brush)
				E.set_entity_position(suppliedBandwidth, 10, -40, 0)
				E.set_entity_scale(suppliedBandwidth, 13,13,1)
				
				-- add entities
				E.parent_entity(customerNameString, pivot)
				E.parent_entity(customerName, pivot)
				E.parent_entity(suppliedFeeString, pivot)
				E.parent_entity(suppliedFee, pivot)
				E.parent_entity(satisfactionString, pivot)
				E.parent_entity(custSatisfaction, pivot)
				E.parent_entity(currentLoadString, pivot)
				E.parent_entity(customerWidget.currentLoadS, pivot)
				E.parent_entity(availableBandwidthString, pivot)
				E.parent_entity(availableBandwidth, pivot)
				E.parent_entity(suppliedBandwidthString, pivot)
				E.parent_entity(suppliedBandwidth, pivot)
				E.parent_entity(background, pivot)

	return pivot
end

-- -----------------------------------------------------------------------------
-- Function: Scene:toggleWidget()
-- Inputs: none
-- Returns: none
-- Toggles widget for currently selected element
-- -----------------------------------------------------------------------------
function Scene:toggleWidget()
	--print("in Scene:toggleWidget()")
	if self.gui.activeWidget ~= nil then
		--E.print_console("Destroy widget")
		-- destroy active widget
		E.delete_entity(self.gui.activeWidget)
		self.gui.activeWidget = nil
		
	else
	
		--E.print_console("Selected element: " .. self.map.selected.o:getElementType())
		
		if self.map.selected == nil then
			-- no element selected, ignore
			E.print_console("No selected element, skipping.")
			
			return
			
		elseif self.map.selected.o:getElementType() == "customer" then
			
			-- first check the state of customer - if already negotiated or not
			-- depending on which state customer is in show different widget
			if self.map.selected.o.state == STATE.CUSTOMER.interested then
			
				self.gui.activeWidget = self:createNegotiateWidget()
				
			elseif self.map.selected.o.state == STATE.CUSTOMER.contracted then
			
				self.gui.activeWidget = self:createCustomerWidget()
			
			else
			
				E.print_console("Customer's state: " .. self.map.selected.o.state)
			end
			
		elseif self.map.selected.o:getElementType() == "cable" then
		
			local pivot = E.create_pivot()
			
			local background = make_sprite("data/widgets/cable.png")
			E.set_entity_alpha(background, 0.9)
			
			-- create brush to be used for strings
			local brush = E.create_brush()
			E.set_brush_color(brush,0,0,0,1)
			E.set_typeface("data/Coprgtb.TTF")
			
			--create string for cable type
			local cableTypeString = E.create_string("Cable type:")
			E.set_string_fill(cableTypeString, brush)
			E.set_entity_position(cableTypeString, -120, 40, 0)
			E.set_entity_scale(cableTypeString, 13,13,1)
			
			if self.map.selected.o.cableType == "cable1" then
				cableType = E.create_string("1 Mbps")
			elseif self.map.selected.o.cableType == "cable10" then
				cableType = E.create_string("10 Mbps")
			elseif self.map.selected.o.cableType == "cable100" then
				cableType = E.create_string("100 Mbps")
			end	
			
			E.set_string_fill(cableType, brush)
			E.set_entity_position(cableType, 10, 40, 0)
			E.set_entity_scale(cableType, 13,13,1)
			
			-- create string for age
			local ageString = E.create_string("Age:")
			E.set_string_fill(ageString, brush)
			E.set_entity_position(ageString, -120, 20, 0)
			E.set_entity_scale(ageString, 13,13,1)
			
			local seconds = math.mod(self.map.selected.o.age, 60)
			local minutes = math.floor(self.map.selected.o.age / 60)
	
			if seconds < 10 then
				seconds = "0" .. seconds 
			end
	
			local timeString = minutes .. "m " .. seconds .. "s"
			
			age = E.create_string(timeString)
			E.set_string_fill(age, brush)
			E.set_entity_position(age, 10, 20, 0)
			E.set_entity_scale(age, 13,13,1)
			
			-- create string for currentLoad
			local currentLoadString = E.create_string("Current Load:")
			E.set_string_fill(currentLoadString, brush)
			E.set_entity_position(currentLoadString, -120, 0, 0)
			E.set_entity_scale(currentLoadString, 13,13,1)
			
			currentLoad = E.create_string(self.map.selected.o.currentLoad .. " Mbps")
			E.set_string_fill(currentLoad, brush)
			E.set_entity_position(currentLoad, 10, 0, 0)
			E.set_entity_scale(currentLoad, 13,13,1)
			
			-- create string for Length
			local lengthString = E.create_string("Cable Length:")
			E.set_string_fill(lengthString, brush)
			E.set_entity_position(lengthString, -120, -20, 0)
			E.set_entity_scale(lengthString, 13,13,1)
			
			local length = E.create_string(string.format("%.2f", self.map.selected.o.length) .. " meters")
			E.set_string_fill(length, brush)
			E.set_entity_position(length, 10, -20, 0)
			E.set_entity_scale(length, 13,13,1)
			
			-- add strings
			E.parent_entity(length, pivot)
			E.parent_entity(lengthString, pivot)
			E.parent_entity(currentLoad, pivot)
			E.parent_entity(currentLoadString, pivot)
			E.parent_entity(age, pivot)
			E.parent_entity(ageString, pivot)
			E.parent_entity(cableType, pivot)
			E.parent_entity(cableTypeString, pivot)
			
			E.parent_entity(background, pivot)
			
			self.gui.activeWidget = pivot
			
		elseif self.map.selected.o:getElementType() == "router" then
			
			pivot = E.create_pivot()
			
			background = make_sprite("data/widgets/router.png")
			E.set_entity_alpha(background, 0.9)
			
			-- create brush to be used for strings
			brush = E.create_brush()
			E.set_brush_color(brush,0,0,0,1)
			E.set_typeface("data/Coprgtb.TTF")
			
			--create string for router name
			routerNameString = E.create_string("Router Name:")
			E.set_string_fill(routerNameString, brush)
			E.set_entity_position(routerNameString, -120, 40, 0)
			E.set_entity_scale(routerNameString, 13,13,1)
			
			routerName = E.create_string(self.map.selected.o.name)
			
			E.set_string_fill(routerName, brush)
			E.set_entity_position(routerName, 10, 40, 0)
			E.set_entity_scale(routerName, 13,13,1)
			
			-- create string for router Type
			routerTypeString = E.create_string("Router Type:")
			E.set_string_fill(routerTypeString, brush)
			E.set_entity_position(routerTypeString, -120, 20, 0)
			E.set_entity_scale(routerTypeString, 13,13,1)
			
			if self.map.selected.o.routerType == "router4" then
				routerType = E.create_string("4 ports")
			elseif self.map.selected.o.routerType == "router6" then
				routerType = E.create_string("6 ports")
			elseif self.map.selected.o.routerType == "router8" then
				routerType = E.create_string("8 ports")
			end
				
			E.set_string_fill(routerType, brush)
			E.set_entity_position(routerType, 10, 20, 0)
			E.set_entity_scale(routerType, 13,13,1)
			
			-- create string for currentLoad
			currentLoadString = E.create_string("Current Load:")
			E.set_string_fill(currentLoadString, brush)
			E.set_entity_position(currentLoadString, -120, 0, 0)
			E.set_entity_scale(currentLoadString, 13,13,1)
			
			currentLoad = E.create_string(self.map.selected.o.currentLoad .. " Mbps")
			E.set_string_fill(currentLoad, brush)
			E.set_entity_position(currentLoad, 10, 0, 0)
			E.set_entity_scale(currentLoad, 13,13,1)
			
			-- create string for age
			ageString = E.create_string("Age:")
			E.set_string_fill(ageString, brush)
			E.set_entity_position(ageString, -120, -20, 0)
			E.set_entity_scale(ageString, 13,13,1)
			
			local seconds = math.mod(self.map.selected.o.age, 60)
			local minutes = math.floor(self.map.selected.o.age / 60)
	
			if seconds < 10 then
				seconds = "0" .. seconds 
			end
	
			local timeString = minutes .. "m " .. seconds .. "s"
			
			age = E.create_string(timeString)
			E.set_string_fill(age, brush)
			E.set_entity_position(age, 10, -20, 0)
			E.set_entity_scale(age, 13,13,1)
			
			-- add strings directly underneath camera, otherwise they don't display (go figure)
			E.parent_entity(routerType, pivot)
			E.parent_entity(routerTypeString, pivot)
			E.parent_entity(currentLoad, pivot)
			E.parent_entity(currentLoadString, pivot)
			E.parent_entity(age, pivot)
			E.parent_entity(ageString, pivot)
			E.parent_entity(routerName, pivot)
			E.parent_entity(routerNameString, pivot)
			
			E.parent_entity(background, pivot)
			
			self.gui.activeWidget = pivot
			
		end
		
		-- position widget in left top corner underneath the toolbar
		E.set_entity_position(self.gui.activeWidget, viewport.R*2 - 130, viewport.B + 165, 0)
		
		-- add it to scene2d hierarchy
		E.parent_entity(self.gui.activeWidget, self.gui.widgetsCamera)
	end		
end

function Scene:updateScene()
	if self.map.selected == nil then
		--do nothing
	
	--print("in Scene:updateWidgetInfo()")
	elseif self.map.selected.o:getElementType() == "router" then
	
		local time = math.floor(self.map.selected.o.age*TIME_STEP)
		local seconds = math.mod(time, 60)
			local minutes = math.floor(time / 60)
	
			if seconds < 10 then
				seconds = "0" .. seconds 
			end
	
			local timeString = minutes .. "m " .. seconds .. "s"
			
		E.set_string_text(age, timeString)
		E.set_string_text(currentLoad, self.map.selected.o.currentLoad .. " Mbps")
		self:updateStatusBar(self.map.selected.e)
	elseif self.map.selected.o:getElementType() == "cable" then
	
		local time = math.floor(self.map.selected.o.age*TIME_STEP)
		local seconds = math.mod(time, 60)
			local minutes = math.floor(time / 60)
	
			if seconds < 10 then
				seconds = "0" .. seconds 
			end
	
			local timeString = minutes .. "m " .. seconds .. "s"
			
		E.set_string_text(age, timeString)
		E.set_string_text(currentLoad, self.map.selected.o.currentLoad .. " Mbps")
		
	elseif self.map.selected.o:getElementType() == "customer" then
		if self.map.selected.o.state == STATE.CUSTOMER.contracted and self.gui.activeWidget ~= nil then
			--print(self.gui.activeWidget)
			--E.print_console(E.get_entity_child(self.gui.activeWidget, 8))
			--E.set_string_text(customerWidget.currentLoadS, self.map.selected.o:getCurrentBandwidth() .. " Mbps")
			E.set_string_text(suppliedBandwidth, self.map.selected.o:getSuppliedBandwidth() .. " Mbps")
			
			local temp = ""
				if self.map.selected.o:getLink() ~= nil then
					temp = self.map.selected.o:getLink().cable:getBandwidth()
				else
					temp = "None"
				end
			--E.set_string_text(availableBandwidth, temp .. " Mbps")
			local percentage = self.map.selected.o:getSatisfactionRate()
			if percentage ~= nil then
				--E.set_string_text(custSatisfaction, percentage .. " %")
			end
			
			-- update status bar
			self:updateStatusBar(self.map.selected.e)
			
		end
	end

end

-- -----------------------------------------------------------------------------
-- Function: Scene:initGUI()
-- Inputs: none
-- Returns: none
-- Sets up 2D scene to be used for game's toolbar interface (and maybe 
-- other things in the future)
-- -----------------------------------------------------------------------------
function Scene:initGUI()
	--print("in Scene:initGUI()")
	-- create a camera for displaying widgets
	self.gui.widgetsCamera = E.create_camera(E.camera_type_orthogonal)
	E.set_entity_position(self.gui.widgetsCamera, 0, -viewport.T*2, 0)	
		
	-- create 2D camera, place it in the center of screen
	self.gui.camera2d = E.create_camera(E.camera_type_orthogonal)
	E.set_entity_position(self.gui.camera2d, -viewport.k * viewport.w/2, 
				-viewport.k * viewport.h/2, 0)
	E.set_entity_scale(self.gui.scene2d, viewport.k, viewport.k, viewport.k)
	
	-- create 2D scene
	self.gui.scene2d = E.create_pivot()

	-- add toolbar to 2D scene
	E.parent_entity(create_balancebar(), self.gui.scene2d)
	E.parent_entity(create_toolbar(), self.gui.scene2d)
	E.parent_entity(self.gui.scene2d, self.gui.camera2d)
		
end

-- -----------------------------------------------------------------------------
-- Function: Scene:loadDemoScene()
-- Inputs: none
-- Returns: none
-- Load 3d Scene
-- -----------------------------------------------------------------------------
function Scene:loadDemoScene()
	--print("in Scene:loadDemoScene()")
	-- create entities
	self.map.scene3d = E.create_pivot()
	self.map.camera3d = E.create_camera(E.camera_type_perspective)
	
	--E.set_camera_range(camera3d, 1, 100)
	local lightL = E.create_light(E.light_type_positional)
	local lightR = E.create_light(E.light_type_positional)
	local lightT = E.create_light(E.light_type_positional)
	local lightB = E.create_light(E.light_type_positional)
	
	self.map.headLight = E.create_light(E.light_type_positional)		
	
	self.map.floor = E.create_object(OBJECTS.floor.model)
		
	-- Create SKY 
	local sky = E.create_object("data/sky.obj")

	local 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 sky
	E.set_entity_scale(sky, 600, 600, 600) 

	-- group all 3D entities under scene3d
	E.parent_entity(lightL, self.map.camera3d)
	E.parent_entity(lightR, lightL)
	E.parent_entity(lightT, lightR)
	E.parent_entity(lightB, lightT)
	E.parent_entity(self.map.scene3d, lightB)
	E.parent_entity(self.map.floor, lightB)

	-- ** SHOW SKY HERE
	E.parent_entity(sky,self.map.headLight)
	
	--light for the sky
	E.parent_entity(self.map.headLight, self.map.scene3d)
	E.set_light_color(self.map.headLight, 1.0, 1.0, 1.0)
	
	-- initial camera position               
	self.map.cameraLocation = {0, 40, 0}
	self.map.cameraRotation = {-30, 20, 0}
	self:moveCamera({0, 20, 30, -10})
	
	-- position light sources
	E.set_entity_position(lightL, -200, 30, 0)
	E.set_entity_position(lightR, 200, 30, 0)
	E.set_entity_position(lightT, 0, 30, -200)
	E.set_entity_position(lightB, 0,80,200)
	
	--E.set_entity_position(self.map.headLight, 0, 400, 0)
		
	-- position sky
	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)
		
	-- initialize selection box
	self.map.selectionBox = E.create_clone(OBJECTS.selectionBox.e)
	E.parent_entity(self.map.selectionBox, self.map.headLight)
	hide(self.map.selectionBox)
	
	-- initialize status bar
	self.map.statusBar = E.create_clone(OBJECTS.statusBar100.e)
	E.parent_entity(self.map.statusBar, self.map.headLight)
	hide(self.map.statusBar)
	
	-- create mouse ray for mouse picking
	self.map.mouseRay = E.create_pivot()
	E.parent_entity(self.map.mouseRay, self.map.camera3d)
	E.set_entity_geom_attr(self.map.mouseRay, E.geom_attr_category, CATEGORY_MOUSERAY)
	
	-- create two customers of type commercial.offices
	local cusType = math.random(CUSTOMER_COUNT)
	cusType = CUSTOMER_TYPE_MAP[cusType]
	
	customer1 = self:createElement(cusType, {20, 0, 0})
	
	local cusType = math.random(CUSTOMER_COUNT)
	cusType = CUSTOMER_TYPE_MAP[cusType]
	
	customer2 = self:createElement(cusType, {-30, 0, 16})
	
	customer1.o:addPeer(customer2.o)
	customer2.o:addPeer(customer1.o)

	-- DEBUG: hide floor
	--E.set_entity_flags(self.map.floor, E.entity_flag_hidden, true)
	
	--initialize sounds
	demolishSound = E.load_sound("data/sounds/demolish.ogg")
	moneySound = E.load_sound("data/sounds/money.ogg")
	--backgroundGamePlayMusic = E.load_sound("data/sounds/backgroundgameplay.ogg")
	
end

-- -----------------------------------------------------------------------------
-- Function: Scene:toggleFloor()
-- Inputs: none
-- Returns: none
-- Show/hide floor on the screen
-- -----------------------------------------------------------------------------
function Scene:toggleFloor()
	--print("in Scene:toggleFloor()")
	local hidden = E.get_entity_flags(self.map.floor, E.entity_flag_hidden)
	if hidden then
		E.set_entity_flags(self.map.floor, E.entity_flag_hidden, false)
	else
		E.set_entity_flags(self.map.floor, E.entity_flag_hidden, true)
	end
end

-- -----------------------------------------------------------------------------
-- Function: Scene:loadModel()
-- Inputs: model, x, y, z
-- Returns: none
-- Load model into the scene at position x,y,z and insert it into debugModels table
-- -----------------------------------------------------------------------------
function Scene:loadModel(model, x, y, z)
	--print("in Scene:loadModel()")
	local e = E.create_object(model)
	E.parent_entity(self.map.headLight, e)
	E.set_entity_position(e, x, y, z)
	table.insert(debugModels, e)
end

-- -----------------------------------------------------------------------------
-- Function: Scene:clearModel()
-- Inputs: none
-- Returns: none
-- remove all models from debugModels table and hide them from the screen
-- -----------------------------------------------------------------------------
function Scene:clearModel()
	--print("in Scene:clearModel()")
	for x, model in debugModels do
		E.delete_entity(model)
	end
	debugModels = {}
end

-- -----------------------------------------------------------------------------
-- Function: do_contact()  (Callback function)
-- Inputs: a,b, px, py, pz, xn, ny, nz, d
-- Returns: none
-- Overwrites function that handles mouse clicks
-- -----------------------------------------------------------------------------
function do_contact(a, b, px, py, pz, nx, ny, nz, d)
	-- Iterate through the currenct collision list to check whether the
	-- current collision pair is already present.
	for i, v in collisions do
		if (v[1] == a and v[2] == b) or
			(v[1] == b and v[2] == a) then
			-- We already registered this collision, ignore it this time.
			return
		end
	end
	-- New collision, add it to the list.
	table.insert(collisions, {a, b, {px, py, pz}})
end

function Scene:process_collisions()

	if table.getn(collisions) == 0 then
		-- no collisions; nothing to do
		return 
	end
	
	local floorPick = nil
	local fP = nil
	
	local elementPick = nil
	local eP = nil
	local elementsCollision = nil
	local testCol = false
	
	-- loop through collisions
	for i, col in collisions do
		
		if col[1] == self.map.colTest or col[2] == self.map.colTest then
			-- collision test: positive
			-- collision test
			testCol = true
			--nt("Test positive!")
			
		elseif col[1] == self.map.floor or col[2] == self.map.floor then
			-- floor picking
			floorPick = true
			fP = col[3]
		elseif col[1] == self:getMouseRay() and col[2] ~= self.map.floor then
			elementPick = col[2]
			eP = col[3]
		elseif col[2] == self:getMouseRay() and col[1] ~= self.map.floor then
			elementPick = col[1]
			eP = col[3]				-- selectable object and new element
		
		elseif	self:getTempElement() == a then
			
			-- collision between two different elements
			elementsCollision = a
			print("Elements collision")
		
		elseif	self:getTempElement() == b then
			
			elementsCollision = b
			--print("Elements collision")
		else
			-- collision between two different elements
			elementsCollision = col
		end
	end
	
	-- element pick overrides floor pick
	if testCol then
		--print("Test collision positive!")
		-- signal positiveness
		self.map.colResult = true
		self:endTestCollision()
		-- remove test Result

	elseif elementsCollision ~= nil then
		if self.map.newElementFit then
			self:tempElementFit(false)
			self:setTempElementCollision(false)
		end
	elseif elementPick ~= nil then
		if input.MouseLDown then
			self:mousePick(elementPick, eP)
		else
			self:mouseSceneHover(elementPick, eP)
		end
	elseif floorPick then
		if input.MouseLDown then
			self:mousePick(self.map.floor, fP)
		else
			self:mouseSceneHover(self.map.floor, fP)
		end
	end
	
	-- disable mouse pointer collision
	self:disableMouseRay()
	
	-- reset
	collisions = {}
	
end
--[[
function do_contact(a, b, px, py, pz, xn, ny, nz, d)
	--print("in do_contact()")
	local p = {px, py, pz}
	
	if a == nil or b == nil then
		return
	
	-- report collision
	elseif a == gameScene:getMouseRay() or b == gameScene:getMouseRay() then
		-- ** Collision between mouse ray and something else

		-- disable mouse ray collision
		gameScene:disableMouseRay()

		if input.MouseLDown then
			if a == gameScene:getMouseRay() then
				gameScene:mousePick(b, p)
			else
				gameScene:mousePick(a, p)
			end
		
		elseif not input.MouseLDown then
			if a == gameScene:getMouseRay() then
				gameScene:mouseSceneHover(b, p)
			else
				gameScene:mouseSceneHover(a, p)
			end
		end
	else
		-- ** Collision between two elements
		E.print_console("*** Elements collision ***")
		-- disable collision on temporary element
		if E.get_entity_geom_attr(a, E.geom_attr_category) == CATEGORY_NEWELEMENT then
			gameScene:removeSceneGeom(a)
		else
			gameScene:removeSceneGeom(b)
		end
		
		gameScene:handleElementsCollision()
			
	end
end
--]]
-- -----------------------------------------------------------------------------
-- Function: 		Scene:animate()
-- Inputs/Outputs:	None
-- Animates the scene by calling animate() function on each entity seperately
--------------------------------------------------------------------------------
function Scene:animate()
	--print("in Scene:animate()")
	-- pace animate at ANIM_FRAME_RATE
	--[[
	if self.lastAnimCall == nil then
		self.lastAnimCall = getTime()
	else
		if getTime() - self.lastAnimCall < ANIM_FRAME_RATE then
			-- skip animation
			return
		end
	end
	--]]
	
	-- loop through elements
	for i=1,3 do
	
		local xtable = nil
		local tableName = ""
		
		if i == 1 then
			xtable = self.map.customers
			tableName = "customers"
		elseif i == 2 then
			xtable = self.map.routers
			tableName = "routers"
		elseif i == 3 then
			xtable = self.map.cables
			tableName = "cables"
		end
		
		for x, element in xtable do
			if element.anim ~= nil then
				element.anim:animate()
			end
		end
	end
	
	self.lastAnimCall = getTime()
end
-- -----------------------------------------------------------------------------
-- Function: Scene:drawString3D
-- Inputs: text, coordinates on 3D scene
-- Returns: none
-- Draws text directly on 3D scene
-- -----------------------------------------------------------------------------
function Scene:drawString3D(text, color, x, y, z)
	
	if color == "black" then
		brushS = blackBrush
	elseif color == "green" then
		brushS = greenBrush
	elseif color == "red" then 
		brushS = redBrush
	elseif color == "blue" then
		brushS = blueBrush
	else
		brushS = redBrush
	end

	local string3D = E.create_string(text)
	E.set_string_fill(string3D, brushS)
	E.set_entity_position(string3D, x, y, z)
	E.set_entity_scale(string3D, 2,2,1)
	E.set_entity_flags(string3D, E.entity_flag_billboard,true)
	--self:display(string3D)
	
	return string3D
end

function Scene:drawArrow(cable, customer)
	
	local angles = cable:getAngles()
	local arrowSegments = {}
	
	for i, cSegment in cable:getE() do
		
		local rotation = angles[i]
		local scaleX, scaleY, scaleZ = E.get_entity_scale(cSegment)
		local segmentLen = scaleZ
		
		local arrow = E.create_clone(OBJECTS.arrow_body.e)
		local head = E.create_clone(OBJECTS.arrow_head.e)
		
		
		E.set_entity_rotation(arrow, 0, rotation, 0)
		E.set_entity_rotation(head, 0, rotation, 0)
		
		E.set_entity_scale(arrow, 1, 1, segmentLen - 6)
		
		E.set_entity_position(arrow, E.get_entity_position(cSegment))
		E.move_entity(arrow, 0, 2, 0)	
		E.set_entity_position(head, E.get_entity_position(arrow))
		
		local x, y, z = E.get_entity_position(head)
		x = x + ((segmentLen - 6) / 2) * math.cos(math.rad(rotation)) 
		z = z + ((segmentLen - 6) / 2) * math.sin(math.rad(rotation))
		E.set_entity_position(head, x, y, z)
		
		E.set_entity_alpha(arrow, 0.6)
		E.set_entity_alpha(head, 0.6)

		-- draw text
		local str = self:drawString3D("" .. cable:getConsumption(customer), "red", E.get_entity_position(arrow))
		
		-- display bandwidth being used
		self:display(arrow)
		self:display(str)
		self:display(head)
		-- arrow heads are not set correctly, delete
		hide(head)
		
		E.move_entity(str, 0, 2, 0)

		table.insert(arrowSegments, {hd = head, ar = arrow, st = str})
	end
	
	return arrowSegments
end
--------------------------------------------------------------------------------
-- Function:	Scene:drawFlowArrows()
-- Inputs:	customer: a customer O object
-- Returns:	none
-- Draws traffic flow for customer to his peers
function Scene:drawFlowArrows(customer)
	
	-- query traffic flow from game logic
	local trafficFlow = customer:traceTrafficFlow()
	if	trafficFlow == nil	or
		table.getn(trafficFlow) == 0
	then
		return
	end
	
	-- loop through flow elements
	for i, flowElement in trafficFlow do
		local arrowSet = self:drawArrow(flowElement.cable, customer)
		table.insert(self.map.trafficArrows, arrowSet)
	end
end

function Scene:removeFlowArrows()
	for i, arrowSet in self.map.trafficArrows do
		for j, arrow in arrowSet do
			E.delete_entity(arrow.ar)
			E.delete_entity(arrow.st)
			E.delete_entity(arrow.hd)
			arrow.ar = nil
			arrow.str = nil
			arrow.hd = nil
		end
	end
	self.map.trafficArrows = {}
end

function Scene:destroy()

	-- loop through all data and destroy it
	E.delete_entity(self.map.scene3d)
	E.delete_entity(self.map.camera3d)
	E.delete_entity(self.gui.scene2d)
	E.delete_entity(self.gui.camera2d)
	E.delete_entity(self.gui.widgetsCamera)
	
	-- nullify all logic objects
	for x=1,3 do
		local xtable = nil
		if x == 1 then
			xtable = self.map.customers
		elseif x == 2 then
			xtable = self.map.routers
		elseif x == 3 then
			xtable = self.map.cables
		end
		
		for j=1, table.getn(xtable) do
			xtable[j] = nil
		end
	end
	--switch sounds
	E.stop_sound(backgroundGamePlayMusic)
	E.loop_sound(introMusic)
	gameState = GAME_STATE.menuSelection
end

function Scene:update()
	
	if self.map.selected ~= nil then
		local old = self.map.selected
		self:deselect()
		self:select(old.e)
	end
end
