/*
 *      Copyright (C) 2005-2013 Team XBMC
 *      http://xbmc.org
 *
 *  This Program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  This Program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with XBMC; see the file COPYING.  If not, see
 *  <http://www.gnu.org/licenses/>.
 *
 */

#include <string>
#include <vector>

#include "GUIDialogSettingsManualBase.h"
#include "settings/SettingAddon.h"
#include "settings/SettingPath.h"
#include "settings/SettingUtils.h"
#include "settings/lib/Setting.h"
#include "settings/lib/SettingSection.h"
#include "settings/lib/SettingsManager.h"
#include "utils/StringUtils.h"
#include "utils/Variant.h"

CGUIDialogSettingsManualBase::CGUIDialogSettingsManualBase(int windowId, const std::string &xmlFile)
    : CGUIDialogSettingsManagerBase(windowId, xmlFile),
      m_section(NULL)
{
  m_settingsManager = new CSettingsManager();
}

CGUIDialogSettingsManualBase::~CGUIDialogSettingsManualBase()
{
  m_settingsManager->Clear();
  m_section = NULL;
  delete m_settingsManager;
}

void CGUIDialogSettingsManualBase::OnOkay()
{
  Save();

  CGUIDialogSettingsBase::OnOkay();
}

void CGUIDialogSettingsManualBase::SetupView()
{
  InitializeSettings();

  // add the created setting section to the settings manager and mark it as ready
  m_settingsManager->AddSection(m_section);
  m_settingsManager->SetInitialized();
  m_settingsManager->SetLoaded();

  CGUIDialogSettingsBase::SetupView();
}

void CGUIDialogSettingsManualBase::InitializeSettings()
{
  m_settingsManager->Clear();
  m_section = NULL;

  // create a new section
  m_section = new CSettingSection(GetProperty("xmlfile").asString(), m_settingsManager);
}

CSettingCategory* CGUIDialogSettingsManualBase::AddCategory(const std::string &id, int label, int help /* = -1 */)
{
  if (id.empty())
    return NULL;

  CSettingCategory *category = new CSettingCategory(id, m_settingsManager);
  if (category == NULL)
    return NULL;

  category->SetLabel(label);
  if (help >= 0)
    category->SetHelp(help);

  m_section->AddCategory(category);
  return category;
}

CSettingGroup* CGUIDialogSettingsManualBase::AddGroup(CSettingCategory *category, int label /* = -1 */, int help /* = -1 */, bool separatorBelowLabel /* = true */, bool hideSeparator /* = false */)
{
  if (category == NULL)
    return NULL;

  size_t groups = category->GetGroups().size();

  CSettingGroup *group = new CSettingGroup(StringUtils::Format("%" PRIuS, groups + 1), m_settingsManager);
  if (group == NULL)
    return NULL;

  if (label >= 0)
    group->SetLabel(label);
  if (help >= 0)
    group->SetHelp(help);
  group->SetControl(GetTitleControl(separatorBelowLabel, hideSeparator));

  category->AddGroup(group);
  return group;
}

CSettingBool* CGUIDialogSettingsManualBase::AddToggle(CSettingGroup *group, const std::string &id, int label, int level, bool value,
                                                      bool delayed /* = false */, bool visible /* = true */, int help /* = -1 */)
{
  if (group == NULL || id.empty() || label < 0 ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingBool *setting = new CSettingBool(id, label, value, m_settingsManager);
  if (setting == NULL)
    return NULL;

  setting->SetControl(GetCheckmarkControl(delayed));
  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

CSettingInt* CGUIDialogSettingsManualBase::AddEdit(CSettingGroup *group, const std::string &id, int label, int level, int value,
                                                   int minimum /* = 0 */, int step /* = 1 */, int maximum /* = 0 */, bool verifyNewValue /* = false */,
                                                   int heading /* = -1 */, bool delayed /* = false */, bool visible /* = true */, int help /* = -1 */)
{
  if (group == NULL || id.empty() || label < 0 ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingInt *setting = new CSettingInt(id, label, value, minimum, step, maximum, m_settingsManager);
  if (setting == NULL)
    return NULL;

  setting->SetControl(GetEditControl("integer", delayed, false, verifyNewValue, heading));
  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

CSettingNumber* CGUIDialogSettingsManualBase::AddEdit(CSettingGroup *group, const std::string &id, int label, int level, float value,
                                                      float minimum /* = 0.0f */, float step /* = 1.0f */, float maximum /* = 0.0f */,
                                                      bool verifyNewValue /* = false */, int heading /* = -1 */, bool delayed /* = false */,
                                                      bool visible /* = true */, int help /* = -1 */)
{
  if (group == NULL || id.empty() || label < 0 ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingNumber *setting = new CSettingNumber(id, label, value, minimum, step, maximum, m_settingsManager);
  if (setting == NULL)
    return NULL;

  setting->SetControl(GetEditControl("number", delayed, false, verifyNewValue, heading));
  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

CSettingString* CGUIDialogSettingsManualBase::AddEdit(CSettingGroup *group, const std::string &id, int label, int level, std::string value,
                                                      bool allowEmpty /* = false */, bool hidden /* = false */,
                                                      int heading /* = -1 */, bool delayed /* = false */, bool visible /* = true */, int help /* = -1 */)
{
  if (group == NULL || id.empty() || label < 0 ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingString *setting = new CSettingString(id, label, value, m_settingsManager);
  if (setting == NULL)
    return NULL;

  setting->SetControl(GetEditControl("string", delayed, hidden, false, heading));
  setting->SetAllowEmpty(allowEmpty);
  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

CSettingString* CGUIDialogSettingsManualBase::AddIp(CSettingGroup *group, const std::string &id, int label, int level, std::string value,
                                                    bool allowEmpty /* = false */, int heading /* = -1 */, bool delayed /* = false */,
                                                    bool visible /* = true */, int help /* = -1 */)
{
  if (group == NULL || id.empty() || label < 0 ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingString *setting = new CSettingString(id, label, value, m_settingsManager);
  if (setting == NULL)
    return NULL;

  setting->SetControl(GetEditControl("ip", delayed, false, false, heading));
  setting->SetAllowEmpty(allowEmpty);
  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

CSettingString* CGUIDialogSettingsManualBase::AddPasswordMd5(CSettingGroup *group, const std::string &id, int label, int level, std::string value,
                                                             bool allowEmpty /* = false */, int heading /* = -1 */, bool delayed /* = false */,
                                                             bool visible /* = true */, int help /* = -1 */)
{
  if (group == NULL || id.empty() || label < 0 ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingString *setting = new CSettingString(id, label, value, m_settingsManager);
  if (setting == NULL)
    return NULL;

  setting->SetControl(GetEditControl("md5", delayed, false, false, heading));
  setting->SetAllowEmpty(allowEmpty);
  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

CSettingAction* CGUIDialogSettingsManualBase::AddButton(CSettingGroup *group, const std::string &id, int label, int level, bool delayed /* = false */,
                                                        bool visible /* = true */, int help /* = -1 */)
{
  if (group == NULL || id.empty() || label < 0 ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingAction *setting = new CSettingAction(id, label, m_settingsManager);
  if (setting == NULL)
    return NULL;

  setting->SetControl(GetButtonControl("action", delayed));
  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

CSettingString* CGUIDialogSettingsManualBase::AddInfoLabelButton(CSettingGroup *group, const std::string &id, int label, int level, std::string info,
                                                                 bool visible /* = true */, int help /* = -1 */)
{
  if (group == NULL || id.empty() || label < 0 ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingString *setting = new CSettingString(id, label, info, m_settingsManager);
  if (setting == NULL)
    return NULL;

  setting->SetControl(GetButtonControl("infolabel", false));
  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

CSettingAddon* CGUIDialogSettingsManualBase::AddAddon(CSettingGroup *group, const std::string &id, int label, int level, std::string value, ADDON::TYPE addonType,
                                                      bool allowEmpty /* = false */, int heading /* = -1 */, bool hideValue /* = false */, bool showInstalledAddons /* = true */,
                                                      bool showInstallableAddons /* = false */, bool showMoreAddons /* = true */, bool delayed /* = false */,
                                                      bool visible /* = true */, int help /* = -1 */)
{
  if (group == NULL || id.empty() || label < 0 ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingAddon *setting = new CSettingAddon(id, label, value, m_settingsManager);
  if (setting == NULL)
    return NULL;

  setting->SetControl(GetButtonControl("addon", delayed, heading, hideValue, showInstalledAddons, showInstallableAddons, showMoreAddons));
  setting->SetAddonType(addonType);
  setting->SetAllowEmpty(allowEmpty);
  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

CSettingPath* CGUIDialogSettingsManualBase::AddPath(CSettingGroup *group, const std::string &id, int label, int level, std::string value, bool writable /* = true */,
                                                    const std::vector<std::string> &sources /* = std::vector<std::string>() */, bool allowEmpty /* = false */,
                                                    int heading /* = -1 */, bool hideValue /* = false */, bool delayed /* = false */,
                                                    bool visible /* = true */, int help /* = -1 */)
{
  if (group == NULL || id.empty() || label < 0 ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingPath *setting = new CSettingPath(id, label, value, m_settingsManager);
  if (setting == NULL)
    return NULL;

  setting->SetControl(GetButtonControl("path", delayed, heading, hideValue));
  setting->SetWritable(writable);
  setting->SetSources(sources);
  setting->SetAllowEmpty(allowEmpty);
  setting->SetAllowEmpty(allowEmpty);
  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

CSettingString* CGUIDialogSettingsManualBase::AddSpinner(CSettingGroup *group, const std::string &id, int label, int level, std::string value,
                                                         StringSettingOptionsFiller filler, bool delayed /* = false */, bool visible /* = true */, int help /* = -1 */)
{
  if (group == NULL || id.empty() || label < 0 || filler == NULL ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingString *setting = new CSettingString(id, label, value, m_settingsManager);
  if (setting == NULL)
    return NULL;

  setting->SetControl(GetSpinnerControl("string", delayed));
  setting->SetOptionsFiller(filler, this);
  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

CSettingInt* CGUIDialogSettingsManualBase::AddSpinner(CSettingGroup *group, const std::string &id, int label, int level, int value, int minimum, int step, int maximum,
                                                      int formatLabel /* = -1 */, int minimumLabel /* = -1 */, bool delayed /* = false */,
                                                      bool visible /* = true */, int help /* = -1 */)
{
  if (group == NULL || id.empty() || label < 0 ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingInt *setting = new CSettingInt(id, label, value, m_settingsManager);
  if (setting == NULL)
    return NULL;

  setting->SetControl(GetSpinnerControl("string", delayed, minimumLabel, formatLabel));
  setting->SetMinimum(minimum);
  setting->SetStep(step);
  setting->SetMaximum(maximum);
  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

CSettingInt* CGUIDialogSettingsManualBase::AddSpinner(CSettingGroup *group, const std::string &id, int label, int level, int value, int minimum, int step, int maximum,
                                                      const std::string &formatString, int minimumLabel /* = -1 */, bool delayed /* = false */,
                                                      bool visible /* = true */, int help /* = -1 */)
{
  if (group == NULL || id.empty() || label < 0 ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingInt *setting = new CSettingInt(id, label, value, m_settingsManager);
  if (setting == NULL)
    return NULL;

  setting->SetControl(GetSpinnerControl("string", delayed, minimumLabel, -1, formatString));
  setting->SetMinimum(minimum);
  setting->SetStep(step);
  setting->SetMaximum(maximum);
  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

CSettingInt* CGUIDialogSettingsManualBase::AddSpinner(CSettingGroup *group, const std::string &id, int label, int level, int value, const StaticIntegerSettingOptions &entries,
                                                      bool delayed /* = false */, bool visible /* = true */, int help /* = -1 */)
{
  if (group == NULL || id.empty() || label < 0 || entries.empty() ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingInt *setting = new CSettingInt(id, label, value, m_settingsManager);
  if (setting == NULL)
    return NULL;

  setting->SetControl(GetSpinnerControl("string", delayed));
  setting->SetOptions(entries);
  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

CSettingInt* CGUIDialogSettingsManualBase::AddSpinner(CSettingGroup *group, const std::string &id, int label, int level, int value, IntegerSettingOptionsFiller filler,
                                                      bool delayed /* = false */, bool visible /* = true */, int help /* = -1 */)
{
  if (group == NULL || id.empty() || label < 0 || filler == NULL ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingInt *setting = new CSettingInt(id, label, value, m_settingsManager);
  if (setting == NULL)
    return NULL;

  setting->SetControl(GetSpinnerControl("string", delayed));
  setting->SetOptionsFiller(filler, this);
  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

CSettingNumber* CGUIDialogSettingsManualBase::AddSpinner(CSettingGroup *group, const std::string &id, int label, int level, float value, float minimum, float step, float maximum,
                                                         int formatLabel /* = -1 */, int minimumLabel /* = -1 */, bool delayed /* = false */,
                                                         bool visible /* = true */, int help /* = -1 */)
{
  if (group == NULL || id.empty() || label < 0 ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingNumber *setting = new CSettingNumber(id, label, value, m_settingsManager);
  if (setting == NULL)
    return NULL;

  setting->SetControl(GetSpinnerControl("number", delayed, minimumLabel, formatLabel));
  setting->SetMinimum(minimum);
  setting->SetStep(step);
  setting->SetMaximum(maximum);
  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

CSettingNumber* CGUIDialogSettingsManualBase::AddSpinner(CSettingGroup *group, const std::string &id, int label, int level, float value, float minimum, float step, float maximum,
                                                         const std::string &formatString, int minimumLabel /* = -1 */, bool delayed /* = false */,
                                                         bool visible /* = true */, int help /* = -1 */)
{
  if (group == NULL || id.empty() || label < 0 ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingNumber *setting = new CSettingNumber(id, label, value, m_settingsManager);
  if (setting == NULL)
    return NULL;

  setting->SetControl(GetSpinnerControl("number", delayed, minimumLabel, -1, formatString));
  setting->SetMinimum(minimum);
  setting->SetStep(step);
  setting->SetMaximum(maximum);
  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

CSettingString* CGUIDialogSettingsManualBase::AddList(CSettingGroup *group, const std::string &id, int label, int level, std::string value,
                                                      StringSettingOptionsFiller filler, int heading, bool visible /* = true */, int help /* = -1 */)
{
  if (group == NULL || id.empty() || label < 0 || filler == NULL ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingString *setting = new CSettingString(id, label, value, m_settingsManager);
  if (setting == NULL)
    return NULL;

  setting->SetControl(GetListControl("string", false, heading, false));
  setting->SetOptionsFiller(filler, this);
  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

CSettingInt* CGUIDialogSettingsManualBase::AddList(CSettingGroup *group, const std::string &id, int label, int level, int value, const StaticIntegerSettingOptions &entries,
                                                  int heading, bool visible /* = true */, int help /* = -1 */)
{
  if (group == NULL || id.empty() || label < 0 || entries.empty() ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingInt *setting = new CSettingInt(id, label, value, m_settingsManager);
  if (setting == NULL)
    return NULL;

  setting->SetControl(GetListControl("integer", false, heading, false));
  setting->SetOptions(entries);
  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

CSettingInt* CGUIDialogSettingsManualBase::AddList(CSettingGroup *group, const std::string &id, int label, int level, int value, IntegerSettingOptionsFiller filler,
                                                   int heading, bool visible /* = true */, int help /* = -1 */)
{
  if (group == NULL || id.empty() || label < 0 || filler == NULL ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingInt *setting = new CSettingInt(id, label, value, m_settingsManager);
  if (setting == NULL)
    return NULL;

  setting->SetControl(GetListControl("integer", false, heading, false));
  setting->SetOptionsFiller(filler, this);
  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

CSettingList* CGUIDialogSettingsManualBase::AddList(CSettingGroup *group, const std::string &id, int label, int level, std::vector<std::string> values,
                                                    StringSettingOptionsFiller filler, int heading, int minimumItems /* = 0 */, int maximumItems /* = -1 */,
                                                    bool visible /* = true */, int help /* = -1 */)
{
  if (group == NULL || id.empty() || label < 0 || filler == NULL ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingString *settingDefinition = new CSettingString(id, m_settingsManager);
  if (settingDefinition == NULL)
    return NULL;
  
  settingDefinition->SetOptionsFiller(filler, this);

  CSettingList *setting = new CSettingList(id, settingDefinition, label, m_settingsManager);
  if (setting == NULL)
  {
    delete settingDefinition;
    return NULL;
  }

  std::vector<CVariant> valueList;
  for (std::vector<std::string>::const_iterator itValue = values.begin(); itValue != values.end(); ++itValue)
    valueList.push_back(CVariant(*itValue));
  SettingPtrList settingValues;
  if (!CSettingUtils::ValuesToList(setting, valueList, settingValues))
  {
    delete settingDefinition;
    delete setting;
    return NULL;
  }
  // setting the default will also set the actual value on an unchanged setting
  setting->SetDefault(settingValues);

  setting->SetControl(GetListControl("string", false, heading, true));
  setting->SetMinimumItems(minimumItems);
  setting->SetMaximumItems(maximumItems);
  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

CSettingList* CGUIDialogSettingsManualBase::AddList(CSettingGroup *group, const std::string &id, int label, int level, std::vector<int> values,
                                                    const StaticIntegerSettingOptions &entries, int heading, int minimumItems /* = 0 */, int maximumItems /* = -1 */,
                                                    bool visible /* = true */, int help /* = -1 */)
{
  if (group == NULL || id.empty() || label < 0 || entries.empty() ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingInt *settingDefinition = new CSettingInt(id, m_settingsManager);
  if (settingDefinition == NULL)
    return NULL;
  
  settingDefinition->SetOptions(entries);

  CSettingList *setting = new CSettingList(id, settingDefinition, label, m_settingsManager);
  if (setting == NULL)
  {
    delete settingDefinition;
    return NULL;
  }

  std::vector<CVariant> valueList;
  for (std::vector<int>::const_iterator itValue = values.begin(); itValue != values.end(); ++itValue)
    valueList.push_back(CVariant(*itValue));
  SettingPtrList settingValues;
  if (!CSettingUtils::ValuesToList(setting, valueList, settingValues))
  {
    delete settingDefinition;
    delete setting;
    return NULL;
  }
  // setting the default will also set the actual value on an unchanged setting
  setting->SetDefault(settingValues);

  setting->SetControl(GetListControl("integer", false, heading, true));
  setting->SetMinimumItems(minimumItems);
  setting->SetMaximumItems(maximumItems);
  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

CSettingList* CGUIDialogSettingsManualBase::AddList(CSettingGroup *group, const std::string &id, int label, int level, std::vector<int> values,
                                                    IntegerSettingOptionsFiller filler, int heading, int minimumItems /* = 0 */, int maximumItems /* = -1 */,
                                                    bool visible /* = true */, int help /* = -1 */, SettingControlListValueFormatter formatter /* = NULL */)
{
  if (group == NULL || id.empty() || label < 0 || filler == NULL ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingInt *settingDefinition = new CSettingInt(id, m_settingsManager);
  if (settingDefinition == NULL)
    return NULL;
  
  settingDefinition->SetOptionsFiller(filler, this);

  CSettingList *setting = new CSettingList(id, settingDefinition, label, m_settingsManager);
  if (setting == NULL)
  {
    delete settingDefinition;
    return NULL;
  }

  std::vector<CVariant> valueList;
  for (std::vector<int>::const_iterator itValue = values.begin(); itValue != values.end(); ++itValue)
    valueList.push_back(CVariant(*itValue));
  SettingPtrList settingValues;
  if (!CSettingUtils::ValuesToList(setting, valueList, settingValues))
  {
    delete settingDefinition;
    delete setting;
    return NULL;
  }
  // setting the default will also set the actual value on an unchanged setting
  setting->SetDefault(settingValues);

  setting->SetControl(GetListControl("integer", false, heading, true, formatter));
  setting->SetMinimumItems(minimumItems);
  setting->SetMaximumItems(maximumItems);
  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

CSettingInt* CGUIDialogSettingsManualBase::AddPercentageSlider(CSettingGroup *group, const std::string &id, int label, int level, int value, int formatLabel,
                                                               int step /* = 1 */, int heading /* = -1 */, bool usePopup /* = false */, bool delayed /* = false */,
                                                               bool visible /* = true */, int help /* = -1 */)
{
  if (group == NULL || id.empty() || label < 0 ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingInt *setting = new CSettingInt(id, label, value, m_settingsManager);
  if (setting == NULL)
    return NULL;

  setting->SetControl(GetSliderControl("percentage", delayed, heading, usePopup, formatLabel));
  setting->SetMinimum(0);
  setting->SetStep(step);
  setting->SetMaximum(100);
  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

CSettingInt* CGUIDialogSettingsManualBase::AddPercentageSlider(CSettingGroup *group, const std::string &id, int label, int level, int value, const std::string &formatString,
                                                               int step /* = 1 */, int heading /* = -1 */, bool usePopup /* = false */, bool delayed /* = false */,
                                                               bool visible /* = true */, int help /* = -1 */)
{
  if (group == NULL || id.empty() || label < 0 ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingInt *setting = new CSettingInt(id, label, value, m_settingsManager);
  if (setting == NULL)
    return NULL;

  setting->SetControl(GetSliderControl("percentage", delayed, heading, usePopup, -1, formatString));
  setting->SetMinimum(0);
  setting->SetStep(step);
  setting->SetMaximum(100);
  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

CSettingInt* CGUIDialogSettingsManualBase::AddSlider(CSettingGroup *group, const std::string &id, int label, int level, int value, int formatLabel, int minimum, int step,
                                                     int maximum, int heading /* = -1 */, bool usePopup /* = false */, bool delayed /* = false */,
                                                     bool visible /* = true */, int help /* = -1 */)
{
  if (group == NULL || id.empty() || label < 0 ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingInt *setting = new CSettingInt(id, label, value, m_settingsManager);
  if (setting == NULL)
    return NULL;

  setting->SetControl(GetSliderControl("integer", delayed, heading, usePopup, formatLabel));
  setting->SetMinimum(minimum);
  setting->SetStep(step);
  setting->SetMaximum(maximum);
  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

CSettingInt* CGUIDialogSettingsManualBase::AddSlider(CSettingGroup *group, const std::string &id, int label, int level, int value, const std::string &formatString,
                                                     int minimum, int step, int maximum, int heading /* = -1 */, bool usePopup /* = false */, bool delayed /* = false */,
                                                     bool visible /* = true */, int help /* = -1 */)
{
  if (group == NULL || id.empty() || label < 0 ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingInt *setting = new CSettingInt(id, label, value, m_settingsManager);
  if (setting == NULL)
    return NULL;

  setting->SetControl(GetSliderControl("integer", delayed, heading, usePopup, -1, formatString));
  setting->SetMinimum(minimum);
  setting->SetStep(step);
  setting->SetMaximum(maximum);
  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

CSettingNumber* CGUIDialogSettingsManualBase::AddSlider(CSettingGroup *group, const std::string &id, int label, int level, float value, int formatLabel, float minimum,
                                                        float step, float maximum, int heading /* = -1 */, bool usePopup /* = false */, bool delayed /* = false */,
                                                        bool visible /* = true */, int help /* = -1 */)
{
  if (group == NULL || id.empty() || label < 0 ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingNumber *setting = new CSettingNumber(id, label, value, m_settingsManager);
  if (setting == NULL)
    return NULL;

  setting->SetControl(GetSliderControl("number", delayed, heading, usePopup, formatLabel));
  setting->SetMinimum(minimum);
  setting->SetStep(step);
  setting->SetMaximum(maximum);
  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

CSettingNumber* CGUIDialogSettingsManualBase::AddSlider(CSettingGroup *group, const std::string &id, int label, int level, float value, const std::string &formatString,
                                                        float minimum, float step, float maximum, int heading /* = -1 */, bool usePopup /* = false */,
                                                        bool delayed /* = false */, bool visible /* = true */, int help /* = -1 */)
{
  if (group == NULL || id.empty() || label < 0 ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingNumber *setting = new CSettingNumber(id, label, value, m_settingsManager);
  if (setting == NULL)
    return NULL;

  setting->SetControl(GetSliderControl("number", delayed, heading, usePopup, -1, formatString));
  setting->SetMinimum(minimum);
  setting->SetStep(step);
  setting->SetMaximum(maximum);
  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

CSettingList* CGUIDialogSettingsManualBase::AddPercentageRange(CSettingGroup *group, const std::string &id, int label, int level, int valueLower, int valueUpper,
                                                               int valueFormatLabel, int step /* = 1 */, int formatLabel /* = 21469 */, bool delayed /* = false */,
                                                               bool visible /* = true */, int help /* = -1 */)
{
  return AddRange(group, id, label, level, valueLower, valueUpper, 0, step, 100, "percentage", formatLabel, valueFormatLabel, "", delayed, visible, help);
}

CSettingList* CGUIDialogSettingsManualBase::AddPercentageRange(CSettingGroup *group, const std::string &id, int label, int level, int valueLower, int valueUpper,
                                                               const std::string &valueFormatString /* = "%i %%" */, int step /* = 1 */, int formatLabel /* = 21469 */,
                                                               bool delayed /* = false */, bool visible /* = true */, int help /* = -1 */)
{
  return AddRange(group, id, label, level, valueLower, valueUpper, 0, step, 100, "percentage", formatLabel, -1, valueFormatString, delayed, visible, help);
}

CSettingList* CGUIDialogSettingsManualBase::AddRange(CSettingGroup *group, const std::string &id, int label, int level, int valueLower, int valueUpper, int minimum,
                                                     int step, int maximum, int valueFormatLabel, int formatLabel /* = 21469 */, bool delayed /* = false */,
                                                     bool visible /* = true */, int help /* = -1 */)
{
  return AddRange(group, id, label, level, valueLower, valueUpper, minimum, step, maximum, "integer", formatLabel, valueFormatLabel, "", delayed, visible, help);
}

CSettingList* CGUIDialogSettingsManualBase::AddRange(CSettingGroup *group, const std::string &id, int label, int level, int valueLower, int valueUpper, int minimum,
                                                     int step, int maximum, const std::string &valueFormatString /* = "%d" */, int formatLabel /* = 21469 */,
                                                     bool delayed /* = false */, bool visible /* = true */, int help /* = -1 */)
{
  return AddRange(group, id, label, level, valueLower, valueUpper, minimum, step, maximum, "integer", formatLabel, -1, valueFormatString, delayed, visible, help);
}

CSettingList* CGUIDialogSettingsManualBase::AddRange(CSettingGroup *group, const std::string &id, int label, int level, float valueLower, float valueUpper, float minimum,
                                                     float step, float maximum, int valueFormatLabel, int formatLabel /* = 21469 */, bool delayed /* = false */,
                                                     bool visible /* = true */, int help /* = -1 */)
{
  return AddRange(group, id, label, level, valueLower, valueUpper, minimum, step, maximum, "number", formatLabel, valueFormatLabel, "", delayed, visible, help);
}

CSettingList* CGUIDialogSettingsManualBase::AddRange(CSettingGroup *group, const std::string &id, int label, int level, float valueLower, float valueUpper, float minimum,
                                                     float step, float maximum, const std::string &valueFormatString /* = "%.1f" */, int formatLabel /* = 21469 */,
                                                     bool delayed /* = false */, bool visible /* = true */, int help /* = -1 */)
{
  return AddRange(group, id, label, level, valueLower, valueUpper, minimum, step, maximum, "number", formatLabel, -1, valueFormatString, delayed, visible, help);
}

CSettingList* CGUIDialogSettingsManualBase::AddDateRange(CSettingGroup *group, const std::string &id, int label, int level, int valueLower, int valueUpper, int minimum,
                                                         int step, int maximum, int valueFormatLabel, int formatLabel /* = 21469 */, bool delayed /* = false */,
                                                         bool visible /* = true */, int help /* = -1 */)
{
  return AddRange(group, id, label, level, valueLower, valueUpper, minimum, step, maximum, "date", formatLabel, valueFormatLabel, "", delayed, visible, help);
}

CSettingList* CGUIDialogSettingsManualBase::AddDateRange(CSettingGroup *group, const std::string &id, int label, int level, int valueLower, int valueUpper, int minimum,
                                                         int step, int maximum, const std::string &valueFormatString /* = "" */, int formatLabel /* = 21469 */,
                                                         bool delayed /* = false */, bool visible /* = true */, int help /* = -1 */)
{
  return AddRange(group, id, label, level, valueLower, valueUpper, minimum, step, maximum, "date", formatLabel, -1, valueFormatString, delayed, visible, help);
}

CSettingList* CGUIDialogSettingsManualBase::AddTimeRange(CSettingGroup *group, const std::string &id, int label, int level, int valueLower, int valueUpper, int minimum,
                                                         int step, int maximum, int valueFormatLabel, int formatLabel /* = 21469 */, bool delayed /* = false */,
                                                         bool visible /* = true */, int help /* = -1 */)
{
  return AddRange(group, id, label, level, valueLower, valueUpper, minimum, step, maximum, "time", formatLabel, valueFormatLabel, "", delayed, visible, help);
}

CSettingList* CGUIDialogSettingsManualBase::AddTimeRange(CSettingGroup *group, const std::string &id, int label, int level, int valueLower, int valueUpper, int minimum,
                                                         int step, int maximum, const std::string &valueFormatString /* = "mm:ss" */, int formatLabel /* = 21469 */,
                                                         bool delayed /* = false */, bool visible /* = true */, int help /* = -1 */)
{
  return AddRange(group, id, label, level, valueLower, valueUpper, minimum, step, maximum, "time", formatLabel, -1, valueFormatString, delayed, visible, help);
}

CSettingList* CGUIDialogSettingsManualBase::AddRange(CSettingGroup *group, const std::string &id, int label, int level, int valueLower, int valueUpper, int minimum,
                                                     int step, int maximum, const std::string &format, int formatLabel, int valueFormatLabel,
                                                     const std::string &valueFormatString, bool delayed, bool visible, int help)
{
  if (group == NULL || id.empty() || label < 0 ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingInt *settingDefinition = new CSettingInt(id, m_settingsManager);
  if (settingDefinition == NULL)
    return NULL;
  
  settingDefinition->SetMinimum(minimum);
  settingDefinition->SetStep(step);
  settingDefinition->SetMaximum(maximum);

  CSettingList *setting = new CSettingList(id, settingDefinition, label, m_settingsManager);
  if (setting == NULL)
  {
    delete settingDefinition;
    return NULL;
  }

  std::vector<CVariant> valueList;
  valueList.push_back(valueLower);
  valueList.push_back(valueUpper);
  SettingPtrList settingValues;
  if (!CSettingUtils::ValuesToList(setting, valueList, settingValues))
  {
    delete settingDefinition;
    delete setting;
    return NULL;
  }
  // setting the default will also set the actual value on an unchanged setting
  setting->SetDefault(settingValues);
  
  setting->SetControl(GetRangeControl(format, delayed, formatLabel, valueFormatLabel, valueFormatString));
  setting->SetMinimumItems(2);
  setting->SetMaximumItems(2);

  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

CSettingList* CGUIDialogSettingsManualBase::AddRange(CSettingGroup *group, const std::string &id, int label, int level, float valueLower, float valueUpper, float minimum,
                                                     float step, float maximum, const std::string &format, int formatLabel, int valueFormatLabel,
                                                     const std::string &valueFormatString, bool delayed, bool visible, int help)
{
  if (group == NULL || id.empty() || label < 0 ||
      GetSetting(id) != NULL)
    return NULL;

  CSettingNumber *settingDefinition = new CSettingNumber(id, m_settingsManager);
  if (settingDefinition == NULL)
    return NULL;
  
  settingDefinition->SetMinimum(minimum);
  settingDefinition->SetStep(step);
  settingDefinition->SetMaximum(maximum);

  CSettingList *setting = new CSettingList(id, settingDefinition, label, m_settingsManager);
  if (setting == NULL)
  {
    delete settingDefinition;
    return NULL;
  }

  std::vector<CVariant> valueList;
  valueList.push_back(valueLower);
  valueList.push_back(valueUpper);
  SettingPtrList settingValues;
  if (!CSettingUtils::ValuesToList(setting, valueList, settingValues))
  {
    delete settingDefinition;
    delete setting;
    return NULL;
  }
  // setting the default will also set the actual value on an unchanged setting
  setting->SetDefault(settingValues);
  
  setting->SetControl(GetRangeControl(format, delayed, formatLabel, valueFormatLabel, valueFormatString));
  setting->SetMinimumItems(2);
  setting->SetMaximumItems(2);

  setSettingDetails(setting, level, visible, help);

  group->AddSetting(setting);
  return setting;
}

void CGUIDialogSettingsManualBase::setSettingDetails(CSetting *setting, int level, bool visible, int help)
{
  if (setting == NULL)
    return;

  if (level < 0)
    level = SettingLevelBasic;
  else if (level > SettingLevelExpert)
    level = SettingLevelExpert;

  setting->SetLevel(static_cast<SettingLevel>(level));
  setting->SetVisible(visible);
  if (help >= 0)
    setting->SetHelp(help);
}

ISettingControl* CGUIDialogSettingsManualBase::GetCheckmarkControl(bool delayed /* = false */)
{
  CSettingControlCheckmark *control = new CSettingControlCheckmark();
  control->SetDelayed(delayed);

  return control;
}

ISettingControl* CGUIDialogSettingsManualBase::GetTitleControl(bool separatorBelowLabel /* = true */, bool hideSeparator /* = false */)
{
  CSettingControlTitle *control = new CSettingControlTitle();
  control->SetSeparatorBelowLabel(separatorBelowLabel);
  control->SetSeparatorHidden(hideSeparator);

  return control;
}

ISettingControl* CGUIDialogSettingsManualBase::GetEditControl(const std::string &format, bool delayed /* = false */, bool hidden /* = false */, bool verifyNewValue /* = false */, int heading /* = -1 */)
{
  CSettingControlEdit *control = new CSettingControlEdit();
  if (!control->SetFormat(format))
  {
    delete control;
    return NULL;
  }
  
  control->SetDelayed(delayed);
  control->SetHidden(hidden);
  control->SetVerifyNewValue(verifyNewValue);
  control->SetHeading(heading);

  return control;
}

ISettingControl* CGUIDialogSettingsManualBase::GetButtonControl(const std::string &format, bool delayed /* = false */, int heading /* = -1 */, bool hideValue /* = false */,
                                                                bool showInstalledAddons /* = true */, bool showInstallableAddons /* = false */, bool showMoreAddons /* = true */)
{
  CSettingControlButton *control = new CSettingControlButton();
  if (!control->SetFormat(format))
  {
    delete control;
    return NULL;
  }
  
  control->SetDelayed(delayed);
  control->SetHeading(heading);
  control->SetHideValue(hideValue);
  control->SetShowInstalledAddons(showInstalledAddons);
  control->SetShowInstallableAddons(showInstallableAddons);
  control->SetShowMoreAddons(showMoreAddons);

  return control;
}

ISettingControl* CGUIDialogSettingsManualBase::GetSpinnerControl(const std::string &format, bool delayed /* = false */, int minimumLabel /* = -1 */, int formatLabel /* = -1 */, const std::string &formatString /* = "" */)
{
  CSettingControlSpinner *control = new CSettingControlSpinner();
  if (!control->SetFormat(format))
  {
    delete control;
    return NULL;
  }
  
  control->SetDelayed(delayed);
  if (formatLabel >= 0)
    control->SetFormatLabel(formatLabel);
  if (!formatString.empty())
    control->SetFormatString(formatString);
  if (minimumLabel >= 0)
    control->SetMinimumLabel(minimumLabel);

  return control;
}

ISettingControl* CGUIDialogSettingsManualBase::GetListControl(const std::string &format, bool delayed /* = false */, int heading /* = -1 */, bool multiselect /* = false */,SettingControlListValueFormatter formatter /* = NULL */)
{
  CSettingControlList *control = new CSettingControlList();
  if (!control->SetFormat(format))
  {
    delete control;
    return NULL;
  }

  control->SetDelayed(delayed);
  control->SetHeading(heading);
  control->SetMultiSelect(multiselect);
  control->SetFormatter(formatter);

  return control;
}

ISettingControl* CGUIDialogSettingsManualBase::GetSliderControl(const std::string &format, bool delayed /* = false */, int heading /* = -1 */, bool usePopup /* = false */,
                                                                int formatLabel /* = -1 */, const std::string &formatString /* = "" */)
{
  CSettingControlSlider *control = new CSettingControlSlider();
  if (!control->SetFormat(format))
  {
    delete control;
    return NULL;
  }

  control->SetDelayed(delayed);
  if (heading >= 0)
    control->SetHeading(heading);
  control->SetPopup(usePopup);
  if (formatLabel >= 0)
    control->SetFormatLabel(formatLabel);
  if (!formatString.empty())
    control->SetFormatString(formatString);

  return control;
}

ISettingControl* CGUIDialogSettingsManualBase::GetRangeControl(const std::string &format, bool delayed /* = false */, int formatLabel /* = -1 */,
                                                               int valueFormatLabel /* = -1 */, const std::string &valueFormatString /* = "" */)
{
  CSettingControlRange *control = new CSettingControlRange();
  if (!control->SetFormat(format))
  {
    delete control;
    return NULL;
  }

  control->SetDelayed(delayed);
  if (formatLabel >= 0)
    control->SetFormatLabel(formatLabel);
  if (valueFormatLabel >= 0)
    control->SetValueFormatLabel(valueFormatLabel);
  if (!valueFormatString.empty())
    control->SetValueFormat(valueFormatString);

  return control;
}
