/*
 * 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.
 */
package ai.individual.grandboss;

import java.util.concurrent.ScheduledFuture;

import javolution.util.FastMap;
import l2.universe.Config;
import l2.universe.gameserver.ThreadPoolManager;
import l2.universe.gameserver.ai.CtrlIntention;
import l2.universe.gameserver.datatables.MapRegionTable;
import l2.universe.gameserver.instancemanager.GrandBossManager;
import l2.universe.gameserver.instancemanager.ZoneManager;
import l2.universe.gameserver.model.L2ItemInstance;
import l2.universe.gameserver.model.L2Party;
import l2.universe.gameserver.model.actor.L2Character;
import l2.universe.gameserver.model.actor.L2Npc;
import l2.universe.gameserver.model.actor.instance.L2GrandBossInstance;
import l2.universe.gameserver.model.actor.instance.L2PcInstance;
import l2.universe.gameserver.model.zone.type.L2BossZone;
import l2.universe.gameserver.network.SystemMessageId;
import l2.universe.gameserver.network.serverpackets.CreatureSay;
import l2.universe.gameserver.network.serverpackets.MagicSkillUse;
import l2.universe.gameserver.network.serverpackets.SpecialCamera;
import l2.universe.gameserver.network.serverpackets.SystemMessage;
import l2.universe.gameserver.templates.StatsSet;
import l2.universe.gameserver.util.Util;
import l2.universe.util.Rnd;
import l2.universe.scripts.ai.L2AttackableAIScript;

/**
 * Retail info about Sailren Presentation for doing it.
 * 1 - It begins the camera, the camera must be done looking a video
 * 2 - A star fall begins to fall 1 second later the camera begins over the invisible npc (SkillID = 5090)
 * The star fall lasts 14 seconds, i think in 2 periods
 * 3 - 16 seconds later of the camera start, Sailren spawns
 * 4 - The camera lasts 30 seconds
 * 
 * @author Synerge
 */
public class Sailren extends L2AttackableAIScript
{
	private static final String qn = "Sailren";
	
	private static final int MANAGER = 32109;
	private static final int CUBE = 32107;
	private static final int DUMMY = 32110;
	
	private static final int SAILREN = 29065;
	private static final int VELO = 22223;
	private static final int PTERO = 22199;
	private static final int TREX = 22217;
	private static final int CUBIC = 32107;
	
	private static final int sailrenX = 27333;
	private static final int sailrenY = -6835;
	private static final int sailrenZ = -1970;
	
	// Boss Zone
	private L2BossZone _nest = null;
	private static final int ZONEID = 35000;
	
	//Guard spawn
	private static final int MOBS_X = 27213;
	private static final int MOBS_Y = -6539;
	private static final int MOBS_Z = -1976;
	
	//requirements 
	private static final int REQUIRED_ITEM = 8784;
	private static final int MIN_PLAYERS = 2;
	private static final int MAX_PLAYERS = 9;
	private static final int MIN_LEVEL = 70;
	
	//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 FIGHTING = 1; //SAILREN is engaged in battle, annihilating his foes. Entry is locked
	private static final byte DEAD = 2; //SAILREN has been killed. Entry is locked
	
	private static final int SPAWN_X = 27190;
	private static final int SPAWN_Y = -7163;
	private static final int SPAWN_Z = -1968;
	
	// Task
	protected ScheduledFuture<?> _activityCheckTask = null;
	protected long _lastAction = 0;
	protected byte _veloKilled = 0;
	protected L2Character _lastTarget = null;
	private FastMap<Integer, L2Npc> _mobs;
	private static final int INACTIVITYTIME = 2700000;
	private static final long CHECK_INTERVAL = 540000;
	
	public Sailren(int id, String name, String descr)
	{
		super(id, name, descr);
		
		addKillId(VELO);
		addKillId(PTERO);
		addKillId(TREX);
		addKillId(SAILREN);
		addStartNpc(MANAGER);
		addTalkId(MANAGER);
		addTalkId(CUBIC);
		
		_nest = (L2BossZone) ZoneManager.getInstance().getZoneById(ZONEID);
		StatsSet info = GrandBossManager.getInstance().getStatsSet(SAILREN);
		final int status = GrandBossManager.getInstance().getBossStatus(SAILREN);
		if (status == DEAD)
		{
			final long temp = (info.getLong("respawn_time") - System.currentTimeMillis());
			if (temp > 0)
				startQuestTimer("unlock", temp, null, null);
			else
				GrandBossManager.getInstance().setBossStatus(SAILREN, DORMANT);
		}
		else if (status != DORMANT && info.getLong("respawn_time") == 0)
			GrandBossManager.getInstance().setBossStatus(SAILREN, DORMANT);
	}
	
	private boolean checkConditions(L2PcInstance player)
	{
		if (player.getInventory().getItemByItemId(REQUIRED_ITEM) == null)
		{
			player.sendMessage("You dont have required item.");
			return false;
		}
		
		final L2Party party = player.getParty();		
		if (party == null)
		{
			player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.NOT_IN_PARTY_CANT_ENTER));
			return false;
		}
		else if (party.getLeader() != player)
		{
			player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.ONLY_PARTY_LEADER_CAN_ENTER));
			return false;
		}
		else if (party.getMemberCount() < MIN_PLAYERS || party.getMemberCount() > MAX_PLAYERS)
		{
			player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.PARTY_EXCEEDED_THE_LIMIT_CANT_ENTER));
			return false;
		}
		
		for (L2PcInstance partyMember : party.getPartyMembers())
		{			
			if (partyMember == null)
				continue;
			
			if (partyMember.getLevel() < MIN_LEVEL)
			{
				SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_LEVEL_REQUIREMENT_NOT_SUFFICIENT);
				sm.addPcName(partyMember);
				party.broadcastToPartyMembers(sm);
				sm = null;
				return false;
			}
			
			if (!Util.checkIfInRange(1000, player, partyMember, true))
			{
				SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_IN_LOCATION_THAT_CANNOT_BE_ENTERED);
				sm.addPcName(partyMember);
				party.broadcastToPartyMembers(sm);
				sm = null;
				return false;
			}
		}
		
		return true;
	}
	
	@Override
	public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
	{
		// Spawn 3 Velociraptors
		if (event.equalsIgnoreCase("start"))
		{
			if (_mobs == null)
				_mobs = new FastMap<Integer, L2Npc>();
			_mobs.clear();
			_lastAction = 0;
			L2Npc temp;
			for (int i = 0; i < 3; i++)
			{
				temp = addSpawn(VELO, sailrenX + Rnd.get(100), sailrenY + Rnd.get(100), MOBS_Z, 0, false, 0);
				temp.getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
				temp.setRunning();
				_mobs.put(temp.getObjectId(), temp);
				//_mobs.add(temp);
			}
			startQuestTimer("despawn", CHECK_INTERVAL, null, null, true);
		}
		// When velos killed, spawn a Pterosaur
		else if (event.equals("round2"))
		{
			final L2Npc temp = addSpawn(PTERO, MOBS_X + Rnd.get(150), MOBS_Y + Rnd.get(150), MOBS_Z + Rnd.get(150), 0, false, 0);
			//_mobs.add(temp);
			_mobs.put(temp.getObjectId(), temp);
			
			if (_lastTarget != null)
			{
				temp.setTarget(_lastTarget);
				temp.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, _lastTarget);
				temp.setRunning();
			}
		}
		// When Pterosaur is dead, spawn a Trex
		else if (event.equals("round3"))
		{
			final L2Npc temp = addSpawn(TREX, MOBS_X + Rnd.get(150), MOBS_Y + Rnd.get(150), MOBS_Z + Rnd.get(150), 0, false, 0);
			temp.broadcastPacket(new CreatureSay(temp.getObjectId(), 0, temp.getName(), "?"));
			//_mobs.add(temp);
			_mobs.put(temp.getObjectId(), temp);
			
			if (_lastTarget != null)
			{
				temp.setTarget(_lastTarget);
				temp.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, _lastTarget);
				temp.setRunning();
			}
		}
		// Prepare the presentation with camera and dummy npc for effects
		else if (event.equalsIgnoreCase("spawn"))
		{			
			final L2Npc temp = addSpawn(DUMMY, sailrenX, sailrenY, sailrenZ, 0, false, 0);
			
			// Start Special Camera
			_nest.broadcastPacket(new SpecialCamera(temp.getObjectId(), 600, -75, 3, -150, 34000, 0, 0, 1, 0));
			
			// 1 second later start showing the Start Fall and Repeat
			startQuestTimer("skill", 2000, temp, null, true);
			
			// Delete dummy 1 second before spawning sailren
			startQuestTimer("delete_dummy", 15000, temp, null);
			
			// After 16 seconds spawn sailren
			startQuestTimer("sailren", 16000, temp, null);
		}
		// Spawn the real Sailren
		else if (event.equalsIgnoreCase("sailren"))
		{
			final L2GrandBossInstance Sailren = (L2GrandBossInstance) addSpawn(SAILREN, sailrenX, sailrenY, sailrenZ, 27306, false, 0);
			GrandBossManager.getInstance().addBoss(Sailren);
			//_mobs.add(Sailren);
			_mobs.put(Sailren.getObjectId(), Sailren);
		}
		// Skill for the presentation
		else if (event.equalsIgnoreCase("skill"))
		{
			_nest.broadcastPacket(new MagicSkillUse(npc, npc, 5090, 1, 2500, 0));
		}
		// Delete the dummy npc
		else if (event.equalsIgnoreCase("delete_dummy"))
		{
			npc.deleteMe();
			cancelQuestTimers("skill");
			_nest.broadcastPacket(new MagicSkillUse(npc, npc, 5091, 1, 2500, 0));
		}
		// Despawn the teleportation cubic
		else if (event.equalsIgnoreCase("despawn"))
		{
			if (_mobs == null)
				return null;
			
			if (npc != null)
				npc.deleteMe();
			
			if (!_mobs.isEmpty())
				for (L2Npc mob : _mobs.values())
					mob.deleteMe();
			
			_mobs.clear();
			_mobs = null;
			_nest.oustAllPlayers();
		}
		else if (event.equalsIgnoreCase("unlock"))
		{
			GrandBossManager.getInstance().setBossStatus(SAILREN, DORMANT);
		}
		
		return null;
	}
	
	@Override
	public String onTalk(L2Npc npc, L2PcInstance player)
	{
		String htmltext = "";
		
		switch (npc.getNpcId())
		{
			case MANAGER:
			{
				switch (GrandBossManager.getInstance().getBossStatus(SAILREN))
				{
					case DORMANT:
						if (!checkConditions(player))
							return htmltext;
						else
						{
							L2ItemInstance item = player.getInventory().getItemByItemId(REQUIRED_ITEM);
							player.getInventory().destroyItem("Sailren AI", item, 1, null, null);
							
							GrandBossManager.getInstance().setBossStatus(SAILREN, FIGHTING);
							
							for (L2PcInstance member : player.getParty().getPartyMembers())
							{						
								if (member == null) // impossible NPE?
									continue;
		
								member.teleToLocation(SPAWN_X + Rnd.get(150), SPAWN_Y + Rnd.get(150), SPAWN_Z + Rnd.get(150), true);
								if (member.getPet() != null)
									member.getPet().teleToLocation(SPAWN_X + Rnd.get(50), SPAWN_Y + Rnd.get(50), SPAWN_Z, true);
							}
							
							_lastAction = System.currentTimeMillis();
							// Start repeating timer to check for inactivity
							_activityCheckTask = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new CheckActivity(), 60000, 60000);
							
							startQuestTimer("start", 60000, npc, player);					
						}
						break;
					case FIGHTING:
						htmltext = "<html><body>Someone else is already inside the Magic Force Field. Try again later.</body></html>";
						break;
					default:
						htmltext = "<html><body>Sailren is dead.<br> Come back later.</body></html>";
						break;
				}
				break;
			}
			case CUBE:
			{
				if (player != null)
				{
					// Teleport all the party outside when party leader request it
					for (L2PcInstance member : player.getParty().getPartyMembers())
					{						
						if (member == null)
							continue;
						
						member.teleToLocation(MapRegionTable.TeleportWhereType.Town);
						if (member.getPet() != null)
							member.getPet().teleToLocation(MapRegionTable.TeleportWhereType.Town);
					}
				}
			}
		}
		
		return htmltext;
	}
	
	@Override
	public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isPet)
	{		
		_lastAction = System.currentTimeMillis();		
		return null;
	}
	
	private class CheckActivity implements Runnable
	{
		public void run()
		{
			final long temp = (System.currentTimeMillis() - _lastAction);
			if (temp > INACTIVITYTIME)
			{
				GrandBossManager.getInstance().setBossStatus(SAILREN, DORMANT);
				_activityCheckTask.cancel(false);
			}
		}
	}
	
	@Override
	public String onKill(L2Npc npc, L2PcInstance killer, boolean isPet)
	{
		switch (npc.getNpcId())
		{
			case VELO:
			{
				if (_mobs == null || !_mobs.containsKey(npc.getObjectId()))
					return null;
				
				_mobs.remove(npc.getObjectId());
				_lastTarget = (L2Character) npc.getTarget();
				npc.deleteMe();
				
				// Only spawn the next, when the 3 VelociRaptors are dead
				if (_mobs.isEmpty())
					startQuestTimer("round2", 4000, npc, killer);
				
				break;
			}
			case PTERO:
			{
				if (_mobs == null || !_mobs.containsKey(npc.getObjectId()))
					return null;

				_mobs.remove(npc);
				_lastTarget = (L2Character) npc.getTarget();
				npc.deleteMe();				
				startQuestTimer("round3", 4000, npc, killer);				
				break;
			}
			case TREX:
			{
				if (_mobs == null || !_mobs.containsKey(npc.getObjectId()))
					return null;
				
				_mobs.remove(npc.getObjectId());
				_lastTarget = null;
				npc.deleteMe();
				startQuestTimer("spawn", 30000, npc, killer); // 5min wait for Sailren. Confirmed.
				break;
			}
			case SAILREN:
			{
				GrandBossManager.getInstance().setBossStatus(SAILREN, DEAD);
				
				// also save the respawn time so that the info is maintained past reboots
				final long respawnTime = (long) Config.Interval_Of_Sailren_Spawn + Rnd.get(Config.Random_Of_Sailren_Spawn);			
				StatsSet info = GrandBossManager.getInstance().getStatsSet(SAILREN);
				info.set("respawn_time", System.currentTimeMillis() + respawnTime);
				GrandBossManager.getInstance().setStatsSet(SAILREN, info);
				
				final L2Npc temp = addSpawn(CUBIC, npc.getX(), npc.getY(), npc.getZ(), 0, false, 0);
				cancelQuestTimers("despawn");
				startQuestTimer("despawn", 300000, temp, killer);
				npc.deleteMe();
				break;
			}
		}
		return null;
	}
		
	public static void main(String[] args)
	{
		new Sailren(-1, qn, "ai");
	}
}
