/*
 * Copyright (C) 2005-2008 L2J_JP / 2008-2013 L2J-SFJP
 * 
 * This file is part of L2J Server.
 * 
 * L2J Server 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 Server 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.individual;

import java.util.ArrayList;
import java.util.List;

import javolution.util.FastList;
import ai.npc.AbstractNpcAI;

import com.l2jserver.Config;
import com.l2jserver.gameserver.ai.CtrlIntention;
import com.l2jserver.gameserver.datatables.SkillTable;
import com.l2jserver.gameserver.instancemanager.GrandBossManager;
import com.l2jserver.gameserver.model.L2Party;
import com.l2jserver.gameserver.model.Location;
import com.l2jserver.gameserver.model.StatsSet;
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.model.quest.Quest;
import com.l2jserver.gameserver.model.quest.QuestState;
import com.l2jserver.gameserver.model.zone.type.L2BossZone;
import com.l2jserver.gameserver.network.serverpackets.MagicSkillUse;
import com.l2jserver.gameserver.network.serverpackets.NpcSay;
import com.l2jserver.gameserver.network.serverpackets.PlaySound;
import com.l2jserver.gameserver.network.serverpackets.SocialAction;
import com.l2jserver.gameserver.network.serverpackets.SpecialCamera;
import com.l2jserver.gameserver.util.Broadcast;
import com.l2jserver.gameserver.util.Util;
import com.l2jserver.util.Rnd;

/**
 * ----/--/-- By L2J_JP SANDMAN
 * 2009/08/27 JOJO Sync: l2jfree-datapack rev4814, timestamp 2008/11/21 04:53
 * 2009/08/28 JOJO Sync: l2jfree-core rev6689, timestamp 2009/07/22 23:45
 * 2009/10/30 JOJO Sync: l2jfree-core rev7164, timestamp 2009/09/20 04:37
 * 2010/06/04 JOJO sailren.py を Sailren.java に書き換え
 * 2010/08/23 JOJO SailrenManager.java と Sailren.java を統合
 * 2010/08/27 JOJO ボス登場ムービーをL2JTWより拝借
 */

// Boss: sailren
public class Sailren extends AbstractNpcAI
{
	private static final String qn = "sailren";
	private static final long INACTIVITYTIME = 900000;	//15 min.

	// NPC
	private static final int STATUE          = 32109;	// シーレンの石像/Shilen's Stone Statue
	private static final int VELOCIRAPTOR    = 22218;	// ヴェロキラプトル/Velociraptor
	private static final int PTEROSAUR       = 22199;	// ランフォリンクス/Pterosaur
	private static final int TYRANNOSAURUS   = 22217;	// ティラノザウルス/Tyrannosaurus
	private static final int SAILREN         = 29065;	// サイレン/Sailren
 //	private static final int CAMERADUMMY     = 32110;	// カメラ用ダミー
	private static final int CUBE            = 32107;	// テレポートキューブ/Teleport cube

	// ITEM
	private static final int GAZKH  = 8784;	// カジク/Gazkh

	//Sailren Status Tracking :
	private static final byte DORMANT = 0;		//Sailren is spawned and no one has entered yet. Entry is unlocked
 //	private static final byte WAITING = 1;		//Sailren is spawend and someone has entered, triggering a ** minute window for additional people to enter
 //												//before he unleashes his attack. Entry is unlocked
	private static final byte FIGHTING = 2;		//Sailren is engaged in battle, annihilating his foes. Entry is locked
	private static final byte DEAD = 3;			//Sailren has been killed. Entry is locked

	// Instance of monsters, players
	private List<L2Npc> _npcTable = new FastList<>();
	private List<L2PcInstance> _players;

	// Zone
	private L2BossZone _zone;

	private long _lastAction = 0;

	private Sailren(int id, String name, String descr)
	{
		super(id, name, descr);

		if ((_zone = GrandBossManager.getInstance().getZone(27734, -6938, -1982)) == null)
			_log.warning("AI script: Failed to load zone 'Lair of Sailren'");

		// Quest NPC starter initialization
		addStartNpc(STATUE);
		addTalkId(STATUE);
		addSpawnId(VELOCIRAPTOR);
		addSpawnId(PTEROSAUR);
		addSpawnId(TYRANNOSAURUS);
		addSpawnId(SAILREN);
		addAttackId(VELOCIRAPTOR);
		addAttackId(PTEROSAUR);
		addAttackId(TYRANNOSAURUS);
		addAttackId(SAILREN);
		addKillId(VELOCIRAPTOR);
		addKillId(PTEROSAUR);
		addKillId(TYRANNOSAURUS);
		addKillId(SAILREN);

		StatsSet info = GrandBossManager.getInstance().getStatsSet(SAILREN);
		int status = GrandBossManager.getInstance().getBossStatus(SAILREN);
		if (status == DEAD)
		{
			long temp = (info.getLong("respawn_time") - System.currentTimeMillis());
			if (temp > 0)
			{
				startQuestTimer("intervalEnd", temp, null, null);
				_log.info("AI script: Next spawn date of Sailren is " + GrandBossManager.respawnTimeFormat(info) + ".");
			}
			else
			{
				GrandBossManager.getInstance().setBossStatus(SAILREN, DORMANT);
			}
		}
		else if (status != DORMANT)
			GrandBossManager.getInstance().setBossStatus(SAILREN, DORMANT);
	}

	// Clean up Sailren's lair.
	private void setUnspawn()
	{
		// Eliminate players.
		_zone.oustAllPlayers();

		// Delete monsters and cube.
		for (L2Npc npc : _npcTable)
			npc.deleteMe();
		_npcTable.clear();
	}

	private L2Npc addSpawnNpc(int npcId, int x, int y, int z, int heading, boolean randomOffset, long despawnDelay)
	{
		L2Npc npc = Quest.addSpawn(npcId, x, y, z, heading, randomOffset, despawnDelay);
		_npcTable.add(npc);
		npc.getSpawn().setXYZ(27734, -6938, -1982);
		return npc;
	}

	private void specialEffect(L2Npc npc, int id, int level)
	{
		npc.setTarget(npc);
		npc.broadcastPacket(new MagicSkillUse(npc, npc, id, level, 4000, 0));
	}

	@Override
	public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
	{
		if (event == "activityTimeEnd") {
			if (System.currentTimeMillis() - _lastAction > INACTIVITYTIME) {
				// cancel all timers.
				cancelAllQuestTimers();
				// clean up sailren's lair.
				setUnspawn();
				GrandBossManager.getInstance().setBossStatus(SAILREN, DORMANT);
				_log.info("AI script: Sailren Activity END.");
			}
		}
		else if (event == "enterZone") {
			for (L2PcInstance mem : _players) {
				_zone.allowPlayerEntry(mem, 30);
				mem.teleToLocation(27734 + Rnd.get(-80, 80), -6938 + Rnd.get(-80, 80), -1982);
			}
			_players = null;
		}
		else if (event == "cubeSpawn") {
			_lastAction = System.currentTimeMillis();
			addSpawnNpc(CUBE, 27734, -6938, -1982, 0, false, 0);
		}
		else if (event == "cubeDespawn") {
			// clean up sailren's lair.
			setUnspawn();
			assert getQuestTimer("intervalEnd", null, null) != null;
		}
		else if (event == "intervalEnd") {
			// Interval end.
			GrandBossManager.getInstance().setBossStatus(SAILREN, DORMANT);
			_log.info("AI script: Sailren Interval END.");
		}
		/********************/
		/* SPAWN UNDERCARDS */
		/********************/
		else if (event == "velociraptorSpawn") {	// ヴェロキラプトル
			_lastAction = System.currentTimeMillis();
			L2Attackable mob = (L2Attackable)addSpawnNpc(VELOCIRAPTOR, 27852, -5536, -1983, 44732, false, 0);
			mob.setIsRaid(true);	//[JOJO] 要注意:子分２匹
			startQuestTimer("moveToBattlePosition", 1000, mob, null);
		}
		else if (event == "pterosaurSpawn") {	// ランフォリンクス
			_lastAction = System.currentTimeMillis();
			L2Attackable mob = (L2Attackable)addSpawnNpc(PTEROSAUR, 27852, -5536, -1983, 44732, false, 0);
			startQuestTimer("moveToBattlePosition", 1000, mob, null);
		}
		else if (event == "tyrannosaurusSpawn") {	// ティラノザウルス
			_lastAction = System.currentTimeMillis();
			L2Attackable mob = (L2Attackable)addSpawnNpc(TYRANNOSAURUS, 27852, -5536, -1983, 44732, false, 0);
			startQuestTimer("moveToBattlePosition", 1000, mob, null);
		}
		else if (event == "moveToBattlePosition") {
			npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(27628, -6109, -1982, 44732));
			startQuestTimer("undercardsSocial", 5000, npc, null);
		}
		else if (event == "undercardsSocial") {		// ヴェロキラプトル・ランフォリンクス・ティラノザウルス
			if (npc.getAI().getIntention() == CtrlIntention.AI_INTENTION_MOVE_TO || npc.isMoving()) {
				// Retry.
				startQuestTimer(event, 777, npc, player);
			}
			else if (npc.getAI().getIntention() == CtrlIntention.AI_INTENTION_ATTACK || npc.isAttackingNow() || npc.isCastingNow() || npc.getCurrentHp() != npc.getMaxHp()) {
				// Cancel social.
			}
			else{
				_zone.updateKnownList(npc);
				npc.broadcastPacket(new SocialAction(npc, 2));
			}
		}
		/********************/
		/* SPAWN SAILREN    */
		/********************/
		else if (event == "sailrenSpawn") {	// サイレン
			_lastAction = System.currentTimeMillis();
			L2Attackable mob = (L2Attackable)addSpawnNpc(SAILREN, 27734, -6938, -1982, 44732, false, 0);
			mob.disableSkill(SkillTable.getInstance().getInfo(5118, 1), 0); //TODO: DELETE npcskills WHERE skillid=5118;
			mob.setRunning();
			mob.setIsInvul(true);
			mob.setIsParalyzed(true);
			mob.setIsImmobilized(true);
			startQuestTimer("camera_1", 2000, mob, null);
			mob.broadcastPacket(new SpecialCamera(mob.getObjectId(), 200, 0, 0, 2000, 11000, 0, 32, 1, 0));
		}
		else if (event == "camera_1") {
			specialEffect(npc, 5118, 1);
			startQuestTimer("camera_2", 4000, npc, null);
			npc.broadcastPacket(new SpecialCamera(npc.getObjectId(), 250, 90, 8, 4000, 11000, 0, 44, 1, 0));
/**			npc.broadcastPacket(new SpecialCamera(npc.getObjectId(), 300, 90, 8, 4000, 11000, 0, 43, 1, 0));	*/
		}
		else if (event == "camera_2") {
			specialEffect(npc, 5118, 1);
			startQuestTimer("camera_3", 4000, npc, null);
			npc.broadcastPacket(new SpecialCamera(npc.getObjectId(), 300, 160, 16, 4000, 11000, 0, 16, 1, 0));
		}
		else if (event == "camera_3") {
			specialEffect(npc, 5118, 1);
			startQuestTimer("camera_4", 4000, npc, null);
			npc.broadcastPacket(new SpecialCamera(npc.getObjectId(), 300, 250, 8, 4000, 11000, 0, 0, 1, 0));
		}
		else if (event == "camera_4") {
			specialEffect(npc, 5118, 1);
			startQuestTimer("camera_5", 4000, npc, null);
			npc.broadcastPacket(new SpecialCamera(npc.getObjectId(), 300, 340, 0, 4000, 11000, 0, 0, 1, 0));
		}
		else if (event == "camera_5") {
			npc.broadcastPacket(new SocialAction(npc, 2));
			startQuestTimer("camera_6", 5000, npc, null);
		}
		else if (event == "camera_6") {
			npc.setIsImmobilized(false);
			npc.setIsParalyzed(false);
			npc.setIsInvul(false);
			_lastAction = System.currentTimeMillis();
		}
		/********************/
		else if (event.length() != 0)
			throw new RuntimeException(event);
		
		return super.onAdvEvent(event, npc, player);
	}

	@Override
	public String onTalk(L2Npc npc, L2PcInstance player)
	{
		QuestState st = player.getQuestState(qn);
		if (st == null) return "<html><body>You are either not on a quest that involves this NPC, or you don't meet this NPC's minimum quest requirements.</body></html>";

		if (npc.getId() == STATUE) {
			// Whether it is permitted to enter the sailren's lair is confirmed.
			if (player.isFlying()) {
				return "<html><body>シーレンの石像:<br>ワイバーンに搭乗中は、中に入れることはできない。</body></html>";
			//	return "<html><body>Shilen's Stone Statue:<br>You may not enter while flying a wyvern</body></html>";
			}
			if (st.getQuestItemsCount(GAZKH) == 0) {
				return "<html><body>シーレンの石像:<br>サイレンを封印するには<font color=LEVEL>カジク</font>が必要だ。</body></html>";
			//	return "<html><body>Shilen's Stone Statue:<br><font color=LEVEL>Gazkh</font> is necessary for seal the sailren.</body></html>";
			}
			if (!Config.FWS_ENABLESINGLEPLAYER && player.getParty() == null) {
				return "<html><body>シーレンの石像:<br>一人でサイレンを封印しようどと考えないことだ。仲間を連れてきなさい。</body></html>";
			//	return "<html><body>Shilen's Stone Statue:<br>You seal the sailren alone? You should not do so! Bring the companion.</body></html>";
			}
			synchronized (this) { // synchronize getBossStatus and setBossStatus
				switch (GrandBossManager.getInstance().getBossStatus(SAILREN)) {
				case DORMANT:
					GrandBossManager.getInstance().setBossStatus(SAILREN, FIGHTING);
					break; // exit synchronized{}
				case DEAD:
					return "data/html/default/32109-INTERVAL.htm";
				//	return "<html><body>シーレンの石像:<br>今はサイレンの力が非常に強い時期にある。中に入れることはできない。</body></html>";
				// 	return "<html><body>Shilen's Stone Statue:<br>The sailren is very powerful now. It is not possible to enter the inside.</body></html>";
					/*break;*/
				default:
					return "data/html/default/32109-FIGHTING.htm";
				//	return "<html><body>シーレンの石像:<br>すでに他の者がサイレンと闘っている。彼らの邪魔をしてはいけない。</body></html>";
				//	return "<html><body>Shilen's Stone Statue:<br>Another adventurers have already fought against the sailren. Do not obstruct them.</body></html>";
					/*break;*/
				}
			}
			st.takeItems(GAZKH, 1);
			// Teleporting player to sailren's lair.
			_players = new FastList<>();
			for (L2PcInstance mem : this.getPartyMembers(player))
			{
				// teleporting it within alive and the range of recognition of the leader of the party.
				if (!mem.isDead() && Util.checkIfInRange(700, player, mem, true))
				{
					_players.add(mem);
					// 5089-1 演出：サイレンの巣窟 入場クエスト
					// 5089-1 Representation - Enter the Sailren Nest Quest
					mem.setTarget(null);
					mem.broadcastPacket(new MagicSkillUse(mem, mem, 5089, 1, 3000, 0));
				}
			}
			startQuestTimer("enterZone", 2500, null, null);
			_lastAction = Long.MAX_VALUE;
			startQuestTimer("activityTimeEnd", 30000, null, null, true);
			startQuestTimer("velociraptorSpawn", Config.FWS_INTERVALOFNEXTMONSTER, null, null, false);	// ヴェロキラプトル
			return "data/html/default/32109-DORMANT.htm";
		//	return "<html><body>シーレンの石像:<br>君たちの力でサイレンを封じてほしい。幸運を祈る。</body></html>";
		//	return "<html><body>Shilen's Stone Statue:<br>Please seal the sailren by your ability.</body></html>";
		}
		else
			throw new IllegalArgumentException("npcId is " + npc.getId());
	}

	@Override
	public String onSpawn(L2Npc npc)
	{
		if (! _zone.isInsideZone(npc)) return null;	//[JOJO]
		((com.l2jserver.gameserver.model.actor.L2Attackable)npc).setOnKillDelay(100);	//Default 5000ms.
		return super.onSpawn(npc);
	}

	@Override
	public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isPet)
	{
		if (! _zone.isInsideZone(npc)) return null;	//[JOJO]
		_lastAction = System.currentTimeMillis();
		return super.onAttack(npc, attacker, damage, isPet);
	}

	@Override
	public String onKill(L2Npc npc, L2PcInstance player, boolean isPet)
	{
		if (! _zone.isInsideZone(npc)) return null;	//[JOJO]
		switch (npc.getId()) {
		case VELOCIRAPTOR:
			startQuestTimer("pterosaurSpawn", Config.FWS_INTERVALOFNEXTMONSTER, null, null);	// ランフォリンクス
			break;
		case PTEROSAUR:
			startQuestTimer("tyrannosaurusSpawn", Config.FWS_INTERVALOFNEXTMONSTER, null, null);	// ティラノザウルス
			break;
		case TYRANNOSAURUS:
			npc.broadcastPacket(new NpcSay(npc.getObjectId(), 1, npc.getId(), 1800011/*わ〜い！ご主人様のお戻りだ。必ず仕返ししてくださるはず！お前ももうちょっとで死体だよ。*/));
			startQuestTimer("sailrenSpawn", Config.FWS_INTERVALOFNEXTMONSTER, null, null);	// サイレン
			break;
		case SAILREN:
			// cancel all timers.
			cancelAllQuestTimers();

			GrandBossManager.getInstance().setBossStatus(SAILREN, DEAD);
			// Task of interval of sailren spawn.
			final long respawnTime = Math.max(INACTIVITYTIME, Rnd.get(Config.FWS_FIXINTERVALOFSAILRENSPAWN - Config.FWS_RANDOMINTERVALOFSAILRENSPAWN, Config.FWS_FIXINTERVALOFSAILRENSPAWN + Config.FWS_RANDOMINTERVALOFSAILRENSPAWN));
			startQuestTimer("intervalEnd", respawnTime, null, null);
			StatsSet info = GrandBossManager.getInstance().getStatsSet(SAILREN);
			info.set("respawn_time", System.currentTimeMillis() + respawnTime);
			GrandBossManager.getInstance().setStatsSet(SAILREN, info);
			Broadcast.announceToOnlinePlayers("太古の島のサイレンが死亡しました。次の復活は "+GrandBossManager.respawnTimeFormat(info)+" ごろです。");	//[JOJO]
			npc.broadcastPacket(new PlaySound(1, "BS01_D", 1, npc.getObjectId(), npc.getX(), npc.getY(), npc.getZ()));

			// Spawn teleport cube.
			startQuestTimer("cubeSpawn", 10000, null, null);
			startQuestTimer("cubeDespawn", INACTIVITYTIME, null, null);
			break;
		default:
			throw new IllegalArgumentException("npcId is " + npc.getId());
		}
		return null;
	}

	List<L2PcInstance> getPartyMembers(L2PcInstance player)
	{
		L2Party party;
		if ((party = player.getParty()) != null)
			return party.getMembers();
		else
		{
			List<L2PcInstance> m = new ArrayList<>(1);
			m.add(player);
			return m;
		}
	}

	// Quest class and state definition
	public static void main(String[] args)
	{
		new Sailren(-1, qn, "ai");
	}
}