/**
       Add a new disk instacne if it does not already exist.

       \param   name name of instance.
       \param   device device string (only used if new instance created).
       \returns NULL if a disk with the given name already exists - otherwise the new disk.

       \note The disk will be marked as online if found.
    */
    SCXCoreLib::SCXHandle<StatisticalPhysicalDiskInstance> StatisticalPhysicalDiskEnumeration::AddDiskInstance(const std::wstring& name, const std::wstring& device)
    {
        SCXCoreLib::SCXHandle<StatisticalPhysicalDiskInstance> disk = FindDiskByDevice(name);
        if (0 == disk)
        {
            disk = new StatisticalPhysicalDiskInstance(m_deps);
            disk->SetId(name);
            disk->m_device = device;
            disk->m_online = true;
            AddInstance(disk);
            return disk;
        }
        disk->m_online = true;
        return SCXCoreLib::SCXHandle<StatisticalPhysicalDiskInstance>(0);
    }
    /**
       Enumeration Helper for the Solaris platform. Not all disks are available from
       MNTTAB on this platform, this it is necessary to perform some additional
       searching of the file system.
    */
    void StaticPhysicalDiskEnumeration::UpdateSolarisHelper()
    {
        // workaround for unknown FS/devices
        // try to get a list of disks from /dev/dsk
        std::vector<SCXCoreLib::SCXHandle<SCXCoreLib::SCXFileInfo> > disk_infos = m_deps->GetDevDskInfo();
        std::map< std::wstring, int > found_devices;

        // iterate through all devices 
        for ( unsigned int i = 0; i < disk_infos.size(); i++ ){
            std::wstring dev_name = disk_infos[i]->GetFullPath().GetFilename();

            dev_name = dev_name.substr(0,dev_name.find_last_not_of(L"0123456789"));

            if ( found_devices.find( dev_name ) != found_devices.end() )
                continue; // already considered

            found_devices[dev_name] = 0;

            try {
                SCXCoreLib::SCXHandle<StaticPhysicalDiskInstance> disk = GetInstance(dev_name);

                if ( disk == 0 ){
                    disk = new StaticPhysicalDiskInstance(m_deps);
                    disk->SetId(dev_name);
                    disk->m_device = disk_infos[i]->GetDirectoryPath().Get() + dev_name;
                    disk->m_online = true;
                    // NOTE: Update will throw in case if disk is removable media, so 
                    // we will skip it (no call to AddInstance)
                    disk->Update();
                    AddInstance(disk);
                   
                } else {
                    disk->Update(); // check if disk is still 'alive'
                    // if disk goes off-line, Update throws and status remains 'false'
                    disk->m_online = true;
                }
            } catch ( SCXCoreLib::SCXException& e )
            {
                //std::wcout << L"excp in dsk update: " << e.What() << endl << e.Where() << endl;
                // ignore errors, since disk may not be accessible and it's fine
            }
        }
    }
    /**
       Add a new disk instance if it does not already exist.

       \param   name name of instance.
       \param   device device string (only used if new instance created).
       \param   cdDrive device is an optical drive.
       \returns NULL if a disk with the given name already exists - otherwise the new disk.

       \note The disk will be marked as online if found.
    */
    SCXCoreLib::SCXHandle<StaticPhysicalDiskInstance> StaticPhysicalDiskEnumeration::AddDiskInstance(
        const std::wstring& name, const std::wstring& device
#if defined(linux)
        , bool cdDrive
#endif
        )
    {
        SCXCoreLib::SCXHandle<StaticPhysicalDiskInstance> disk = GetInstance(name);
        if (0 == disk)
        {
            disk = new StaticPhysicalDiskInstance(m_deps);
            disk->SetId(name);
            disk->m_device = device;
            disk->m_online = true;
#if defined(linux)
            disk->m_cdDrive = cdDrive;
#endif
            AddInstance(disk);
            return disk;
        }
        disk->m_online = true;
        return SCXCoreLib::SCXHandle<StaticPhysicalDiskInstance>(0);
    }
    /**
       Discover logical disks.
    
       Logical disks are identified by the /etc/mnttab file (by design). If ever
       seen in that file, the disk will be discovered. If the disk is removed it 
       will be marked as offline.
    
    */
    void StatisticalLogicalDiskEnumeration::FindLogicalDisks()
    {
        for (EntityIterator iter=Begin(); iter!=End(); iter++)
        {
            SCXCoreLib::SCXHandle<StatisticalLogicalDiskInstance> disk = *iter;
            disk->m_online = false;
        }

        m_deps->RefreshMNTTab();
        for (std::vector<MntTabEntry>::const_iterator it = m_deps->GetMNTTab().begin(); 
             it != m_deps->GetMNTTab().end(); it++)
        {
            if ( ! m_deps->FileSystemIgnored(it->fileSystem) && ! m_deps->DeviceIgnored(it->device))
            {
                SCXCoreLib::SCXHandle<StatisticalLogicalDiskInstance> disk = FindDiskByDevice(it->device);
                if (0 == disk)
                {
                    disk = new StatisticalLogicalDiskInstance(m_deps);
                    disk->m_device = it->device;
                    disk->m_mountPoint = it->mountPoint;
                    disk->m_fsType = it->fileSystem;
                    disk->SetId(disk->m_mountPoint);

#if defined(linux)
                    static SCXLVMUtils lvmUtils;

                    if (lvmUtils.IsDMDevice(it->device))
                    {
                    try
                    {
                            // Try to convert the potential LVM device path into its matching
                            // device mapper (dm) device path.
                            std::wstring dmDevice = lvmUtils.GetDMDevice(it->device);

                            SCXASSERT(!dmDevice.empty());
                            disk->m_samplerDevices.push_back(dmDevice);
                    }
                        catch (SCXCoreLib::SCXException& e)
                    {
                            static SCXCoreLib::LogSuppressor suppressor(SCXCoreLib::eWarning, SCXCoreLib::eTrace);
                            std::wstringstream               out;

                            out << L"An exception occurred resolving the dm device that represents the LVM partition " << it->device
                                << L" : " << e.What();
                            SCX_LOG(m_log, suppressor.GetSeverity(out.str()), out.str());
                        }
                    }
                    // no else required; device was not an LVM device
#endif

                    AddInstance(disk);

#if defined(hpux)
                    if (m_pathToRdev.end() == m_pathToRdev.find(disk->m_device))
                    {
                        SCXCoreLib::SCXFilePath fp(disk->m_device);
                        fp.SetFilename(L"");
                        UpdatePathToRdev(fp.Get());
                    }
                    SCXASSERT(m_pathToRdev.end() != m_pathToRdev.find(disk->m_device));

                    m_deps->AddDeviceInstance(disk->m_device, L"", disk->FindLVInfoByID(m_pathToRdev.find(disk->m_device)->second), m_pathToRdev.find(disk->m_device)->second);
#endif
                }
                disk->m_online = true;
            }
        }
    }
    /**
       Enumeration Helper for the Solaris platform. Not all disks are available from
       MNTTAB on this platform, this it is necessary to perform some additional
       searching of the file system.
    */
    void StatisticalPhysicalDiskEnumeration::UpdateSolarisHelper()
    {
        // workaround for unknown FS/devices
        // try to get a list of disks from /dev/dsk
        SCXCoreLib::SCXDirectoryInfo oDisks( L"/dev/dsk/" );

        std::vector<SCXCoreLib::SCXHandle<SCXCoreLib::SCXFileInfo> > disk_infos = oDisks.GetSysFiles();
        std::map< std::wstring, int > found_devices;

        // iterate through all devices
        for ( unsigned int i = 0; i < disk_infos.size(); i++ ){
            std::wstring dev_name = disk_infos[i]->GetFullPath().GetFilename();

            dev_name = dev_name.substr(0,dev_name.find_last_not_of(L"0123456789"));

            if ( found_devices.find( dev_name ) != found_devices.end() )
                continue; // already considered

            found_devices[dev_name] = 0;

            try {
                SCXCoreLib::SCXHandle<StatisticalPhysicalDiskInstance> disk = FindDiskByDevice(dev_name);

                if ( disk == 0 ){
                    disk = new StatisticalPhysicalDiskInstance(m_deps);
                    disk->SetId(dev_name);
                    disk->m_device = disk_infos[i]->GetDirectoryPath().Get() + dev_name;
                    disk->m_online = true;

                    // verify that hardware is accessible by calling 'physical' disk instance
                    {
                        SCXCoreLib::SCXHandle<StaticPhysicalDiskInstance> disk_physical;

                        disk_physical = new StaticPhysicalDiskInstance(m_deps);
                        disk_physical->SetId(dev_name);
                        disk_physical->SetDevice(disk_infos[i]->GetDirectoryPath().Get() + dev_name);
                        // update will throw exception if disk is not accessible
                        disk_physical->Update();
                    }

                    AddInstance(disk);
                } else {
                    if ( !disk->m_online ){
                        // verify if dsik is online
                        {
                            SCXCoreLib::SCXHandle<StaticPhysicalDiskInstance> disk_physical;

                            disk_physical = new StaticPhysicalDiskInstance(m_deps);
                            disk_physical->SetId(dev_name);
                            disk_physical->SetDevice(disk_infos[i]->GetDirectoryPath().Get() + dev_name);
                            disk_physical->Update();
                        }

                        disk->m_online = true;
                    }
                }

            } catch ( SCXCoreLib::SCXException& e )
            {
                //wcout << L"excp in dsk update: " << e.What() << endl << e.Where() << endl;
                // ignore errors, since disk may not be accessible and it's fine
            }
        }
    }