/*
 * This file is part of the OregonCore Project. See AUTHORS file for Copyright information
 *
 */

/* ScriptData
SDName: instance_uldaman
SD%Complete: 99%
SDComment: Need some cosmetics updates when archeadas door are closing (Guardians Waypoints).
SDCategory: Uldaman
EndScriptData */

#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "uldaman.h"

#define SPELL_ARCHAEDAS_AWAKEN        10347
#define SPELL_AWAKEN_VAULT_WALKER     10258

#define ARCHAEDAS_TEMPLE_DOOR           141869
#define ALTAR_OF_ARCHAEDAS              133234

#define ALTAR_OF_THE_KEEPER_TEMPLE_DOOR 124367
#define ALTAR_OF_THE_KEEPER_TEMPLE      130511

#define ANCIENT_VAULT_DOOR              124369
#define IRONAYA_SEAL_DOOR               124372

#define KEYSTONE_GO                     124371

#define ENCOUNTERS 3

struct instance_uldaman : public ScriptedInstance
{
    instance_uldaman(Map* pMap) : ScriptedInstance(pMap)
    {
        Initialize();
    };

    void Initialize()
    {
        archaedasGUID = 0;
        iron

        whoWokeArchaedasGUID = 0;

        altarOfTheKeeperTempleDoor = 0;
        archaedasTempleDoor = 0;
        ancientVaultDoor = 0;
        ironayaSealDoor = 0;

        keystoneGUID = 0;

        ironayaSealDoorTimer = 26000;
        keystoneCheck = false;

        for (uint8 i = 0; i < ENCOUNTERS; ++i)
            Encounters[i] = NOT_STARTED;

    }

    uint64 archaedasGUID;
    uint64 ironayaGUID;
    uint64 whoWokeArchaedasGUID;

    uint64 altarOfTheKeeperTempleDoor;
    uint64 archaedasTempleDoor;
    uint64 ancientVaultDoor;
    uint64 ironayaSealDoor;

    uint64 keystoneGUID;

    uint32 ironayaSealDoorTimer;
    bool keystoneCheck;

    std::vector<uint64> stoneKeeper;
    std::vector<uint64> altarOfTheKeeperCount;
    std::vector<uint64> vaultWalker;
    std::vector<uint64> earthenGuardian;
    std::vector<uint64> archaedasWallMinions;    // minions lined up around the wall

    uint32 Encounters[ENCOUNTERS];
    std::string str_data;

    void OnGameObjectCreate(GameObject* pGo, bool /*add*/)
    {
        switch (pGo->GetEntry())
        {
        case ALTAR_OF_THE_KEEPER_TEMPLE_DOOR:         // lock the door
            altarOfTheKeeperTempleDoor = pGo->GetGUID();

            if (Encounters[0] == DONE)
                HandleGameObject(0, true, pGo);
            break;

        case ARCHAEDAS_TEMPLE_DOOR:
            archaedasTempleDoor = pGo->GetGUID();

            if (Encounters[0] == DONE)
                HandleGameObject(0, true, pGo);
            break;

        case ANCIENT_VAULT_DOOR:
            pGo->SetGoState(GO_STATE_READY);
            pGo->SetUInt32Value(GAMEOBJECT_FLAGS, 33);
            ancientVaultDoor = pGo->GetGUID();

            if (Encounters[1] == DONE)
                HandleGameObject(0, true, pGo);
            break;

        case IRONAYA_SEAL_DOOR:
            ironayaSealDoor = pGo->GetGUID();

            if (Encounters[2] == DONE)
                HandleGameObject(0, true, pGo);
            break;

        case KEYSTONE_GO:
            keystoneGUID = pGo->GetGUID();
            if (Encounters[2] == DONE)
            {
                HandleGameObject(0, true, pGo);
                pGo->SetUInt32Value(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND);
            }
            break;
        }
    }

    void SetFrozenState(Creature* pCreature)
    {
        pCreature->SetFaction(35);
        pCreature->RemoveAllAuras();
        pCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
		pCreature->SetRooted(true);
    }

    void SetDoor(uint64 guid, bool open)
    {
        GameObject* pGo = instance->GetGameObject(guid);
        if (!pGo)
            return;

        HandleGameObject(0, open, pGo);
    }

    void BlockGO(uint64 guid)
    {
        GameObject* go = instance->GetGameObject(guid);
        if (!go)
            return;
        go->SetUInt32Value(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND);

    }

    void ActivateStoneKeepers()
    {
        for (std::vector<uint64>::const_iterator i = stoneKeeper.begin(); i != stoneKeeper.end(); ++i)
        {
            Creature* pTarget = instance->GetCreature(*i);
            if (!pTarget || !pTarget->IsAlive() || pTarget->GetFaction() == 14)
                continue;
			pTarget->SetRooted(false);
            pTarget->SetFaction(14);
            pTarget->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
            return;        // only want the first one we find
        }
        // if we get this far than all four are dead so open the door
        SetData (DATA_ALTAR_DOORS, DONE);
        SetDoor (archaedasTempleDoor, true); //open next the door too
    }

    void ActivateWallMinions()
    {
        Creature* archaedas = instance->GetCreature(archaedasGUID);
        if (!archaedas)
            return;

        for (std::vector<uint64>::const_iterator i = archaedasWallMinions.begin(); i != archaedasWallMinions.end(); ++i)
        {
            Creature* pTarget = instance->GetCreature(*i);
            if (!pTarget || !pTarget->IsAlive() || pTarget->GetFaction() == 14)
                continue;
            archaedas->CastSpell(pTarget, SPELL_AWAKEN_VAULT_WALKER, true);
            pTarget->CastSpell(pTarget, SPELL_ARCHAEDAS_AWAKEN, true);
            return;        // only want the first one we find
        }
    }

    // used when Archaedas dies.  All active minions must be despawned.
    void DeActivateMinions()
    {
        // first despawn any aggroed wall minions
        for (std::vector<uint64>::const_iterator i = archaedasWallMinions.begin(); i != archaedasWallMinions.end(); ++i)
        {
            Creature* pTarget = instance->GetCreature(*i);
            if (!pTarget || pTarget->isDead() || pTarget->GetFaction() != 14)
                continue;
            pTarget->setDeathState(JUST_DIED);
            pTarget->RemoveCorpse();
        }

        // Vault Walkers
        for (std::vector<uint64>::const_iterator i = vaultWalker.begin(); i != vaultWalker.end(); ++i)
        {
            Creature* pTarget = instance->GetCreature(*i);
            if (!pTarget || pTarget->isDead() || pTarget->GetFaction() != 14)
                continue;
            pTarget->setDeathState(JUST_DIED);
            pTarget->RemoveCorpse();
        }

        // Earthen Guardians
        for (std::vector<uint64>::const_iterator i = earthenGuardian.begin(); i != earthenGuardian.end(); ++i)
        {
            Creature* pTarget = instance->GetCreature(*i);
            if (!pTarget || pTarget->isDead() || pTarget->GetFaction() != 14)
                continue;
            pTarget->setDeathState(JUST_DIED);
            pTarget->RemoveCorpse();
        }
    }

    void ActivateArchaedas(uint64 target)
    {
        Creature* archaedas = instance->GetCreature(archaedasGUID);
        if (!archaedas)
            return;

        if (/*Unit* victim = */Unit::GetUnit(*archaedas, target))
        {
            archaedas->CastSpell(archaedas, SPELL_ARCHAEDAS_AWAKEN, false);
            whoWokeArchaedasGUID = target;
        }
    }

    void ActivateIronaya()
    {
        Creature* ironaya = instance->GetCreature(ironayaGUID);
        if (!ironaya)
            return;

        ironaya->SetFaction(415);
		ironaya->SetRooted(false);
        ironaya->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
    }

    void RespawnMinions()
    {
        // first respawn any aggroed wall minions
        for (std::vector<uint64>::const_iterator i = archaedasWallMinions.begin(); i != archaedasWallMinions.end(); ++i)
        {
            Creature* pTarget = instance->GetCreature(*i);
            if (pTarget && pTarget->isDead())
            {
                pTarget->Respawn();
                pTarget->GetMotionMaster()->MoveTargetedHome();
                SetFrozenState(pTarget);
            }
        }

        // Vault Walkers
        for (std::vector<uint64>::const_iterator i = vaultWalker.begin(); i != vaultWalker.end(); ++i)
        {
            Creature* pTarget = instance->GetCreature(*i);
            if (pTarget && pTarget->isDead())
            {
                pTarget->Respawn();
                pTarget->GetMotionMaster()->MoveTargetedHome();
                SetFrozenState(pTarget);
            }
        }

        // Earthen Guardians
        for (std::vector<uint64>::const_iterator i = earthenGuardian.begin(); i != earthenGuardian.end(); ++i)
        {
            Creature* pTarget = instance->GetCreature(*i);
            if (pTarget && pTarget->isDead())
            {
                pTarget->Respawn();
                pTarget->GetMotionMaster()->MoveTargetedHome();
                SetFrozenState(pTarget);
            }
        }
    }

    void Update(uint32 diff)
    {
        if (!keystoneCheck)
            return;

        if (ironayaSealDoorTimer <= diff)
        {
            ActivateIronaya();

            SetDoor(ironayaSealDoor, true);
            BlockGO(keystoneGUID);

            SetData(DATA_IRONAYA_DOOR, DONE); //save state
            keystoneCheck = false;
        }
        else
            ironayaSealDoorTimer -= diff;
    }

    void SetData (uint32 type, uint32 data)
    {
        switch (type)
        {
        case DATA_ALTAR_DOORS:
            Encounters[0] = data;
            if (data == DONE)
                SetDoor (altarOfTheKeeperTempleDoor, true);
            break;

        case DATA_ANCIENT_DOOR:
            Encounters[1] = data;
            if (data == DONE) //archeadas defeat
            {
                SetDoor (archaedasTempleDoor, true); //re open enter door
                SetDoor (ancientVaultDoor, true);
            }
            break;

        case DATA_IRONAYA_DOOR:
            Encounters[2] = data;
            break;

        case DATA_STONE_KEEPERS:
            ActivateStoneKeepers();
            break;

        case DATA_MINIONS:
            switch (data)
            {
            case NOT_STARTED:
                if (Encounters[0] == DONE) //if players opened the doors
                    SetDoor (archaedasTempleDoor, true);

                RespawnMinions();
                break;
            case IN_PROGRESS:
                ActivateWallMinions();
                break;
            case SPECIAL:
                DeActivateMinions();
                break;
            }
            break;

        case DATA_IRONAYA_SEAL:
            keystoneCheck = true;
            break;
        }

        if (data == DONE)
        {
            OUT_SAVE_INST_DATA;

            std::ostringstream saveStream;
            saveStream << Encounters[0] << " " << Encounters[1] << " " << Encounters[2];

            str_data = saveStream.str();

            SaveToDB();
            OUT_SAVE_INST_DATA_COMPLETE;
        }
    }

    void SetData64 (uint32 type, uint64 data)
    {
        // Archaedas
        if (type == 0)
        {
            ActivateArchaedas (data);
            SetDoor (archaedasTempleDoor, false); //close when event is started
        }
    }

    void OnCreatureCreate(Creature* pCreature, bool /*add*/)
    {
        switch (pCreature->GetEntry())
        {
        case 4857:    // Stone Keeper
            SetFrozenState (pCreature);
            stoneKeeper.push_back(pCreature->GetGUID());
            break;

        case 7309:    // Earthen Custodian
            archaedasWallMinions.push_back(pCreature->GetGUID());
            break;

        case 7077:    // Earthen Hallshaper
            archaedasWallMinions.push_back(pCreature->GetGUID());
            break;

        case 7076:    // Earthen Guardian
            earthenGuardian.push_back(pCreature->GetGUID());
            break;

        case 7228:    // Ironaya
            ironayaGUID = pCreature->GetGUID();

            if (Encounters[2] != DONE)
                SetFrozenState(pCreature);
            break;

        case 10120:   // Vault Walker
            vaultWalker.push_back(pCreature->GetGUID());
            break;

        case 2748:    // Archaedas
            archaedasGUID = pCreature->GetGUID();
            break;

        } // end switch
    } // end OnCreatureCreate

    uint64 GetData64 (uint32 identifier)
    {
        if (identifier == 0) return whoWokeArchaedasGUID;
        if (identifier == 1) return vaultWalker[0];    // VaultWalker1
        if (identifier == 2) return vaultWalker[1];    // VaultWalker2
        if (identifier == 3) return vaultWalker[2];    // VaultWalker3
        if (identifier == 4) return vaultWalker[3];    // VaultWalker4

        if (identifier == 5) return earthenGuardian[0];
        if (identifier == 6) return earthenGuardian[1];
        if (identifier == 7) return earthenGuardian[2];
        if (identifier == 8) return earthenGuardian[3];
        if (identifier == 9) return earthenGuardian[4];
        if (identifier == 10) return earthenGuardian[5];

        return 0;
    } // end GetData64

    std::string GetSaveData()
    {
        return str_data.c_str();
    }

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

        OUT_LOAD_INST_DATA(in);

        std::istringstream loadStream(in);
        loadStream >> Encounters[0] >> Encounters[1] >> Encounters[2];

        for (uint8 i = 0; i < ENCOUNTERS; ++i)
            if (Encounters[i] == IN_PROGRESS)
                Encounters[i] = NOT_STARTED;

        OUT_LOAD_INST_DATA_COMPLETE;
    }
};

InstanceData* GetInstanceData_instance_uldaman(Map* pMap)
{
    return new instance_uldaman(pMap);
}

void AddSC_instance_uldaman()
{
    Script* newscript;
    newscript = new Script;
    newscript->Name = "instance_uldaman";
    newscript->GetInstanceData = &GetInstanceData_instance_uldaman;
    newscript->RegisterSelf();
}


std::string GetSaveData()
    {
        return str_data.c_str();
    }

/*
 * This file is part of the OregonCore Project. See AUTHORS file for Copyright information
 *
 */

/* ScriptData
SDName: instance_uldaman
SD%Complete: 99%
SDComment: Need some cosmetics updates when archeadas door are closing (Guardians Waypoints).
SDCategory: Uldaman
EndScriptData */

#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "uldaman.h"

#define SPELL_ARCHAEDAS_AWAKEN        10347
#define SPELL_AWAKEN_VAULT_WALKER     10258

#define ARCHAEDAS_TEMPLE_DOOR           141869
#define ALTAR_OF_ARCHAEDAS              133234

#define ALTAR_OF_THE_KEEPER_TEMPLE_DOOR 124367
#define ALTAR_OF_THE_KEEPER_TEMPLE      130511

#define ANCIENT_VAULT_DOOR              124369
#define IRONAYA_SEAL_DOOR               124372

#define KEYSTONE_GO                     124371

#define ENCOUNTERS 3

struct instance_uldaman : public ScriptedInstance
{
    instance_uldaman(Map* pMap) : ScriptedInstance(pMap)
    {
        Initialize();
    };

    void Initialize()
    {
        archaedasGUID = 0;
        ironayaGUID = 0;
        whoWokeArchaedasGUID = 0;

        altarOfTheKeeperTempleDoor = 0;
        archaedasTempleDoor = 0;
        ancientVaultDoor = 0;
        ironayaSealDoor = 0;

        keystoneGUID = 0;

        ironayaSealDoorTimer = 26000;
        keystoneCheck = false;

        for (uint8 i = 0; i < ENCOUNTERS; ++i)
            Encounters[i] = NOT_STARTED;

    }

    uint64 archaedasGUID;
    uint64 ironayaGUID;
    uint64 whoWokeArchaedasGUID;

    uint64 altarOfTheKeeperTempleDoor;
    uint64 archaedasTempleDoor;
    uint64 ancientVaultDoor;
    uint64 ironayaSealDoor;

    uint64 keystoneGUID;

    uint32 ironayaSealDoorTimer;
    bool keystoneCheck;

    std::vector<uint64> stoneKeeper;
    std::vector<uint64> altarOfTheKeeperCount;
    std::vector<uint64> vaultWalker;
    std::vector<uint64> earthenGuardian;
    std::vector<uint64> archaedasWallMinions;    // minions lined up around the wall

    uint32 Encounters[ENCOUNTERS];
    std::string str_data;

    void OnGameObjectCreate(GameObject* pGo, bool /*add*/)
    {
        switch (pGo->GetEntry())
        {
        case ALTAR_OF_THE_KEEPER_TEMPLE_DOOR:         // lock the door
            altarOfTheKeeperTempleDoor = pGo->GetGUID();

            if (Encounters[0] == DONE)
                HandleGameObject(0, true, pGo);
            break;

        case ARCHAEDAS_TEMPLE_DOOR:
            archaedasTempleDoor = pGo->GetGUID();

            if (Encounters[0] == DONE)
                HandleGameObject(0, true, pGo);
            break;

        case ANCIENT_VAULT_DOOR:
            pGo->SetGoState(GO_STATE_READY);
            pGo->SetUInt32Value(GAMEOBJECT_FLAGS, 33);
            ancientVaultDoor = pGo->GetGUID();

            if (Encounters[1] == DONE)
                HandleGameObject(0, true, pGo);
            break;

        case IRONAYA_SEAL_DOOR:
            ironayaSealDoor = pGo->GetGUID();

            if (Encounters[2] == DONE)
                HandleGameObject(0, true, pGo);
            break;

        case KEYSTONE_GO:
            keystoneGUID = pGo->GetGUID();
            if (Encounters[2] == DONE)
            {
                HandleGameObject(0, true, pGo);
                pGo->SetUInt32Value(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND);
            }
            break;
        }
    }

    void SetFrozenState(Creature* pCreature)
    {
        pCreature->SetFaction(35);
        pCreature->RemoveAllAuras();
        pCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
		pCreature->SetRooted(true);
    }

    void SetDoor(uint64 guid, bool open)
    {
        GameObject* pGo = instance->GetGameObject(guid);
        if (!pGo)
            return;

        HandleGameObject(0, open, pGo);
    }

    void BlockGO(uint64 guid)
    {
        GameObject* go = instance->GetGameObject(guid);
        if (!go)
            return;
        go->SetUInt32Value(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND);

    }

    void ActivateStoneKeepers()
    {
        for (std::vector<uint64>::const_iterator i = stoneKeeper.begin(); i != stoneKeeper.end(); ++i)
        {
            Creature* pTarget = instance->GetCreature(*i);
            if (!pTarget || !pTarget->IsAlive() || pTarget->GetFaction() == 14)
                continue;
			pTarget->SetRooted(false);
            pTarget->SetFaction(14);
            pTarget->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
            return;        // only want the first one we find
        }
        // if we get this far than all four are dead so open the door
        SetData (DATA_ALTAR_DOORS, DONE);
        SetDoor (archaedasTempleDoor, true); //open next the door too
    }

    void ActivateWallMinions()
    {
        Creature* archaedas = instance->GetCreature(archaedasGUID);
        if (!archaedas)
            return;

        for (std::vector<uint64>::const_iterator i = archaedasWallMinions.begin(); i != archaedasWallMinions.end(); ++i)
        {
            Creature* pTarget = instance->GetCreature(*i);
            if (!pTarget || !pTarget->IsAlive() || pTarget->GetFaction() == 14)
                continue;
            archaedas->CastSpell(pTarget, SPELL_AWAKEN_VAULT_WALKER, true);
            pTarget->CastSpell(pTarget, SPELL_ARCHAEDAS_AWAKEN, true);
            return;        // only want the first one we find
        }
    }

    // used when Archaedas dies.  All active minions must be despawned.
    void DeActivateMinions()
    {
        // first despawn any aggroed wall minions
        for (std::vector<uint64>::const_iterator i = archaedasWallMinions.begin(); i != archaedasWallMinions.end(); ++i)
        {
            Creature* pTarget = instance->GetCreature(*i);
            if (!pTarget || pTarget->isDead() || pTarget->GetFaction() != 14)
                continue;
            pTarget->setDeathState(JUST_DIED);
            pTarget->RemoveCorpse();
        }

        // Vault Walkers
        for (std::vector<uint64>::const_iterator i = vaultWalker.begin(); i != vaultWalker.end(); ++i)
        {
            Creature* pTarget = instance->GetCreature(*i);
            if (!pTarget || pTarget->isDead() || pTarget->GetFaction() != 14)
                continue;
            pTarget->setDeathState(JUST_DIED);
            pTarget->RemoveCorpse();
        }

        // Earthen Guardians
        for (std::vector<uint64>::const_iterator i = earthenGuardian.begin(); i != earthenGuardian.end(); ++i)
        {
            Creature* pTarget = instance->GetCreature(*i);
            if (!pTarget || pTarget->isDead() || pTarget->GetFaction() != 14)
                continue;
            pTarget->setDeathState(JUST_DIED);
            pTarget->RemoveCorpse();
        }
    }

    void ActivateArchaedas(uint64 target)
    {
        Creature* archaedas = instance->GetCreature(archaedasGUID);
        if (!archaedas)
            return;

        if (/*Unit* victim = */Unit::GetUnit(*archaedas, target))
        {
            archaedas->CastSpell(archaedas, SPELL_ARCHAEDAS_AWAKEN, false);
            whoWokeArchaedasGUID = target;
        }
    }

    void ActivateIronaya()
    {
        Creature* ironaya = instance->GetCreature(ironayaGUID);
        if (!ironaya)
            return;

        ironaya->SetFaction(415);
		ironaya->SetRooted(false);
        ironaya->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
    }

    void RespawnMinions()
    {
        // first respawn any aggroed wall minions
        for (std::vector<uint64>::const_iterator i = archaedasWallMinions.begin(); i != archaedasWallMinions.end(); ++i)
        {
            Creature* pTarget = instance->GetCreature(*i);
            if (pTarget && pTarget->isDead())
            {
                pTarget->Respawn();
                pTarget->GetMotionMaster()->MoveTargetedHome();
                SetFrozenState(pTarget);
            }
        }

        // Vault Walkers
        for (std::vector<uint64>::const_iterator i = vaultWalker.begin(); i != vaultWalker.end(); ++i)
        {
            Creature* pTarget = instance->GetCreature(*i);
            if (pTarget && pTarget->isDead())
            {
                pTarget->Respawn();
                pTarget->GetMotionMaster()->MoveTargetedHome();
                SetFrozenState(pTarget);
            }
        }

        // Earthen Guardians
        for (std::vector<uint64>::const_iterator i = earthenGuardian.begin(); i != earthenGuardian.end(); ++i)
        {
            Creature* pTarget = instance->GetCreature(*i);
            if (pTarget && pTarget->isDead())
            {
                pTarget->Respawn();
                pTarget->GetMotionMaster()->MoveTargetedHome();
                SetFrozenState(pTarget);
            }
        }
    }

    void Update(uint32 diff)
    {
        if (!keystoneCheck)
            return;

        if (ironayaSealDoorTimer <= diff)
        {
            ActivateIronaya();

            SetDoor(ironayaSealDoor, true);
            BlockGO(keystoneGUID);

            SetData(DATA_IRONAYA_DOOR, DONE); //save state
            keystoneCheck = false;
        }
        else
            ironayaSealDoorTimer -= diff;
    }

    void SetData (uint32 type, uint32 data)
    {
        switch (type)
        {
        case DATA_ALTAR_DOORS:
            Encounters[0] = data;
            if (data == DONE)
                SetDoor (altarOfTheKeeperTempleDoor, true);
            break;

        case DATA_ANCIENT_DOOR:
            Encounters[1] = data;
            if (data == DONE) //archeadas defeat
            {
                SetDoor (archaedasTempleDoor, true); //re open enter door
                SetDoor (ancientVaultDoor, true);
            }
            break;

        case DATA_IRONAYA_DOOR:
            Encounters[2] = data;
            break;

        case DATA_STONE_KEEPERS:
            ActivateStoneKeepers();
            break;

        case DATA_MINIONS:
            switch (data)
            {
            case NOT_STARTED:
                if (Encounters[0] == DONE) //if players opened the doors
                    SetDoor (archaedasTempleDoor, true);

                RespawnMinions();
                break;
            case IN_PROGRESS:
                ActivateWallMinions();
                break;
            case SPECIAL:
                DeActivateMinions();
                break;
            }
            break;

        case DATA_IRONAYA_SEAL:
            keystoneCheck = true;
            break;
        }

        if (data == DONE)
        {
            OUT_SAVE_INST_DATA;

            std::ostringstream saveStream;
            saveStream << Encounters[0] << " " << Encounters[1] << " " << Encounters[2];

            str_data = saveStream.str();

            SaveToDB();
            OUT_SAVE_INST_DATA_COMPLETE;
        }
    }

    void SetData64 (uint32 type, uint64 data)
    {
        // Archaedas
        if (type == 0)
        {
            ActivateArchaedas (data);
            SetDoor (archaedasTempleDoor, false); //close when event is started
        }
    }

    void OnCreatureCreate(Creature* pCreature, bool /*add*/)
    {
        switch (pCreature->GetEntry())
        {
        case 4857:    // Stone Keeper
            SetFrozenState (pCreature);
            stoneKeeper.push_back(pCreature->GetGUID());
            break;

        case 7309:    // Earthen Custodian
            archaedasWallMinions.push_back(pCreature->GetGUID());
            break;

        case 7077:    // Earthen Hallshaper
            archaedasWallMinions.push_back(pCreature->GetGUID());
            break;

        case 7076:    // Earthen Guardian
            earthenGuardian.push_back(pCreature->GetGUID());
            break;

        case 7228:    // Ironaya
            ironayaGUID = pCreature->GetGUID();

            if (Encounters[2] != DONE)
                SetFrozenState(pCreature);
            break;

        case 10120:   // Vault Walker
            vaultWalker.push_back(pCreature->GetGUID());
            break;

        case 2748:    // Archaedas
            archaedasGUID = pCreature->GetGUID();
            break;

        } // end switch
    } // end OnCreatureCreate

    uint64 GetData64 (uint32 identifier)
    {
        if (identifier == 0) return whoWokeArchaedasGUID;
        if (identifier == 1) return vaultWalker[0];    // VaultWalker1
        if (identifier == 2) return vaultWalker[1];    // VaultWalker2
        if (identifier == 3) return vaultWalker[2];    // VaultWalker3
        if (identifier == 4) return vaultWalker[3];    // VaultWalker4

        if (identifier == 5) return earthenGuardian[0];
        if (identifier == 6) return earthenGuardian[1];
        if (identifier == 7) return earthenGuardian[2];
        if (identifier == 8) return earthenGuardian[3];
        if (identifier == 9) return earthenGuardian[4];
        if (identifier == 10) return earthenGuardian[5];

        return 0;
    } // end GetData64

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

        OUT_LOAD_INST_DATA(in);

        std::istringstream loadStream(in);
        loadStream >> Encounters[0] >> Encounters[1] >> Encounters[2];

        for (uint8 i = 0; i < ENCOUNTERS; ++i)
            if (Encounters[i] == IN_PROGRESS)
                Encounters[i] = NOT_STARTED;

        OUT_LOAD_INST_DATA_COMPLETE;
    }
};

InstanceData* GetInstanceData_instance_uldaman(Map* pMap)
{
    return new instance_uldaman(pMap);
}

void AddSC_instance_uldaman()
{
    Script* newscript;
    newscript = new Script;
    newscript->Name = "instance_uldaman";
    newscript->GetInstanceData = &GetInstanceData_instance_uldaman;
    newscript->RegisterSelf();
}


switch (data)
            {
            case NOT_STARTED:
                if (Encounters[0] == DONE) //if players opened the doors
                    SetDoor (archaedasTempleDoor, true);

                RespawnMinions();
                break;
            case IN_PROGRESS:
                ActivateWallMinions();
                break;
            case SPECIAL:
                DeActivateMinions();
                break;
            }

/*
 * This file is part of the OregonCore Project. See AUTHORS file for Copyright information
 *
 */

/* ScriptData
SDName: instance_uldaman
SD%Complete: 99%
SDComment: Need some cosmetics updates when archeadas door are closing (Guardians Waypoints).
SDCategory: Uldaman
EndScriptData */

#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "uldaman.h"

#define SPELL_ARCHAEDAS_AWAKEN        10347
#define SPELL_AWAKEN_VAULT_WALKER     10258

#define ARCHAEDAS_TEMPLE_DOOR           141869
#define ALTAR_OF_ARCHAEDAS              133234

#define ALTAR_OF_THE_KEEPER_TEMPLE_DOOR 124367
#define ALTAR_OF_THE_KEEPER_TEMPLE      130511

#define ANCIENT_VAULT_DOOR              124369
#define IRONAYA_SEAL_DOOR               124372

#define KEYSTONE_GO                     124371

#define ENCOUNTERS 3

struct instance_uldaman : public ScriptedInstance
{
    instance_uldaman(Map* pMap) : ScriptedInstance(pMap)
    {
        Initialize();
    };

    void Initialize()
    {
        archaedasGUID = 0;
        ironayaGUID = 0;
        whoWokeArchaedasGUID = 0;

        altarOfTheKeeperTempleDoor = 0;
        archaedasTempleDoor = 0;
        ancientVaultDoor = 0;
        ironayaSealDoor = 0;

        keystoneGUID = 0;

        ironayaSealDoorTimer = 26000;
        keystoneCheck = false;

        for (uint8 i = 0; i < ENCOUNTERS; ++i)
            Encounters[i] = NOT_STARTED;

    }

    uint64 archaedasGUID;
    uint64 ironayaGUID;
    uint64 whoWokeArchaedasGUID;

    uint64 altarOfTheKeeperTempleDoor;
    uint64 archaedasTempleDoor;
    uint64 ancientVaultDoor;
    uint64 ironayaSealDoor;

    uint64 keystoneGUID;

    uint32 ironayaSealDoorTimer;
    bool keystoneCheck;

    std::vector<uint64> stoneKeeper;
    std::vector<uint64> altarOfTheKeeperCount;
    std::vector<uint64> vaultWalker;
    std::vector<uint64> earthenGuardian;
    std::vector<uint64> archaedasWallMinions;    // minions lined up around the wall

    uint32 Encounters[ENCOUNTERS];
    std::string str_data;

    void OnGameObjectCreate(GameObject* pGo, bool /*add*/)
    {
        switch (pGo->GetEntry())
        {
        case ALTAR_OF_THE_KEEPER_TEMPLE_DOOR:         // lock the door
            altarOfTheKeeperTempleDoor = pGo->GetGUID();

            if (Encounters[0] == DONE)
                HandleGameObject(0, true, pGo);
            break;

        case ARCHAEDAS_TEMPLE_DOOR:
            archaedasTempleDoor = pGo->GetGUID();

            if (Encounters[0] == DONE)
                HandleGameObject(0, true, pGo);
            break;

        case ANCIENT_VAULT_DOOR:
            pGo->SetGoState(GO_STATE_READY);
            pGo->SetUInt32Value(GAMEOBJECT_FLAGS, 33);
            ancientVaultDoor = pGo->GetGUID();

            if (Encounters[1] == DONE)
                HandleGameObject(0, true, pGo);
            break;

        case IRONAYA_SEAL_DOOR:
            ironayaSealDoor = pGo->GetGUID();

            if (Encounters[2] == DONE)
                HandleGameObject(0, true, pGo);
            break;

        case KEYSTONE_GO:
            keystoneGUID = pGo->GetGUID();
            if (Encounters[2] == DONE)
            {
                HandleGameObject(0, true, pGo);
                pGo->SetUInt32Value(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND);
            }
            break;
        }
    }

    void SetFrozenState(Creature* pCreature)
    {
        pCreature->SetFaction(35);
        pCreature->RemoveAllAuras();
        pCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
		pCreature->SetRooted(true);
    }

    void SetDoor(uint64 guid, bool open)
    {
        GameObject* pGo = instance->GetGameObject(guid);
        if (!pGo)
            return;

        HandleGameObject(0, open, pGo);
    }

    void BlockGO(uint64 guid)
    {
        GameObject* go = instance->GetGameObject(guid);
        if (!go)
            return;
        go->SetUInt32Value(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND);

    }

    void ActivateStoneKeepers()
    {
        for (std::vector<uint64>::const_iterator i = stoneKeeper.begin(); i != stoneKeeper.end(); ++i)
        {
            Creature* pTarget = instance->GetCreature(*i);
            if (!pTarget || !pTarget->IsAlive() || pTarget->GetFaction() == 14)
                continue;
			pTarget->SetRooted(false);
            pTarget->SetFaction(14);
            pTarget->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
            return;        // only want the first one we find
        }
        // if we get this far than all four are dead so open the door
        SetData (DATA_ALTAR_DOORS, DONE);
        SetDoor (archaedasTempleDoor, true); //open next the door too
    }

    void ActivateWallMinions()
    {
        Creature* archaedas = instance->GetCreature(archaedasGUID);
        if (!archaedas)
            return;

        for (std::vector<uint64>::const_iterator i = archaedasWallMinions.begin(); i != archaedasWallMinions.end(); ++i)
        {
            Creature* pTarget = instance->GetCreature(*i);
            if (!pTarget || !pTarget->IsAlive() || pTarget->GetFaction() == 14)
                continue;
            archaedas->CastSpell(pTarget, SPELL_AWAKEN_VAULT_WALKER, true);
            pTarget->CastSpell(pTarget, SPELL_ARCHAEDAS_AWAKEN, true);
            return;        // only want the first one we find
        }
    }

    // used when Archaedas dies.  All active minions must be despawned.
    void DeActivateMinions()
    {
        // first despawn any aggroed wall minions
        for (std::vector<uint64>::const_iterator i = archaedasWallMinions.begin(); i != archaedasWallMinions.end(); ++i)
        {
            Creature* pTarget = instance->GetCreature(*i);
            if (!pTarget || pTarget->isDead() || pTarget->GetFaction() != 14)
                continue;
            pTarget->setDeathState(JUST_DIED);
            pTarget->RemoveCorpse();
        }

        // Vault Walkers
        for (std::vector<uint64>::const_iterator i = vaultWalker.begin(); i != vaultWalker.end(); ++i)
        {
            Creature* pTarget = instance->GetCreature(*i);
            if (!pTarget || pTarget->isDead() || pTarget->GetFaction() != 14)
                continue;
            pTarget->setDeathState(JUST_DIED);
            pTarget->RemoveCorpse();
        }

        // Earthen Guardians
        for (std::vector<uint64>::const_iterator i = earthenGuardian.begin(); i != earthenGuardian.end(); ++i)
        {
            Creature* pTarget = instance->GetCreature(*i);
            if (!pTarget || pTarget->isDead() || pTarget->GetFaction() != 14)
                continue;
            pTarget->setDeathState(JUST_DIED);
            pTarget->RemoveCorpse();
        }
    }

    void ActivateArchaedas(uint64 target)
    {
        Creature* archaedas = instance->GetCreature(archaedasGUID);
        if (!archaedas)
            return;

        if (/*Unit* victim = */Unit::GetUnit(*archaedas, target))
        {
            archaedas->CastSpell(archaedas, SPELL_ARCHAEDAS_AWAKEN, false);
            whoWokeArchaedasGUID = target;
        }
    }

    void ActivateIronaya()
    {
        Creature* ironaya = instance->GetCreature(ironayaGUID);
        if (!ironaya)
            return;

        ironaya->SetFaction(415);
		ironaya->SetRooted(false);
        ironaya->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
    }

    void RespawnMinions()
    {
        // first respawn any aggroed wall minions
        for (std::vector<uint64>::const_iterator i = archaedasWallMinions.begin(); i != archaedasWallMinions.end(); ++i)
        {
            Creature* pTarget = instance->GetCreature(*i);
            if (pTarget && pTarget->isDead())
            {
                pTarget->Respawn();
                pTarget->GetMotionMaster()->MoveTargetedHome();
                SetFrozenState(pTarget);
            }
        }

        // Vault Walkers
        for (std::vector<uint64>::const_iterator i = vaultWalker.begin(); i != vaultWalker.end(); ++i)
        {
            Creature* pTarget = instance->GetCreature(*i);
            if (pTarget && pTarget->isDead())
            {
                pTarget->Respawn();
                pTarget->GetMotionMaster()->MoveTargetedHome();
                SetFrozenState(pTarget);
            }
        }

        // Earthen Guardians
        for (std::vector<uint64>::const_iterator i = earthenGuardian.begin(); i != earthenGuardian.end(); ++i)
        {
            Creature* pTarget = instance->GetCreature(*i);
            if (pTarget && pTarget->isDead())
            {
                pTarget->Respawn();
                pTarget->GetMotionMaster()->MoveTargetedHome();
                SetFrozenState(pTarget);
            }
        }
    }

    void Update(uint32 diff)
    {
        if (!keystoneCheck)
            return;

        if (ironayaSealDoorTimer <= diff)
        {
            ActivateIronaya();

            SetDoor(ironayaSealDoor, true);
            BlockGO(keystoneGUID);

            SetData(DATA_IRONAYA_DOOR, DONE); //save state
            keystoneCheck = false;
        }
        else
            ironayaSealDoorTimer -= diff;
    }

    void SetData (uint32 type, uint32 data)
    {
        switch (type)
        {
        case DATA_ALTAR_DOORS:
            Encounters[0] = data;
            if (data == DONE)
                SetDoor (altarOfTheKeeperTempleDoor, true);
            break;

        case DATA_ANCIENT_DOOR:
            Encounters[1] = data;
            if (data == DONE) //archeadas defeat
            {
                SetDoor (archaedasTempleDoor, true); //re open enter door
                SetDoor (ancientVaultDoor, true);
            }
            break;

        case DATA_IRONAYA_DOOR:
            Encounters[2] = data;
            break;

        case DATA_STONE_KEEPERS:
            ActivateStoneKeepers();
            break;

        case DATA_MINIONS:

            break;

        case DATA_IRONAYA_SEAL:
            keystoneCheck = true;
            break;
        }

        if (data == DONE)
        {
            OUT_SAVE_INST_DATA;

            std::ostringstream saveStream;
            saveStream << Encounters[0] << " " << Encounters[1] << " " << Encounters[2];

            str_data = saveStream.str();

            SaveToDB();
            OUT_SAVE_INST_DATA_COMPLETE;
        }
    }

    void SetData64 (uint32 type, uint64 data)
    {
        // Archaedas
        if (type == 0)
        {
            ActivateArchaedas (data);
            SetDoor (archaedasTempleDoor, false); //close when event is started
        }
    }

    void OnCreatureCreate(Creature* pCreature, bool /*add*/)
    {
        switch (pCreature->GetEntry())
        {
        case 4857:    // Stone Keeper
            SetFrozenState (pCreature);
            stoneKeeper.push_back(pCreature->GetGUID());
            break;

        case 7309:    // Earthen Custodian
            archaedasWallMinions.push_back(pCreature->GetGUID());
            break;

        case 7077:    // Earthen Hallshaper
            archaedasWallMinions.push_back(pCreature->GetGUID());
            break;

        case 7076:    // Earthen Guardian
            earthenGuardian.push_back(pCreature->GetGUID());
            break;

        case 7228:    // Ironaya
            ironayaGUID = pCreature->GetGUID();

            if (Encounters[2] != DONE)
                SetFrozenState(pCreature);
            break;

        case 10120:   // Vault Walker
            vaultWalker.push_back(pCreature->GetGUID());
            break;

        case 2748:    // Archaedas
            archaedasGUID = pCreature->GetGUID();
            break;

        } // end switch
    } // end OnCreatureCreate

    uint64 GetData64 (uint32 identifier)
    {
        if (identifier == 0) return whoWokeArchaedasGUID;
        if (identifier == 1) return vaultWalker[0];    // VaultWalker1
        if (identifier == 2) return vaultWalker[1];    // VaultWalker2
        if (identifier == 3) return vaultWalker[2];    // VaultWalker3
        if (identifier == 4) return vaultWalker[3];    // VaultWalker4

        if (identifier == 5) return earthenGuardian[0];
        if (identifier == 6) return earthenGuardian[1];
        if (identifier == 7) return earthenGuardian[2];
        if (identifier == 8) return earthenGuardian[3];
        if (identifier == 9) return earthenGuardian[4];
        if (identifier == 10) return earthenGuardian[5];

        return 0;
    } // end GetData64

    std::string GetSaveData()
    {
        return str_data.c_str();
    }

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

        OUT_LOAD_INST_DATA(in);

        std::istringstream loadStream(in);
        loadStream >> Encounters[0] >> Encounters[1] >> Encounters[2];

        for (uint8 i = 0; i < ENCOUNTERS; ++i)
            if (Encounters[i] == IN_PROGRESS)
                Encounters[i] = NOT_STARTED;

        OUT_LOAD_INST_DATA_COMPLETE;
    }
};

InstanceData* GetInstanceData_instance_uldaman(Map* pMap)
{
    return new instance_uldaman(pMap);
}

void AddSC_instance_uldaman()
{
    Script* newscript;
    newscript = new Script;
    newscript->Name = "instance_uldaman";
    newscript->GetInstanceData = &GetInstanceData_instance_uldaman;
    newscript->RegisterSelf();
}


void Vec::projectOnAxis(const Vec &direction)

/****************************************************************************

 This file is part of the QGLViewer library version 2.7.1.

 http://www.libqglviewer.com - example@nnthink.com

 libQGLViewer uses dual licensing. Commercial/proprietary software must
 purchase a libQGLViewer Commercial License.

*****************************************************************************/

#include "vec.h"
#include "domUtils.h"

// Most of the methods are declared inline in vec.h

using namespace qglviewer;
using namespace std;

/*! Projects the Vec on the axis of direction \p direction that passes through
the origin.

\p direction does not need to be normalized (but must be non null). */

{
#ifndef QT_NO_DEBUG
  if (direction.squaredNorm() < 1.0E-10)
    qWarning("Vec::projectOnAxis: axis direction is not normalized (norm=%f).",
             direction.norm());
#endif

  *this = (((*this) * direction) / direction.squaredNorm()) * direction;
}

/*! Projects the Vec on the plane whose normal is \p normal that passes through
the origin.

\p normal does not need to be normalized (but must be non null). */
void Vec::projectOnPlane(const Vec &normal) {
#ifndef QT_NO_DEBUG
  if (normal.squaredNorm() < 1.0E-10)
    qWarning("Vec::projectOnPlane: plane normal is not normalized (norm=%f).",
             normal.norm());
#endif

  *this -= (((*this) * normal) / normal.squaredNorm()) * normal;
}

/*! Returns a Vec orthogonal to the Vec. Its norm() depends on the Vec, but is
 zero only for a null Vec. Note that the function that associates an
 orthogonalVec() to a Vec is not continous. */
Vec Vec::orthogonalVec() const {
  // Find smallest component. Keep equal case for null values.
  if ((fabs(y) >= 0.9 * fabs(x)) && (fabs(z) >= 0.9 * fabs(x)))
    return Vec(0.0, -z, y);
  else if ((fabs(x) >= 0.9 * fabs(y)) && (fabs(z) >= 0.9 * fabs(y)))
    return Vec(-z, 0.0, x);
  else
    return Vec(-y, x, 0.0);
}

/*! Constructs a Vec from a \c QDomElement representing an XML code of the form
 \code< anyTagName x=".." y=".." z=".." />\endcode

If one of these attributes is missing or is not a number, a warning is displayed
and the associated value is set to 0.0.

See also domElement() and initFromDOMElement(). */
Vec::Vec(const QDomElement &element) {
  QStringList attribute;
  attribute << "x"
            << "y"
            << "z";
  for (int i = 0; i < attribute.size(); ++i)
#ifdef QGLVIEWER_UNION_NOT_SUPPORTED
    this->operator[](i) = DomUtils::qrealFromDom(element, attribute[i], 0.0);
#else
    v_[i] = DomUtils::qrealFromDom(element, attribute[i], 0.0);
#endif
}

/*! Returns an XML \c QDomElement that represents the Vec.

 \p name is the name of the QDomElement tag. \p doc is the \c QDomDocument
 factory used to create QDomElement.

 When output to a file, the resulting QDomElement will look like:
 \code
 <name x=".." y=".." z=".." />
 \endcode

 Use initFromDOMElement() to restore the Vec state from the resulting \c
 QDomElement. See also the Vec(const QDomElement&) constructor.

 Here is complete example that creates a QDomDocument and saves it into a file:
 \code
 Vec sunPos;
 QDomDocument document("myDocument");
 QDomElement sunElement = document.createElement("Sun");
 document.appendChild(sunElement);
 sunElement.setAttribute("brightness", sunBrightness());
 sunElement.appendChild(sunPos.domElement("sunPosition", document));
 // Other additions to the document hierarchy...

 // Save doc document
 QFile f("myFile.xml");
 if (f.open(IO_WriteOnly))
 {
   QTextStream out(&f);
   document.save(out, 2);
   f.close();
 }
 \endcode

 See also Quaternion::domElement(), Frame::domElement(), Camera::domElement()...
 */
QDomElement Vec::domElement(const QString &name, QDomDocument &document) const {
  QDomElement de = document.createElement(name);
  de.setAttribute("x", QString::number(x));
  de.setAttribute("y", QString::number(y));
  de.setAttribute("z", QString::number(z));
  return de;
}

/*! Restores the Vec state from a \c QDomElement created by domElement().

 The \c QDomElement should contain \c x, \c y and \c z attributes. If one of
 these attributes is missing or is not a number, a warning is displayed and the
 associated value is set to 0.0.

 To restore the Vec state from an xml file, use:
 \code
 // Load DOM from file
 QDomDocument doc;
 QFile f("myFile.xml");
 if (f.open(IO_ReadOnly))
 {
   doc.setContent(&f);
   f.close();
 }
 // Parse the DOM tree and initialize
 QDomElement main=doc.documentElement();
 myVec.initFromDOMElement(main);
 \endcode

 See also the Vec(const QDomElement&) constructor. */
void Vec::initFromDOMElement(const QDomElement &element) {
  const Vec v(element);
  *this = v;
}

ostream &operator<<(ostream &o, const Vec &v) {
  return o << v.x << '\t' << v.y << '\t' << v.z;
}


{
  QStringList attribute;
  attribute << "x"
            << "y"
            << "z";
  for (int i = 0; i < attribute.size(); ++i)
#ifdef QGLVIEWER_UNION_NOT_SUPPORTED
    this->operator[](i) = DomUtils::qrealFromDom(element, attribute[i], 0.0);
#else
    v_[i] = DomUtils::qrealFromDom(element, attribute[i], 0.0);
#endif
}

/****************************************************************************

 This file is part of the QGLViewer library version 2.7.1.

 http://www.libqglviewer.com - example@nnthink.com

 libQGLViewer uses dual licensing. Commercial/proprietary software must
 purchase a libQGLViewer Commercial License.

*****************************************************************************/

#include "vec.h"
#include "domUtils.h"

// Most of the methods are declared inline in vec.h

using namespace qglviewer;
using namespace std;

/*! Projects the Vec on the axis of direction \p direction that passes through
the origin.

\p direction does not need to be normalized (but must be non null). */
void Vec::projectOnAxis(const Vec &direction) {
#ifndef QT_NO_DEBUG
  if (direction.squaredNorm() < 1.0E-10)
    qWarning("Vec::projectOnAxis: axis direction is not normalized (norm=%f).",
             direction.norm());
#endif

  *this = (((*this) * direction) / direction.squaredNorm()) * direction;
}

/*! Projects the Vec on the plane whose normal is \p normal that passes through
the origin.

\p normal does not need to be normalized (but must be non null). */
void Vec::projectOnPlane(const Vec &normal) {
#ifndef QT_NO_DEBUG
  if (normal.squaredNorm() < 1.0E-10)
    qWarning("Vec::projectOnPlane: plane normal is not normalized (norm=%f).",
             normal.norm());
#endif

  *this -= (((*this) * normal) / normal.squaredNorm()) * normal;
}

/*! Returns a Vec orthogonal to the Vec. Its norm() depends on the Vec, but is
 zero only for a null Vec. Note that the function that associates an
 orthogonalVec() to a Vec is not continous. */
Vec Vec::orthogonalVec() const {
  // Find smallest component. Keep equal case for null values.
  if ((fabs(y) >= 0.9 * fabs(x)) && (fabs(z) >= 0.9 * fabs(x)))
    return Vec(0.0, -z, y);
  else if ((fabs(x) >= 0.9 * fabs(y)) && (fabs(z) >= 0.9 * fabs(y)))
    return Vec(-z, 0.0, x);
  else
    return Vec(-y, x, 0.0);
}

/*! Constructs a Vec from a \c QDomElement representing an XML code of the form
 \code< anyTagName x=".." y=".." z=".." />\endcode

If one of these attributes is missing or is not a number, a warning is displayed
and the associated value is set to 0.0.

See also domElement() and initFromDOMElement(). */
Vec::Vec(const QDomElement &element)

/*! Returns an XML \c QDomElement that represents the Vec.

 \p name is the name of the QDomElement tag. \p doc is the \c QDomDocument
 factory used to create QDomElement.

 When output to a file, the resulting QDomElement will look like:
 \code
 <name x=".." y=".." z=".." />
 \endcode

 Use initFromDOMElement() to restore the Vec state from the resulting \c
 QDomElement. See also the Vec(const QDomElement&) constructor.

 Here is complete example that creates a QDomDocument and saves it into a file:
 \code
 Vec sunPos;
 QDomDocument document("myDocument");
 QDomElement sunElement = document.createElement("Sun");
 document.appendChild(sunElement);
 sunElement.setAttribute("brightness", sunBrightness());
 sunElement.appendChild(sunPos.domElement("sunPosition", document));
 // Other additions to the document hierarchy...

 // Save doc document
 QFile f("myFile.xml");
 if (f.open(IO_WriteOnly))
 {
   QTextStream out(&f);
   document.save(out, 2);
   f.close();
 }
 \endcode

 See also Quaternion::domElement(), Frame::domElement(), Camera::domElement()...
 */
QDomElement Vec::domElement(const QString &name, QDomDocument &document) const {
  QDomElement de = document.createElement(name);
  de.setAttribute("x", QString::number(x));
  de.setAttribute("y", QString::number(y));
  de.setAttribute("z", QString::number(z));
  return de;
}

/*! Restores the Vec state from a \c QDomElement created by domElement().

 The \c QDomElement should contain \c x, \c y and \c z attributes. If one of
 these attributes is missing or is not a number, a warning is displayed and the
 associated value is set to 0.0.

 To restore the Vec state from an xml file, use:
 \code
 // Load DOM from file
 QDomDocument doc;
 QFile f("myFile.xml");
 if (f.open(IO_ReadOnly))
 {
   doc.setContent(&f);
   f.close();
 }
 // Parse the DOM tree and initialize
 QDomElement main=doc.documentElement();
 myVec.initFromDOMElement(main);
 \endcode

 See also the Vec(const QDomElement&) constructor. */
void Vec::initFromDOMElement(const QDomElement &element) {
  const Vec v(element);
  *this = v;
}

ostream &operator<<(ostream &o, const Vec &v) {
  return o << v.x << '\t' << v.y << '\t' << v.z;
}


*this -= (((*this) * normal) / normal.squaredNorm()) * normal;

/****************************************************************************

 This file is part of the QGLViewer library version 2.7.1.

 http://www.libqglviewer.com - example@nnthink.com

 libQGLViewer uses dual licensing. Commercial/proprietary software must
 purchase a libQGLViewer Commercial License.

*****************************************************************************/

#include "vec.h"
#include "domUtils.h"

// Most of the methods are declared inline in vec.h

using namespace qglviewer;
using namespace std;

/*! Projects the Vec on the axis of direction \p direction that passes through
the origin.

\p direction does not need to be normalized (but must be non null). */
void Vec::projectOnAxis(const Vec &direction) {
#ifndef QT_NO_DEBUG
  if (direction.squaredNorm() < 1.0E-10)
    qWarning("Vec::projectOnAxis: axis direction is not normalized (norm=%f).",
             direction.norm());
#endif

  *this = (((*this) * direction) / direction.squaredNorm()) * direction;
}

/*! Projects the Vec on the plane whose normal is \p normal that passes through
the origin.

\p normal does not need to be normalized (but must be non null). */
void Vec::projectOnPlane(const Vec &normal) {
#ifndef QT_NO_DEBUG
  if (normal.squaredNorm() < 1.0E-10)
    qWarning("Vec::projectOnPlane: plane normal is not normalized (norm=%f).",
             normal.norm());
#endif

}

/*! Returns a Vec orthogonal to the Vec. Its norm() depends on the Vec, but is
 zero only for a null Vec. Note that the function that associates an
 orthogonalVec() to a Vec is not continous. */
Vec Vec::orthogonalVec() const {
  // Find smallest component. Keep equal case for null values.
  if ((fabs(y) >= 0.9 * fabs(x)) && (fabs(z) >= 0.9 * fabs(x)))
    return Vec(0.0, -z, y);
  else if ((fabs(x) >= 0.9 * fabs(y)) && (fabs(z) >= 0.9 * fabs(y)))
    return Vec(-z, 0.0, x);
  else
    return Vec(-y, x, 0.0);
}

/*! Constructs a Vec from a \c QDomElement representing an XML code of the form
 \code< anyTagName x=".." y=".." z=".." />\endcode

If one of these attributes is missing or is not a number, a warning is displayed
and the associated value is set to 0.0.

See also domElement() and initFromDOMElement(). */
Vec::Vec(const QDomElement &element) {
  QStringList attribute;
  attribute << "x"
            << "y"
            << "z";
  for (int i = 0; i < attribute.size(); ++i)
#ifdef QGLVIEWER_UNION_NOT_SUPPORTED
    this->operator[](i) = DomUtils::qrealFromDom(element, attribute[i], 0.0);
#else
    v_[i] = DomUtils::qrealFromDom(element, attribute[i], 0.0);
#endif
}

/*! Returns an XML \c QDomElement that represents the Vec.

 \p name is the name of the QDomElement tag. \p doc is the \c QDomDocument
 factory used to create QDomElement.

 When output to a file, the resulting QDomElement will look like:
 \code
 <name x=".." y=".." z=".." />
 \endcode

 Use initFromDOMElement() to restore the Vec state from the resulting \c
 QDomElement. See also the Vec(const QDomElement&) constructor.

 Here is complete example that creates a QDomDocument and saves it into a file:
 \code
 Vec sunPos;
 QDomDocument document("myDocument");
 QDomElement sunElement = document.createElement("Sun");
 document.appendChild(sunElement);
 sunElement.setAttribute("brightness", sunBrightness());
 sunElement.appendChild(sunPos.domElement("sunPosition", document));
 // Other additions to the document hierarchy...

 // Save doc document
 QFile f("myFile.xml");
 if (f.open(IO_WriteOnly))
 {
   QTextStream out(&f);
   document.save(out, 2);
   f.close();
 }
 \endcode

 See also Quaternion::domElement(), Frame::domElement(), Camera::domElement()...
 */
QDomElement Vec::domElement(const QString &name, QDomDocument &document) const {
  QDomElement de = document.createElement(name);
  de.setAttribute("x", QString::number(x));
  de.setAttribute("y", QString::number(y));
  de.setAttribute("z", QString::number(z));
  return de;
}

/*! Restores the Vec state from a \c QDomElement created by domElement().

 The \c QDomElement should contain \c x, \c y and \c z attributes. If one of
 these attributes is missing or is not a number, a warning is displayed and the
 associated value is set to 0.0.

 To restore the Vec state from an xml file, use:
 \code
 // Load DOM from file
 QDomDocument doc;
 QFile f("myFile.xml");
 if (f.open(IO_ReadOnly))
 {
   doc.setContent(&f);
   f.close();
 }
 // Parse the DOM tree and initialize
 QDomElement main=doc.documentElement();
 myVec.initFromDOMElement(main);
 \endcode

 See also the Vec(const QDomElement&) constructor. */
void Vec::initFromDOMElement(const QDomElement &element) {
  const Vec v(element);
  *this = v;
}

ostream &operator<<(ostream &o, const Vec &v) {
  return o << v.x << '\t' << v.y << '\t' << v.z;
}


QDomElement Vec::domElement(const QString &name, QDomDocument &document) const {
  QDomElement de = document.createElement(name);
  de.setAttribute("x", QString::number(x));
  de.setAttribute("y", QString::number(y));
  de.setAttribute("z", QString::number(z));
  return de;
}

/****************************************************************************

 This file is part of the QGLViewer library version 2.7.1.

 http://www.libqglviewer.com - example@nnthink.com

 libQGLViewer uses dual licensing. Commercial/proprietary software must
 purchase a libQGLViewer Commercial License.

*****************************************************************************/

#include "vec.h"
#include "domUtils.h"

// Most of the methods are declared inline in vec.h

using namespace qglviewer;
using namespace std;

/*! Projects the Vec on the axis of direction \p direction that passes through
the origin.

\p direction does not need to be normalized (but must be non null). */
void Vec::projectOnAxis(const Vec &direction) {
#ifndef QT_NO_DEBUG
  if (direction.squaredNorm() < 1.0E-10)
    qWarning("Vec::projectOnAxis: axis direction is not normalized (norm=%f).",
             direction.norm());
#endif

  *this = (((*this) * direction) / direction.squaredNorm()) * direction;
}

/*! Projects the Vec on the plane whose normal is \p normal that passes through
the origin.

\p normal does not need to be normalized (but must be non null). */
void Vec::projectOnPlane(const Vec &normal) {
#ifndef QT_NO_DEBUG
  if (normal.squaredNorm() < 1.0E-10)
    qWarning("Vec::projectOnPlane: plane normal is not normalized (norm=%f).",
             normal.norm());
#endif

  *this -= (((*this) * normal) / normal.squaredNorm()) * normal;
}

/*! Returns a Vec orthogonal to the Vec. Its norm() depends on the Vec, but is
 zero only for a null Vec. Note that the function that associates an
 orthogonalVec() to a Vec is not continous. */
Vec Vec::orthogonalVec() const {
  // Find smallest component. Keep equal case for null values.
  if ((fabs(y) >= 0.9 * fabs(x)) && (fabs(z) >= 0.9 * fabs(x)))
    return Vec(0.0, -z, y);
  else if ((fabs(x) >= 0.9 * fabs(y)) && (fabs(z) >= 0.9 * fabs(y)))
    return Vec(-z, 0.0, x);
  else
    return Vec(-y, x, 0.0);
}

/*! Constructs a Vec from a \c QDomElement representing an XML code of the form
 \code< anyTagName x=".." y=".." z=".." />\endcode

If one of these attributes is missing or is not a number, a warning is displayed
and the associated value is set to 0.0.

See also domElement() and initFromDOMElement(). */
Vec::Vec(const QDomElement &element) {
  QStringList attribute;
  attribute << "x"
            << "y"
            << "z";
  for (int i = 0; i < attribute.size(); ++i)
#ifdef QGLVIEWER_UNION_NOT_SUPPORTED
    this->operator[](i) = DomUtils::qrealFromDom(element, attribute[i], 0.0);
#else
    v_[i] = DomUtils::qrealFromDom(element, attribute[i], 0.0);
#endif
}

/*! Returns an XML \c QDomElement that represents the Vec.

 \p name is the name of the QDomElement tag. \p doc is the \c QDomDocument
 factory used to create QDomElement.

 When output to a file, the resulting QDomElement will look like:
 \code
 <name x=".." y=".." z=".." />
 \endcode

 Use initFromDOMElement() to restore the Vec state from the resulting \c
 QDomElement. See also the Vec(const QDomElement&) constructor.

 Here is complete example that creates a QDomDocument and saves it into a file:
 \code
 Vec sunPos;
 QDomDocument document("myDocument");
 QDomElement sunElement = document.createElement("Sun");
 document.appendChild(sunElement);
 sunElement.setAttribute("brightness", sunBrightness());
 sunElement.appendChild(sunPos.domElement("sunPosition", document));
 // Other additions to the document hierarchy...

 // Save doc document
 QFile f("myFile.xml");
 if (f.open(IO_WriteOnly))
 {
   QTextStream out(&f);
   document.save(out, 2);
   f.close();
 }
 \endcode

 See also Quaternion::domElement(), Frame::domElement(), Camera::domElement()...
 */

/*! Restores the Vec state from a \c QDomElement created by domElement().

 The \c QDomElement should contain \c x, \c y and \c z attributes. If one of
 these attributes is missing or is not a number, a warning is displayed and the
 associated value is set to 0.0.

 To restore the Vec state from an xml file, use:
 \code
 // Load DOM from file
 QDomDocument doc;
 QFile f("myFile.xml");
 if (f.open(IO_ReadOnly))
 {
   doc.setContent(&f);
   f.close();
 }
 // Parse the DOM tree and initialize
 QDomElement main=doc.documentElement();
 myVec.initFromDOMElement(main);
 \endcode

 See also the Vec(const QDomElement&) constructor. */
void Vec::initFromDOMElement(const QDomElement &element) {
  const Vec v(element);
  *this = v;
}

ostream &operator<<(ostream &o, const Vec &v) {
  return o << v.x << '\t' << v.y << '\t' << v.z;
}


//! \example tutorial-draw-line.cpp
#include <visp3/gui/vpDisplayGDI.h>
#include <visp3/gui/vpDisplayX.h>

{
  vpImage<unsigned char> I(2160, 3840, 128);

  try {

#if defined(VISP_HAVE_X11)
    vpDisplayX d(I, vpDisplay::SCALE_AUTO);
#elif defined(VISP_HAVE_GDI)
    vpDisplayGDI d(I, vpDisplay::SCALE_AUTO);
#endif

    vpDisplay::setTitle(I, "My image");
    vpDisplay::display(I);
    vpDisplay::displayLine(I, I.getHeight() / 4, I.getWidth() / 4, (3 * I.getHeight() ) / 4, (3 * I.getWidth() ) / 4, vpColor::red, 10);
    vpDisplay::flush(I);
    std::cout << "A click to quit..." << std::endl;
    vpDisplay::getClick(I);
  } catch (const vpException &e) {
    std::cout << "Catch an exception: " << e.getMessage() << std::endl;
  }
}


//! \example tutorial-draw-line.cpp
#include <visp3/gui/vpDisplayGDI.h>
#include <visp3/gui/vpDisplayX.h>

int main()
{
  vpImage<unsigned char> I(2160, 3840, 1

  try {

#if defined(VISP_HAVE_X11)
    vpDisplayX d(I, vpDisplay::SCALE_AUTO);
#elif defined(VISP_HAVE_GDI)
    vpDisplayGDI d(I, vpDisplay::SCALE_AUTO);
#endif

    vpDisplay::setTitle(I, "My image");
    vpDisplay::display(I);
    vpDisplay::displayLine(I, I.getHeight() / 4, I.getWidth() / 4, (3 * I.getHeight() ) / 4, (3 * I.getWidth() ) / 4, vpColor::red, 10);
    vpDisplay::flush(I);
    std::cout << "A click to quit..." << std::endl;
    vpDisplay::getClick(I);
  } catch (const vpException &e) {
    std::cout << "Catch an exception: " << e.getMessage() << std::endl;
  }
}


/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
*
*
*
* The Original Code is Coreseek.com code.
*
*
* Author:
*	Li monan <example@nnthink.com>
*
* ***** END LICENSE BLOCK ***** */

#include "UnigramRecord.h"

namespace css {

{ count = 0; }

} /* End of namespace css */


/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
*
*
*
* The Original Code is Coreseek.com code.
*
*
* Author:
*	Li monan <example@nnthink.com>
*
* ***** END LICENSE BLOCK ***** */

#include "UnigramRecord.h"

namespace css {

UnigramRecord::UnigramRecord()


/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
*
*
*
* The Original Code is Coreseek.com code.
*
*
* Author:
*	Li monan <example@nnthink.com>
*
* ***** END LICENSE BLOCK ***** */

#include "UnigramRecord.h"

namespace css {

UnigramRecord::UnigramRecord() { cou


std::vector<Light> LightManager::GetAllLights(LightGroup type) const

#include "carla/client/LightManager.h"

#include "carla/client/detail/Simulator.h"

namespace carla {
namespace client {

  using LightGroup = rpc::LightState::LightGroup;

LightManager::~LightManager(){
  if(_episode.IsValid()) {
    _episode.Lock()->RemoveOnTickEvent(_on_light_update_register_id);
    _episode.Lock()->RemoveLightUpdateChangeEvent(_on_light_update_register_id);
  }
  UpdateServerLightsState(true);
}

void LightManager::SetEpisode(detail::EpisodeProxy episode) {

  _episode = episode;

  _on_tick_register_id = _episode.Lock()->RegisterOnTickEvent(
    [&](const WorldSnapshot&) {
      UpdateServerLightsState();
    });

  _on_light_update_register_id = _episode.Lock()->RegisterLightUpdateChangeEvent(
    [&](const WorldSnapshot& ) {
      QueryLightsStateToServer();
      ApplyChanges();
    });

    QueryLightsStateToServer();
}

{
  std::vector<Light> result;

  for(auto lights_state : _lights_state) {
    LightGroup group = lights_state.second._group;
    if((type == LightGroup::None) || (group == type)) {
      auto it_light = _lights.find(lights_state.first);
      result.push_back(it_light->second);
    }
  }

  return result;
}

void LightManager::TurnOn(std::vector<Light>& lights) {
  for(Light& light : lights) {
    SetActive(light._id, true);
  }
}

void LightManager::TurnOff(std::vector<Light>& lights) {
  for(Light& light : lights) {
    SetActive(light._id, false);
  }
}

void LightManager::SetActive(std::vector<Light>& lights, std::vector<bool>& active) {
  size_t lights_to_update = (lights.size() < active.size()) ? lights.size() : active.size();
  for(size_t i = 0; i < lights_to_update; i++) {
    SetActive(lights[i]._id, active[i]);
  }
}

std::vector<bool> LightManager::IsActive(std::vector<Light>& lights) const {
  std::vector<bool> result;
  for(Light& light : lights) {
    result.push_back( IsActive(light._id) );
  }
  return result;
}

std::vector<Light> LightManager::GetTurnedOnLights(LightGroup type) const {
  std::vector<Light> result;

  for(auto lights_state : _lights_state) {
    LightState& state = lights_state.second;
    LightGroup group = state._group;
    if( (type == LightGroup::None || group == type) && state._active ) {
      auto it_light = _lights.find(lights_state.first);
      result.push_back(it_light->second);
    }
  }

  return result;
}

std::vector<Light> LightManager::GetTurnedOffLights(LightGroup type) const {
  std::vector<Light> result;

  for(auto lights_state : _lights_state) {
    LightState& state = lights_state.second;
    LightGroup group = state._group;
    if( (type == LightGroup::None || group == type) && !state._active ) {
      auto it_light = _lights.find(lights_state.first);
      result.push_back(it_light->second);
    }
  }

  return result;
}

void LightManager::SetColor(std::vector<Light>& lights, Color color) {
  for(Light& light : lights) {
    SetColor(light._id, color);
  }
}

void LightManager::SetColor(std::vector<Light>& lights, std::vector<Color>& colors) {
  size_t lights_to_update = (lights.size() < colors.size()) ? lights.size() : colors.size();
  for(size_t i = 0; i < lights_to_update; i++) {
    SetColor(lights[i]._id, colors[i]);
  }
}

std::vector<Color> LightManager::GetColor(std::vector<Light>& lights) const {
  std::vector<Color> result;
  for(Light& light : lights) {
    result.push_back( GetColor(light._id) );
  }
  return result;
}

void LightManager::SetIntensity(std::vector<Light>& lights, float intensity) {
  for(Light& light : lights) {
    SetIntensity(light._id, intensity);
  }
}

void LightManager::SetIntensity(std::vector<Light>& lights, std::vector<float>& intensities) {
  size_t lights_to_update = (lights.size() < intensities.size()) ? lights.size() : intensities.size();
  for(size_t i = 0; i < lights_to_update; i++) {
    SetIntensity(lights[i]._id, intensities[i]);
  }
}

std::vector<float> LightManager::GetIntensity(std::vector<Light>& lights) const {
  std::vector<float> result;
  for(Light& light : lights) {
    result.push_back( GetIntensity(light._id) );
  }
  return result;
}

void LightManager::SetLightGroup(std::vector<Light>& lights, LightGroup group) {
  for(Light& light : lights) {
    SetLightGroup(light._id, group);
  }
}

void LightManager::SetLightGroup(std::vector<Light>& lights, std::vector<LightGroup>& groups) {
  size_t lights_to_update = (lights.size() < groups.size()) ? lights.size() : groups.size();
  for(size_t i = 0; i < lights_to_update; i++) {
    SetLightGroup(lights[i]._id, groups[i]);
  }
}

std::vector<LightGroup> LightManager::GetLightGroup(std::vector<Light>& lights) const {
  std::vector<LightGroup> result;
  for(Light& light : lights) {
    result.push_back( GetLightGroup(light._id) );
  }
  return result;
}

void LightManager::SetLightState(std::vector<Light>& lights, LightState state) {
  for(Light& light : lights) {
    SetLightState(light._id, state);
  }
}

void LightManager::SetLightState(std::vector<Light>& lights, std::vector<LightState>& states) {
  size_t lights_to_update = (lights.size() < states.size()) ? lights.size() : states.size();
  for(size_t i = 0; i < lights_to_update; i++) {
    SetLightState(lights[i]._id, states[i]);
  }
}

std::vector<LightState> LightManager::GetLightState(std::vector<Light>& lights) const {
  std::vector<LightState> result;
  for(Light& light : lights) {
    result.push_back( RetrieveLightState(light._id) );
  }
  return result;
}

Color LightManager::GetColor(LightId id) const {
  return RetrieveLightState(id)._color;
}

float LightManager::GetIntensity(LightId id) const {
  return RetrieveLightState(id)._intensity;
}

LightState LightManager::GetLightState(LightId id) const {
  return RetrieveLightState(id);
}

LightGroup LightManager::GetLightGroup(LightId id) const {
  return RetrieveLightState(id)._group;
}

bool LightManager::IsActive(LightId id) const {
  return RetrieveLightState(id)._active;
}

void LightManager::SetActive(LightId id, bool active) {
  std::lock_guard<std::mutex> lock(_mutex);
  LightState& state = const_cast<LightState&>(RetrieveLightState(id));
  state._active = active;
  _lights_changes[id] = state;
  _dirty = true;
}

void LightManager::SetColor(LightId id, Color color) {
  std::lock_guard<std::mutex> lock(_mutex);
  LightState& state = const_cast<LightState&>(RetrieveLightState(id));
  state._color = color;
  _lights_changes[id] = state;
  _dirty = true;
}

void LightManager::SetIntensity(LightId id, float intensity) {
  std::lock_guard<std::mutex> lock(_mutex);
  LightState& state = const_cast<LightState&>(RetrieveLightState(id));
  state._intensity = intensity;
  _lights_changes[id] = state;
  _dirty = true;
}

void LightManager::SetLightState(LightId id, const LightState& new_state) {
  std::lock_guard<std::mutex> lock(_mutex);
  LightState& state = const_cast<LightState&>(RetrieveLightState(id));
  state = new_state;
  _lights_changes[id] = state;
  _dirty = true;
}

void LightManager::SetLightGroup(LightId id, LightGroup group) {
  std::lock_guard<std::mutex> lock(_mutex);
  LightState& state = const_cast<LightState&>(RetrieveLightState(id));
  state._group = group;
  _lights_changes[id] = state;
  _dirty = true;
}

const LightState& LightManager::RetrieveLightState(LightId id) const {
  auto it = _lights_state.find(id);
  if(it == _lights_state.end()) {
    carla::log_warning("Invalid light", id);
    return _state;
  }
  return it->second;
}

void LightManager::QueryLightsStateToServer() {
  std::lock_guard<std::mutex> lock(_mutex);
  // Send blocking query
  std::vector<rpc::LightState> lights_snapshot = _episode.Lock()->QueryLightsStateToServer();

  // Update lights
  SharedPtr<LightManager> lm = _episode.Lock()->GetLightManager();

  for(const auto& it : lights_snapshot) {
    _lights_state[it._id] = LightState(
        it._intensity,
        Color(it._color.r, it._color.g, it._color.b),
        static_cast<LightState::LightGroup>(it._group),
        it._active
    );

    if(_lights.find(it._id) == _lights.end())
    {
      _lights[it._id] = Light(lm, it._location, it._id);
    }
  }
}

void LightManager::UpdateServerLightsState(bool discard_client) {
  std::lock_guard<std::mutex> lock(_mutex);

  if(_dirty) {
    std::vector<rpc::LightState> message;
    for(auto it : _lights_changes) {
      auto it_light = _lights.find(it.first);
      if(it_light != _lights.end()) {
        rpc::LightState state(
          it_light->second.GetLocation(),
          it.second._intensity,
          it.second._group,
          rpc::Color(it.second._color.r, it.second._color.g, it.second._color.b),
          it.second._active
        );
        state._id = it.first;
        // Add to command
        message.push_back(state);
      }
    }
    _episode.Lock()->UpdateServerLightsState(message, discard_client);

    _lights_changes.clear();
    _dirty = false;
  }
}

void LightManager::ApplyChanges() {
  std::lock_guard<std::mutex> lock(_mutex);
  for(const auto& it : _lights_changes) {
    SetLightState(it.first, it.second);
  }
}

} // namespace client
} // namespace carla


{
  for(Light& light : lights) {
    SetLightGroup(light._id, group);
  }
}

#include "carla/client/LightManager.h"

#include "carla/client/detail/Simulator.h"

namespace carla {
namespace client {

  using LightGroup = rpc::LightState::LightGroup;

LightManager::~LightManager(){
  if(_episode.IsValid()) {
    _episode.Lock()->RemoveOnTickEvent(_on_light_update_register_id);
    _episode.Lock()->RemoveLightUpdateChangeEvent(_on_light_update_register_id);
  }
  UpdateServerLightsState(true);
}

void LightManager::SetEpisode(detail::EpisodeProxy episode) {

  _episode = episode;

  _on_tick_register_id = _episode.Lock()->RegisterOnTickEvent(
    [&](const WorldSnapshot&) {
      UpdateServerLightsState();
    });

  _on_light_update_register_id = _episode.Lock()->RegisterLightUpdateChangeEvent(
    [&](const WorldSnapshot& ) {
      QueryLightsStateToServer();
      ApplyChanges();
    });

    QueryLightsStateToServer();
}

std::vector<Light> LightManager::GetAllLights(LightGroup type) const {
  std::vector<Light> result;

  for(auto lights_state : _lights_state) {
    LightGroup group = lights_state.second._group;
    if((type == LightGroup::None) || (group == type)) {
      auto it_light = _lights.find(lights_state.first);
      result.push_back(it_light->second);
    }
  }

  return result;
}

void LightManager::TurnOn(std::vector<Light>& lights) {
  for(Light& light : lights) {
    SetActive(light._id, true);
  }
}

void LightManager::TurnOff(std::vector<Light>& lights) {
  for(Light& light : lights) {
    SetActive(light._id, false);
  }
}

void LightManager::SetActive(std::vector<Light>& lights, std::vector<bool>& active) {
  size_t lights_to_update = (lights.size() < active.size()) ? lights.size() : active.size();
  for(size_t i = 0; i < lights_to_update; i++) {
    SetActive(lights[i]._id, active[i]);
  }
}

std::vector<bool> LightManager::IsActive(std::vector<Light>& lights) const {
  std::vector<bool> result;
  for(Light& light : lights) {
    result.push_back( IsActive(light._id) );
  }
  return result;
}

std::vector<Light> LightManager::GetTurnedOnLights(LightGroup type) const {
  std::vector<Light> result;

  for(auto lights_state : _lights_state) {
    LightState& state = lights_state.second;
    LightGroup group = state._group;
    if( (type == LightGroup::None || group == type) && state._active ) {
      auto it_light = _lights.find(lights_state.first);
      result.push_back(it_light->second);
    }
  }

  return result;
}

std::vector<Light> LightManager::GetTurnedOffLights(LightGroup type) const {
  std::vector<Light> result;

  for(auto lights_state : _lights_state) {
    LightState& state = lights_state.second;
    LightGroup group = state._group;
    if( (type == LightGroup::None || group == type) && !state._active ) {
      auto it_light = _lights.find(lights_state.first);
      result.push_back(it_light->second);
    }
  }

  return result;
}

void LightManager::SetColor(std::vector<Light>& lights, Color color) {
  for(Light& light : lights) {
    SetColor(light._id, color);
  }
}

void LightManager::SetColor(std::vector<Light>& lights, std::vector<Color>& colors) {
  size_t lights_to_update = (lights.size() < colors.size()) ? lights.size() : colors.size();
  for(size_t i = 0; i < lights_to_update; i++) {
    SetColor(lights[i]._id, colors[i]);
  }
}

std::vector<Color> LightManager::GetColor(std::vector<Light>& lights) const {
  std::vector<Color> result;
  for(Light& light : lights) {
    result.push_back( GetColor(light._id) );
  }
  return result;
}

void LightManager::SetIntensity(std::vector<Light>& lights, float intensity) {
  for(Light& light : lights) {
    SetIntensity(light._id, intensity);
  }
}

void LightManager::SetIntensity(std::vector<Light>& lights, std::vector<float>& intensities) {
  size_t lights_to_update = (lights.size() < intensities.size()) ? lights.size() : intensities.size();
  for(size_t i = 0; i < lights_to_update; i++) {
    SetIntensity(lights[i]._id, intensities[i]);
  }
}

std::vector<float> LightManager::GetIntensity(std::vector<Light>& lights) const {
  std::vector<float> result;
  for(Light& light : lights) {
    result.push_back( GetIntensity(light._id) );
  }
  return result;
}

void LightManager::SetLightGroup(std::vector<Light>& lights, LightGroup group)

void LightManager::SetLightGroup(std::vector<Light>& lights, std::vector<LightGroup>& groups) {
  size_t lights_to_update = (lights.size() < groups.size()) ? lights.size() : groups.size();
  for(size_t i = 0; i < lights_to_update; i++) {
    SetLightGroup(lights[i]._id, groups[i]);
  }
}

std::vector<LightGroup> LightManager::GetLightGroup(std::vector<Light>& lights) const {
  std::vector<LightGroup> result;
  for(Light& light : lights) {
    result.push_back( GetLightGroup(light._id) );
  }
  return result;
}

void LightManager::SetLightState(std::vector<Light>& lights, LightState state) {
  for(Light& light : lights) {
    SetLightState(light._id, state);
  }
}

void LightManager::SetLightState(std::vector<Light>& lights, std::vector<LightState>& states) {
  size_t lights_to_update = (lights.size() < states.size()) ? lights.size() : states.size();
  for(size_t i = 0; i < lights_to_update; i++) {
    SetLightState(lights[i]._id, states[i]);
  }
}

std::vector<LightState> LightManager::GetLightState(std::vector<Light>& lights) const {
  std::vector<LightState> result;
  for(Light& light : lights) {
    result.push_back( RetrieveLightState(light._id) );
  }
  return result;
}

Color LightManager::GetColor(LightId id) const {
  return RetrieveLightState(id)._color;
}

float LightManager::GetIntensity(LightId id) const {
  return RetrieveLightState(id)._intensity;
}

LightState LightManager::GetLightState(LightId id) const {
  return RetrieveLightState(id);
}

LightGroup LightManager::GetLightGroup(LightId id) const {
  return RetrieveLightState(id)._group;
}

bool LightManager::IsActive(LightId id) const {
  return RetrieveLightState(id)._active;
}

void LightManager::SetActive(LightId id, bool active) {
  std::lock_guard<std::mutex> lock(_mutex);
  LightState& state = const_cast<LightState&>(RetrieveLightState(id));
  state._active = active;
  _lights_changes[id] = state;
  _dirty = true;
}

void LightManager::SetColor(LightId id, Color color) {
  std::lock_guard<std::mutex> lock(_mutex);
  LightState& state = const_cast<LightState&>(RetrieveLightState(id));
  state._color = color;
  _lights_changes[id] = state;
  _dirty = true;
}

void LightManager::SetIntensity(LightId id, float intensity) {
  std::lock_guard<std::mutex> lock(_mutex);
  LightState& state = const_cast<LightState&>(RetrieveLightState(id));
  state._intensity = intensity;
  _lights_changes[id] = state;
  _dirty = true;
}

void LightManager::SetLightState(LightId id, const LightState& new_state) {
  std::lock_guard<std::mutex> lock(_mutex);
  LightState& state = const_cast<LightState&>(RetrieveLightState(id));
  state = new_state;
  _lights_changes[id] = state;
  _dirty = true;
}

void LightManager::SetLightGroup(LightId id, LightGroup group) {
  std::lock_guard<std::mutex> lock(_mutex);
  LightState& state = const_cast<LightState&>(RetrieveLightState(id));
  state._group = group;
  _lights_changes[id] = state;
  _dirty = true;
}

const LightState& LightManager::RetrieveLightState(LightId id) const {
  auto it = _lights_state.find(id);
  if(it == _lights_state.end()) {
    carla::log_warning("Invalid light", id);
    return _state;
  }
  return it->second;
}

void LightManager::QueryLightsStateToServer() {
  std::lock_guard<std::mutex> lock(_mutex);
  // Send blocking query
  std::vector<rpc::LightState> lights_snapshot = _episode.Lock()->QueryLightsStateToServer();

  // Update lights
  SharedPtr<LightManager> lm = _episode.Lock()->GetLightManager();

  for(const auto& it : lights_snapshot) {
    _lights_state[it._id] = LightState(
        it._intensity,
        Color(it._color.r, it._color.g, it._color.b),
        static_cast<LightState::LightGroup>(it._group),
        it._active
    );

    if(_lights.find(it._id) == _lights.end())
    {
      _lights[it._id] = Light(lm, it._location, it._id);
    }
  }
}

void LightManager::UpdateServerLightsState(bool discard_client) {
  std::lock_guard<std::mutex> lock(_mutex);

  if(_dirty) {
    std::vector<rpc::LightState> message;
    for(auto it : _lights_changes) {
      auto it_light = _lights.find(it.first);
      if(it_light != _lights.end()) {
        rpc::LightState state(
          it_light->second.GetLocation(),
          it.second._intensity,
          it.second._group,
          rpc::Color(it.second._color.r, it.second._color.g, it.second._color.b),
          it.second._active
        );
        state._id = it.first;
        // Add to command
        message.push_back(state);
      }
    }
    _episode.Lock()->UpdateServerLightsState(message, discard_client);

    _lights_changes.clear();
    _dirty = false;
  }
}

void LightManager::ApplyChanges() {
  std::lock_guard<std::mutex> lock(_mutex);
  for(const auto& it : _lights_changes) {
    SetLightState(it.first, it.second);
  }
}

} // namespace client
} // namespace carla


#include "carla/client/LightManager.h"

#include "carla/client/detail/Simulator.h"

namespace carla {
namespace client {

  using LightGroup = rpc::LightState::LightGroup;

LightManager::~LightManager(){
  if(_episode.IsValid()) {
    _episode.Lock()->RemoveOnTickEvent(_on_light_update_register_id);
    _episode.Lock()->RemoveLightUpdateChangeEvent(_on_light_update_register_id);
  }
  UpdateServerLightsState(true);
}

void LightManager::SetEpisode(detail::EpisodeProxy episode) {

  _episode = episode;

  _on_tick_register_id = _episode.Lock()->RegisterOnTickEvent(
    [&](const WorldSnapshot&) {
      UpdateServerLightsState();
    });

  _on_light_update_register_id = _episode.Lock()->RegisterLightUpdateChangeEvent(
    [&](const WorldSnapshot& ) {
      QueryLightsStateToServer();
      ApplyChanges();
    });

    QueryLightsStateToServer();
}

std::vector<Light> LightManager::GetAllLights(LightGroup type) const {
  std::vector<Light> result;

  for(auto lights_state : _lights_state) {
    LightGroup group = lights_state.second._group;
    if((type == LightGroup::None) || (group == type)) {
      auto it_light = _lights.find(lights_state.first);
      result.push_back(it_light->second);
    }
  }

  return result;
}

void LightManager::TurnOn(std::vector<Light>& lights) {
  for(Light& light : lights) {
    SetActive(light._id, true);
  }
}

void LightManager::TurnOff(std::vector<Light>& lights) {
  for(Light& light : lights) {
    SetActive(light._id, false);
  }
}

void LightManager::SetActive(std::vector<Light>& lights, std::vector<bool>& active) {
  size_t lights_to_update = (lights.size() < active.size()) ? lights.size() : active.size();
  for(size_t i = 0; i < lights_to_update; i++) {
    SetActive(lights[i]._id, active[i]);
  }
}

std::vector<bool> LightManager::IsActive(std::vector<Light>& lights) const {
  std::vector<bool> result;
  for(Light& light : lights) {
    result.push_back( IsActive(light._id) );
  }
  return result;
}

std::vector<Light> LightManager::GetTurnedOnLights(LightGroup type) const {
  std::vector<Light> result;

  for(auto lights_state : _lights_state) {
    LightState& state = lights_state.second;
    LightGroup group = state._group;
    if( (type == LightGroup::None || group == type) && state._active ) {
      auto it_light = _lights.find(lights_state.first);
      result.push_back(it_light->second);
    }
  }

  return result;
}

std::vector<Light> LightManager::GetTurnedOffLights(LightGroup type) const {
  std::vector<Light> result;

  for(auto lights_state : _lights_state) {
    LightState& state = lights_state.second;
    LightGroup group = state._group;
    if( (type == LightGroup::None || group == type) && !state._active ) {
      auto it_light = _lights.find(lights_state.first);
      result.push_back(it_light->second);
    }
  }

  return result;
}

void LightManager::SetColor(std::vector<Light>& lights, Color color) {
  for(Light& light : lights) {
    SetColor(light._id, color);
  }
}

void LightManager::SetColor(std::vector<Light>& lights, std::vector<Color>& colors) {
  size_t lights_to_update = (lights.size() < colors.size()) ? lights.size() : colors.size();
  for(size_t i = 0; i < lights_to_update; i++) {
    SetColor(lights[i]._id, colors[i]);
  }
}

std::vector<Color> LightManager::GetColor(std::vector<Light>& lights) const {
  std::vector<Color> result;
  for(Light& light : lights) {
    result.push_back( GetColor(light._id) );
  }
  return result;
}

void LightManager::SetIntensity(std::vector<Light>& lights, float intensity) {
  for(Light& light : lights) {
    SetIntensity(light._id, intensity);
  }
}

void LightManager::SetIntensity(std::vector<Light>& lights, std::vector<float>& intensities) {
  size_t lights_to_update = (lights.size() < intensities.size()) ? lights.size() : intensities.size();
  for(size_t i = 0; i < lights_to_update; i++) {
    SetIntensity(lights[i]._id, intensities[i]);
  }
}

std::vector<float> LightManager::GetIntensity(std::vector<Light>& lights) const {
  std::vector<float> result;
  for(Light& light : lights) {
    result.push_back( GetIntensity(light._id) );
  }
  return result;
}

void LightManager::SetLightGroup(std::vector<Light>& lights, LightGroup group) {
  for(Light& light : lights) {
    SetLightGroup(light._id, group);
  }
}

void LightManager::SetLightGroup(std::vector<Light>& lights, std::vector<LightGroup>& groups) {
  size_t lights_to_update = (lights.size() < groups.size()) ? lights.size() : groups.size();
  for(size_t i = 0; i < lights_to_update; i++) {
    SetLightGroup(lights[i]._id, groups[i]);
  }
}

std::vector<LightGroup> LightManager::GetLightGroup(std::vector<Light>& lights) const {
  std::vector<LightGroup> result;
  for(Light& light : lights) {
    result.push_back( GetLightGroup(light._id) );
  }
  return result;
}

void LightManager::SetLightState(std::vector<Light>& lights, LightState state) {
  for(Light& light : lights) {
    SetLightState(light._id, state);
  }
}

void LightManager::SetLightState(std::vector<Light>& lights, std::vector<LightState>& states) {
  size_t lights_to_update = (lights.size() < states.size()) ? lights.size() : states.size();
  for(size_t i = 0; i < lights_to_update; i++) {
    SetLightState(lights[i]._id, states[i]);
  }
}

std::vector<LightState> LightManager::GetLightState(std::vector<Light>& lights) const {
  std::vector<LightState> result;
  for(Light& light : lights) {
    result.push_back( RetrieveLightState(light._id) );
  }
  return result;
}

Color LightManager::GetColor(LightId id) const {
  return RetrieveLightState(id)._color;
}

float LightManager::GetIntensity(LightId id) const {
  return RetrieveLightState(id)._intensity;
}

LightState LightManager::GetLightState(LightId id) const {
  return RetrieveLightState(id);
}

LightGroup LightManager::GetLightGroup(LightId id) const {
  return RetrieveLightState(id)._group;
}

bool LightManager::IsActive(LightId id) const {
  return RetrieveLightState(id)._active;
}

void LightManager::SetActive(LightId id, bool active) {
  std::lock_guard<std::mutex> lock(_mutex);
  LightState& state = const_cast<LightState&>(RetrieveLightState(id));
  state._active = active;
  _lights_changes[id] = state;
  _dirty = true;
}

void LightManager::SetColor(LightId id, Color color) {
  std::lock_guard<std::mutex> lock(_mu

  LightState& state = const_cast<LightState&>(RetrieveLightState(id));
  state._color = color;
  _lights_changes[id] = state;
  _dirty = true;
}

void LightManager::SetIntensity(LightId id, float intensity) {
  std::lock_guard<std::mutex> lock(_mutex);
  LightState& state = const_cast<LightState&>(RetrieveLightState(id));
  state._intensity = intensity;
  _lights_changes[id] = state;
  _dirty = true;
}

void LightManager::SetLightState(LightId id, const LightState& new_state) {
  std::lock_guard<std::mutex> lock(_mutex);
  LightState& state = const_cast<LightState&>(RetrieveLightState(id));
  state = new_state;
  _lights_changes[id] = state;
  _dirty = true;
}

void LightManager::SetLightGroup(LightId id, LightGroup group) {
  std::lock_guard<std::mutex> lock(_mutex);
  LightState& state = const_cast<LightState&>(RetrieveLightState(id));
  state._group = group;
  _lights_changes[id] = state;
  _dirty = true;
}

const LightState& LightManager::RetrieveLightState(LightId id) const {
  auto it = _lights_state.find(id);
  if(it == _lights_state.end()) {
    carla::log_warning("Invalid light", id);
    return _state;
  }
  return it->second;
}

void LightManager::QueryLightsStateToServer() {
  std::lock_guard<std::mutex> lock(_mutex);
  // Send blocking query
  std::vector<rpc::LightState> lights_snapshot = _episode.Lock()->QueryLightsStateToServer();

  // Update lights
  SharedPtr<LightManager> lm = _episode.Lock()->GetLightManager();

  for(const auto& it : lights_snapshot) {
    _lights_state[it._id] = LightState(
        it._intensity,
        Color(it._color.r, it._color.g, it._color.b),
        static_cast<LightState::LightGroup>(it._group),
        it._active
    );

    if(_lights.find(it._id) == _lights.end())
    {
      _lights[it._id] = Light(lm, it._location, it._id);
    }
  }
}

void LightManager::UpdateServerLightsState(bool discard_client) {
  std::lock_guard<std::mutex> lock(_mutex);

  if(_dirty) {
    std::vector<rpc::LightState> message;
    for(auto it : _lights_changes) {
      auto it_light = _lights.find(it.first);
      if(it_light != _lights.end()) {
        rpc::LightState state(
          it_light->second.GetLocation(),
          it.second._intensity,
          it.second._group,
          rpc::Color(it.second._color.r, it.second._color.g, it.second._color.b),
          it.second._active
        );
        state._id = it.first;
        // Add to command
        message.push_back(state);
      }
    }
    _episode.Lock()->UpdateServerLightsState(message, discard_client);

    _lights_changes.clear();
    _dirty = false;
  }
}

void LightManager::ApplyChanges() {
  std::lock_guard<std::mutex> lock(_mutex);
  for(const auto& it : _lights_changes) {
    SetLightState(it.first, it.second);
  }
}

} // namespace client
} // namespace carla


/*-------------------------------------------------------------------------------
---------------------------------------------------------------------------------*/

//changes 0.96 -> 0.97: speed variable is global, detects bumpers, all timed (no enter), lbumper speed toggler
//changes 0.97 -> 0.98: performance improvements, operational volume function, shorter beeps, no XY text
//changes 0.98 -> 0.985: 144Hz, Y to hide window(added float stillHoldingY), code cleanup, comments added
//changes 0.985 -> 0.986: Adding configuration file, changing from beeps to vibration.
//changes 0.986 -> 0.989: Improved speeds and speed reporting, created automatic config generator!
//TODO FOR FUTURE VERSIONS - offload speeds into config file

#include <windows.h> // for Beep()
#include <iostream>

#pragma comment(lib, "XInput9_1_0.lib")
#pragma comment(lib, "winmm") // for volume

#include "Gopher.h"

bool ChangeVolume(double nVolume, bool bScalar); // Not used yet
BOOL isRunningAsAdministrator(); // Check if administrator, makes on-screen keyboard clickable

/* TODO:
 * Enable/disable button
 * Key Codes:
 *   http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731%28v=vs.85%29.aspx
 * xinput:
 *   http://msdn.microsoft.com/en-us/library/windows/desktop/microsoft.directx_sdk.reference.xinput_gamepad%28v=vs.85%29.aspx
 */

int main()
{
  CXBOXController controller(1);
  Gopher gopher(&controller);
  HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
  SetConsoleTitle( TEXT( "Gopher360" ) );

  system("Color 1D");

  printf("Welcome to Gopher360 - a VERY fast and lightweight controller-to-keyboard & mouse input tool.\n");
  printf("All you need is an Xbox360/Xbone controller (wired or wireless adapter), or DualShock (with InputMapper 1.5+)\n");
  printf("Gopher will autofind the xinput device and begin reading input - if nothing happens, verify connectivity.\n");
  printf("See the GitHub repository at bit.ly/1syAhMT for more info. Twitter contact: TylerAt60FPS\n\n-------------------------\n\n");

  SetConsoleTextAttribute(hConsole, 23);
  printf("Gopher is free (as in freedom) software: you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n");
  printf("\nYou should have received a copy of the GNU General Public License\nalong with this program. If not, see http://www.gnu.org/licenses/.");
  SetConsoleTextAttribute(hConsole, 29);
  printf("\n\n-------------------------\n\n");

  SetConsoleTextAttribute(hConsole, 5); // set color to purple on black (windows only)

  // dump important tips
  printf("Tip - Press left and right bumpers simultaneously to toggle speeds! (Default is left and right bumpers, configurable in config.ini)\n");

  if (!isRunningAsAdministrator())
  {
    printf("Tip - Not running as an admin! Windows on-screen keyboard and others won't work without admin rights.\n");
  }

  gopher.loadConfigFile();

  // Start the Gopher program loop
  while (true)
  {
    gopher.loop();
  }
}

{
  BOOL   fRet = FALSE;
  HANDLE hToken = NULL;

  if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
  {
    TOKEN_ELEVATION Elevation;
    DWORD cbSize = sizeof( TOKEN_ELEVATION );

    if (GetTokenInformation(hToken, TokenElevation, &Elevation, sizeof( Elevation), &cbSize))
    {
      fRet = Elevation.TokenIsElevated;
    }
  }

  if (hToken)
  {
    CloseHandle(hToken);
  }

  return fRet;
}

// This works, but it's not enabled in the software since the best button for it is still undecided
bool ChangeVolume(double nVolume, bool bScalar) //o b
{
  HRESULT hr = NULL;
  bool decibels = false;
  bool scalar = false;
  double newVolume = nVolume;

  CoInitialize(NULL);
  IMMDeviceEnumerator *deviceEnumerator = NULL;
  hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER,
                        __uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator);
  IMMDevice *defaultDevice = NULL;

  hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);
  deviceEnumerator->Release();
  deviceEnumerator = NULL;

  IAudioEndpointVolume *endpointVolume = NULL;
  hr = defaultDevice->Activate(__uuidof(IAudioEndpointVolume),
                               CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&endpointVolume);
  defaultDevice->Release();
  defaultDevice = NULL;

  float currentVolume = 0;
  endpointVolume->GetMasterVolumeLevel(&currentVolume);
  //printf("Current volume in dB is: %f\n", currentVolume);

  hr = endpointVolume->GetMasterVolumeLevelScalar(&currentVolume);

  // printf("Current volume as a scalar is: %f\n", currentVolume);
  if (bScalar == false)
  {
    hr = endpointVolume->SetMasterVolumeLevel((float)newVolume, NULL);
  }
  else if (bScalar == true)
  {
    hr = endpointVolume->SetMasterVolumeLevelScalar((float)newVolume, NULL);
  }
  endpointVolume->Release();

  CoUninitialize();

  return FALSE;
}