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, "学習行動:" .. 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 beforeCaptureInfo = nil;
		if (captureInfo == nil)
		then
			return;
		end

		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

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

		-- tracerの履歴を見て前回行動に相当するものを検索
		-- tracedBeforeからなので開始Indexは2
		for i = 2, 5
		do
			beforeCaptureInfo = tracer[self.target]:history(i);
			if (beforeCaptureInfo == nil)
			then
				break;
			end

			if (isRelativeMotion(beforeCaptureInfo.act))
			then
				-- AI切り替え時のスキマ対応 act == 0 はありえない。
				if (not self.relationTable:hasNextMotion(beforeCaptureInfo.act))
				then
					self.relationTable:addNextMotion(MotionRelation.new(beforeCaptureInfo.act));
					self.relationTable.frequency[beforeCaptureInfo.act] = 0;
				end
				break;
			end
		end

		if (beforeCaptureInfo == nil)
		then
			-- 連鎖学習不能
			return;
		end

		if (beforeCaptureInfo.act == 0)
		then
			-- 基点とみなす
			self:registMotionRelation(self.relationTable, MotionRelation.new(captureInfo.act));
		else
			-- self.relationTableにないとおかしい。
			self:registMotionRelation(self.relationTable:getNextMotion(beforeCaptureInfo.act), MotionRelation.new(captureInfo.act));
		end
		self.beforeLearnedCaptureInfo = captureInfo;
	end

	function LearnRelation:registMotionRelation(targetMotionRelation, addMotionRelation)
		targetMotionRelation:addNextMotion(addMotionRelation);

		-- 最初の一回だけは root に保存。ほんとはfrequency = 0 だけどね。まあいいや。⇒ダメ
		if (not self.relationTable:hasNextMotion(addMotionRelation.act))
		then
			self.relationTable:addNextMotion(addMotionRelation);
			if (not isRootMotion(addMotionRelation.act))
			then
				self.relationTable.frequency[addMotionRelation.act] = 0;
			end
		end
	end
