/*
 * Copyright (C) 2004-2014 L2J DataPack
 * 
 * This file is part of L2J DataPack.
 * 
 * L2J DataPack is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * L2J DataPack is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package ai.group_template;

import ai.npc.AbstractNpcAI;

import com.l2jserver.gameserver.GameTimeController;
import com.l2jserver.gameserver.ai.CtrlIntention;
import com.l2jserver.gameserver.datatables.SkillTable;
import com.l2jserver.gameserver.datatables.SpawnTable;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.L2Spawn;
import com.l2jserver.gameserver.model.L2World;
import com.l2jserver.gameserver.model.Location;
import com.l2jserver.gameserver.model.actor.L2Attackable;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.skills.AbnormalVisualEffect;
import com.l2jserver.gameserver.model.skills.L2Skill;
import com.l2jserver.gameserver.network.NpcStringId;
import com.l2jserver.gameserver.network.clientpackets.Say2;
import com.l2jserver.gameserver.util.Util;

/**
 * Sel Mahum Training Ground AI for squads and chefs.
 * @author GKR
 */
public final class SelMahumSquad extends AbstractNpcAI
{
	private static final boolean AI_OMIT = true;	// まわりにプレイヤーがいないときはAIを手抜きする
	private static final boolean FIX_SKILL_6688_TARGET = true;
	private static final long CHEF_DISABLE_REWARD_DELAY = 60000;
	private static final long CHEF_SET_INVUL_DELAY = 60000;
	private static final long CHEF_INVUL_TIME = 120000;

	// NPC's
	private static final int CHEF = 18908;
	private static final int FIRE = 18927;
	private static final int STOVE = 18933;
	
	private static final int OHS_Weapon = 15280;
	private static final int THS_Weapon = 15281;
	
	// Sel Mahum Squad Leaders
	private static final int[] SQUAD_LEADERS =
	{
		22786,
		22787,
		22788
	};
	
	private static final NpcStringId[] CHEF_FSTRINGS =
	{
		NpcStringId.I_BROUGHT_THE_FOOD,
		NpcStringId.COME_AND_EAT
	};
	
	private static final int FIRE_EFFECT_BURN = 1;
	private static final int FIRE_EFFECT_NONE = 2;
	
	private static final int MAHUM_EFFECT_EAT = 1;
	private static final int MAHUM_EFFECT_SLEEP = 2;
	private static final int MAHUM_EFFECT_NONE = 3;
	
	private SelMahumSquad()
	{
		super(SelMahumSquad.class.getSimpleName(), "ai/group_template");
		
		addAttackId(CHEF);
		addAttackId(SQUAD_LEADERS);
		addEventReceivedId(CHEF, FIRE, STOVE);
		addEventReceivedId(SQUAD_LEADERS);
		addFactionCallId(SQUAD_LEADERS);
		addKillId(CHEF);
		addMoveFinishedId(SQUAD_LEADERS);
		addNodeArrivedId(CHEF);
		addSkillSeeId(STOVE);
		addSpawnId(CHEF, FIRE, STOVE);
		addSpawnId(SQUAD_LEADERS);
		addSpellFinishedId(CHEF);
		
if (!com.l2jserver.Config.FIX_onSpawn_for_SpawnTable) {{
		// Send event to monsters, that was spawned through SpawnTable at server start (it is impossible to track first spawn)
		for (L2Spawn npcSpawn : SpawnTable.getInstance().getSpawns(CHEF))
		{
			onSpawn(npcSpawn.getLastSpawn());
		}
		for (L2Spawn npcSpawn : SpawnTable.getInstance().getSpawns(FIRE))
		{
			onSpawn(npcSpawn.getLastSpawn());
		}
}}
	}
	
	@Override
	public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
	{
		switch (event)
		{
			case "chef_disable_reward": // 2019005
			{
				// event, CHEF, null
				if (!isValidQuestTimer(event, npc, player))
					break;
				npc.getVariables().set("REWARD_TIME_GONE", true); // i_ai6 = 1
				break;
			}
			case "chef_heal_player": // 2019003
			{
				// event, CHEF, player
				if (!isValidQuestTimer(event, npc, player))
					break;
				healPlayer(npc, player);
				npc.getVariables().set("BUSY_STATE", false); // i_ai2 = 0
				break;
			}
			case "chef_remove_invul": // 2019006
			{
				// event, CHEF, player
				if (!isValidQuestTimer(event, npc, player))
					break;
				npc.stopAbnormalVisualEffect(true, AbnormalVisualEffect.INVINCIBILITY);
				npc.setIsInvul(false);
				npc.getVariables().remove("INVUL_REMOVE_TIMER_STARTED"); // i_ai5 = 0
				if (player != null && !player.isDead() && npc.getKnownList().knowsThePlayer(player))
				{
					attackPlayer((L2Attackable) npc, player);
				}
				break;
			}
			case "chef_set_invul":
			{
				// event, CHEF, null
				if (!isValidQuestTimer(event, npc, player))
					break;
				npc.setIsInvul(true);
				npc.startAbnormalVisualEffect(true, AbnormalVisualEffect.INVINCIBILITY);
				break;
			}
			case "fire":
			{
				// event, FIRE, null
				startQuestTimer("fire", 30000 + getRandom(5000), npc, null);
if (AI_OMIT) {{
				if (!canFire(npc))
					break;
}}
				
				if (getRandom(GameTimeController.getInstance().isNight() ? 2 : 4) < 1)
				{
					if (npc.getDisplayEffect() != FIRE_EFFECT_BURN)
					{
						npc.setDisplayEffect(FIRE_EFFECT_BURN); // fire burns
						broadcastEvent("SCE_CAMPFIRE_START", npc, 600, null);
					}
				}
				else
				{
					if (npc.getDisplayEffect() != FIRE_EFFECT_NONE)
					{
						npc.setDisplayEffect(FIRE_EFFECT_NONE); // fire goes out
						broadcastEvent("SCE_CAMPFIRE_END", npc, 600, null);
					}
				}
				break;
			}
			case "fire_arrived":
			{
				// event, SQUAD_LEADERS[], null
				if (npc.isNoRndWalk()) // i_ai0 == 1
				{
					// myself.i_quest0 = 1;
					npc.setIsRunning(false);
					npc.setTarget(npc);
					
					if (npc.getVariables().getBoolean("BUSY_STATE", false)) // Eating - i_ai3 = 1
					{
						npc.doCast(SkillTable.getInstance().getInfo(6332, 1));
						npc.setDisplayEffect(MAHUM_EFFECT_EAT);
					}
					else
					{
						npc.doCast(SkillTable.getInstance().getInfo(6331, 1));
						npc.setDisplayEffect(MAHUM_EFFECT_SLEEP);
					}
					
					startQuestTimer("remove_effects", 300000, npc, null);
				}
				break;
			}
			case "notify_dinner":
			{
				// event, CHEF, nujll
				broadcastEvent("SCE_DINNER_EAT", npc, 600, null);
				break;
			}
			case "remove_effects":
			{
				// event, SQUAD_LEADERS[], null
				// myself.i_quest0 = 0;
				npc.setIsRunning(true);
				npc.setDisplayEffect(MAHUM_EFFECT_NONE);
				break;
			}
			case "return_from_fire":
			{
				// event, SQUAD_LEADERS[], null
				if (!isValidQuestTimer(event, npc, player))
					break;
if (AI_OMIT) {{
				if (!canMove(npc))
					break;
}}
				final L2Attackable mob = (L2Attackable) npc;
				if (!mob.isInCombat() && !mob.isNoRndWalk() && !mob.isReturningToSpawnPoint())
				{
					mob.setisReturningToSpawnPoint(true);
					mob.returnHome();
				}
				break;
			}
		}
		return null;
	}
	
	@Override
	public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon, L2Skill skill)
	{
		if (npc.getId() == CHEF)
		{
			if (npc.compareAndSetScriptValue("INVUL_REMOVE_TIMER_STARTED", false, true)) // if i_ai5 == 0 then 1
			{
				startQuestTimer("chef_disable_reward", CHEF_DISABLE_REWARD_DELAY, npc, null); // 2019005
				startQuestTimer("chef_set_invul", CHEF_SET_INVUL_DELAY, npc, null); // 2019006
				startQuestTimer("chef_remove_invul", CHEF_SET_INVUL_DELAY + CHEF_INVUL_TIME, npc, attacker); // 2019004
			}
			if (npc.compareAndSetScriptValue("BUSY_STATE", false, true)) // if i_ai2 == 0 then i_ai2 = 1
			{
				startQuestTimer("chef_heal_player", 1000, npc, attacker); // 2019003
			}
		}
		else if (Util.contains(SQUAD_LEADERS, npc.getId()))
		{
			handlePreAttackMotion(npc);
		}
		return null;
	}
	
	@Override
	public String onFactionCall(L2Npc npc, L2Npc caller, L2PcInstance attacker, boolean isSummon)
	{
		// SQUAD_LEADERS[]
		handlePreAttackMotion(npc);
		return null;
	}
	
	@Override
	public String onEventReceived(String eventName, L2Npc sender, L2Npc receiver, L2Object reference)
	{
		switch (eventName)
		{
			case "SCE_DINNER_CHECK":
			{
				if (receiver.getId() == FIRE)
				{
					// sender=CHEF, receiver=FIRE, reference=null
					receiver.setDisplayEffect(FIRE_EFFECT_BURN);
					final L2Npc stove = addSpawn(STOVE, receiver.getX(), receiver.getY(), receiver.getZ() + 100, 0, false, 0);
					stove.setSummoner(receiver);
					startQuestTimer("notify_dinner", 2000, receiver, null); // @SCE_DINNER_EAT
					broadcastNpcSay(sender, Say2.NPC_ALL, CHEF_FSTRINGS[getRandom(2)], 1250);
				}
				break;
			}
			case "SCE_CAMPFIRE_START":
			{
				if (Util.contains(SQUAD_LEADERS, receiver.getId()))
				{
					// sender=FIRE, receiver=SQUAD_LEADERS[], reference=null
if (AI_OMIT) {{
					if (!canMove(receiver))
						break;
}}
					if (!receiver.isNoRndWalk() && !receiver.isDead() && !receiver.isInCombat())
					{
						setIsNoRndWalk(receiver, true); // Moving to fire - i_ai0 = 1
						receiver.setIsRunning(true);
						final Location loc = sender.getPointInRange(100, 200);
						receiver.getVariables().set("DESTINATION_X", loc.getX());
						receiver.getVariables().set("DESTINATION_Y", loc.getY());
						receiver.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, loc);
					}
			}
				break;
			}
			case "SCE_CAMPFIRE_END":
			{
				if (receiver.getId() == STOVE)
				{
					// sender=FIRE, receiver=STOVE, reference=null
					if (receiver.getSummoner() == sender)
					{
						receiver.deleteMe();
					}
				}
				else if (Util.contains(SQUAD_LEADERS, receiver.getId()))
				{
					// sender=FIRE, receiver=SQUAD_LEADERS[], reference=null
					final L2Attackable mob = (L2Attackable) receiver;
					if (!mob.isInCombat() && !mob.isReturningToSpawnPoint() && mob.isNoRndWalk())
					{
						setIsNoRndWalk(mob, false);
						mob.getVariables().remove("BUSY_STATE");
						mob.setDisplayEffect(MAHUM_EFFECT_NONE);	//+[JOJO]
						mob.setRHandId(THS_Weapon);
						startQuestTimer("return_from_fire", getRandom(2000, 4000), mob, null);
					}
				}
				break;
			}
			case "SCE_DINNER_EAT":
			{
				if (Util.contains(SQUAD_LEADERS, receiver.getId()))
				{
					// sender=FIRE, receiver=SQUAD_LEADERS[], reference=null
if (AI_OMIT) {{
					if (!canMove(receiver))
						break;
}}
					if (!receiver.isDead() && !receiver.isInCombat() && receiver.compareAndSetScriptValue("BUSY_STATE", false, true)) // Eating - i_ai3 = 1
					{
						final boolean isNoRndWalk = receiver.isNoRndWalk();
						setIsNoRndWalk(receiver, true); // Moving to fire - i_ai0 = 1
						if (isNoRndWalk && !receiver.isMoving() && receiver.isInsideRadius(sender, 200, false, true))
						{
							broadcastNpcSay(receiver, Say2.NPC_ALL, NpcStringId.LOOKS_DELICIOUS);
							onAdvEvent("fire_arrived", receiver, null);
						}
						else
						{
							broadcastNpcSay(receiver, Say2.NPC_ALL, getRandom(3) < 1 ? NpcStringId.LOOKS_DELICIOUS : NpcStringId.LETS_GO_EAT);
							/*if (receiver.getDisplayEffect() != MAHUM_EFFECT_NONE)*/ receiver.setDisplayEffect(MAHUM_EFFECT_NONE);	//+[JOJO]
							if (receiver.getRightHandItem() != THS_Weapon) receiver.setRHandId(THS_Weapon);
							receiver.setIsRunning(true);
							final Location loc = sender.getPointInRange(100, 200);
							receiver.getVariables().set("DESTINATION_X", loc.getX());
							receiver.getVariables().set("DESTINATION_Y", loc.getY());
							receiver.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, loc);
						}
					}
				}
				break;
			}
		}
		
		return null;
	}
	
	@Override
	public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
	{
		// CHEF
		if (!npc.getVariables().getBoolean("REWARD_TIME_GONE", false))
		{
			npc.dropItem(killer, 15492, 1);
		}
		//cancelQuestTimer("chef_remove_invul", npc, null);
		//cancelQuestTimer("chef_disable_reward", npc, null);
		//cancelQuestTimer("chef_heal_player", npc, null);
		//cancelQuestTimer("chef_set_invul", npc, null);
		
		return null;
	}
	
	@Override
	public boolean onMoveFinished(L2Npc npc)
	{
		// SQUAD_LEADERS[]
		// Npc moves to fire
		if (npc.isNoRndWalk() && npc.getX() == npc.getVariables().getInt("DESTINATION_X") && npc.getY() == npc.getVariables().getInt("DESTINATION_Y"))
		{
			npc.getVariables().remove("DESTINATION_X");	//+[JOJO]
			npc.getVariables().remove("DESTINATION_Y");	//+[JOJO]
			npc.setRHandId(OHS_Weapon);
			startQuestTimer("fire_arrived", 3000, npc, null);
		}
		return false;
	}
	
	@Override
	public void onNodeArrived(L2Npc npc)
	{
		// CHEF
if (AI_OMIT) {{
		if (!canFire(npc))
			return;
}}
		npc.getVariables().remove("REWARD_TIME_GONE");
		broadcastEvent("SCE_DINNER_CHECK", npc, 300, null);
	}
	
	@Override
	public String onSkillSee(L2Npc npc, L2PcInstance caster, L2Skill skill, L2Object[] targets, boolean isSummon)
	{
		// STOVE
		if (skill.getId() == 9075 && Util.contains(targets, npc))
		{
if (FIX_SKILL_6688_TARGET) {{
			// 「焚き火のスープの容器」がスキル6688-1「台無しになったスープ」を使うと
			// 「セル マフム プライベート」が「焚き火のスープの容器」に反撃アッタックしてしまう.
			// @skills/06600-06699.xml
			// 	<skill id="6688" levels="1" name="Soup of Failure">
			// 		...
			// -		<set name="targetType" val="CLAN" /> <!-- FIXME: Aura Friendly ? -->
			// +		<set name="targetType" val="ONE" /> <!-- FIXME: Aura Friendly ? -->
			// 	</skill>
			
			/*if (SkillTable.getInstance().getInfo(6688, 1).getTargetType() != L2TargetType.ONE) throw new RuntimeException();*/
			final L2Skill effect = SkillTable.getInstance().getInfo(6688, 1);
			final int radius = effect.getAffectRange();
			for (L2Character c : npc.getKnownList().getKnownCharacters()) {
				if (c instanceof L2Attackable) {
					final L2Attackable mob = (L2Attackable) c;
					if (Util.contains(SQUAD_LEADERS, mob.getNpcId()) && mob.getDisplayEffect() == MAHUM_EFFECT_EAT && mob.isInsideRadius(npc, radius, false, true))
						effect.applyEffects(caster, mob);
				}
			}
}} else {{
			/*if (SkillTable.getInstance().getInfo(6688, 1).getTargetType() != L2TargetType.CLAN) throw new RuntimeException();*/
			npc.doCast(SkillTable.getInstance().getInfo(6688, 1));
}}
		}
		
		return null;
	}
	
	@Override
	public String onSpawn(L2Npc npc)
	{
		if (!npc.isTeleporting())
		{
			switch (npc.getId())
			{
				case CHEF:
					npc.setIsInvul(false);
					npc.disableSkill(SkillTable.getInstance().getInfo(6330, 1), -1);	//[JOJO] サーモン スープ アタック
					break;
					
				case FIRE:
					startQuestTimer("fire", 1000, npc, null);
					npc.setRandomAnimationEnabled(false);
					break;
					
				case STOVE:
					npc.setRandomAnimationEnabled(false);
					break;
					
				case 22786: // SQUAD_LEADERS
				case 22787: // SQUAD_LEADERS
				case 22788: // SQUAD_LEADERS
					setIsNoRndWalk(npc, false);
					npc.setDisplayEffect(MAHUM_EFFECT_NONE);
					break;
					
				default:
					throw new RuntimeException("onSpawn(" + npc.toString() + ")");
			}
		}
		return null;
	}
	
	@Override
	public String onSpellFinished(L2Npc npc, L2PcInstance player, L2Skill skill)
	{
		// CHEF
		if (skill.getId() == 6330)
		{
			healPlayer(npc, player);
		}
		
		return null;
	}
	
	private void healPlayer(L2Npc npc, L2PcInstance player)
	{
		// CHEF
		if (npc.isInvul() && npc.isInCombat() && !npc.isCastingNow() && !player.isAlikeDead())
		{
			npc.setTarget(player);
			npc.doCast(SkillTable.getInstance().getInfo(6330, 1));
		}
	}
	
	private void handlePreAttackMotion(L2Npc attacked)
	{
		// SQUAD_LEADERS[]
		if (!attacked.isNoRndWalk()) return;	//+[JOJO] i_ai0
		
		cancelQuestTimer("remove_effects", attacked, null);
		setIsNoRndWalk(attacked, false); // i_ai0 == 0
		attacked.getVariables().remove("BUSY_STATE");
		attacked.setDisplayEffect(MAHUM_EFFECT_NONE);
		if (attacked.getRightHandItem() == OHS_Weapon)
		{
			attacked.setRHandId(THS_Weapon);
		}
		// TODO: Check about i_quest0
	}
	
	//[JOJO]-------------------------------------------------
	private final void setIsNoRndWalk(L2Npc npc, boolean value)
	{
		// SQUAD_LEADERS[]
		npc.setIsNoRndWalk(value); // i_ai0
		npc.setRandomAnimationEnabled(!value);
		((L2Attackable) npc).setCanReturnToSpawnPoint(!value);
	}
	
	private final boolean canFire(L2Npc npc)
	{
		// CHEF, FIRE
if (AI_OMIT) {{
		return npc.isInActiveRegion();
	//	return !npc.getKnownList().getKnownPlayers().isEmpty();
}} else {{
		return true;
}}
	}
	
	private final boolean canMove(L2Npc npc)
	{
		// SQUAD_LEADERS[]
if (AI_OMIT) {{
		if (!npc.hasAI())
		{
			handlePreAttackMotion(npc);
			return false;
		}
		else
		{
			return true;
		}
}} else {{
		return true;
}}
	}
	
	private final boolean isValidQuestTimer(String event, L2Npc npc, L2PcInstance player)
	{
		// onAdvEvent
		if (npc.isDead() || !npc.isVisible())
		{
			cancelQuestTimer(event, npc, player);
			return false;
		}
		else
		{
			return true;
		}
	}
	
	@Override
	public boolean unload()
	{
		for (L2Object o : L2World.getInstance().getVisibleObjects()) {
			if (o instanceof L2Npc) {
				L2Npc npc = (L2Npc) o;
				switch (npc.getNpcId()) {
					case CHEF:
					case FIRE:
					case STOVE:
					case 22786: // SQUAD_LEADERS
					case 22787: // SQUAD_LEADERS
					case 22788: // SQUAD_LEADERS
						npc.deleteMe();
						break;
				}
			}
		}
		return super.unload();
	}
	//-------------------------------------------------------
	
	public static void main(String[] args)
	{
		new SelMahumSquad();
	}
}