/*
 * 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;

import java.util.Collection;

import ai.group_template.L2AttackableAIScript;

import com.l2jserver.gameserver.ai.CtrlIntention;
import com.l2jserver.gameserver.datatables.DoorTable;
import com.l2jserver.gameserver.datatables.SpawnTable;
import com.l2jserver.gameserver.idfactory.IdFactory;
import com.l2jserver.gameserver.instancemanager.CastleManager;
import com.l2jserver.gameserver.instancemanager.GrandBossManager;
import com.l2jserver.gameserver.model.L2CharPosition;
import com.l2jserver.gameserver.model.L2ItemInstance;
import com.l2jserver.gameserver.model.L2Spawn;
import com.l2jserver.gameserver.model.L2World;
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.entity.GrandBossState.StateEnum;
import com.l2jserver.gameserver.network.serverpackets.NpcSay;
import com.l2jserver.gameserver.network.serverpackets.SocialAction;
import com.l2jserver.gameserver.network.serverpackets.AbstractNpcInfo.NpcInfo;
import com.l2jserver.util.Rnd;
import com.l2jserver.util.Util;

/**
 * Benom AI
 * @author theOne
 *      "benom.py" l2jfree-datapack rev6024, timestamp 2009/06/01 04:08:49
 * JOJO Translate
 *      "benom.py" to "Benom.java"
 */

public class Benom extends L2AttackableAIScript
{
	static final boolean DEBUG = true;
	static final boolean TEST = true;

	static final boolean OPTION1 = true;
					//JOJO ルール変更
					// ルウン城の城主がＮＰＣのときは、
					//   ベノム(テレポーター)が伝令の横に出現し、
					//   誰でもベノム(ボス)を討伐することができる。
					// ルウン城に城主がいるときは、
					//   ベノム(テレポーター)が玉座の間に出現し、
					//   城の血盟のみが狩ることができる。

	private static final int BENOM = 29054;
	private static final int BENOM_TELEPORT = 13101;

	private static final int BENOM_SPAWN_TIME = 86400000;	//getSiegeDate()-24H
	private static final int BENOM_DESPAWN_TIME = 5400000;	//getSiegeDate()+1.5H

	private static final String[] benomSpeak =
	{
		  "You should have finished me when you had the chance!!!"
		, "I will crush all of you!!!"
		, "I am not finished here, come face me!!!"
		, "You cowards!!! I will torture each and everyone of you!!!"
	};

	private int checkState()
	{
		return GrandBossManager.getInstance().getBossStatus(BENOM);
	}

	private void updateState(int status)
	{
		if (checkState() != status)
		{
			GrandBossManager.getInstance().setBossStatus(BENOM, status);
			GrandBossManager.getInstance().setStatsSet(BENOM, null);
		}
	}

	@Override
	public L2Npc addSpawn(int npcId, int x, int y, int z, int heading, boolean randomOffSet, long despawnDelay)
	{
		L2Npc npc = super.addSpawn(npcId, x, y, z, heading, randomOffSet, despawnDelay, false);
		if (DEBUG) SpawnTable.getInstance().addNewSpawn(npc.getSpawn(), false);
		return npc;
	}

	private void unspawnNpc(int npcId)
	{
		if (DEBUG) {
			for (L2Spawn spawn : SpawnTable.getInstance().getSpawnTable().values())
			{
				if (spawn.getNpcid() == npcId)
				{
					SpawnTable.getInstance().deleteSpawn(spawn, false);
					L2Npc npc = spawn.getLastSpawn();
					npc.deleteMe();
				}
			}
		}
	}

	private static final int[][] benomWalkRoutes = {
	//		      x      y     z     time	[open close]
	/*0*/	 { 12565,-49739, -547	, 9000 }
	/*1*/	,{ 11242,-49689,  -33	,18000 }
	/*2*/	,{ 10751,-49702,   83	, 6500 }
	/*3*/	,{ 10824,-50808,  316	,14000 }
	/*4*/	,{  9084,-50786,  972	,16000 }
	/*5*/	,{  9095,-49787, 1252	,25000 }
	/*6*/	,{  8371,-49711, 1252	, 9500 }
	/*7*/	,{  8423,-48545, 1252	,15000 }
	/*8*/	,{  9105,-48474, 1252	, 8500 }
	/*9*/	,{  9085,-47488,  972	,13500 }
	/*10*/	,{ 10858,-47527,  316	,25000 }
	/*11*/	,{ 10842,-48626,   75	,15000 }
	/*12*/	,{ 12171,-48464, -547	,19500 }
	/*13*/	,{ 13565,-49145, -535	,17000 }
	/*14*/	,{ 15653,-49159,-1059	,30500	,15000,23000 }
	/*15*/	,{ 15423,-48402, -839	,18000 }
	/*16*/	,{ 15066,-47438, -419	,14000 }
	/*17*/	,{ 13990,-46843, -292	,15500 }
	/*18*/	,{ 13685,-47371, -163	, 8000 }
	/*19*/	,{ 13384,-47470, -163	, 4000 }
	/*20*/	,{ 14609,-48608,  346	,22000 }
	/*21*/	,{ 14301,-47906,  498	,10000 }
	/*22*/	,{ 13667,-47488,  743	,10000 }
	/*23*/	,{ 12894,-49109,  980	,23000 }
	/*24*/	,{ 10135,-49150,  996	,34500 }
	/*25*/	,{ 12894,-49109,  980	,35000 }
	/*26*/	,{ 13738,-50894,  747	,25500 }
	/*27*/	,{ 14398,-50314,  462	,12000 }
	/*28*/	,{ 14579,-49698,  347	, 8500 }
	/*29*/	,{ 12896,-51135, -166	,29500 }
	/*30*/	,{ 12852,-51922, -295	,10500 }
	/*31*/	,{ 14275,-51487, -295	,19000 }
	/*32*/	,{ 15328,-50406, -603	,20000 }
	/*33*/	,{ 15594,-49192,-1059	,17500 }
	/*34*/	,{ 12956,-49153, -537	,33500	,500,4000 }
	};

	private L2Npc _benom = null;
	private L2Npc _benomTeleport = null;
	private int _benomWalkRouteStep = -1;

	//[JOJO]-------------------------------------------------
	private class SpecialCamera extends com.l2jserver.gameserver.network.serverpackets.SpecialCamera
	{
		public SpecialCamera(int id, int dist, int yaw, int pitch, int time, int duration)
		{
			super(id, dist, yaw, pitch, time, duration, 0, 0, 1, 0);
		}
	}
	//-------------------------------------------------------

	public Benom(int id, String name, String descr)
	{
		super(id,name,descr);

		// Quest NPC starter initialization
		addStartNpc(BENOM_TELEPORT);
		addTalkId(BENOM_TELEPORT);
		addAggroRangeEnterId(BENOM);
		addKillId(BENOM);

		switch (checkState()) {
		case StateEnum.DEAD:
		case StateEnum.INTERVAL:
			interval();
			break;
	/*	case StateEnum.NOTSPAWN: */
	/*	case StateEnum.ALIVE: */
		default:
    		init();
		}
	}

	/**
	 * 攻城時刻の24時間前になったらベノム(テレポとレイド)を配置するようタイマー設定
	 */
	private void init()
	{
		long now = System.currentTimeMillis();
		long siegeDate = CastleManager.getInstance().getCastleById(8).getSiegeDate().getTimeInMillis();
		if (now < siegeDate - /*24H*/BENOM_SPAWN_TIME)
		{
			long t = siegeDate - BENOM_SPAWN_TIME - now;
			updateState(StateEnum.NOTSPAWN);
			startQuestTimer("BenomRaidRoomSpawn", t, null, null);
		}
		else if (now < siegeDate + /*1.5H*/BENOM_DESPAWN_TIME)
		{
			long t = 1000;
			updateState(StateEnum.NOTSPAWN);
			startQuestTimer("BenomRaidRoomSpawn", t, null, null);
		}
		else
		{
			updateState(StateEnum.INTERVAL);
			interval();
		}
	}

	/**
	 * 攻城戦(2時間)が終了して次回の日程が確定するまで(24時間)待機する
	 */
	private void interval()
	{
		long now = System.currentTimeMillis();
		long timeRegistrationOverDate = CastleManager.getInstance().getCastleById(8).getSiege().getTimeRegistrationOverDate().getTimeInMillis();
		long siegeDate = CastleManager.getInstance().getCastleById(8).getSiegeDate().getTimeInMillis();


		if (timeRegistrationOverDate < now && now < siegeDate - /*24H*/BENOM_SPAWN_TIME)
		{
			//次回の攻城戦の日時が確定している
			updateState(StateEnum.NOTSPAWN);
			init();
			return;
		}

		//次回の攻城戦の日時が確定するまで(繰り返し)待つ
		long intervalTime = Math.max(21600000, timeRegistrationOverDate - now);
		startQuestTimer("interval", intervalTime, null, null);
	}

	private L2PcInstance getRandomPlayer(L2Npc npc)
	{
		Collection<L2PcInstance> knowns = npc.getKnownList().getKnownPlayers().values();
		if (knowns.size() <= 0)
			return null;
		L2PcInstance[] knownPlayers = new L2PcInstance[knowns.size()];
		int count = 0;
		for (L2PcInstance player : knowns)
		{
			if (player == null || player.isDead())
				continue;
			knownPlayers[count++] = player;
		}
		if (count > 0)
			return knownPlayers[Rnd.get(count)];
		else
			return null;
	}

	public String onTalk(L2Npc npc, L2PcInstance player)
	{
///*#IF DEBUG#*/if (true) {{
//visualizeWalkRoutes(null);
//cancelQuestTimers("BenomRaidSiegeSpawn");
//startQuestTimer("BenomRaidSiegeSpawn", 1000, _benom, null);
//return "デバッグ開始";
///*#END IF#*/}}
		int castleOwner = CastleManager.getInstance().getCastleById(8).getOwnerId();
		int clanId = player.getClanId();
		if (castleOwner == 0 && OPTION1
		 || castleOwner != 0 && castleOwner == clanId)
		{
			int x =  12558 + Rnd.get(-100, 100);
			int y = -49279 + Rnd.get(-100, 100);
			player.teleToLocation(x, y, -3007);
			return null;
		}
		else
			return "<html><body>Benom's Avatar:<br>Your clan does not own this castle. Only members of this Castle's owning clan can challenge Benom.</body></html>";
	}

	public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
	{
		if (event == "BenomRaidRoomSpawn")
		{
			if (checkState() == StateEnum.DEAD)
			{
				return null;
			}

			_benom = addSpawn(BENOM, 12047, -49211, -3009, 0, false, 0);	//underground jail dungeon
			if (DEBUG) SpawnTable.getInstance().addNewSpawn(_benom.getSpawn(), false);


			if (CastleManager.getInstance().getCastleById(8).getOwnerId() > 0)
			{
				_benomTeleport = addSpawn(BENOM_TELEPORT, 11013, -49629, -547, 13400, false, 0);	//throne room
			}
			else
			{
				_benomTeleport = addSpawn(BENOM_TELEPORT, 26969, -49278, -1305, 0, false, 0);	//out of the castle
			}
			
			_benomWalkRouteStep = -1;	//disable walk
			updateState(StateEnum.ALIVE);

			/**
			 * 攻城時刻になったらトリオルの長ベノムが地下収容所から玉座の間にテレポートするようタイマー設定
			 */
			long now = System.currentTimeMillis();
			long siegeDate = CastleManager.getInstance().getCastleById(8).getSiegeDate().getTimeInMillis();
			long t = Math.max(1000, siegeDate - now);
			startQuestTimer("BenomRaidSiegeSpawn", t, _benom, null);
		}
		else if (event == "BenomRaidSiegeSpawn")
		{
			if (_benomTeleport != null)
			{
				_benomTeleport.deleteMe();
				_benomTeleport = null;
				unspawnNpc(BENOM_TELEPORT);
			}

			if (npc == null)
			{
				return null;
			}
			if (npc.isDead())
			{
				return null;
			}
			if (! npc.isVisible())
			{
				return null;
			}
			if (checkState() != StateEnum.ALIVE)
			{
				return null;
			}

			npc.teleToLocation(11025, -49152, -537);	//throne room
			startQuestTimer("BenomSpawnEffect", 100, npc, null);
			startQuestTimer("BenomBossDespawn", BENOM_DESPAWN_TIME, npc, null);
		}
		else if (event == "BenomSpawnEffect")
		{
			npc.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
			npc.broadcastPacket(new SpecialCamera(npc.getObjectId(), 200, 0, 150, 0, 5000));
			npc.broadcastPacket(new SocialAction(npc.getObjectId(), 3));

			_benomWalkRouteStep = benomWalkRoutes.length - 1;	//enable walk. next route is #0.
			startQuestTimer("BenomWalk", 5000, npc, null);
		}
		else if (event == "Attacking")
		{
			if (npc.isDead() || ! npc.isVisible())
				return null;

			L2PcInstance target;
			if ((target = getRandomPlayer(npc)) != null)
			{
				((L2Attackable)npc).addDamageHate(target, 0, 999);
				npc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, target);
				startQuestTimer("Attacking", 2000, npc, null/*player*/);
			}
			else if (_benomWalkRouteStep >= 0)
			{
				 startQuestTimer("BenomWalkFinish", 2000, npc, null);
			}
		}
		else if (event == "BenomWalkFinish")
		{
			if (npc.isDead() || ! npc.isVisible())
				return null;

			if (_benomWalkRouteStep >= 0)
		//	if (npc.getCastle().getSiege().getIsInProgress())
			{
				cancelQuestTimers("Attacking");
				int[] route = benomWalkRoutes[_benomWalkRouteStep];
				int x = route[0];
				int y = route[1];
				int z = route[2];
			/*	int time = route[3]; */
				npc.teleToLocation(x, y, z);
				npc.setWalking();
				startQuestTimer("BenomWalk", 2200, npc, null);
			}
		}
		else if (event == "BenomWalk")
		{
			if (npc.isDead() || ! npc.isVisible())
				return null;

			if (npc.getAI().getIntention() == CtrlIntention.AI_INTENTION_MOVE_TO)
			{
				startQuestTimer("BenomWalk", 1000, npc, null);
			}
			else
			{
				startQuestTimer("Talk", 100, npc, null);
				npc.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
				_benomWalkRouteStep = (_benomWalkRouteStep + 1) % benomWalkRoutes.length;
				int[] route = benomWalkRoutes[_benomWalkRouteStep];
				int x = route[0];
				int y = route[1];
				int z = route[2];
				long time = route[3];
				if (route.length > 5) {
					startQuestTimer("DoorOpen" , route[4], null, null);
					startQuestTimer("DoorClose", route[5], null, null);
				}
				npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new L2CharPosition(x, y, z, 0));
				startQuestTimer("BenomWalk", time, npc, null);
			}
		}
		else if (event == "DoorOpen")
		{
			DoorTable.getInstance().getDoor(20160005).openMe();
		}
		else if (event == "DoorClose")
		{
			DoorTable.getInstance().getDoor(20160005).closeMe();
		}
		else if (event == "Talk")
		{
			if (Rnd.get(100) < 40)
				npc.broadcastPacket(new NpcSay(npc.getObjectId(), 0, npc.getNpcId(), benomSpeak[Rnd.get(benomSpeak.length)]));
		}
		else if (event == "BenomBossDespawn")
		{
			cancelBenomTimers(npc);
			npc.deleteMe();
			_benom = npc = null;
			unspawnNpc(BENOM);
			updateState(StateEnum.INTERVAL);
			interval();
		}
		else if (event == "interval")
		{
			interval();
		}
		else
		{
		}
//		return;
		return super.onAdvEvent(event, npc, player);
	}

	public String onAggroRangeEnter(L2Npc npc, L2PcInstance player, boolean isPet)
	{
		cancelQuestTimers("BenomWalk");
		cancelQuestTimers("BenomWalkFinish");
		startQuestTimer("Attacking", 100, npc, null/*player*/);
		return super.onAggroRangeEnter(npc, player, isPet);
	}

	public String onKill(L2Npc npc, L2PcInstance killer, boolean isPet) 
	{
		cancelBenomTimers(npc);
		_benom = npc = null;

		if (_benomTeleport != null)
		{
			_benomTeleport.deleteMe();
			_benomTeleport = null;
			unspawnNpc(BENOM_TELEPORT);
		}

		updateState(StateEnum.DEAD);
		interval();
//		return;
		return super.onKill(npc,killer,isPet);
	}

	private void cancelBenomTimers(L2Npc npc)
	{
		cancelQuestTimers("BenomWalk");
		cancelQuestTimers("BenomWalkFinish");
		cancelQuestTimers("BenomBossDespawn");
		cancelQuestTimers("Talk");
		cancelQuestTimers("Attacking");
	}

	/**
	 * DEBUG
	 */
	@SuppressWarnings("unused")
	private void visualizeWalkRoutes(L2PcInstance player)
	{
		for (int e = 0; e < benomWalkRoutes.length; e++) {
			final int[] route = benomWalkRoutes[e];
			final int[] next  = benomWalkRoutes[(e + 1) % benomWalkRoutes.length];

			final int x1 = route[0], y1 = route[1], z1 = route[2];
			L2Npc n = addSpawn(32467, x1, y1, z1, 0, false, BENOM_DESPAWN_TIME/*86400000*/);
			n.setTitle("#"+e);
			n.broadcastPacket(new NpcInfo(n, null));

			final double dx = next[0] - x1, dy = next[1] - y1, dz = next[2] - z1;
			final double distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
			final double pitch = 50;
			for (double p = pitch; p < distance; p += pitch) {
				double a = p / distance;
				int x = x1 + (int)Math.round(dx * a);
				int y = y1 + (int)Math.round(dy * a);
				int z = z1 + (int)Math.round(dz * a) + 20;
				L2ItemInstance i = new L2ItemInstance(IdFactory.getInstance().getNextId(), 57);
				if (player != null) i.setOwnerId(player.getObjectId());
				i.new ItemDropTask(i, null, x, y, z).run();
				i.setProtected(false);
				L2World.getInstance().storeObject(i);
			}
		}
	}

	public static void main(String[] args)
	{
		// now call the constructor (starts up the ai)
		new Benom(-1,"benom","ai");
	}
}
