/*
 * This program 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 2, or (at your option)
 * any later version.
 *
 * This program 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 *
 * http://www.gnu.org/copyleft/gpl.html
 */

package net.sf.l2j.gameserver.instancemanager;

import java.util.logging.Logger;
import java.util.concurrent.ScheduledFuture;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import javolution.util.FastList;

import net.sf.l2j.Config;
import net.sf.l2j.gameserver.datatables.NpcTable;
import net.sf.l2j.gameserver.datatables.SpawnTable;
import net.sf.l2j.gameserver.ThreadPoolManager;
import net.sf.l2j.gameserver.model.L2Spawn;
import net.sf.l2j.gameserver.model.L2CharPosition;
import net.sf.l2j.gameserver.model.actor.instance.L2NpcInstance;
import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
import net.sf.l2j.gameserver.templates.chars.L2NpcTemplate;
import net.sf.l2j.gameserver.templates.StatsSet;
import net.sf.l2j.gameserver.util.Util;
import net.sf.l2j.gameserver.network.serverpackets.SocialAction;
import net.sf.l2j.util.Rnd;
import net.sf.l2j.gameserver.ai.CtrlIntention;
import net.sf.l2j.gameserver.model.actor.status.GrandBossStatus;
import net.sf.l2j.gameserver.instancemanager.GrandBossManager;

/**
 *
 * This class ...
 * サイレンとの戦闘をコントロールするクラス。
 * @version $Revision: $ $Date: $
 * @author  L2J_JP SANDMAN
 *  modify  JOJO
 */
public class SailrenManager
{
	static Logger _log = Logger.getLogger(SailrenManager.class.getName());
	private static SailrenManager _instance = new SailrenManager();
	
	// NPC
	private static final int VELOCIRAPTOR = 22218;	//ヴェロキラプトル
	private static final int PTEROSAUR = 22199;		//ランフォリンクス
	private static final int TYRANNOSAURUS = 22217;	//ティラノザウルス
	private static final int SAILREN = 29065;		//サイレン
	
	// 帰還用キューブの出現データ
	private final int _sailrenCubeLocation[][] =
	{
		{27734,-6838,-1982,0}
	};
	private List<L2Spawn> _sailrenCubeSpawn = new FastList<L2Spawn>();
	private List<L2NpcInstance> _sailrenCube = new FastList<L2NpcInstance>();
	
	// サイレンの巣窟に侵入したプレイヤーのリスト
	private List<L2PcInstance> _playersInSailrenLair = new FastList<L2PcInstance>();
	
	// モンスター の出現データ
	L2Spawn _velociraptorSpawn;		// ヴァロキラプトル
	L2Spawn _pterosaurSpawn;		// ランフォリンクス
	L2Spawn _tyrannoSpawn;			// ティラノザウルス
	L2Spawn _sailrenSapwn;			// サイレン
	
	// モンスター のインスタンス
	L2NpcInstance _velociraptor;	// ヴァロキラプトル
	L2NpcInstance _pterosaur;		// ランフォリンクス
	L2NpcInstance _tyranno;			// ティラノザウルス
	L2NpcInstance _sailren;			// サイレン
	
	// タスク
	private ScheduledFuture<?> _cubeSpawnTask = null;
	ScheduledFuture<?> _sailrenSpawnTask = null;
	private ScheduledFuture<?> _intervalEndTask = null;
	ScheduledFuture<?> _activityTimeEndTask = null;
	ScheduledFuture<?> _onPartyAnnihilatedTask = null;
	ScheduledFuture<?> _socialTask = null;
	
	// サイレンの巣窟の状態
	private final String _zoneName = "LairofSailren";
	private final String _questName = "sailren";
	private boolean _isAlreadyEnteredOtherParty = false;
	StatsSet _stateSet;
	int _alive;
	private final int _bossId = SAILREN;
	
	public SailrenManager()
	{
	}
	
	public static SailrenManager getInstance()
	{
		if (_instance == null)
			_instance = new SailrenManager();
		
		return _instance;
	}
	
	// 初期化
	public void init()
	{
		// 巣の状態の初期化
		_playersInSailrenLair.clear();
		_isAlreadyEnteredOtherParty = false;
		_stateSet = GrandBossManager.getInstance().getStatsSet(_bossId);
		_alive = GrandBossManager.getInstance().getBossStatus(_bossId);
		
		// ボスの出現データを設定する
		try
		{
			L2NpcTemplate template1;
			
			// ヴァロキラプトル
			template1 = NpcTable.getInstance().getTemplate(VELOCIRAPTOR); //Velociraptor
			_velociraptorSpawn = new L2Spawn(template1);
			_velociraptorSpawn.setLocx(27852);
			_velociraptorSpawn.setLocy(-5536);
			_velociraptorSpawn.setLocz(-1983);
			_velociraptorSpawn.setHeading(44732);
			_velociraptorSpawn.setAmount(1);
			_velociraptorSpawn.setRespawnDelay(Config.FWS_ACTIVITYTIMEOFMOBS * 2);
			SpawnTable.getInstance().addNewSpawn(_velociraptorSpawn, false);
			
			// ランフォリンクス
			template1 = NpcTable.getInstance().getTemplate(PTEROSAUR); //Pterosaur
			_pterosaurSpawn = new L2Spawn(template1);
			_pterosaurSpawn.setLocx(27852);
			_pterosaurSpawn.setLocy(-5536);
			_pterosaurSpawn.setLocz(-1983);
			_pterosaurSpawn.setHeading(44732);
			_pterosaurSpawn.setAmount(1);
			_pterosaurSpawn.setRespawnDelay(Config.FWS_ACTIVITYTIMEOFMOBS * 2);
			SpawnTable.getInstance().addNewSpawn(_pterosaurSpawn, false);
			
			// ティラノザウルス
			template1 = NpcTable.getInstance().getTemplate(TYRANNOSAURUS); //Tyrannosaurus
			_tyrannoSpawn = new L2Spawn(template1);
			_tyrannoSpawn.setLocx(27852);
			_tyrannoSpawn.setLocy(-5536);
			_tyrannoSpawn.setLocz(-1983);
			_tyrannoSpawn.setHeading(44732);
			_tyrannoSpawn.setAmount(1);
			_tyrannoSpawn.setRespawnDelay(Config.FWS_ACTIVITYTIMEOFMOBS * 2);
			SpawnTable.getInstance().addNewSpawn(_tyrannoSpawn, false);
			
			// サイレン
			template1 = NpcTable.getInstance().getTemplate(SAILREN); //Sailren
			_sailrenSapwn = new L2Spawn(template1);
			_sailrenSapwn.setLocx(27810);
			_sailrenSapwn.setLocy(-5655);
			_sailrenSapwn.setLocz(-1983);
			_sailrenSapwn.setHeading(44732);
			_sailrenSapwn.setAmount(1);
			_sailrenSapwn.setRespawnDelay(Config.FWS_ACTIVITYTIMEOFMOBS * 2);
			SpawnTable.getInstance().addNewSpawn(_sailrenSapwn, false);
			
		}
		catch (Exception e)
		{
			_log.warning(e.getMessage());
		}
		
		// テレポートキューブの出現データを作成する
		try
		{
			L2NpcTemplate cube = NpcTable.getInstance().getTemplate(32107);
			L2Spawn spawnDat;
			
			for (int i = 0; i < _sailrenCubeLocation.length; i++)
			{
				spawnDat = new L2Spawn(cube);
				spawnDat.setAmount(1);
				spawnDat.setLocx(_sailrenCubeLocation[i][0]);
				spawnDat.setLocy(_sailrenCubeLocation[i][1]);
				spawnDat.setLocz(_sailrenCubeLocation[i][2]);
				spawnDat.setHeading(_sailrenCubeLocation[i][3]);
				spawnDat.setRespawnDelay(60);
				spawnDat.setLocation(0);
				SpawnTable.getInstance().addNewSpawn(spawnDat, false);
				_sailrenCubeSpawn.add(spawnDat);
			}
		}
		catch (Exception e)
		{
			_log.warning(e.getMessage());
		}
		
		_log.info("SailrenManager : State of Sailren is " + _alive + ".");
		if (_alive != GrandBossStatus.NOTSPAWN)
			setInetrvalEndTask();
		
		Date dt = new Date(_stateSet.getLong("respawn_time"));
		_log.info("SailrenManager : Next spawn date of Sailren is " + dt + ".");
		_log.info("SailrenManager : Init SailrenManager.");
		
	}
	
	// 住処に入ったプレイヤーリストを渡す
	public List<L2PcInstance> getPlayersInLair()
	{
		return _playersInSailrenLair;
	}
	
	// サイレンの巣に入る事が出来るか確認する。
	public int canIntoSailrenLair(L2PcInstance pc)
	{
		if (Config.FWS_ENABLESINGLEPLAYER == false && pc.getParty() == null) return 4;
		else if (_isAlreadyEnteredOtherParty) return 2;
		else if (_alive == GrandBossStatus.NOTSPAWN) return 0;
		else if (_alive == GrandBossStatus.ALIVE || _alive == GrandBossStatus.DEAD) return 1;	//+[JOJO]
//		else if (_alive == GrandBossStatus.ALIVE || _alive != GrandBossStatus.DEAD) return 1;	//-[JOJO]
		else if (_alive == GrandBossStatus.INTERVAL) return 3;
		else return 0;
	}
	
	// サイレン出現タスクの設定
	public void setSailrenSpawnTask(int npcId)
	{
		if (npcId == VELOCIRAPTOR && _playersInSailrenLair.size() >= 1)
			return;
		
		if (_sailrenSpawnTask == null)
		{
			_sailrenSpawnTask = ThreadPoolManager.getInstance().scheduleGeneral(new SailrenSpawn(npcId), Config.FWS_INTERVALOFNEXTMONSTER);
		}
	}
	
	// サイレンの巣に入ったプレイヤーリストの更新
	public void addPlayerToSailrenLair(L2PcInstance pc)
	{
		if (!_playersInSailrenLair.contains(pc))
			_playersInSailrenLair.add(pc);
	}
	
	// プレイヤーをサイレンの巣に移動させる
	public void entryToSailrenLair(L2PcInstance pc)
	{
		int driftx;
		int drifty;
		
		if (canIntoSailrenLair(pc) != 0)
		{
			pc.sendMessage("条件を満たしていないため、入場が拒否されました。");
			_isAlreadyEnteredOtherParty = false;
			return;
		}
		
		if (pc.getParty() == null)
		{
			GrandBossManager.getInstance().getZone(27734, -6938, -1982).allowPlayerEntry(pc, 30); //+[JOJO]
			driftx = Rnd.get(-80, 80);
			drifty = Rnd.get(-80, 80);
			pc.teleToLocation(27734 + driftx, -6938 + drifty, -1982);
			addPlayerToSailrenLair(pc);
		}
		else
		{
			for (L2PcInstance mem : pc.getParty().getPartyMembers())
			{
				// 生きていて、パーティリーダーの認識範囲内にいれば、テレポートさせる
				if (!mem.isDead() && Util.checkIfInRange(700, pc, mem, true))
				{
					GrandBossManager.getInstance().getZone(27734, -6938, -1982).allowPlayerEntry(pc, 30); //+[JOJO]
					driftx = Rnd.get(-80, 80);
					drifty = Rnd.get(-80, 80);
					mem.teleToLocation(27734 + driftx, -6938 + drifty, -1982);
					addPlayerToSailrenLair(mem);
				}
			}
		}
		_isAlreadyEnteredOtherParty = true;
	}
	
	// パーティが全滅したかを確認（プレイヤー死亡時）
	public void checkAnnihilated(L2PcInstance pc)
	{
		// 全滅した場合は５秒後に太古の島の船着場に飛ばす。
		if (isPartyAnnihilated(pc))
		{
			_onPartyAnnihilatedTask = ThreadPoolManager.getInstance().scheduleGeneral(new OnPartyAnnihilatedTask(pc), 5000);
		}
	}
	
	// パーティが全滅したかを確認
	public synchronized boolean isPartyAnnihilated(L2PcInstance pc)
	{
		if (pc.getParty() != null)
		{
			for (L2PcInstance mem : pc.getParty().getPartyMembers())
			{
				if (!mem.isDead() && GrandBossManager.getInstance().checkIfInZone(_zoneName, pc))
				{
					return false;
				}
			}
			return true;
		}
		else
		{
			return true;
		}
	}
	
	// 時間切れおよび全滅時にプレイヤーをサイレンの巣窟から強制移動する処理
	public void banishesPlayers()
	{
		for (L2PcInstance pc : _playersInSailrenLair)
		{
			if (pc.getQuestState(_questName) != null)
				pc.getQuestState(_questName).exitQuest(true);
			if (GrandBossManager.getInstance().checkIfInZone(_zoneName, pc))
			{
				int driftX = Rnd.get(-80, 80);
				int driftY = Rnd.get(-80, 80);
				pc.teleToLocation(10468 + driftX, -24569 + driftY, -3650);
			}
		}
		_playersInSailrenLair.clear();
		_isAlreadyEnteredOtherParty = false;
	}
	
	// サイレンの巣窟を掃除
	public void setUnspawn()
	{
		// 中のプレイヤーを排除
		banishesPlayers();
		
		// テレポートキューブを消去
		for (L2NpcInstance cube : _sailrenCube)
		{
			cube.getSpawn().stopRespawn();
			cube.deleteMe();
		}
		_sailrenCube.clear();
		
		// 仕込まれているタスクをキャンセル
		if (_cubeSpawnTask != null)
		{
			_cubeSpawnTask.cancel(true);
			_cubeSpawnTask = null;
		}
		if (_sailrenSpawnTask != null)
		{
			_sailrenSpawnTask.cancel(true);
			_sailrenSpawnTask = null;
		}
		if (_intervalEndTask != null)
		{
			_intervalEndTask.cancel(true);
			_intervalEndTask = null;
		}
		if (_activityTimeEndTask != null)
		{
			_activityTimeEndTask.cancel(true);
			_activityTimeEndTask = null;
		}
		
		// 状態の初期化
		_velociraptor = null;
		_pterosaur = null;
		_tyranno = null;
		_sailren = null;
		
		// 既定の時間まで中に入れないようにしておく
		setInetrvalEndTask();
	}
	
	// 帰還用キューブを出現させる
	public void spawnCube()
	{
		for (L2Spawn spawnDat : _sailrenCubeSpawn)
		{
			_sailrenCube.add(spawnDat.doSpawn());
		}
	}
	
	// 帰還用キューブを出現させるタスクの仕込み
	public void setCubeSpawn()
	{
		_alive = GrandBossStatus.DEAD;
		_stateSet.set("respawn_time",
				Calendar.getInstance().getTimeInMillis()
				+ Config.FWS_FIXINTERVALOFSAILRENSPAWN
				+ Rnd.get(Config.FWS_RANDOMINTERVALOFSAILRENSPAWN));
		GrandBossManager.getInstance().setBossStatus(_bossId, _alive);
		GrandBossManager.getInstance().setStatsSet(_bossId, _stateSet);
		GrandBossManager.getInstance().save();
		
		_cubeSpawnTask = ThreadPoolManager.getInstance().scheduleGeneral(new CubeSpawn(), 10000);
		
		Date dt = new Date(_stateSet.getLong("respawn_time"));
		_log.info("SailrenManager : Sailren is dead.");
		_log.info("SailrenManager : Next spawn date of Sailren is " + dt + ".");
	}
	
	// サイレンの出現禁止解除タスクの仕込み
	public void setInetrvalEndTask()
	{
		if (_alive != GrandBossStatus.INTERVAL)
		{
			_alive = GrandBossStatus.INTERVAL;
			GrandBossManager.getInstance().setBossStatus(_bossId, _alive);
			GrandBossManager.getInstance().save();
		}
		
		_intervalEndTask = ThreadPoolManager.getInstance().scheduleGeneral(
					new IntervalEnd(), GrandBossManager.getInstance().getInterval(_bossId));
		_log.info("SailrenManager : Interval START.");
	}
	
	// update knownlist.
	void updateKnownList(L2NpcInstance boss)
	{
		boss.getKnownList().getKnownPlayers().clear();
		for (L2PcInstance pc : _playersInSailrenLair)
		{
			boss.getKnownList().getKnownPlayers().put(pc.getObjectId(), pc);
		}
	}
	
	// モンスターを出現させる
	private class SailrenSpawn implements Runnable
	{
		int _npcId;
		L2CharPosition _pos = new L2CharPosition(27628, -6109, -1982, 44732);
		
		public SailrenSpawn(int npcId)
		{
			_npcId = npcId;
		}
		
		public void run()
		{
			switch (_npcId)
			{
				case VELOCIRAPTOR: // ヴェロキラプトル
					_velociraptor = _velociraptorSpawn.doSpawn();
					_velociraptor.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, _pos);
					if (_socialTask != null)
					{
						_socialTask.cancel(true);
						_socialTask = null;
					}
					_socialTask = ThreadPoolManager.getInstance().scheduleGeneral(new Social(_velociraptor, 2), 6000);
					if (_activityTimeEndTask != null)
					{
						_activityTimeEndTask.cancel(true);
						_activityTimeEndTask = null;
					}
					_activityTimeEndTask = ThreadPoolManager.getInstance().scheduleGeneral(
								new ActivityTimeEnd(_velociraptor), Config.FWS_ACTIVITYTIMEOFMOBS);
					break;
				
				case PTEROSAUR: // ランフォリンクス
					_velociraptorSpawn.stopRespawn();
					_pterosaur = _pterosaurSpawn.doSpawn();
					_pterosaur.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, _pos);
					if (_socialTask != null)
					{
						_socialTask.cancel(true);
						_socialTask = null;
					}
					_socialTask = ThreadPoolManager.getInstance().scheduleGeneral(new Social(_pterosaur, 2), 6000);
					if (_activityTimeEndTask != null)
					{
						_activityTimeEndTask.cancel(true);
						_activityTimeEndTask = null;
					}
					_activityTimeEndTask = ThreadPoolManager.getInstance().scheduleGeneral(
								new ActivityTimeEnd(_pterosaur), Config.FWS_ACTIVITYTIMEOFMOBS);
					break;
				
				case TYRANNOSAURUS: // ティラノザウルス
					_pterosaurSpawn.stopRespawn();
					_tyranno = _tyrannoSpawn.doSpawn();
					_tyranno.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, _pos);
					if (_socialTask != null)
					{
						_socialTask.cancel(true);
						_socialTask = null;
					}
					_socialTask = ThreadPoolManager.getInstance().scheduleGeneral(new Social(_tyranno, 2), 6000);
					if (_activityTimeEndTask != null)
					{
						_activityTimeEndTask.cancel(true);
						_activityTimeEndTask = null;
					}
					_activityTimeEndTask = ThreadPoolManager.getInstance().scheduleGeneral(
								new ActivityTimeEnd(_tyranno), Config.FWS_ACTIVITYTIMEOFMOBS);
					break;
				
				case SAILREN: // サイレン
					_tyrannoSpawn.stopRespawn();
					_sailren = _sailrenSapwn.doSpawn();
					
					_stateSet.set("respawn_time",
							Calendar.getInstance().getTimeInMillis()
							+ Config.FWS_FIXINTERVALOFSAILRENSPAWN
							+ Rnd.get(Config.FWS_RANDOMINTERVALOFSAILRENSPAWN)
							+ Config.FWS_ACTIVITYTIMEOFMOBS);
					_alive = GrandBossStatus.ALIVE;
					GrandBossManager.getInstance().setBossStatus(_bossId, _alive);
					GrandBossManager.getInstance().setStatsSet(_bossId, _stateSet);
					GrandBossManager.getInstance().save();
					_log.info("SailrenManager : Spawn Sailren.");
					
					_sailren.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, _pos);
					if (_socialTask != null)
					{
						_socialTask.cancel(true);
						_socialTask = null;
					}
					_socialTask = ThreadPoolManager.getInstance().scheduleGeneral(new Social(_sailren, 2), 6000);
					if (_activityTimeEndTask != null)
					{
						_activityTimeEndTask.cancel(true);
						_activityTimeEndTask = null;
					}
					_activityTimeEndTask = ThreadPoolManager.getInstance().scheduleGeneral(
								new ActivityTimeEnd(_sailren), Config.FWS_ACTIVITYTIMEOFMOBS);
					break;
			}
			
			if (_sailrenSpawnTask != null)
			{
				_sailrenSpawnTask.cancel(true);
				_sailrenSpawnTask = null;
			}
		}
	}
	
	// 帰還用キューブを出現させる
	private class CubeSpawn implements Runnable
	{
		public CubeSpawn()
		{
		}
		
		public void run()
		{
			spawnCube();
		}
	}
	
	// 時間切れ処理
	private class ActivityTimeEnd implements Runnable
	{
		L2NpcInstance _mob;
		
		public ActivityTimeEnd(L2NpcInstance npc)
		{
			_mob = npc;
		}
		
		public void run()
		{
			if (!_mob.isDead())
			{
				_mob.deleteMe();
				_mob.getSpawn().stopRespawn();
				_mob = null;
			}
			// サイレンの巣窟を掃除
			setUnspawn();
		}
	}
	
	// サイレン出現インターバルの終了
	private class IntervalEnd implements Runnable
	{
		public IntervalEnd()
		{
		}
		
		public void run()
		{
			doIntervalEnd();
		}
	}
	
	void doIntervalEnd()
	{
		_playersInSailrenLair.clear();
		_alive = GrandBossStatus.NOTSPAWN;
		GrandBossManager.getInstance().setBossStatus(_bossId, _alive);
		GrandBossManager.getInstance().save();
		_log.info("SailrenManager : Interval END.");
	}
	
	// パーティが全滅していれば太古の島の船着場へ飛ばす
	private class OnPartyAnnihilatedTask implements Runnable
	{
		L2PcInstance _player;
		
		public OnPartyAnnihilatedTask(L2PcInstance player)
		{
			_player = player;
		}
		
		public void run()
		{
			setUnspawn();
		}
	}
	
	// ソーシャルアクションの実行
	private class Social implements Runnable
	{
		private int _action;
		private L2NpcInstance _npc;
		
		public Social(L2NpcInstance npc, int actionId)
		{
			_npc = npc;
			_action = actionId;
		}
		
		public void run()
		{
			updateKnownList(_npc);
			SocialAction sa = new SocialAction(_npc.getObjectId(), _action);
			_npc.broadcastPacket(sa);
		}
	}
}
