/*
 * Copyright (C) 2004-2013 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 javolution.util.FastList;
import jp.sf.l2j.arrayMaps.SortedIntObjectArrayMap;
import jp.sf.l2j.troja.FastIntObjectMap;
import ai.npc.AbstractNpcAI;

import com.l2jserver.gameserver.ai.CtrlIntention;
import com.l2jserver.gameserver.enums.QuestEventType;
import com.l2jserver.gameserver.model.actor.L2Attackable;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.network.NpcStringId;
import com.l2jserver.gameserver.network.clientpackets.Say2;

/**
 * Summon Minions AI. Based on work of Slyce.
 * @author Sandro
 */
public class SummonMinions extends AbstractNpcAI
{
	private static final int MIN_ATTACKERS = 3;			// 3名以上のパーティで攻撃すると巫女の守護者が出現する
	private static final boolean MOD_SINGLE_PLAYER = false;	// パーティに関係なく3名以上から攻撃されたら巫女の守護者が出現する
	
	private static int HasSpawned;
	private static FastIntObjectMap<Object> myTrackingSet = new FastIntObjectMap<>().shared(); // Used to track instances of npcs
	private final FastIntObjectMap<FastList<L2PcInstance>> _attackersList = new FastIntObjectMap<FastList<L2PcInstance>>().shared();
	private static final int[] WITCH_WARDER_18364 = new int[]{18364, 18364};
	private static final int[] WITCH_WARDER_18365 = new int[]{18365, 18365};
	private static final int[] WITCH_WARDER_18366 = new int[]{18366, 18366};
	private static final SortedIntObjectArrayMap<int[]> MINIONS = new SortedIntObjectArrayMap<int[]>()
		// Timak Orc Troop
		.append(20767, new int[]{20768, 20769, 20770})	// 20767 ティマック オーク アサルト リーダー => 20768 ティマック オーク アサルト シャーマン, 20769 ティマック オーク アサルト ファイター, 20770 ティマック オーク アサルト アーチャー
		// Ragna Orc Shaman
		// .append(22030, new int[]{22045, 22047, 22048})	// 22030 ラグナ オーク シャーマン => 22045 ダーク コープス, 22047 廃村の監視者, 22048 ダークネス スパイダー
		// Ragna Orc Warrior - summons shaman but not 22030 ><
		// .append(22032, new int[]{22036})	// 22032 ラグナ オーク ウォーリア => 22036 ラグナ オーク メイジ
		// Ragna Orc Hero
		// .append(22038, new int[]{22037})	// 22038 ラグナ オーク ヒーロー => 22037 ラグナ オーク ヒーラー
		// Blade of Splendor
		.append(21524, new int[]{21525})	// 21524 ブリリアント ブレード => 21525 ブリリアント ブレード
		// Punishment of Splendor
		.append(21531, new int[]{21658})	// 21531 ブリリアント ヴェンジェンス => 21658 ブリリアント ヴェンジェンス
		// Wailing of Splendor
		.append(21539, new int[]{21540})	// 21539 ブリリアント アンギッシュ => 21540 ブリリアント アンギッシュ
		// Island Guardian
		.append(22257, WITCH_WARDER_18364)	// 22257 島の門番 => 18364 巫女の守護者
		// White Sand Mirage
		.append(22258, WITCH_WARDER_18364)	// 22258 白浜の幻像 => 18364 巫女の守護者
		// Muddy Coral
		.append(22259, WITCH_WARDER_18364)	// 22259 珊瑚泥 => 18364 巫女の守護者
		// Kleopora
		.append(22260, WITCH_WARDER_18364)	// 22260 クリナイア => 18364 巫女の守護者
		// Seychelles
		.append(22261, WITCH_WARDER_18365)	// 22261 セイシェル => 18365 巫女の守護者
		// Naiad
		.append(22262, WITCH_WARDER_18365)	// 22262 ナイアス => 18365 巫女の守護者
		// Sonneratia
		.append(22263, WITCH_WARDER_18365)	// 22263 ソネラティア => 18365 巫女の守護者
		// Castalia
		.append(22264, WITCH_WARDER_18366)	// 22264 キャスタリア => 18366 巫女の守護者
		// Chrysocolla
		.append(22265, WITCH_WARDER_18366)	// 22265 クリソキラ => 18366 巫女の守護者
		// Pythia
		.append(22266, WITCH_WARDER_18366)	// 22266 ピティア => 18366 巫女の守護者
		// Invader Soldier of Nightmare
		.append(22715, new int[]{22716,22716,22716,22716,22716,22716,22716,22716,22716})	// 22715 悪夢の侵略軍ソルジャー => 22716 同*9
		// Nihil Invader Soldier
		.append(22726, new int[]{22727,22727,22727,22727,22727,22727,22727,22727,22727})	// 22726 虚無の侵略軍ソルジャー => 22727 同*9
		// Mutant Soldier
		.append(22737, new int[]{22738,22738,22738,22738,22738,22738,22738,22738,22738})	// 22737 怪奇の侵略軍ソルジャー => 22738 同*9
		// Tanta Lizardman Summoner
		.append(22774, new int[]{22768, 22768})	// 22774 タンタ リザードマン サマナー => 22768 タンタ リザードマン スカウト
	;
	// Timak Orc Troop Messages
	private static final NpcStringId[] ATTACK_LEADER_MSG =
	{
		NpcStringId.FORCES_OF_DARKNESS_FOLLOW_ME,		// 1000404 Forces of darkness! Follow me!		闇の軍勢よ、私に続け！
		NpcStringId.DESTROY_THE_ENEMY_MY_BROTHERS,		// 1000405 Destroy the enemy, my brothers!		兄弟たちよ、敵を殲滅させろ！
		NpcStringId.SHOW_YOURSELVES,					// 1000403 Show yourselves!						皆の者！出て来い！
		NpcStringId.COME_OUT_YOU_CHILDREN_OF_DARKNESS	// 1000294 Come out, you children of darkness!	出でよ！闇の者ども！
	};
	
	private SummonMinions()
	{
		super(SummonMinions.class.getSimpleName(), "ai/group_template");
		registerMobs(MINIONS.keySet(), QuestEventType.ON_ATTACK, QuestEventType.ON_KILL);
	}
	
	@Override
	public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
	{
		int npcId = npc.getId();
		int npcObjId = npc.getObjectId();
		
		if (myTrackingSet.putIfAbsent(npcObjId, npc) == null) // this allows to handle multiple instances of npc
		{
			HasSpawned = npcObjId;
		}
		if (HasSpawned == npcObjId)
		{
			switch (npcId)
			{
				case 22030:	// 22030 ラグナ オーク シャーマン
				case 22032:	// 22032 ラグナ オーク ウォーリア
				case 22038:	// 22038 ラグナ オーク ヒーロー
					// mobs that summon minions only on certain hp
					if (npc.getCurrentHp() < npc.getMaxHp() / 2.0)
					{
						HasSpawned = 0;
						if (getRandom(100) < 33) // mobs that summon minions only on certain chance
						{
							for (int val : MINIONS.get(npcId))
							{
								L2Attackable newNpc = (L2Attackable) addSpawn(val, (npc.getX() + getRandom(-150, 150)), (npc.getY() + getRandom(-150, 150)), npc.getZ(), 0, false, npc.getInstanceId());
								newNpc.setRunning();
								newNpc.addDamageHate(attacker, 0, 999);
								newNpc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, attacker);
							}
						}
					}
					break;
				
				case 22257:	// 22257 島の門番
				case 22258:	// 22258 白浜の幻像
				case 22259:	// 22259 珊瑚泥
				case 22260:	// 22260 クリナイア
				case 22261:	// 22261 セイシェル
				case 22262:	// 22262 ナイアス
				case 22263:	// 22263 ソネラティア
				case 22264:	// 22264 キャスタリア
				case 22265:	// 22265 クリソキラ
				case 22266:	// 22266 ピティア
					if (isSummon)
					{
						attacker = attacker.getSummon().getOwner();
					}
					final boolean ready;
					if (attacker.getParty() != null && attacker.getParty().getMemberCount() >= MIN_ATTACKERS) // Just to make sure..
					{
						ready = true;	//  http://www.google.co.jp/search?q="リネージュ２"+"巫女の守護者" 
					}
					else if (MOD_SINGLE_PLAYER)
					{
						if (attacker.getParty() != null)
						{
							for (L2PcInstance member : attacker.getParty().getMembers())
							{
								FastList<L2PcInstance> attackers;
								if ((attackers = _attackersList.get(npcObjId)) == null)
								{
									FastList<L2PcInstance> player = new FastList<>();
									player.add(member);
									_attackersList.put(npcObjId, player);
								}
								else if (!attackers.contains(member))
								{
									attackers.add(member);
								}
							}
						}
						else
						{
							FastList<L2PcInstance> attackers;
							if ((attackers = _attackersList.get(npcObjId)) == null)
							{
								FastList<L2PcInstance> player = new FastList<>();
								player.add(attacker);
								_attackersList.put(npcObjId, player);
							}
							else if (!attackers.contains(attacker))
							{
								attackers.add(attacker);
							}
						}
						ready = _attackersList.get(npcObjId).size() >= MIN_ATTACKERS; // Just to make sure..
					}
					else
					{
						break;//ready = false;
					}
					if (ready) // Just to make sure..
					{
						HasSpawned = 0;
						for (int val : MINIONS.get(npcId))
						{
							L2Attackable newNpc = (L2Attackable) addSpawn(val, npc.getX() + getRandom(-150, 150), npc.getY() + getRandom(-150, 150), npc.getZ(), 0, false, npc.getInstanceId());
							newNpc.setRunning();
							newNpc.addDamageHate(attacker, 0, 999);
							newNpc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, attacker);
						}
					}
					break;
				
				case 20767:	// ティマック オーク アサルト リーダー
					HasSpawned = 0;
					broadcastNpcSay(npc, Say2.NPC_ALL, ATTACK_LEADER_MSG[getRandom(ATTACK_LEADER_MSG.length)]);
					for (int val : MINIONS.get(npcId))
					{
						addSpawn(val, (npc.getX() + getRandom(-100, 100)), (npc.getY() + getRandom(-100, 100)), npc.getZ(), 0, false, npc.getInstanceId());
					}
					break;
				
				case 21524:	// 21524 ブリリアント ブレード
				case 21531:	// 21531 ブリリアント ヴェンジェンス
				case 21539:	// 21539 ブリリアント アンギッシュ
				case 22774:	// 22774 タンタ リザードマン サマナー
				case 22715:	// 22715 悪夢の侵略軍ソルジャー
				case 22726:	// 22726 虚無の侵略軍ソルジャー
				case 22737:	// 22737 怪奇の侵略軍ソルジャー
					// mobs without special conditions
					HasSpawned = 0;
					for (int val : MINIONS.get(npcId))
					{
						L2Attackable newNpc = (L2Attackable) addSpawn(val, npc.getX() + getRandom(-150, 150), npc.getY() + getRandom(-150, 150), npc.getZ(), 0, false, npc.getInstanceId());
						newNpc.setRunning();
						newNpc.addDamageHate(attacker, 0, 999);
						newNpc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, attacker);
					}
					// Despawn Invader Soldier of Nightmare, Nihil Invader Soldiers, Mutant Soldiers after minions have been summoned
					if (((npcId == 22715) || (npcId == 22726) || (npcId == 22737)) && !npc.isDead())
					{
						onKill(npc, attacker, isSummon);
						npc.deleteMe();
					}
					break;
				
				default:
					throw new RuntimeException();
			}
		}
		return super.onAttack(npc, attacker, damage, isSummon);
	}
	
	@Override
	public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
	{
		int npcObjId = npc.getObjectId();
		
		myTrackingSet.remove(npcObjId);
		_attackersList.remove(npcObjId);	//[JOJO]
		
		return super.onKill(npc, killer, isSummon);
	}
	
	public static void main(String[] args)
	{
		new SummonMinions();
	}
}
