require("debug.lua");
if(DEBUG_FUNCTION)
then
	require("101_common_oop.lua");
	require("111_logger.lua");
	require("113_common_collections.lua");
	require("151_common_environment.lua");
	require("152_global_instance.lua");
	require("161_common_functions.lua");
	require("162_round_utils.lua");
	require("201_capture_info.lua");
end

----------------------------------------------------------------------------------------------------------
--
-- 学習関係常駐物共通
--
----------------------------------------------------------------------------------------------------------
AbstractLearnDaemon=extends(NamedObject);

	function AbstractLearnDaemon:constructor(name, target, enable, learnSituation, learnCondition)
		self.name = name;						-- 学習インスタンス名
		self.target = target;					-- 学習対象
		self.enable = enable;					-- 学習 on/off
		self.learnSituation = learnSituation;	-- 学習する状況
		self.learnCondition = learnCondition;	-- 学習条件
	end

	function AbstractLearnDaemon:learn()
		while (not battleFinished())
		do
			self.target = learningTarget;
			self.enable = runningLearning;
			if ((self.enable) and (self.learnSituation(self.target)))
			then
				self:process();
			end
			yield();
		end
	end

	function AbstractLearnDaemon:process()
		error("process実装してね");
	end

----------------------------------------------------------------------------------------------------------
--
-- 行動学習処理クラス
--
----------------------------------------------------------------------------------------------------------
LearnMotion=extends(AbstractLearnDaemon);

	function LearnMotion:constructor(name, target, enable, learnSituation, learnCondition)
		self.name = name;						-- 学習インスタンス名
		self.target = target;					-- 学習対象
		self.enable = enable;					-- 学習 on/off
		self.learnSituation = learnSituation;	-- 学習する状況
		self.learnCondition = learnCondition;	-- 学習条件
		self.learnTable = learnTableManager:getLearnTable(self.name);	-- 学習テーブル(LearnTableインスタンス 301_learn_table.lua)
		self.beforeLearnedCaptureInfo = nil;
	end

	function LearnMotion:process()

		-- tracedCurrentはある前提で・・・。
		-- from 201_motion_tracer.lua
		local captureInfo = tracer[self.target]:tracedCurrent();
		if (captureInfo == nil)
		then
			return;
		end
		--print(self.name, self.target, tracer[self.target]:tracedCurrent():serialize());

		--[[
		if (captureInfo.frame < LEARNING_FRAME_BORDER)
		then
			return;
		end
		]]--

		if (captureInfo:equals(self.beforeLearnedCaptureInfo))
		then
			return;
		end

		if (not self.learnCondition(self.target))
		then
			return;
		end

		self.learnTable:add(captureInfo);
		self.beforeLearnedCaptureInfo = captureInfo;
		logger:debug(self.name, " 学習対象:" .. self.target ..
								" 学習キャラ:" .. captureInfo:getParameter(CaptureInfo_my_char) .. 
								" 学習行動:" .. captureInfo.act);
	end


----------------------------------------------------------------------------------------------------------
--
-- 行動連鎖学習処理クラス
--
----------------------------------------------------------------------------------------------------------
LearnRelation=extends(AbstractLearnDaemon);

	function LearnRelation:constructor(name, target, enable, learnSituation, learnCondition)
		self.name = name;						-- 学習インスタンス名
		self.target = target;					-- 学習対象
		self.enable = enable;					-- 学習 on/off
		self.learnSituation = learnSituation;	-- 学習する状況
		self.learnCondition = learnCondition;	-- 学習条件
		self.relationTable = learnTableManager:getRelationTable(self.name);
		self.beforeLearnedCaptureInfo = nil;
	end

	function LearnRelation:process()

		-- from 201_motion_tracer.lua
		local captureInfo = tracer[self.target]:tracedCurrent();
		local beforeTracedCaptureInfo = tracer[self.target]:tracedBefore();
		local beforeTracedCaptureInfoBefore = tracer[self.target]:history(3)

		if (captureInfo == nil)
		then
			return;
		end

		--[[
		if (beforeTracedCaptureInfo ~= nil)
		then
			print("★", beforeTracedCaptureInfo.act, captureInfo.act);
		end

		if (captureInfo.frame < LEARNING_FRAME_BORDER)
		then
			return;
		end
		]]--

		-- 同じインスタンス学習はしない
		if (captureInfo:equals(self.beforeLearnedCaptureInfo))
		then
			return;
		end

		--[[
		if (beforeTracedCaptureInfo ~= nil)
		then
			print("★★", beforeTracedCaptureInfo.act, captureInfo.act);
		end
		]]--

		-- 現在棒立ち状態は学習しない。
		if (captureInfo.act == 0)
		then
			return;
		end
		
		-- 学習条件にそぐわないものは学習しない
		if (not self.learnCondition(self.target))
		then
			return;
		end


		--[[
		if (beforeTracedCaptureInfo ~= nil)
		then
			print("★★★", beforeTracedCaptureInfo.act, captureInfo.act);
		end
		]]--

		--print(self.name, "tables:", getTargetAct(self.target), self.beforeLearnedCaptureInfo, beforeTracedCaptureInfoBefore, beforeTracedCaptureInfo, captureInfo);
		--[[
		if (beforeTracedCaptureInfo ~= nil) and (beforeTracedCaptureInfoBefore == nil)
		then
			print("★", beforeTracedCaptureInfo.act, captureInfo.act);
		elseif (beforeTracedCaptureInfo ~= nil) and (beforeTracedCaptureInfoBefore ~= nil)
		then
			print("★", beforeTracedCaptureInfoBefore.act, beforeTracedCaptureInfo.act, captureInfo.act);
		end
		]]--

		-- どうせ専用なのでいいや。⇒よくない
		--[[
		if (not isRelativeMotion(captureInfo.act))
		then
			return;
		end
		]]--

		if (beforeTracedCaptureInfo == nil)
		then
			--print("beforeTracedCaptureInfo == nil");
			-- 基点とみなす
			self:registMotionRelation(self.relationTable, MotionRelation.new(captureInfo.act));
		elseif (beforeTracedCaptureInfo.act == 0)
		then
			--print("beforeTracedCaptureInfo.act == 0", self.beforeLearnedCaptureInfo, beforeTracedCaptureInfo, captureInfo);
			-- 基点とみなす
			self:registMotionRelation(self.relationTable, MotionRelation.new(captureInfo.act));
		elseif (not self.relationTable:hasNextMotion(beforeTracedCaptureInfo.act))
		then
			--print("本来行動連鎖の要素ではないが");
			-- 本来行動連鎖の要素ではないが、基点の1つとなりうるため頻度は強制0。
			-- あくまで行動連鎖のキーとして登録。例えば落下中⇒攻撃とか。
			self.relationTable:addNextMotion(MotionRelation.new(beforeTracedCaptureInfo.act));
			self.relationTable.frequency[beforeTracedCaptureInfo.act] = 0;
			self:registMotionRelation(self.relationTable:getNextMotion(beforeTracedCaptureInfo.act), MotionRelation.new(captureInfo.act));
		else
			--print("それ以外");
			-- self.relationTableにないとおかしい。
			--print(beforeTracedCaptureInfo.act, captureInfo.act, self.relationTable:hasNextMotion(beforeTracedCaptureInfo.act));
			self:registMotionRelation(self.relationTable:getNextMotion(beforeTracedCaptureInfo.act), MotionRelation.new(captureInfo.act));
		end
		--[[
		if (self.beforeLearnedCaptureInfo == nil)
		then
			-- 基点とみなす
			self:registMotionRelation(self.relationTable, MotionRelation.new(captureInfo.act));
		elseif (self.beforeLearnedCaptureInfo.act == 0)
		then
			-- 基点とみなす
			self:registMotionRelation(self.relationTable, MotionRelation.new(captureInfo.act));
		else
			-- self.relationTableにないとおかしい。
			--print(self.beforeLearnedCaptureInfo.act, captureInfo.act, self.relationTable:hasNextMotion(self.beforeLearnedCaptureInfo.act));
			self:registMotionRelation(self.relationTable:getNextMotion(self.beforeLearnedCaptureInfo.act), MotionRelation.new(captureInfo.act));
		end
		]]--
		self.beforeLearnedCaptureInfo = captureInfo;
		if (beforeTracedCaptureInfo ~= nil)
		then
		logger:debug(self.name, " 学習対象:" .. self.target ..
								" 学習キャラ:" .. captureInfo:getParameter(CaptureInfo_my_char) .. 
								" 前回行動:" .. beforeTracedCaptureInfo.act ..
								" 学習行動:" .. captureInfo.act);
		else
		logger:debug(self.name, " 学習対象:" .. self.target ..
								" 学習キャラ:" .. captureInfo:getParameter(CaptureInfo_my_char) .. 
								" 学習行動:" .. captureInfo.act);
		end
	end

	function LearnRelation:registMotionRelation(targetMotionRelation, addMotionRelation)

		print("★★regist:", targetMotionRelation.act, addMotionRelation.act);

		targetMotionRelation:addNextMotion(addMotionRelation);

		-- 最初の一回だけは root に保存。frequency = 0 は強制。
		if (not self.relationTable:hasNextMotion(addMotionRelation.act))
		then
			self.relationTable:addNextMotion(addMotionRelation);
			-- モーション値 0 から行動できないもの、連鎖行動ではないものは頻度0強制。
			if (not isRootMotion(addMotionRelation.act))
			then
				self.relationTable.frequency[addMotionRelation.act] = 0;
			end
		end
	end
