function foo()
	tree()
		.node("p1", Quaternion(), Vector3(0, 0, -200))
		.entity("b1", "residental-house1.glb")
		.endnode()
		.node("p2", Quaternion(), Vector3(0, 0, -150))
		.entity("residental-house1.glb")
		.endnode()
		.node("p3", Quaternion(), Vector3(0, 0, -100))
		.entity("residental-house1.glb")
		.endnode()
		.node("p4", Quaternion(), Vector3(0, 0, -50))
		.entity("residental-house1.glb")
		.endnode()
		.node("p5", Quaternion(), Vector3(0, 0, 50))
		.entity("residental-house1.glb")
		.endnode()
		.node("p6", Quaternion(), Vector3(0, 0, 100))
		.entity("residental-house1.glb")
		.endnode()
		.node("p7", Quaternion(), Vector3(0, 0, 150))
		.entity("residental-house2.glb")
		.endnode()
		.node("p8", Quaternion(), Vector3(0, 0, 200))
		.entity("residental-house3.glb")
		.endnode()
	for x = -1000, 1000, 50 do
		for z = -1000, 1000, 50 do
			if not ((x >-100 and x < 100) and (z > -100 and z < 100)) then
				tree()
					.node("p00" .. tostring(x * 1000 + z), Quaternion(), Vector3(x, 0, z))
					.entity("residental-house2.glb")
				.endnode()
			end
		end
	end
	v = Vector3(0, 1, 2)
end
--[[
narration = {
	position = 1,
	narration_start = {
		"The party was hot, girls were sexy the wine, beer and whisky were in \
enormous numbers. It was anniversary since you set sail with your friends. \
The sea was calm and everything promised you another great night.",
"The whole year with your friends on your ship over vast seas of the world in decay was almost over.\
It was so good year full of adventure, romance, indecency and luxury.",
"Your trusted friends decided that you have too much, they have too much of you and you owe them a lot.",
"They found you drunk in your room and moved to the deck and used ropes to \
restrain you and attach a bucket of stones or something else heavy to your body.",
"After a few hours passed two strong people pulled you to the side and \
dropped you into the sea. Last thing you heard before you hit the water was happy laugher..."
	},
	progress = function(this)
		if #this.narration_start < this.position then
			return ""
		end
		local ret = this.narration_start[this.position]
		this.position = this.position + 1
		return ret
	end,
}
]]--
local narrator = require('narrator.narrator')
local json = require('json.json')

function dump(o)
   if type(o) == 'table' then
      local s = '{ '
      for k,v in pairs(o) do
         if type(k) ~= 'number' then k = '"'..k..'"' end
         s = s .. '['..k..'] = ' .. dump(v) .. ','
      end
      return s .. '} '
   else
      return tostring(o)
   end
end


--[[
function _narration()
		local ret = ""
		local choices = {}
		if story:can_continue() then
			print("can continue")
  			local paragraph = story:continue(1)
			print(dump(paragraph))
			local text = paragraph.text
   			if paragraph.tags then
				text = text .. ' #' .. table.concat(paragraph.tags, ' #')
				for i, tag in ipairs(paragraph.tags) do
					if tag == "mc_is_free" then
						ecs_character_set("player", "gravity", true)
						ecs_character_set("player", "buoyancy", true)
					end
				end
			end
			ret = text
			if story:can_choose() then
				local ch = story:get_choices()
				for i, choice in ipairs(ch) do
					table.insert(choices, choice.text)
					print(i, dump(choice))
				end
				if #choices == 1 and choices[1] == "Ascend" then
					story:choose(1)
					choices = {}
				end
				if #choices == 1 and choices[1] == "Continue" then
					story:choose(1)
					choices = {}
				end
			end
		else
			print("can NOT continue")
		end
		print(ret)
		if (#choices > 0) then
			print("choices!!!")
			narrate(ret, choices)
		else
			narrate(ret)
		end
end
]]--
function Quest(name, book)
	local quest = {
		name = name,
		active = false,
		activate = function(this)
			this.active = true
			this.story:begin()
			this:_narration()
		end,
		event = function(this, event, event_data)
			if not this.active then
				return
			end
			if event == "narration_progress" then
				print(" in progress...")
				this:_narration()
			elseif event == "narration_answered" then
				local answer = narration_get_answer()
				this.story:choose(answer)
				print("answered:", answer)
				this:_narration()
			end
		end,
		_handle_tag = function(this, tag)
			if tag == "mc_is_free" then
				ecs_character_set("player", "gravity", true)
				ecs_character_set("player", "buoyancy", true)
			end
		end,
		_narration = function(this)
			local ret = ""
			local choices = {}
			local have_choice = false
			local have_paragraph = false
			if not this.active then
				print("not active")
				return
			end
			if this.story:can_continue() then
				print("can continue")
				have_paragraph = true
				local paragraph = this.story:continue(1)
				print(dump(paragraph))
				local text = paragraph.text
				if paragraph.tags then
					text = text .. ' #' .. table.concat(paragraph.tags, ' #')
					for i, tag in ipairs(paragraph.tags) do
						this:_handle_tag(tag)
					end
				end
				ret = text
				if this.story:can_choose() then
					have_choice = true
					local ch = this.story:get_choices()
					for i, choice in ipairs(ch) do
						table.insert(choices, choice.text)
						print(i, dump(choice))
					end
					if #choices == 1 and choices[1] == "Ascend" then
						this.story:choose(1)
						choices = {}
					end
					if #choices == 1 and choices[1] == "Continue" then
						this.story:choose(1)
						choices = {}
					end
				end
			else
				print("can NOT continue")
			end
			print(ret)
			if (#choices > 0) then
				print("choices!!!")
				narrate(ret, choices)
			else
				narrate(ret)
			end
			if not have_choice and not have_paragraph then
				this:complete()
				this.active = false
			else
				print("can continue")
			end
		end,
		complete = function(this)
			print(this.name .. 'complete')
		end,
		story = narrator.init_story(book)
	}

	-- Begin the story

	return quest
end
function StartGameQuest()
	local quest = {}
	-- Parse a book from the Ink file.
	quest.activate = function(this)
		print('activate...')
		local book = narrator.parse_file('stories.initiation')
		local story = narrator.init_story(book)
		this._add_narration({
			book = book,
			story = story,
			activate = function(this)
			local mc_is_free = function()
				this.boat = true
				local ent = ecs_get_player_entity()
				ecs_character("params-set", ent, "gravity", true)
				ecs_character("params-set", ent, "buoyancy", true)
			end
			this.story:bind('mc_is_free', mc_is_free)
				this.story:begin()
				this:narration_update()
			end,
			event = function(this, event)
				if event == "narration_progress" then
					this:narration_update()
				end
				if event == "narration_answered" then
					local answer = this._get_narration_answer()
					this.story:choose(answer)
					this:narration_update()
				end
			end,
			finish = function(this)
			end,
			narration_update = function(this)
				local ret = ""
				local choices = {}
				local have_choice = false
				local have_paragraph = false
				print("narration_update")
				if this.story:can_continue() then
					print("CAN continue")
					have_paragraph = true
					local paragraph = this.story:continue(1)
					print(dump(paragraph))
					local text = paragraph.text
					if paragraph.tags then
						-- text = text .. ' #' .. table.concat(paragraph.tags, ' #')
						for i, tag in ipairs(paragraph.tags) do
							if tag == 'discard' then
								text = ''
							elseif tag == 'crash' then
								print(text)
								crash()
							end
							this:handle_tag(tag)
						end
					end
					ret = text
					if this.story:can_choose() then
						have_choice = true
						local ch = this.story:get_choices()
						for i, choice in ipairs(ch) do
							table.insert(choices, choice.text)
							print(i, dump(choice))
						end
						if #choices == 1 and choices[1] == "Ascend" then
							this.story:choose(1)
							choices = {}
						end
						if #choices == 1 and choices[1] == "Continue" then
							this.story:choose(1)
							choices = {}
						end
					end
				else
					print("can NOT continue")
				end
				print(ret)
				if (#choices > 0) then
					print("choices!!!")
					this._narration(ret, choices)
				else
					this._narration(ret, {})
				end
				if not have_choice and not have_paragraph then
					this._finish()
				end
			end,
			handle_tag = function(this, tag)
				print("tag: " .. tag)
			end,
		})
	end
	quest.finish = function(this)
	end
	return quest
end
function BoatControlQuest()
	-- Parse a book from the Ink file.
	local book = narrator.parse_file('stories.boat_control')
	local quest = Quest('boat control', book)
	quest.base = {}
	quest.base.activate = quest.activate
	quest.base.complete = quest.complete
	quest.boat = false
	quest.activate = function(this)
		print('activate...')
		local ent = ecs_get_player_entity()
		ecs_set_slot(this.boat.boat_id, ent, "seat1")
		-- ecs_character_set_actuator(ent, "sitting")
		ecs_character("set-actuator", ent, "idle")
		local boat_activated = function()
--			local ent = ecs_get_player_entity()
--			ecs_character_set_actuator(ent, "idle")
--			ecs_character_physics_control(ent, false)
--			ecs_character_params_set(ent, "gravity", false)
--			ecs_character_params_set(ent, "buoyancy", false)
		end
		this.story:bind('boat_activated', boat_activated)
		this.base.activate(this)
	end
	quest.complete = function(this)
		this.base.complete(this)
		this.active = false
		local ent = ecs_get_player_entity()
		ecs_set_slot(this.boat.boat_id, this.boat.passengers[1], "seat0")
		ecs_character("set-actuator", ent, "sitting")
		ecs_set_slot(this.boat.boat_id, ent, "seat1")
		ecs_character("set-actuator", ent, "sitting")
		print("SLOT", "captain_seat", "boo1")
		ecs_set_slot(this.boat.boat_id, ent, "captain_seat")
		ecs_character("set-actuator", ent, "sitting")
	end
	return quest
end
function create_actuator()
	return {
		is_complete = false,
		complete = function(this)
			return this.is_complete
		end,
		finish = function(this)
			this.is_complete = true
			ecs_character("set-actuator", this.entity, "")
			ecs_character("physics-control", this.entity, true)
			print("COMPLETE")
		end,
		forward = function(this)
			if (this.forward_animation) then
				this:animation(this.forward_animation)
			end
		end,
		animation = function(this, animation)
			print("ANIMATION: ", animation)
			ecs_character("set-actuator", this.entity, animation)
		end,
		event = function(this, event, trigger_entity, what_entity)
			print("actuator events: ", event)
			if event == "actuator_forward" then
				this:forward()
				return true
			elseif event == "_in_actuator_forward" then
				this:forward()
				return true
			elseif event == "actuator_exit" then
				this:finish()
				return true
			end
			if this.finish_events then
				for i, p in ipairs(this.finish_events) do
					if p == event then
						this:finish()
						break
					end
				end
				if this.is_complete then
					return true
				end
			end
			return false
		end,
	}
end
quests = {}
local actuator = nil
function check_actuator_event(event, trigger_entity, what_entity)
	print("check_actuator_event: ", event)
	--[[
	if event == "actuator_enter" then
		if not ecs_character("is-player", what_entity) then
			return
		end
		ecs_character("physics-control", what_entity, false)
		local animation = ecs_trigger_get_animation(trigger_entity)
		ecs_character("set-actuator", what_entity, animation)
		ecs_trigger_set_position(trigger_entity, what_entity)
		local ent = ecs_get_entity(what_entity)
		if (ent.is_character()) then
			print("character")
		end
		if (ent.is_player()) then
			print("player")
		end
--		crash()
		actuator = create_actuator()
		actuator.trigger = trigger_entity
		actuator.entity = what_entity
		actuator.forward = function(this)
			this:animation("swimming-edge-climb")
			local ent = ecs_get_player_entity()
			ecs_character("params-set", ent, "gravity", true)
			ecs_character("params-set", ent, "buoyancy", true)
		end
		actuator.base_event = actuator.event
		actuator.finish_events = {"animation:swimming-edge-climb:end"}
		actuator.event = function(this, event, te, we)
			print("actuator events 1: ", event)
			if this.base_event(this, event, te, we) then
				return true
			end
			return false
		end
		]]--
	if event == "character_enter" then
		if not ecs_character("is-player", trigger_entity) then
			return
		end
		actuator = create_actuator()
		actuator.trigger = trigger_entity
		actuator.entity = trigger_entity
		actuator.other_entity = what_entity
		actuator.forward_animation = "pass-character"
		actuator.finish_events = {"animation:pass-character:end"}
		actuator.base_event = actuator.event
		actuator.event = function(this, event, te, we)
			print("actuator events 2: ", event)
			if event == "actuator_exit" then
				this:animation("idle")
				return true
			end
			if this.base_event(this, event, te, we) then
				return true
			end
			if event == "character_enter" then
				-- why?
--				ecs_character_set_actuator(this.entity, "idle")
--				ecs_character_set_actuator(this.entity, "idle")
				return true
			elseif event == "actuator_enter" then
				-- why?
--				ecs_character_set_actuator(this.entity, "idle")
--				ecs_character_set_actuator(this.entity, "idle")
				return true
			end
			return false
		end
		actuator:animation("idle")
	end
end
-- ecs_set_debug_drawing(true)

local vehicles = {}
local player_vehicles = {}
local actuators = {}


function create_vehicle(vtype, passengers, position)
	local vehicle = {}
	vehicle.id = ecs_vehicle_set(vtype, position[1], position[2], position[3], position[4])
	vehicle.passengers = {}
	vehicle.actuators = {}
	vehicle.add_passenger = function(this, data)
		local npc_id = ecs_npc_set(data.model, data.position[1], data.position[2], data.position[3], data.position[4])
		table.insert(this.passengers, npc_id)
		ecs_character("physics-control", npc_id, false)
		ecs_character("params-set", npc_id, "gravity", false)
		ecs_character("params-set", npc_id, "buoyancy", false)
		ecs_set_slot(this.id, npc_id, data.slot)
		ecs_character("set-actuator", npc_id, data.animation)
	end
	for i, v in ipairs(passengers) do
		vehicle:add_passenger(v)
	end
	return vehicle
end
function create_boat()
	local boat = create_vehicle("boat", {
		model = "normal-female.glb",
		position = {0, 2, -10, 1.75},
		slot = "captain_seat",
		animation = "sitting"}, {0, 0, -10, 1.75})
--[[
	boat.id = ecs_vehicle_set("boat", 0, 0, -10, 1.75)
	local npc_id = ecs_npc_set("normal-female.glb", 0, 2, -10, 1.75)
	boat.passengers = {npc_id}
	ecs_character("physics-control", npc_id, false)
	ecs_character("params-set", npc_id, "gravity", false)
	ecs_character("params-set", npc_id, "buoyancy", false)
	print("SLOT", "captain_seat", "boo")
	ecs_set_slot(boat.boat_id, npc_id, "captain_seat")
	ecs_character("set-actuator", npc_id, "sitting")
--	ecs_set_animation_state(npc_id, "main", "actuator", true)
--	ecs_set_animation_state(npc_id, "actuator-state", "sitting", true)
]]--
	boat.event = function(this, event, event_data)
		print("boat: ", event)
		if event == "boat_control_enter" then
			local quest = BoatControlQuest()
			quest.boat = this
			quests[quest.name] = quest
			quest:activate()
			return true
		end
		if event == "boat_control_exit" then
			return true
		end
		return false
	end
	return boat
end
function create_actuator2(ent)
	print("create actuator")
	local act = {
		id = ent,
		activated = false,
		contained = {},
		enter = function(this, what)
			print(this.id, "visited by", what)
			if not ecs_character("is-player", what) then
				-- actuators are only for players
				return
			end
			ecs_character("physics-control", what, false)
			local animation = ecs_trigger_get_animation(this.id)
			print(animation)
			ecs_character("set-actuator", what, animation)
			ecs_trigger_set_position(this.id, what)
			local ent = ecs_get_entity(what)
			if (ent.is_character()) then
				print("character")
			end
			if (ent.is_player()) then
				print("player")
			end
			table.insert(this.contained, what)
			this.activated = true
			print("position: ", _ecs.position(what).y)
		end,
		exit = function(this, what)
			print(this.id, "left by", what)
			if this.contained[1] ~= what then
				crash()
			end
			ecs_character("set-actuator", this.contained[1], "")
			ecs_character("physics-control", this.contained[1], true)
			this.activated = false
			print("COMPLETE")
		end,
		event = function(this, event, trigger, what)
			if this.activated then
				print("!!!", event)
				if event == "actuator_forward" then
					this:animation("swimming-edge-climb")
					local ent = this.contained[1]
					ecs_character("params-set", ent, "gravity", true)
					ecs_character("params-set", ent, "buoyancy", true)
					return true
				elseif event == "actuator_backward" then
					return true
				elseif event == "animation:swimming-edge-climb:end" then
					this:exit(this.contained[1])
					return true
				end

			end
			return false
		end,
		animation = function(this, animation)
			if this.activated then
				print("ANIMATION: ", animation)
				local ent = this.contained[1]
				ecs_character("set-actuator", ent, animation)
			end
		end,
	}
	return act
end

function endswith(s, suffix)
    return string.sub(s, -#suffix) == suffix
end

function startswith(s, prefix)
    return string.sub(s, 1, #prefix) == prefix
end


setup_handler(function(event, trigger_entity, what_entity)
	print(event)
	local event_handled = false
	if startswith(event, "actuator_") and event ~= "actuator_created" then
		for i, act in ipairs(actuators) do
			if act.id == trigger_entity then
				if event == "actuator_enter" then
					if not act.activated then
						act:enter(what_entity)
						event_handled = true
						break
					end
				elseif event == "actuator_exit" then
					if act.activated then
						act:exit(what_entity)
						event_handled = true
						break
					end
				else
					if act.activated then
						if act:event(event, trigger_entity, what_entity) then
							event_handled = true
							break
						end
					end
				end
				event_handled = true
			end
		end
	elseif startswith(event, "animation:") and endswith(event, ":end") then
		for i, act in ipairs(actuators) do
			if act.activated then
				if act:event(event, trigger_entity, what_entity) then
					event_handled = true
					break
				end
			end
		end
	end
	if event_handled then
		return
	end
	if event == "actuator_enter" or  event == "actuator_exit" or event == "actuator_forward" then
		print("bad event:", event, trigger_entity, what_entity)
		crash()
	end

	for k, v in pairs(quests) do
		if v.active then
			local event_data = {}
			event_data.trigger_entity = trigger_entity
			event_data.object_entity = what_entity
			v:event(event, event_data)
		end
	end
	for i, vehicle in ipairs(vehicles) do
		print(i, vehicle)
		if vehicle.event then
			local event_data = {}
			event_data.trigger_entity = trigger_entity
			event_data.object_entity = what_entity
			if vehicle:event(event, event_data) then
				event_handled = true
			end
		end
	end
	if event_handled then
		return
	end
	if event == "startup" then
		--
	elseif event == "narration_progress" then
		print("narration progress!")
	elseif event == "narration_answered" then
		local answer = narration_get_answer()
		print("answered:", answer)
	elseif event == "spawn_player" then
	elseif event == "new_game" then
		local ent = ecs_get_player_entity()
		ecs_character("params-set", ent, "gravity", true)
		ecs_character("params-set", ent, "buoyancy", false)
		local start_boat = create_boat()
		table.insert(vehicles, start_boat)
		table.insert(player_vehicles, start_boat)
		local quest = StartGameQuest()
		add_quest("main", quest)
--		quests[quest.name] = quest
--		for k, v in pairs(quests) do
--			print(k, v.active)
--		end
--		quest:activate()
	elseif event == "actuator_created" then
		print(trigger_entity)
		local act = create_actuator2(trigger_entity)
		table.insert(actuators, act)
	--[[
	else
		if not actuator then
			check_actuator_event(event, trigger_entity, what_entity)
		else
			if not actuator:event(event, trigger_entity, what_entity) then
				crash()
			end
			if actuator:complete() then
				print("ACTUATOR COMPLETE")
				print("EXIT ACTUATOR")
				actuator = nil
			end
		end
	--]]
	end
end)

setup_action_handler("talk", {
	activate = function(this)
		local book = narrator.parse_file('stories.talk')
		this.story = narrator.init_story(book)
		local get_crash_bind = function(this)
			local crash_bind = function()
				print("variables")
				print(dump(this.story.variables))
				crash()
			end
			return crash_bind
		end
		this.story:bind('crash', get_crash_bind(this))
		local props = this._get_properties()
		local goals = this._get_goals()
		print("node activated")
		-- print(dump(goals))
		local json_data = json.decode(props)
		print(dump(json_data))
		for i, v in ipairs(goals) do
			print("Goal: ", i)
			local goal_data = json.decode(v)
			print(dump(goal_data))
		end
		this.story:begin()
		this:narration_update()
		get_crash_bind(this)()
		crash()
	end,
	event = function(this, event)
		if event == "narration_progress" then
			this:narration_update()
		end
		if event == "narration_answered" then
			local answer = this._get_narration_answer()
			this.story:choose(answer)
			this:narration_update()
		end
	end,
	finish = function(this)
	end,
	narration_update = function(this)
		local ret = ""
		local choices = {}
		local have_choice = false
		local have_paragraph = false
		print("narration_update")
		if this.story:can_continue() then
			print("CAN continue")
			have_paragraph = true
			local paragraph = this.story:continue(1)
			print(dump(paragraph))
			local text = paragraph.text
			if paragraph.tags then
				-- text = text .. ' #' .. table.concat(paragraph.tags, ' #')
				for i, tag in ipairs(paragraph.tags) do
					if tag == 'discard' then
						text = ''
					elseif tag == 'crash' then
						print(text)
						crash()
					end
					this:handle_tag(tag)
				end
			end
			ret = text
			if this.story:can_choose() then
				have_choice = true
				local ch = this.story:get_choices()
				for i, choice in ipairs(ch) do
					table.insert(choices, choice.text)
					print(i, dump(choice))
				end
				if #choices == 1 and choices[1] == "Ascend" then
					this.story:choose(1)
					choices = {}
				end
				if #choices == 1 and choices[1] == "Continue" then
					this.story:choose(1)
					choices = {}
				end
			end
		else
			print("can NOT continue")
		end
		print(ret)
		if (#choices > 0) then
			print("choices!!!")
			this._narration(ret, choices)
		else
			this._narration(ret, {})
		end
		if not have_choice and not have_paragraph then
			this._finish()
		end
	end,
	handle_tag = function(this, tag)
		print("tag: " .. tag)
	end,
})
setup_action_handler("sit", {
	activate = function(this)
		print('sit activate')
		crash()
	end,
	event = function(this, event)
		print('event', event)
	end,
	finish = function(this)
	end,
})
setup_action_handler("use", {
	activate = function(this)
		print('sit activate')
		crash()
	end,
	event = function(this, event)
		print('event', event)
	end,
	finish = function(this)
	end,
})
--[[
active_dialogues = {}
setup_action_handler("talk", function(town, index, word)
	local ret = ""
	local choices = {}
	local have_choice = false
	local have_paragraph = false
	local book = narrator.parse_file('stories.talk')
	local story = narrator.init_story(book)
	if story == nil then
		crash()
	end
	story:begin()
	narrate("Boo!!!!")
	if story.can_continue() then
		local paragraph = story:continue(1)
		print(dump(paragraph))
		if story:can_choose() then
			have_choice = true
			local ch = story:get_choices()
			for i, choice in ipairs(ch) do
				table.insert(choices, choice.text)
				print(i, dump(choice))
			end
			if #choices == 1 and choices[1] == "Ascend" then
				story:choose(1)
				choices = {}
			end
			if #choices == 1 and choices[1] == "Continue" then
				this.story:choose(1)
				choices = {}
			end
		end
	end
	if (#choices > 0) then
		print("choices!!!")
		narrate(ret, choices)
	else
		narrate(ret)
	end
		if not have_choice and not have_paragraph then
			-- complete
			crash()
	else
		print("can continue")
	end

end)
]]--

main_menu()

