/*
REWRITTEN BY XINEF
*/

#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "drak_tharon_keep.h"

enum Yells
{
    SAY_AGGRO                       = 0,
    SAY_KILL                        = 1,
    SAY_FLESH                       = 2,
    SAY_SKELETON                    = 3,
    SAY_DEATH                       = 4
};

enum Spells
{
    SPELL_CURSE_OF_LIFE                 = 49527,
    SPELL_RAIN_OF_FIRE                  = 49518,
    SPELL_SHADOW_VOLLEY                 = 49528,

    // flesh spells
    SPELL_EYE_BEAM                      = 49544,
    SPELL_LIGHTNING_BREATH              = 49537,
    SPELL_POISON_CLOUD                  = 49548,

    SPELL_TURN_FLESH                    = 49356,
    SPELL_TURN_BONES                    = 53463,
    SPELL_GIFT_OF_THARON_JA             = 52509,
    SPELL_DUMMY                         = 49551,
    SPELL_FLESH_VISUAL                  = 52582,
    SPELL_CLEAR_GIFT                    = 53242,

    SPELL_ACHIEVEMENT_CHECK             = 61863
};

enum Misc
{
    ACTION_TURN_BONES                   = 1,

    EVENT_SPELL_CURSE_OF_LIFE           = 1,
    EVENT_SPELL_RAIN_OF_FIRE            = 2,
    EVENT_SPELL_SHADOW_VOLLEY           = 3,
    EVENT_SPELL_EYE_BEAM                = 4,
    EVENT_SPELL_LIGHTNING_BREATH        = 5,
    EVENT_SPELL_POISON_CLOUD            = 6,
    EVENT_SPELL_TURN_FLESH              = 7,
    EVENT_TURN_FLESH_REAL               = 9,
    EVENT_TURN_BONES_REAL               = 10,
    EVENT_KILL_TALK                     = 11
};

class boss_tharon_ja : public CreatureScript
{
    public:
        boss_tharon_ja() : CreatureScript("boss_tharon_ja") { }

        CreatureAI *GetAI(Creature *creature) const
        {
            return GetInstanceAI<boss_tharon_jaAI>(creature);
        }

        struct boss_tharon_jaAI : public BossAI
        {
            boss_tharon_jaAI(Creature* creature) : BossAI(creature, DATA_THARON_JA)
            {
            }

            void Reset()
            {
                BossAI::Reset();
                me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true);
                me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK_DEST, true);
                me->SetDisplayId(me->GetNativeDisplayId());
                me->CastSpell(me, SPELL_CLEAR_GIFT, true);
            }

            void EnterCombat(Unit* who)
            {
                Talk(SAY_AGGRO);
                BossAI::EnterCombat(who);
                events.ScheduleEvent(EVENT_SPELL_CURSE_OF_LIFE, 5000);
                events.ScheduleEvent(EVENT_SPELL_RAIN_OF_FIRE, urand(14000,18000));
                events.ScheduleEvent(EVENT_SPELL_SHADOW_VOLLEY, urand(8000,10000));
                events.ScheduleEvent(EVENT_SPELL_TURN_FLESH, 1000);
            }

            void KilledUnit(Unit *victim)
            {
                if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
                {
                    Talk(SAY_KILL);
                    events.ScheduleEvent(EVENT_KILL_TALK, 6000);
                }
            }

            void DoAction(int32 param)
            {
                if (param == ACTION_TURN_BONES && me->IsAlive())
                {
                    Talk(SAY_SKELETON);
                    events.Reset();
                    events.ScheduleEvent(EVENT_TURN_BONES_REAL, 3000);
                }
            }

            void JustDied(Unit* killer)
            {
                Talk(SAY_DEATH);
                BossAI::JustDied(killer);
                me->CastSpell(me, SPELL_ACHIEVEMENT_CHECK, true);
                me->CastSpell(me, SPELL_CLEAR_GIFT, true);
                if (me->GetDisplayId() != me->GetNativeDisplayId())
                {
                    me->SetDisplayId(me->GetNativeDisplayId());
                    me->CastSpell(me, SPELL_FLESH_VISUAL, true);
                }
            }

            void UpdateAI(uint32 diff)
            {
                if (!UpdateVictim())
                    return;

                events.Update(diff);
                if (me->HasUnitState(UNIT_STATE_CASTING))
                    return;

                switch (events.ExecuteEvent())
                {
                    case EVENT_SPELL_CURSE_OF_LIFE:
                        if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 30.0f, true))
                            me->CastSpell(target, SPELL_CURSE_OF_LIFE, false);
                        events.ScheduleEvent(EVENT_SPELL_CURSE_OF_LIFE, 13000);
                        break;
                    case EVENT_SPELL_RAIN_OF_FIRE:
                        if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 30.0f, true))
                            me->CastSpell(target, SPELL_RAIN_OF_FIRE, false);
                        events.ScheduleEvent(EVENT_SPELL_RAIN_OF_FIRE, 16000);
                        break;
                    case EVENT_SPELL_SHADOW_VOLLEY:
                        me->CastSpell(me, SPELL_SHADOW_VOLLEY, false);
                        events.ScheduleEvent(EVENT_SPELL_SHADOW_VOLLEY, 9000);
                        break;
                    case EVENT_SPELL_TURN_FLESH:
                        if (me->HealthBelowPct(50))
                        {
                            Talk(SAY_FLESH);
                            me->getThreatManager().resetAllAggro();
                            me->CastSpell((Unit*)NULL, SPELL_TURN_FLESH, false);

                            events.Reset();
                            events.ScheduleEvent(EVENT_TURN_FLESH_REAL, 3000);
                            return;
                        }
                        events.ScheduleEvent(EVENT_SPELL_TURN_FLESH, 1000);
                        break;
                    case EVENT_TURN_FLESH_REAL:
                        me->CastSpell(me, SPELL_DUMMY, true);

                        me->GetMotionMaster()->MoveChase(me->GetVictim());
                        events.ScheduleEvent(EVENT_SPELL_EYE_BEAM, 11000);
                        events.ScheduleEvent(EVENT_SPELL_LIGHTNING_BREATH, 3000);
                        events.ScheduleEvent(EVENT_SPELL_POISON_CLOUD, 6000);
                        break;
                    case EVENT_SPELL_EYE_BEAM:
                        if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 35.0f, true))
                            me->CastSpell(target, SPELL_EYE_BEAM, false);
                        break;
                    case EVENT_SPELL_LIGHTNING_BREATH:
                        me->CastSpell(me->GetVictim(), SPELL_LIGHTNING_BREATH, false);
                        events.ScheduleEvent(EVENT_SPELL_LIGHTNING_BREATH, 8000);
                        break;
                    case EVENT_SPELL_POISON_CLOUD:
                        if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 35.0f, true))
                            me->CastSpell(target, SPELL_POISON_CLOUD, false);
                        events.ScheduleEvent(EVENT_SPELL_POISON_CLOUD, 10000);
                        break;
                    case EVENT_TURN_BONES_REAL:
                        me->SetDisplayId(me->GetNativeDisplayId());
                        me->CastSpell(me, SPELL_FLESH_VISUAL, true);
                        me->CastSpell(me, SPELL_CLEAR_GIFT, true);
                        events.Reset();
                        events.ScheduleEvent(EVENT_SPELL_CURSE_OF_LIFE, 1000);
                        events.ScheduleEvent(EVENT_SPELL_RAIN_OF_FIRE, urand(12000,14000));
                        events.ScheduleEvent(EVENT_SPELL_SHADOW_VOLLEY, urand(8000,10000));
                        break;
                }

                DoMeleeAttackIfReady();
            }
        };
};

class spell_tharon_ja_curse_of_life : public SpellScriptLoader
{
    public:
        spell_tharon_ja_curse_of_life() : SpellScriptLoader("spell_tharon_ja_curse_of_life") { }

        class spell_tharon_ja_curse_of_life_AuraScript : public AuraScript
        {
            PrepareAuraScript(spell_tharon_ja_curse_of_life_AuraScript);

            void OnPeriodic(AuraEffect const* /*aurEff*/)
            {
                if (GetUnitOwner()->HealthBelowPct(50))
                {
                    PreventDefaultAction();
                    SetDuration(0);
                }
            }

            void Register()
            {
                OnEffectPeriodic += AuraEffectPeriodicFn(spell_tharon_ja_curse_of_life_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE);
            }
        };

        AuraScript* GetAuraScript() const
        {
            return new spell_tharon_ja_curse_of_life_AuraScript();
        }
};

class spell_tharon_ja_dummy : public SpellScriptLoader
{
    public:
        spell_tharon_ja_dummy() : SpellScriptLoader("spell_tharon_ja_dummy") { }

        class spell_tharon_ja_dummy_AuraScript : public AuraScript
        {
            PrepareAuraScript(spell_tharon_ja_dummy_AuraScript)

            void HandleEffectApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
            {
                PreventDefaultAction();
                GetUnitOwner()->CastSpell(GetUnitOwner(), SPELL_FLESH_VISUAL, true);
                GetUnitOwner()->CastSpell(GetUnitOwner(), SPELL_GIFT_OF_THARON_JA, true);
                GetUnitOwner()->SetDisplayId(GetUnitOwner()->GetNativeDisplayId()+1);
            }

            void HandleEffectRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
            {
                PreventDefaultAction();
                GetUnitOwner()->getThreatManager().resetAllAggro();
                GetUnitOwner()->GetMotionMaster()->Clear();
                GetUnitOwner()->CastSpell((Unit*)NULL, SPELL_TURN_BONES, false);
                GetUnitOwner()->GetAI()->DoAction(ACTION_TURN_BONES);
            }

            void Register()
            {
                OnEffectApply += AuraEffectApplyFn(spell_tharon_ja_dummy_AuraScript::HandleEffectApply, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
                OnEffectRemove += AuraEffectRemoveFn(spell_tharon_ja_dummy_AuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
            }
        };

        AuraScript* GetAuraScript() const
        {
            return new spell_tharon_ja_dummy_AuraScript();
        }
};

class spell_tharon_ja_clear_gift_of_tharon_ja : public SpellScriptLoader
{
    public:
        spell_tharon_ja_clear_gift_of_tharon_ja() : SpellScriptLoader("spell_tharon_ja_clear_gift_of_tharon_ja") { }

        class spell_tharon_ja_clear_gift_of_tharon_ja_SpellScript : public SpellScript
        {
            PrepareSpellScript(spell_tharon_ja_clear_gift_of_tharon_ja_SpellScript);

            void HandleScript(SpellEffIndex /*effIndex*/)
            {
                if (Unit* target = GetHitUnit())
                    target->RemoveAura(SPELL_GIFT_OF_THARON_JA);
            }

            void Register()
            {
                OnEffectHitTarget += SpellEffectFn(spell_tharon_ja_clear_gift_of_tharon_ja_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
            }
        };

        SpellScript* GetSpellScript() const
        {
            return new spell_tharon_ja_clear_gift_of_tharon_ja_SpellScript();
        }
};

void AddSC_boss_tharon_ja()
{
    new boss_tharon_ja();
    new spell_tharon_ja_curse_of_life();
    new spell_tharon_ja_dummy();
    new spell_tharon_ja_clear_gift_of_tharon_ja();
}
