-- -----------------------------------------------------------------------------
-- SimNetwork
-- scene.lua
-- 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

debugModels = {}

MODEL = {
	
}

OBJECTS = {	-- Contains all 3D Models
	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"
	},
	
	university = {
		e = nil,
		bounds = nil,
		model = "data/customers/university/university.obj"
	},
	
	residential = {
		e = nil,
		bounds = {},
		model = "data/customers/residential/residential.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"
	},
	
	selectionBox = {
		e = nil,
		bounds = {5, 5, 5},
		offset = {0, 3, 0},
		model = "data/selectionbox.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",
	},

}

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()
	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
		},
		
		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
		},

		-- 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
		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
	
	setmetatable(newScene, sceneMt)
	return newScene
end

function Scene:printMessage(msg, msgType)
	--E.print_console(msg)
	--E.print_console("\n")
	setMessage(msg, msgType)
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)
	
	-- 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)
	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)
	E.set_entity_alpha(entity, 1.0)
end

-- -----------------------------------------------------------------------------
-- Function: Scene:select()
-- Inputs: entity
-- Returns: none
-- Hanle object selection
-- -----------------------------------------------------------------------------
function Scene:select(entity)
	local newSelect = self:retrieveObject(entity)
	
	if	self.map.selected == newSelect and 
		self.map.selected ~= nil
	then
		-- same element reselected, toggle widget
		gameScene:toggleWidget()
		
	elseif	self.map.selected ~= newSelect 
	then
		self:deselect()
		self.map.selected = newSelect	
		
		-- HiLight selected element
		--print("Selected element: ", self.map.selected.o:getElementType())
		
		-- See if element is a cable
		if 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.o:getElementType() == "customer" then
			
			-- highlight the customer
			self:hiLight(self.map.selected.e)

			-- display selection box
			self:showSelectionBox(self.map.selected.e)
		
			-- show customer satisfaction bar using status bar
			self:showStatusBar(self.map.selected.e)
			
		elseif 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()
	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()
		self:hideStatusBar()
	end
	
	self.map.selected = nil
	self.state = SCENE_STATE.normal
end

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

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

function Scene:tempRouterFit(status)
	
	local template 
	if status then
		template = OBJECTS[self.toolType].e
	else
		template = OBJECTS[self.toolType].eNotFit
	end
	
	if 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
	
	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)

	-- 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)
	--]]
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)
	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()
	if self.map.tempRouter ~= nil then
		E.delete_entity(self.map.tempRouter)
		self.map.tempRouter = nil
	end
end

function Scene:resetPreviousTool(newTool)
	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)
	
	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()

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

	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)
	
	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
			
			
			-- create a new router
			local router = self:createElement(self.toolType, p)
			
			-- delete temporary router
			E.delete_entity(self.map.tempRouter)
			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 = self:drawCable({x, y, z})
				cable:setSegments(segments)
				cable:setLength(len)
				
				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()
	
	-- 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:showSelectionBox()
-- Inputs: entity
-- Returns: none
-- Shows selection box around the entity
-- -----------------------------------------------------------------------------
function Scene:showSelectionBox(entity)
	
	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()
	hide(self.map.selectionBox)
end

-- -----------------------------------------------------------------------------
-- Function: Scene:showStatusBar()
-- Inputs: entity
-- Returns: none
-- Shows status bar of the entity
-- -----------------------------------------------------------------------------
function Scene:showStatusBar(entity)
	
	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
	
		--get satisfaction of the customer and based on that, set status bar
		if self.map.selected.o.satisfaction > 85 then
			self.map.statusBar = E.create_clone(OBJECTS.statusBar100.e)
		elseif self.map.selected.o.satisfaction > 60 then
			self.map.statusBar = E.create_clone(OBJECTS.statusBar75.e)
		elseif self.map.selected.o.satisfaction > 35 then
			self.map.statusBar = E.create_clone(OBJECTS.statusBar50.e)
		elseif self.map.selected.o.satisfaction > 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()
	E.delete_entity(self.map.statusBar)
	self.map.statusBar = nil
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)

	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: amek geometry visible
	-- E.set_entity_flags(o.e, E.entity_flag_visible_geom, true)
	
	if	elementType == "university"	or	
		elementType == "lab"		or
		elementType == "offices"	or
		elementType == "corporate"	then
		
		gObject.o = Customer:new(elementType, "Customer " .. (table.getn(self.map.customers)+1), gObject.e)
		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
	
	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)
	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: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)
	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)
	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)
	
	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)

	local pointA = nil
	local pointB = nil
	local cableSegments = {}
	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)
	end

	return cableSegments, totalLen
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)

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

-- -----------------------------------------------------------------------------
-- Function: Scene:disableMouseRay()
-- Inputs: none
-- Returns: none
-- disables the mouse ray
-- -----------------------------------------------------------------------------
function Scene:disableMouseRay()
	
	-- 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

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

-- -----------------------------------------------------------------------------
-- Function: Scene:disableFloorCollision()
-- Inputs: none
-- Returns: none
-- disables collision between floor and other elements
-- -----------------------------------------------------------------------------
function Scene:disableFloorCollision()
	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()
	if self.gui.activeWidget ~= nil then
		return true
	else
		return false
	end
end

-- -----------------------------------------------------------------------------
-- Function: Scene:toggleWidget()
-- Inputs: none
-- Returns: none
-- Toggles widget for currently selected element
-- -----------------------------------------------------------------------------
function 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
		hide(cableTypeString)
		hide(cableType)
		hide(age)
		hide(ageString)
		hide(currentLoad)
		hide(currentLoadString)
		hide(length)
		hide(lengthString)
		hide(routerName)
		hide(routerNameString)
		hide(routerType)
		hide(routerTypeString)
		
	else
		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
			self.gui.activeWidget = E.create_clone(WIDGETS.customer)
			
		elseif self.map.selected.o:getElementType() == "cable" then
		
			pivot = E.create_pivot()
			
			background = make_sprite("data/widgets/cable.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 cable type
			cableTypeString = E.create_string("Cable type:")
			E.set_string_fill(cableTypeString, brush)
			E.set_entity_position(cableTypeString, viewport.R*2 - 250, viewport.B + 220, 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, viewport.R*2 - 140, viewport.B + 220, 0)
			E.set_entity_scale(cableType, 13,13,1)
			
			-- create string for age
			ageString = E.create_string("Age:")
			E.set_string_fill(ageString, brush)
			E.set_entity_position(ageString, viewport.R*2 - 250, viewport.B + 200, 0)
			E.set_entity_scale(ageString, 13,13,1)
			
			age = E.create_string(self.map.selected.o.age)
			E.set_string_fill(age, brush)
			E.set_entity_position(age, viewport.R*2 - 140, viewport.B + 200, 0)
			E.set_entity_scale(age, 13,13,1)
			
			-- create string for currentLoad
			currentLoadString = E.create_string("Current load:")
			E.set_string_fill(currentLoadString, brush)
			E.set_entity_position(currentLoadString, viewport.R*2 - 250, viewport.B + 180, 0)
			E.set_entity_scale(currentLoadString, 13,13,1)
			
			currentLoad = E.create_string(self.map.selected.o.currentLoad)
			E.set_string_fill(currentLoad, brush)
			E.set_entity_position(currentLoad, viewport.R*2 - 140, viewport.B + 180, 0)
			E.set_entity_scale(currentLoad, 13,13,1)
			
			-- create string for Length
			lengthString = E.create_string("Cable length:")
			E.set_string_fill(lengthString, brush)
			E.set_entity_position(lengthString, viewport.R*2 - 250, viewport.B + 160, 0)
			E.set_entity_scale(lengthString, 13,13,1)
			
			length = E.create_string(string.format("%.2f", self.map.selected.o.length) .. " meters")
			E.set_string_fill(length, brush)
			E.set_entity_position(length, viewport.R*2 - 140, viewport.B + 160, 0)
			E.set_entity_scale(length, 13,13,1)
			
			-- add strings directly underneath camera, otherwise they don't display (go figure)
			E.parent_entity(length, self.gui.widgetsCamera)
			E.parent_entity(lengthString, self.gui.widgetsCamera)
			E.parent_entity(currentLoad, self.gui.widgetsCamera)
			E.parent_entity(currentLoadString, self.gui.widgetsCamera)
			E.parent_entity(age, self.gui.widgetsCamera)
			E.parent_entity(ageString, self.gui.widgetsCamera)
			E.parent_entity(cableType, self.gui.widgetsCamera)
			E.parent_entity(cableTypeString, self.gui.widgetsCamera)
			
			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, viewport.R*2 - 250, viewport.B + 220, 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, viewport.R*2 - 140, viewport.B + 220, 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, viewport.R*2 - 250, viewport.B + 200, 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, viewport.R*2 - 140, viewport.B + 200, 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, viewport.R*2 - 250, viewport.B + 180, 0)
			E.set_entity_scale(currentLoadString, 13,13,1)
			
			currentLoad = E.create_string(self.map.selected.o.currentLoad)
			E.set_string_fill(currentLoad, brush)
			E.set_entity_position(currentLoad, viewport.R*2 - 140, viewport.B + 180, 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, viewport.R*2 - 250, viewport.B + 160, 0)
			E.set_entity_scale(ageString, 13,13,1)
			
			age = E.create_string(self.map.selected.o.age)
			E.set_string_fill(age, brush)
			E.set_entity_position(age, viewport.R*2 - 140, viewport.B + 160, 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, self.gui.widgetsCamera)
			E.parent_entity(routerTypeString, self.gui.widgetsCamera)
			E.parent_entity(currentLoad, self.gui.widgetsCamera)
			E.parent_entity(currentLoadString, self.gui.widgetsCamera)
			E.parent_entity(age, self.gui.widgetsCamera)
			E.parent_entity(ageString, self.gui.widgetsCamera)
			E.parent_entity(routerName, self.gui.widgetsCamera)
			E.parent_entity(routerNameString, self.gui.widgetsCamera)
			
			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 + 180, 0)
		
		-- add it to scene2d hierarchy
		E.parent_entity(self.gui.activeWidget, self.gui.widgetsCamera)
	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()
		
	-- 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()
	-- 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)
	
	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
	customer1 = self:createElement("offices", {20, 0, 0})
	customer2 = self:createElement("offices", {-30, 0, 16})

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

-- -----------------------------------------------------------------------------
-- Function: Scene:toggleFloor()
-- Inputs: none
-- Returns: none
-- Show/hide floor on the screen
-- -----------------------------------------------------------------------------
function 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)
	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()
	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, xn, ny, nz, d)

	local p = {px, py, pz}
	
	-- report collision
	if 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
