extends Spatial
class_name SmartObject

# Declare member variables here. Examples:
# var a = 2
# var b = "text"


# Called when the node enters the scene tree for the first time.

# Called every frame. 'delta' is the elapsed time since the previous frame.
#func _process(delta):
#	pass
var first
var second
var script1
var script2
var state = -1
var _state

class SmartObjectState:
	var first
	var second
	var script1
	var script2
	var active = false
	var next_cond
	var exit_cond
	var stage_name
	func init(n, p1, s1, p2, s2):
		stage_name = n
		first = p1
		second = p2
		script1 = s1
		script2 = s2
		first.set_meta("smart_object", true)
		second.set_meta("smart_object", true)
	func activate():
		second.add_collision_exception_with(first)
		second.global_transform = first.global_transform
		first.smart_obj(script1)
		second.smart_obj(script2)
		active = true
	func leave():
		active = false
	func process():
		if active:
			second.global_transform = first.global_transform
	func finalize():
		second.remove_collision_exception_with(first)
		first.do_stop()
		second.do_stop()
		first.set_meta("smart_object", false)
		second.set_meta("smart_object", false)

func parse(sc: String):
	var stages = {}
	var init_stage
	var cur_stage
	var cur_character
	for k in sc.split("\n"):
		var sc_line: String = k
		sc_line = sc_line.strip_edges()
		if sc_line.substr(0, 1) == "#":
			continue
		var words: = Array(sc_line.split(" "))
		if words[0] == "stage":
			cur_stage = words[1]
			if !init_stage:
				init_stage = cur_stage
		elif words[0] == "init:":
			init_stage = cur_stage
		elif words[0] == "first:":
			cur_character = "first"
		elif words[0] == "second:":
			cur_character = "second"
		elif words[0] == "next_cond":
			assert(cur_stage)
			if !stages.has(cur_stage):
				stages[cur_stage] = {}
			stages[cur_stage].next_cond = words.slice(1, words.size() - 1)
		elif words[0] == "exit_cond":
			assert(cur_stage)
			if !stages.has(cur_stage):
				stages[cur_stage] = {}
			stages[cur_stage].exit_cond = words.slice(1, words.size() - 1)
		elif words[0] == "next_stage":
			assert(cur_stage)
			if !stages.has(cur_stage):
				stages[cur_stage] = {}
			stages[cur_stage].next_stage = words[1]
		elif words[0] == "mod_stat":
			assert(cur_stage)
			assert(cur_character)
			if !stages.has(cur_stage):
				stages[cur_stage] = {}
			if !stages[cur_stage].has(cur_character):
				stages[cur_stage][cur_character] = []
			if !stages[cur_stage].has("mod_stats"):
				stages[cur_stage].mod_stats = {}
			if !stages[cur_stage].mod_stats.has(cur_character):
				stages[cur_stage].mod_stats[cur_character] = {}
			stages[cur_stage].mod_stats[cur_character][words[1]] = float(words[2])
		else:
			assert(cur_stage)
			assert(cur_character)
			if !stages.has(cur_stage):
				stages[cur_stage] = {}
			if !stages[cur_stage].has(cur_character):
				stages[cur_stage][cur_character] = []
			stages[cur_stage][cur_character].push_back(words)
	for k in stages:
		for e in stages[k]:
			if e == "mod_stats":
				continue
			if !stages[k].has("mod_stats"):
				stages[k].mod_stats = {}
			if !stages[k].mod_stats.has(e):
				stages[k].mod_stats[e] = {}
	stages.init_stage = init_stage
	print(stages)
	return stages

func activate(npc, m_script, s, s_script):
	main.init(npc, m_script, s, s_script)
	_state = main
	main.activate()
var _stages
var _exit_cond
var npcs = {}
func activate2(npc, s, script):
	npcs.first = npc
	npcs.second = s
	_stages = parse(script)
	for k in _stages.keys():
		if k == "init_stage":
			continue
		var st = SmartObjectState.new()
		_stages[k].obj = st
		_stages[k].obj.init(k, npc, _stages[k].first, s, _stages[k].second)
		if _stages[k].has("next_cond"):
			_stages[k].obj.next_cond = _stages[k].next_cond
		if _stages[k].has("exit_cond"):
			_stages[k].obj.exit_cond = _stages[k].exit_cond
		if k == _stages.init_stage:
			_state = st
	_state.activate()
func cond_stat_morethan(which, stat, val):
	if npcs[which].get_meta(stat) > float(val):
		return true
	return false
func cond_stat_lessthan(which, stat, val):
	if npcs[which].get_meta(stat) < float(val):
		return true
	return false

func _physics_process(delta):
	if _state:
		_state.process()
		var nextc = false
		var leave = false
		for k in _stages[_state.stage_name]:
			if k in ["mod_stats", "next_stage", "next_cond", "obj"]:
				continue
			var mod_stats = _stages[_state.stage_name].mod_stats[k]
			for l in mod_stats.keys():
				if npcs.has(k):
					var sval = npcs[k].get_meta(l)
					sval += mod_stats[l] * delta
					npcs[k].set_meta(l, sval)
		if _state.next_cond:
			var c = _state.next_cond
			if c.size() > 1:
				nextc = callv(c[0], c.slice(1, c.size() - 1))
			else:
				nextc = callv(c[0], [])
		if _state.exit_cond:
			var c = _state.exit_cond
			if c.size() > 1:
				leave = callv(c[0], c.slice(1, c.size() - 1))
			else:
				leave = callv(c[0], [])
		if nextc:
			_state.leave()
			if _stages[_state.stage_name].has("next_stage"):
				var next = _stages[_state.stage_name].next_stage
				_state = _stages[next].obj
				_state.activate()
			else:
				_state.finalize()
				_state = null
				queue_free()
		if leave:
			_state.finalize()
			_state = null
			queue_free()
var main
func _ready():
	main = SmartObjectState.new()
