/*
REWRITTEN FROM SCRATCH BY PUSSYWIZARD, IT OWNS NOW!
*/

#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "oculus.h"
#include "LFGMgr.h"
#include "Group.h"
#include "Player.h"

class instance_oculus : public InstanceMapScript
{
public:
    instance_oculus() : InstanceMapScript("instance_oculus", 578) { }

    InstanceScript* GetInstanceScript(InstanceMap* pMap) const
    {
        return new instance_oculus_InstanceMapScript(pMap);
    }

    struct instance_oculus_InstanceMapScript : public InstanceScript
    {
        instance_oculus_InstanceMapScript(Map* pMap) : InstanceScript(pMap) { Initialize(); }

        uint32 m_auiEncounter[MAX_ENCOUNTER];
        uint64 DragonCageDoorGUID[3];
        uint64 EregosCacheGUID;
        uint32 CentrifugeCount;

        uint64 uiDrakosGUID;
        uint64 uiVarosGUID;
        uint64 uiUromGUID;
        uint64 uiEregosGUID;

        bool bAmberVoid;
        bool bEmeraldVoid;
        bool bRubyVoid;
        
        void Initialize()
        {
            EregosCacheGUID = 0;
            uiDrakosGUID    = 0;
            uiVarosGUID     = 0;
            uiUromGUID      = 0;
            uiEregosGUID    = 0;
            CentrifugeCount = 0;
            bAmberVoid = false;
            bEmeraldVoid = false;
            bRubyVoid = false;

            memset(&m_auiEncounter, 0, sizeof(m_auiEncounter));
            memset(&DragonCageDoorGUID, 0, sizeof(DragonCageDoorGUID));
        }
        
        void OnCreatureCreate(Creature* pCreature)
        {
            switch( pCreature->GetEntry() )
            {
                case NPC_DRAKOS:
                    uiDrakosGUID = pCreature->GetGUID();
                    break;
                case NPC_VAROS:
                    uiVarosGUID = pCreature->GetGUID();
                    break;
                case NPC_UROM:
                    uiUromGUID = pCreature->GetGUID();
                    break;
                case NPC_EREGOS:
                    uiEregosGUID = pCreature->GetGUID();
                    break;
            }
        }

        void OnGameObjectCreate(GameObject* pGo)
        {
            switch( pGo->GetEntry() )
            {
                case GO_DRAGON_CAGE_DOOR:
                    for( uint8 i=0; i<3; ++i )
                    {
                        if( DragonCageDoorGUID[i] )
                            continue;

                        DragonCageDoorGUID[i] = pGo->GetGUID();
                        break;
                    }
                    if( m_auiEncounter[DATA_DRAKOS] == DONE )
                        if( pGo->GetGoState() != GO_STATE_ACTIVE )
                        {
                            pGo->SetLootState(GO_READY);
                            pGo->UseDoorOrButton(0, false);
                        }
                    break;
                case GO_CACHE_OF_EREGOS:
                case GO_CACHE_OF_EREGOS_HERO:
                    EregosCacheGUID = pGo->GetGUID();
                    break;
            }
        }

        void OnPlayerEnter(Player* player)
        {
            if (m_auiEncounter[DATA_DRAKOS] == DONE && m_auiEncounter[DATA_VAROS] != DONE)
            {
                player->SendUpdateWorldState(WORLD_STATE_CENTRIFUGE_CONSTRUCT_SHOW, 1);
                player->SendUpdateWorldState(WORLD_STATE_CENTRIFUGE_CONSTRUCT_AMOUNT, 10-CentrifugeCount);
            }
            else
            {
                player->SendUpdateWorldState(WORLD_STATE_CENTRIFUGE_CONSTRUCT_SHOW, 0);
                player->SendUpdateWorldState(WORLD_STATE_CENTRIFUGE_CONSTRUCT_AMOUNT, 0);
            }
        }

        void OnUnitDeath(Unit* unit)
        {
            if (unit->GetEntry() == NPC_CENTRIFUGE_CONSTRUCT)
                SetData(DATA_CC_COUNT, DONE);
        }
        
        void SetData(uint32 type, uint32 data)
        {
            switch( type )
            {
                case DATA_DRAKOS:
                    m_auiEncounter[DATA_DRAKOS] = data;
                    if( data == DONE )
                    {
                        DoUpdateWorldState(WORLD_STATE_CENTRIFUGE_CONSTRUCT_SHOW, 1);
                        DoUpdateWorldState(WORLD_STATE_CENTRIFUGE_CONSTRUCT_AMOUNT, 10-CentrifugeCount);

                        if (instance->IsHeroic())
                            DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_MAKE_IT_COUNT_TIMED_EVENT);
                    }
                    break;
                case DATA_VAROS:
                    m_auiEncounter[DATA_VAROS] = data;
                    if( data == DONE )
                    {
                        DoUpdateWorldState(WORLD_STATE_CENTRIFUGE_CONSTRUCT_SHOW, 0);

                        if( Creature* urom = instance->GetCreature(uiUromGUID) )
                            urom->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
                    }
                    break;
                case DATA_UROM:
                    m_auiEncounter[DATA_UROM] = data;
                    if( data == DONE )
                        if( Creature* eregos = instance->GetCreature(uiEregosGUID) )
                            eregos->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
                    break;
                case DATA_EREGOS:
                    m_auiEncounter[DATA_EREGOS] = data;
                    if (data == DONE)
                        DoRespawnGameObject(EregosCacheGUID, 7*DAY);
                    break;
                case DATA_CC_COUNT:
                    if( CentrifugeCount < 10 )
                    {
                        ++CentrifugeCount;
                        DoUpdateWorldState(WORLD_STATE_CENTRIFUGE_CONSTRUCT_AMOUNT, 10-CentrifugeCount);
                    }
                    if( CentrifugeCount >= 10 )
                        if( Creature* varos = instance->GetCreature(uiVarosGUID) )
                        {
                            varos->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
                            varos->InterruptNonMeleeSpells(false);
                            varos->RemoveAura(50053);
                        }
                    break;
                case DATA_AMBER_VOID:
                    bAmberVoid = data ? true : false;
                    break;
                case DATA_EMERALD_VOID:
                    bEmeraldVoid = data ? true : false;
                    break;
                case DATA_RUBY_VOID:
                    bRubyVoid = data ? true : false;
                    break;
            }

            if( data == DONE )
                SaveToDB();
        }
        
        uint32 GetData(uint32 type) const
        {
            switch( type )
            {
                case DATA_DRAKOS:
                case DATA_VAROS:
                case DATA_UROM:
                case DATA_EREGOS:
                    return m_auiEncounter[type];
                case DATA_CC_COUNT:
                    return CentrifugeCount;
            }

            return 0;
        }
        
        uint64 GetData64(uint32 identifier) const
        {
            switch( identifier )
            {
                case DATA_DRAKOS:
                    return uiDrakosGUID;
                case DATA_VAROS:
                    return uiVarosGUID;
                case DATA_UROM:
                    return uiUromGUID;
                case DATA_EREGOS:
                    return uiEregosGUID;
                case DATA_DCD_1:
                case DATA_DCD_2:
                case DATA_DCD_3:
                    return DragonCageDoorGUID[identifier-100];
            }

            return 0;
        }

        
        std::string GetSaveData()
        {
            OUT_SAVE_INST_DATA;

            std::ostringstream saveStream;
            saveStream << "T O " << m_auiEncounter[0] << ' ' << m_auiEncounter[1] << ' ' << m_auiEncounter[2] << ' ' << m_auiEncounter[3] << ' ' << CentrifugeCount;

            OUT_SAVE_INST_DATA_COMPLETE;
            return saveStream.str();
        }

        void Load(const char* in)
        {
            if( !in )
            {
                OUT_LOAD_INST_DATA_FAIL;
                return;
            }

            OUT_LOAD_INST_DATA(in);

            char dataHead1, dataHead2;
            std::istringstream loadStream(in);
            loadStream >> dataHead1 >> dataHead2;

            if( dataHead1 == 'T' && dataHead2 == 'O' )
            {
                loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] >> CentrifugeCount;

                for( uint8 i=0; i<MAX_ENCOUNTER; ++i )
                    if( m_auiEncounter[i] == IN_PROGRESS )
                        m_auiEncounter[i] = NOT_STARTED;

            }
            else
                OUT_LOAD_INST_DATA_FAIL;

            OUT_LOAD_INST_DATA_COMPLETE;
        }

        bool CheckAchievementCriteriaMeet(uint32 criteria_id, Player const* source, Unit const* target = NULL, uint32 miscvalue1 = 0)
        {
            switch(criteria_id)
            {
                case CRITERIA_EXPERIENCED_AMBER:
                    if( source )
                        if( Unit* drake = source->GetVehicleBase() )
                            if( drake->GetEntry() == NPC_AMBER_DRAKE )
                                return true;
                    break;
                case CRITERIA_EXPERIENCED_EMERALD:
                    if( source )
                        if( Unit* drake = source->GetVehicleBase() )
                            if( drake->GetEntry() == NPC_EMERALD_DRAKE )
                                return true;
                    break;
                case CRITERIA_EXPERIENCED_RUBY:
                    if( source )
                        if( Unit* drake = source->GetVehicleBase() )
                            if( drake->GetEntry() == NPC_RUBY_DRAKE )
                                return true;
                    break;
                case CRITERIA_AMBER_VOID:
                    return bAmberVoid;
                case CRITERIA_EMERALD_VOID:
                    return bEmeraldVoid;
                case CRITERIA_RUBY_VOID:
                    return bRubyVoid;
            }
            return false;
        }
    };
};

void AddSC_instance_oculus()
{
    new instance_oculus();
}
