/* static */
ProfileHashtable*
GonkRecorderProfile::GetProfileHashtable(uint32_t aCameraId)
{
  ProfileHashtable* profiles = sProfiles.Get(aCameraId);
  if (!profiles) {
    profiles = new ProfileHashtable;
    sProfiles.Put(aCameraId, profiles);

    for (uint32_t i = 0; ProfileList[i].name; ++i) {
      if (IsProfileSupported(aCameraId, i)) {
        DOM_CAMERA_LOGI("Profile %d '%s' supported by platform\n", i, ProfileList[i].name);
        nsAutoString name;
        name.AssignASCII(ProfileList[i].name);
        nsRefPtr<GonkRecorderProfile> profile = new GonkRecorderProfile(aCameraId, i, name);
        if (!profile->IsValid()) {
          DOM_CAMERA_LOGE("Profile %d '%s' is not valid\n", i, ProfileList[i].name);
          continue;
        }
        profiles->Put(name, profile);
      } else {
        DOM_CAMERA_LOGI("Profile %d '%s' not supported by platform\n", i, ProfileList[i].name);
      }
    }
  }
  return profiles;
}
/* static */ nsresult
GonkRecorderProfile::GetAll(uint32_t aCameraId,
                            nsTArray<nsRefPtr<ICameraControl::RecorderProfile>>& aProfiles)
{
  ProfileHashtable* profiles = GetProfileHashtable(aCameraId);
  if (!profiles) {
    return NS_ERROR_FAILURE;
  }

  aProfiles.Clear();
  profiles->EnumerateRead(Enumerate, static_cast<void*>(&aProfiles));
  
  return NS_OK;
}
/* static */ nsresult
GonkRecorderProfile::GetAll(uint32_t aCameraId,
                            nsTArray<RefPtr<ICameraControl::RecorderProfile>>& aProfiles)
{
  ProfileHashtable* profiles = GetProfileHashtable(aCameraId);
  if (!profiles) {
    return NS_ERROR_FAILURE;
  }

  aProfiles.Clear();
  for (auto iter = profiles->Iter(); !iter.Done(); iter.Next()) {
    aProfiles.AppendElement(iter.UserData());
  }

  return NS_OK;
}
/* static */ nsresult
GonkRecorderProfile::ConfigureRecorder(android::GonkRecorder& aRecorder,
                                       uint32_t aCameraId,
                                       const nsAString& aProfileName)
{
  ProfileHashtable* profiles = GetProfileHashtable(aCameraId);
  if (!profiles) {
    return NS_ERROR_FAILURE;
  }

  GonkRecorderProfile* profile;
  if (!profiles->Get(aProfileName, &profile)) {
    return NS_ERROR_INVALID_ARG;
  }

  return profile->ConfigureRecorder(aRecorder);
}
/* static */
ProfileHashtable*
GonkRecorderProfile::GetProfileHashtable(uint32_t aCameraId)
{
  ProfileHashtable* profiles = sProfiles.Get(aCameraId);
  if (!profiles) {
    profiles = new ProfileHashtable();
    sProfiles.Put(aCameraId, profiles);

    /* First handle the profiles with a known enum. We can process those
       efficently because MediaProfiles indexes their profiles that way. */
    int highestKnownQuality = CAMCORDER_QUALITY_LIST_START - 1;
    for (size_t i = 0; i < ProfileListSize; ++i) {
      const ProfileConfig& p = ProfileList[i];
      if (p.quality > highestKnownQuality) {
        highestKnownQuality = p.quality;
      }

      nsRefPtr<GonkRecorderProfile> profile = CreateProfile(aCameraId, p.quality);
      if (!profile) {
        continue;
      }

      DOM_CAMERA_LOGI("Profile %d '%s' supported by platform\n", p.quality, p.name);
      profile->mName.AssignASCII(p.name);
      profiles->Put(profile->GetName(), profile);
    }

    /* However not all of the potentially supported profiles have a known
       enum on all of our supported platforms because some entries may
       be missing from MediaProfiles.h. As such, we can't rely upon
       having the CAMCORDER_QUALITY_* enums for those profiles. We need
       to map the profiles to a name by matching the width and height of
       the video resolution to our configured values.

       In theory there may be collisions given that there can be multiple
       resolutions sharing the same name (e.g. 800x480 and 768x480 are both
       wvga). In practice this should not happen because there should be
       only one WVGA profile given there is only one enum for it. In the
       situation there is a collision, it will merely select the last
       detected profile. */
    for (int q = highestKnownQuality + 1; q <= CAMCORDER_QUALITY_LIST_END; ++q) {
      nsRefPtr<GonkRecorderProfile> profile = CreateProfile(aCameraId, q);
      if (!profile) {
        continue;
      }

      const ICameraControl::Size& s = profile->GetVideo().GetSize();
      size_t match;
      for (match = 0; match < ProfileListDetectSize; ++match) {
        const ProfileConfigDetect& p = ProfileListDetect[match];
        if (s.width == p.width && s.height == p.height) {
          DOM_CAMERA_LOGI("Profile %d '%s' supported by platform\n", q, p.name);
          profile->mName.AssignASCII(p.name);
          profiles->Put(profile->GetName(), profile);
          break;
        }
      }

      if (match == ProfileListDetectSize) {
        DOM_CAMERA_LOGW("Profile %d size %u x %u is not recognized\n",
                        q, s.width, s.height);
      }
    }
  }
  return profiles;
}