NS_IMETHODIMP
sbAlbumArtService::GetFetcherList(PRUint32 aType,
                                  PRBool aIncludeDisabled,
                                  nsIArray** _retval)
{
  TRACE(("sbAlbumArtService[0x%8.x] - GetFetcherList", this));
  // Validate arguments.
  NS_ENSURE_ARG_POINTER(_retval);

  // Function variables.
  nsresult rv;
  
  // Update the fetcher information first so our priorities are correct
  rv = UpdateAlbumArtFetcherInfo();
  NS_ENSURE_SUCCESS(rv, rv);

  // Create the fetcher list array.
  nsCOMPtr<nsIMutableArray>
    fetcherList = do_CreateInstance
                    ("@songbirdnest.com/moz/xpcom/threadsafe-array;1", &rv);
  NS_ENSURE_SUCCESS(rv, rv);

  // Add each fetcher contract ID to fetcher list.
  PRUint32 fetcherCount = mFetcherInfoList.Length();
  for (PRUint32 i = 0; i < fetcherCount; i++) {
    // Append the fetcher to the list only if it is enabled and the caller
    // only wants enabled ones.
    if (!mFetcherInfoList[i].enabled && !aIncludeDisabled) {
      continue;
    }
    
    // Check if the types match
    switch (aType) {
      case sbIAlbumArtFetcherSet::TYPE_LOCAL:
        if (!mFetcherInfoList[i].local) {
          continue;
        }
      break;
      case sbIAlbumArtFetcherSet::TYPE_REMOTE:
        if (mFetcherInfoList[i].local) {
          continue;
        }
      break;
    }
    
    // Ok we can add this fetcher to the list
    nsCOMPtr<nsIVariant>
      contractID = sbNewVariant(mFetcherInfoList[i].contractID).get();
    NS_ENSURE_TRUE(contractID, NS_ERROR_OUT_OF_MEMORY);

    rv = fetcherList->AppendElement(contractID, PR_FALSE);
    NS_ENSURE_SUCCESS(rv, rv);
  }
  
  // Return results.
  NS_ADDREF(*_retval = fetcherList);

  return NS_OK;
}
nsresult
sbCDDeviceMarshall::AddDevice(sbICDDevice *aCDDevice)
{
  NS_ENSURE_ARG_POINTER(aCDDevice);

  nsresult rv;

  nsString deviceName;
  rv = aCDDevice->GetName(deviceName);
  NS_ENSURE_SUCCESS(rv, rv);

  // Don't bother watching this device if this marshall is already watching
  // it in mKnownDevices.
  PRBool hasDevice = PR_FALSE;
  rv = GetHasDevice(deviceName, &hasDevice);
  if (NS_FAILED(rv) || hasDevice) {
    return NS_OK;
  }

  // Fill out some properties for this device.
  nsCOMPtr<nsIWritablePropertyBag> propBag =
    do_CreateInstance("@mozilla.org/hash-property-bag;1", &rv);
  NS_ENSURE_SUCCESS(rv, rv);

  nsCOMPtr<nsIWritableVariant> deviceType =
    do_CreateInstance("@songbirdnest.com/Songbird/Variant;1", &rv);
  NS_ENSURE_SUCCESS(rv, rv);

  rv = deviceType->SetAsAString(NS_LITERAL_STRING("CD"));
  NS_ENSURE_SUCCESS(rv, rv);

  rv = propBag->SetProperty(NS_LITERAL_STRING("DeviceType"),
                             deviceType);
  NS_ENSURE_SUCCESS(rv, rv);

  nsCOMPtr<sbIDeviceController> controller = FindCompatibleControllers(propBag);
  NS_ENSURE_TRUE(controller, NS_ERROR_UNEXPECTED);

  // Stash the device with the property bag.
  nsCOMPtr<nsIWritableVariant> deviceVar =
    do_CreateInstance("@songbirdnest.com/Songbird/Variant;1", &rv);
  NS_ENSURE_SUCCESS(rv, rv);

  rv = deviceVar->SetAsISupports(aCDDevice);
  NS_ENSURE_SUCCESS(rv, rv);

  rv = propBag->SetProperty(NS_LITERAL_STRING("sbICDDevice"), deviceVar);
  NS_ENSURE_SUCCESS(rv, rv);

  // Have the controller create the device for us.
  nsCOMPtr<sbIDevice> sbDevice;
  rv = controller->CreateDevice(propBag, getter_AddRefs(sbDevice));
  NS_ENSURE_SUCCESS(rv, rv);

  // Ensure that the device has media inserted into it.
  PRBool hasDisc = PR_FALSE;
  rv = aCDDevice->GetIsDiscInserted(&hasDisc);
  if (NS_FAILED(rv) || !hasDisc) {
    return NS_OK;
  }

  // Ensure that the inserted disc is a media disc
  PRUint32 discType;
  rv = aCDDevice->GetDiscType(&discType);
  if (NS_FAILED(rv) || discType != sbICDDevice::AUDIO_DISC_TYPE) {
    return NS_OK;
  }

  nsCOMPtr<sbIDeviceManager2> deviceManager =
    do_GetService("@songbirdnest.com/Songbird/DeviceManager;2", &rv);
  NS_ENSURE_SUCCESS(rv, rv);

  nsCOMPtr<sbIDeviceRegistrar> deviceRegistrar =
    do_QueryInterface(deviceManager, &rv);
  NS_ENSURE_SUCCESS(rv, rv);

  // Register this device with the device registrar.
  rv = deviceRegistrar->RegisterDevice(sbDevice);
  NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to register device!");

  // Dispatch the added device event.
  CreateAndDispatchDeviceManagerEvent(sbIDeviceEvent::EVENT_DEVICE_ADDED,
                                      sbNewVariant(sbDevice),
                                      static_cast<sbIDeviceMarshall *>(this));

  // Stash this device in the hash of known CD devices.
  nsAutoMonitor mon(mKnownDevicesLock);
  mKnownDevices.Put(deviceName, sbDevice);

  return NS_OK;
}
/* void disconnect (); */
nsresult sbMockDevice::DeviceSpecificDisconnect()
{
  NS_ENSURE_STATE(mIsConnected);

  nsresult rv;
  nsRefPtr<sbBaseDeviceVolume> volume;
  {
    nsAutoLock autoVolumeLock(mVolumeLock);
    volume = mDefaultVolume;
    mDefaultVolume = nsnull;
  }
  if (volume)
    RemoveVolume(volume);

  mIsConnected = PR_FALSE;

  // Finalize the device content and device libraries
  if (mContent) {
    // Get a copy of the list of device libraries
    nsCOMArray<sbIDeviceLibrary> libraryListCopy;
    PRInt32                      libraryListCopyCount;
    nsCOMPtr<nsIArray>           libraryList;
    PRUint32                     libraryCount;
    rv = mContent->GetLibraries(getter_AddRefs(libraryList));
    if (NS_SUCCEEDED(rv))
      rv = libraryList->GetLength(&libraryCount);
    if (NS_SUCCEEDED(rv)) {
      for (PRUint32 i = 0; i < libraryCount; i++) {
        nsCOMPtr<sbIDeviceLibrary>
          library = do_QueryElementAt(libraryList, i, &rv);
        if (NS_FAILED(rv))
          continue;
        libraryListCopy.AppendObject(library);
      }
    }
    libraryListCopyCount = libraryListCopy.Count();

    // Finalize each device library
    for (PRInt32 i = 0; i < libraryListCopyCount; i++) {
      RemoveLibrary(libraryListCopy[i]);
      FinalizeDeviceLibrary(libraryListCopy[i]);
    }

    // Finalize the device content
    mContent->Finalize();
    mContent = nsnull;
  }

  PRUint32 state = sbIDevice::STATE_IDLE;

  nsCOMPtr<sbIDeviceManager2> manager =
    do_GetService("@songbirdnest.com/Songbird/DeviceManager;2", &rv);
  NS_ENSURE_SUCCESS(rv, rv);

  sbNewVariant data(static_cast<sbIDevice*>(static_cast<sbBaseDevice*>(this)));
  nsCOMPtr<sbIDeviceEvent> deviceEvent;
  rv = manager->CreateEvent(sbIDeviceEvent::EVENT_DEVICE_REMOVED,
                            sbNewVariant(static_cast<sbIDevice*>(static_cast<sbBaseDevice*>(this))),
                            data,
                            state,
                            state,
                            getter_AddRefs(deviceEvent));
  NS_ENSURE_SUCCESS(rv, rv);

  bool dispatched;
  rv = DispatchEvent(deviceEvent, PR_TRUE, &dispatched);
  NS_ENSURE_SUCCESS(rv, rv);

  return NS_OK;
}
nsresult
sbDeviceXMLInfo::GetStorageDeviceInfoList(nsIArray** aStorageDeviceInfoList)
{
  // Validate arguments and ensure this is called on the main thread.
  NS_ENSURE_ARG_POINTER(aStorageDeviceInfoList);
  NS_ASSERTION(NS_IsMainThread(), "not on main thread");

  // Function variables.
  nsresult rv;

  // Check if a device info element is available.  There doesn't have to be, so,
  // if not, just return an error without any warnings.
  if (!mDeviceInfoElement)
    return NS_ERROR_NOT_AVAILABLE;

  // Get the list of storage nodes.
  nsTArray< nsCOMPtr<nsIDOMNode> > storageNodeList;
  rv = GetDeviceInfoNodes(NS_LITERAL_STRING("storage"), storageNodeList);
  NS_ENSURE_SUCCESS(rv, rv);

  // Create the storage device info list.
  nsCOMPtr<nsIMutableArray> storageDeviceInfoList =
    do_CreateInstance("@songbirdnest.com/moz/xpcom/threadsafe-array;1", &rv);
  NS_ENSURE_SUCCESS(rv, rv);

  // Get the storage device info.
  PRUint32 nodeCount = storageNodeList.Length();
  for (PRUint32 nodeIndex = 0; nodeIndex < nodeCount; ++nodeIndex) {
    // Get the storage device node.
    nsCOMPtr<nsIDOMNode> storageDeviceNode = storageNodeList[nodeIndex];

    // Get the storage device attributes.
    nsCOMPtr<nsIDOMNamedNodeMap> attributes;
    PRUint32                     attributeCount;
    rv = storageDeviceNode->GetAttributes(getter_AddRefs(attributes));
    NS_ENSURE_SUCCESS(rv, rv);
    rv = attributes->GetLength(&attributeCount);
    NS_ENSURE_SUCCESS(rv, rv);

    // Create the storage device info property bag.
    nsCOMPtr<nsIWritablePropertyBag> storageDeviceInfo =
      do_CreateInstance("@mozilla.org/hash-property-bag;1", &rv);
    NS_ENSURE_SUCCESS(rv, rv);

    // Get the storage device info.
    for (PRUint32 attributeIndex = 0;
         attributeIndex < attributeCount;
         ++attributeIndex) {
      // Get the next attribute.
      nsCOMPtr<nsIDOMNode> attribute;
      rv = attributes->Item(attributeIndex, getter_AddRefs(attribute));
      NS_ENSURE_SUCCESS(rv, rv);

      // Get the attribute name.
      nsAutoString attributeName;
      rv = attribute->GetNodeName(attributeName);
      NS_ENSURE_SUCCESS(rv, rv);

      // Get the attribute value.
      nsAutoString attributeValue;
      rv = attribute->GetNodeValue(attributeValue);
      NS_ENSURE_SUCCESS(rv, rv);

      // Set the storage device info.
      storageDeviceInfo->SetProperty(attributeName,
                                     sbNewVariant(attributeValue));
      NS_ENSURE_SUCCESS(rv, rv);
    }

    // Add the storage device info.
    rv = storageDeviceInfoList->AppendElement(storageDeviceInfo, PR_FALSE);
    NS_ENSURE_SUCCESS(rv, rv);
  }

  // Return results.
  rv = CallQueryInterface(storageDeviceInfoList, aStorageDeviceInfoList);
  NS_ENSURE_SUCCESS(rv, rv);

  return NS_OK;
}
nsresult
sbDeviceXMLInfo::DeviceMatchesDeviceNode(nsIDOMNode*      aDeviceNode,
                                         nsIPropertyBag2* aDeviceProperties,
                                         bool*          aDeviceMatches)
{
  NS_ENSURE_ARG_POINTER(aDeviceNode);
  NS_ENSURE_ARG_POINTER(aDeviceProperties);
  NS_ENSURE_ARG_POINTER(aDeviceMatches);

  nsresult rv;

  // Get the device node attributes.
  nsCOMPtr<nsIDOMNamedNodeMap> attributes;
  rv = aDeviceNode->GetAttributes(getter_AddRefs(attributes));
  NS_ENSURE_SUCCESS(rv, rv);

  // Check if each device node attribute matches the device.
  bool matches = PR_TRUE;
  PRUint32 attributeCount;
  rv = attributes->GetLength(&attributeCount);
  NS_ENSURE_SUCCESS(rv, rv);
  for (PRUint32 attributeIndex = 0;
       attributeIndex < attributeCount;
       ++attributeIndex) {
    // Get the next attribute.
    nsCOMPtr<nsIDOMNode> attribute;
    rv = attributes->Item(attributeIndex, getter_AddRefs(attribute));
    NS_ENSURE_SUCCESS(rv, rv);

    // Get the attribute name.
    nsAutoString attributeName;
    rv = attribute->GetNodeName(attributeName);
    NS_ENSURE_SUCCESS(rv, rv);

    // Get the attribute value.
    nsAutoString attributeValue;
    rv = attribute->GetNodeValue(attributeValue);
    NS_ENSURE_SUCCESS(rv, rv);

    // Get the corresponding device property key.
    nsAutoString deviceKey(NS_LITERAL_STRING(SB_DEVICE_PROPERTY_BASE));
    deviceKey.Append(attributeName);

    // If the device property key does not exist, the device does not match.
    bool hasKey;
    rv = aDeviceProperties->HasKey(deviceKey, &hasKey);
    NS_ENSURE_SUCCESS(rv, rv);
    if (!hasKey) {
      matches = PR_FALSE;
      break;
    }

    // Get the device property value.
    nsCOMPtr<nsIVariant> deviceValue;
    rv = aDeviceProperties->Get(deviceKey, getter_AddRefs(deviceValue));
    NS_ENSURE_SUCCESS(rv, rv);

    // If the device property value and the attribute value are not equal, the
    // device does not match.
    bool equal;
    rv = sbVariantsEqual(deviceValue, sbNewVariant(attributeValue), &equal);
    NS_ENSURE_SUCCESS(rv, rv);
    if (!equal) {
      matches = PR_FALSE;
      break;
    }
  }

  // Return results.
  *aDeviceMatches = matches;

  return NS_OK;
}