/**
       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);
    }
    /**
       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
            }
        }
    }