// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/download/download_dir_policy_handler.h"

#include <stddef.h>

#include <memory>

#include "base/files/file_path.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "build/build_config.h"
#include "chrome/browser/ash/policy/skyvault/policy_utils.h"
#include "chrome/browser/download/download_dir_util.h"
#include "chrome/browser/download/download_prefs.h"
#include "chrome/browser/policy/policy_path_parser.h"
#include "chrome/common/pref_names.h"
#include "components/drive/drive_pref_names.h"
#include "components/policy/core/browser/configuration_policy_handler_parameters.h"
#include "components/policy/core/browser/policy_error_map.h"
#include "components/policy/core/common/policy_map.h"
#include "components/policy/core/common/policy_types.h"
#include "components/policy/policy_constants.h"
#include "components/prefs/pref_value_map.h"
#include "components/strings/grit/components_strings.h"

#if BUILDFLAG(IS_CHROMEOS)
#include "ash/constants/ash_pref_names.h"
#endif  // BUILDFLAG(IS_CHROMEOS)

DownloadDirPolicyHandler::DownloadDirPolicyHandler()
    : TypeCheckingPolicyHandler(policy::key::kDownloadDirectory,
                                base::Value::Type::STRING) {}

DownloadDirPolicyHandler::~DownloadDirPolicyHandler() = default;

bool DownloadDirPolicyHandler::CheckPolicySettings(
    const policy::PolicyMap& policies,
    policy::PolicyErrorMap* errors) {
  const base::Value* value = nullptr;
  if (!CheckAndGetValue(policies, errors, &value)) {
    return false;
  }

#if BUILDFLAG(IS_CHROMEOS)
  // Download directory can only be set as a user policy. If it is set through
  // platform policy for a chromeos=1 build, ignore it.
  if (value &&
      policies.Get(policy_name())->scope != policy::POLICY_SCOPE_USER) {
    errors->AddError(policy_name(), IDS_POLICY_SCOPE_ERROR);
    return false;
  }
#endif

  return true;
}

void DownloadDirPolicyHandler::ApplyPolicySettingsWithParameters(
    const policy::PolicyMap& policies,
    const policy::PolicyHandlerParameters& parameters,
    PrefValueMap* prefs) {
  const base::Value* value =
      policies.GetValue(policy_name(), base::Value::Type::STRING);
  if (!value) {
    return;
  }
  std::string str_value = value->GetString();
  base::FilePath::StringType string_value =
#if BUILDFLAG(IS_WIN)
      base::UTF8ToWide(str_value);
#else
      str_value;
#endif

  // Make sure the path isn't empty, since that will point to an undefined
  // location; the default location is used instead in that case.
  // This is checked after path expansion because a non-empty policy value can
  // lead to an empty path value after expansion (e.g. "\"\"").
  base::FilePath::StringType expanded_value =
      download_dir_util::ExpandDownloadDirectoryPath(string_value, parameters);
  if (expanded_value.empty()) {
    expanded_value = policy::path_parser::ExpandPathVariables(
        DownloadPrefs::GetDefaultDownloadDirectory().value());
  }
#if BUILDFLAG(IS_WIN)
  prefs->SetValue(prefs::kDownloadDefaultDirectory,
                  base::Value(base::WideToUTF8(expanded_value)));
#else
  prefs->SetValue(prefs::kDownloadDefaultDirectory,
                  base::Value(expanded_value));
#endif

  const bool is_mandatory =
      policies.Get(policy_name())->level == policy::POLICY_LEVEL_MANDATORY;

  // If the policy is mandatory, prompt for download should be disabled.
  // Otherwise, it would enable a user to bypass the mandatory policy.
  if (is_mandatory) {
    prefs->SetBoolean(prefs::kPromptForDownload, false);
  }

#if BUILDFLAG(IS_CHROMEOS)
  const bool download_to_drive =
      download_dir_util::DownloadToDrive(string_value, parameters);
  const bool download_to_one_drive =
      download_dir_util::DownloadToOneDrive(string_value, parameters);

  // If the policy enforces a cloud location, ensure the corresponding service
  // remains enabled.
  if (is_mandatory) {
    if (download_to_drive) {
      prefs->SetBoolean(drive::prefs::kDisableDrive, false);
    } else if (download_to_one_drive) {
      prefs->SetBoolean(ash::prefs::kAllowUserToRemoveODFS, false);
    }
  }

  // Set the Files App default folder, regardless of policy enforcement.
  if (download_to_drive) {
    prefs->SetString(ash::prefs::kFilesAppDefaultLocation,
                     download_dir_util::kLocationGoogleDrive);
  } else if (download_to_one_drive) {
    prefs->SetString(ash::prefs::kFilesAppDefaultLocation,
                     download_dir_util::kLocationOneDrive);
  }
#endif  // BUILDFLAG(IS_CHROMEOS)
}

void DownloadDirPolicyHandler::ApplyPolicySettings(
    const policy::PolicyMap& /* policies */,
    PrefValueMap* /* prefs */) {
  NOTREACHED();
}
