/*
 * 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.npc.NpcBuffers.impl;

import java.util.concurrent.ScheduledFuture;

import ai.npc.AbstractNpcAI;

import com.l2jserver.gameserver.SevenSigns;
import com.l2jserver.gameserver.ThreadPoolManager;
import com.l2jserver.gameserver.datatables.SkillTable;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.skills.BuffInfo;
import com.l2jserver.gameserver.model.skills.L2Skill;
import com.l2jserver.gameserver.network.NpcStringId;
import com.l2jserver.gameserver.network.clientpackets.Say2;
import com.l2jserver.gameserver.network.serverpackets.NpcSay;

/**
 * Preacher of Doom and Orator of Revelations AI
 * @author UnAfraid, malyelfik
 * mod JOJO
 * 
 * 31093 滅亡を叫ぶ者
 * 31094 啓示を言い伝える者
 */
public final class CabaleBuffer extends AbstractNpcAI
{
	private static final int DISTANCE_TO_WATCH_OBJECT = 900;
	private static final int AUTOCHAT_RANGE = 1200;
	private static final int AUTOCHAT_RATE = 8;	// percent
	private static final long MINIMAL_SOCIAL_INTERVAL = 6000L;
	
	// Messages
	protected static final NpcStringId[] ORATOR_AUTOCHAT_PLAYER =
	{
		NpcStringId.S1_I_GIVE_YOU_THE_BLESSING_OF_PROPHECY,	//$s1！そなたに啓示の祝福を与えよう！
		NpcStringId.S1_I_BESTOW_UPON_YOU_THE_AUTHORITY_OF_THE_ABYSS,	//$s1！そなたに深淵の権能を与えよう！
	};
	protected static final NpcStringId[] ORATOR_AUTOCHAT_DEFAULT =
	{
		NpcStringId.THE_DAY_OF_JUDGMENT_IS_NEAR,	//裁きの日が近づいている！
		NpcStringId.THE_PROPHECY_OF_DARKNESS_HAS_BEEN_FULFILLED,	//闇の啓示に耳を傾けろ！闇が眠りから覚めたのだ！
		NpcStringId.AS_FORETOLD_IN_THE_PROPHECY_OF_DARKNESS_THE_ERA_OF_CHAOS_HAS_BEGUN,	//闇の啓示に耳を傾けろ！混沌の時代が始まったのだ！
		NpcStringId.THE_PROPHECY_OF_DARKNESS_HAS_COME_TO_PASS,	//闇の啓示に耳を傾けろ！間もなく死の楽園となるだろう！
		NpcStringId.HERALD_OF_THE_NEW_ERA_OPEN_YOUR_EYES,	//新しい時代を開く者よ、目を覚ませ！
	};
	
	protected static final NpcStringId[] PREACHER_AUTOCHAT_PLAYER =
	{
		NpcStringId.S1_YOU_BRING_AN_ILL_WIND,	//$s1！そなたに滅亡の兆しが見える！
		NpcStringId.S1_YOU_MIGHT_AS_WELL_GIVE_UP,	//$s1！そなたに絶望をくれてやろう！
	};
	protected static final NpcStringId[] PREACHER_AUTOCHAT_DEFAULT =
	{
		NpcStringId.THIS_WORLD_WILL_SOON_BE_ANNIHILATED,	//まもなくこの世は滅びるであろう！
		NpcStringId.ALL_IS_LOST_PREPARE_TO_MEET_THE_GODDESS_OF_DEATH,	//皆の者、悲しみに暮れるがよい！間もなく死の女神が降臨するのだ！
		NpcStringId.ALL_IS_LOST_THE_PROPHECY_OF_DESTRUCTION_HAS_BEEN_FULFILLED,	//皆の者、悲しみに暮れるがよい！間もなく滅亡の予言が実現されるであろう！
		NpcStringId.THE_END_OF_TIME_HAS_COME_THE_PROPHECY_OF_DESTRUCTION_HAS_BEEN_FULFILLED,	//滅亡の予言に耳を傾けろ！間もなく終末の時代が始まるのだ！
		NpcStringId.YOU_DONT_HAVE_ANY_HOPE_YOUR_END_HAS_COME,	//終末の時代を生きる者よ、絶望の淵に落ちよ！
	};
	
	// Skills
	private static final int ORATOR_FIGTER = 4364;
	private static final int ORATOR_MAGE = 4365;
	private static final int PREACHER_FIGTER = 4361;
	private static final int PREACHER_MAGE = 4362;
	
	private CabaleBuffer()
	{
		super(CabaleBuffer.class.getSimpleName(), "ai/npc");
		addFirstTalkId(SevenSigns.ORATOR_NPC_ID, SevenSigns.PREACHER_NPC_ID);
		addSpawnId(SevenSigns.ORATOR_NPC_ID, SevenSigns.PREACHER_NPC_ID);
	}
	
	@Override
	public String onFirstTalk(L2Npc npc, L2PcInstance player)
	{
		return null;
	}
	
	@Override
	public String onSpawn(L2Npc npc)
	{
		new CabaleAI(npc);
		return super.onSpawn(npc);
	}
	
	private static class CabaleAI implements Runnable
	{
		private final L2Npc _npc;
		private final int _playerCabal;
		private final int _skillFighter, _skillMage;
		private final NpcStringId[] _autoChatPlayer, _autoChatDefault;
		private long _lastSocialBroadcast;
		private final ScheduledFuture<?> _aiTask;
		
		protected CabaleAI(L2Npc npc)
		{
			_npc = npc;
			final int winningCabal = SevenSigns.getInstance().getCabalHighestScore();
			final int losingCabal = winningCabal == SevenSigns.CABAL_DAWN ? SevenSigns.CABAL_DUSK
			                      : winningCabal == SevenSigns.CABAL_DUSK ? SevenSigns.CABAL_DAWN
			                      : SevenSigns.CABAL_NULL;
			switch (npc.getId())
			{
			default:
				//_log.warning("__FILE__:__LINE__: " + npc);
			case SevenSigns.PREACHER_NPC_ID:	// 31093 滅亡を叫ぶ者
				_playerCabal = losingCabal;
				// 4361-1 滅亡の呪い - 滅亡を叫ぶ者の呪い。一定時間、命中率が低下した状態。効力1
				// 4361-2 滅亡の呪い - 滅亡を叫ぶ者の呪い。一定時間、命中率、睡眠、ホールド、ショック攻撃に対する耐性が低下した状態。効力2
				_skillFighter = PREACHER_FIGTER;
				// 4362-1 滅亡の呪い - 滅亡を叫ぶ者の呪い。一定時間、魔法詠唱速度が低下した状態。効力1
				// 4362-2 滅亡の呪い - 滅亡を叫ぶ者の呪い。一定時間、魔法詠唱速度、睡眠、ホールド、ショック攻撃に対する耐性が低下した状態。効力2
				_skillMage = PREACHER_MAGE;
				_autoChatPlayer = PREACHER_AUTOCHAT_PLAYER;
				_autoChatDefault = PREACHER_AUTOCHAT_DEFAULT;
				break;
			case SevenSigns.ORATOR_NPC_ID:	// 31094 啓示を言い伝える者
				_playerCabal = winningCabal;
				// 4364-1 啓示の祝福 - 啓示を言い伝える者の祝福。一定時間、体が軽くなり、毒/出血攻撃に対する耐性が向上した状態。効力1
				// 4364-2 啓示の祝福 - 啓示を言い伝える者の祝福。一定時間、体が軽くなり、毒/出血/ホールド/ショック/麻痺攻撃に対する耐性が向上した状態。効力2
				_skillFighter = ORATOR_FIGTER;
				// 4365-1 啓示の祝福 - 啓示を言い伝える者の祝福。一定時間、ダメージに対する魔法キャンセル率が低下して、ホールド、精神攻撃に対する耐性が向上した状態。効力1
				// 4365-2 啓示の祝福 - 啓示を言い伝える者の祝福。一定時間、ダメージに対する魔法キャンセル率が低下して、ホールド、精神、ショック、麻痺攻撃に対する耐性が向上した状態。効力2
				_skillMage = ORATOR_MAGE;
				_autoChatPlayer = ORATOR_AUTOCHAT_PLAYER;
				_autoChatDefault = ORATOR_AUTOCHAT_DEFAULT;
				break;
			}
			
			if (_playerCabal != SevenSigns.CABAL_NULL)
				_aiTask = ThreadPoolManager.getInstance().scheduleGeneralWithFixedDelay(this, 3000, 3000);
			else
				_aiTask = null;
		}
		
		@Override
		public void run()
		{
			if (!_npc.isVisible())
			{
				_aiTask.cancel(false);	//月曜日午後6時
				return;
			}
			if (_npc.getKnownList().getKnownPlayers().size() == 0)
				return;
			
			boolean success = false;
			
			for (L2PcInstance player : _npc.getKnownList().getKnownPlayers().values())
			{
				if (player == null || !player.isVisible() || player.isInvul() || player.isMovementDisabled())
					continue;
				if (!_npc.isInsideRadius(player, DISTANCE_TO_WATCH_OBJECT, false, false))
					continue;
				
				final int playerCabal = SevenSigns.getInstance().getPlayerCabal(player.getObjectId());
				
				if (playerCabal == _playerCabal)
				{
					if (handleCast(player, player.isMageClass() ? _skillMage : _skillFighter))
					{
						success = true;
						autoChat(_autoChatPlayer[getRandom(_autoChatPlayer.length)], player);
					}
				}
			}
			
			if (!success && getRandom(100) < AUTOCHAT_RATE)
				autoChat(_autoChatDefault[getRandom(_autoChatDefault.length)], null);
		}
		
		/**
		 * For each known player in range, cast either the positive or negative buff. <BR>
		 * The stats affected depend on the player type, either a fighter or a mystic. <BR>
		 * <BR>
		 * Curse of Destruction (Loser)<BR>
		 * - Fighters: -25% Accuracy, -25% Effect Resistance<BR>
		 * - Mystics: -25% Casting Speed, -25% Effect Resistance<BR>
		 * <BR>
		 * <BR>
		 * Blessing of Prophecy (Winner)<br>
		 * - Fighters: +25% Max Load, +25% Effect Resistance<BR>
		 * - Mystics: +25% Magic Cancel Resist, +25% Effect Resistance<BR>
		 * @param player
		 * @param skillId
		 * @return
		 */
		private boolean handleCast(L2PcInstance player, int skillId)
		{
		//	if (player.isDead() || !player.isVisible() || !_npc.isInsideRadius(player, DISTANCE_TO_WATCH_OBJECT, false, false))
		//	{
		//		return false;
		//	}
			
			final int skillLevel;
			
			final int abnormalLevel = getAbnormalLvl(player, skillId);
			if (abnormalLevel == 0)
				skillLevel = 1;
			else if (abnormalLevel == 1 && getRandom(100) < 5)
				skillLevel = 2;
			else
				return false;
			
			final L2Skill skill = SkillTable.getInstance().getInfo(skillId, skillLevel);
			_npc.setTarget(player);
			_npc.doCast(skill);
			return true;
		}
		
		private void autoChat(NpcStringId npcStringID, L2PcInstance player)
		{
			long now = System.currentTimeMillis();
			if (now - _lastSocialBroadcast > MINIMAL_SOCIAL_INTERVAL)
			{
				broadcastSay(npcStringID, player);
				_lastSocialBroadcast = now;
			}
		}
		
		private void broadcastSay(NpcStringId npcStringID, L2PcInstance player)
		{
			NpcSay ns = new NpcSay(_npc.getObjectId(), Say2.ALL, _npc.getId(), npcStringID);
			if (player != null)
				ns.addPcName(player);
			_npc.broadcastPacket(ns, AUTOCHAT_RANGE);
		}
		
		private int getAbnormalLvl(L2PcInstance player, int skillId)
		{
			final BuffInfo info = player.getEffectList().getBuffInfoBySkillId(skillId);
			return (info != null) ? info.getSkill().getAbnormalLvl() : 0;
		}
	}
	
	public static void main(String[] args)
	{
		new CabaleBuffer();
	}
}
