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

#include "power_manager/powerd/policy/dark_resume_policy.h"

#include <algorithm>

#include <base/file_util.h>
#include <base/files/file_path.h>
#include <base/logging.h>
#include <base/strings/string_number_conversions.h>
#include <base/strings/string_split.h>
#include <base/strings/string_util.h>
#include <base/time/time.h>

#include "power_manager/common/power_constants.h"
#include "power_manager/common/prefs.h"
#include "power_manager/common/util.h"

namespace power_manager {
namespace policy {

namespace {

const char kDarkResumeStatePath[] = "/sys/power/dark_resume_state";

// Within a device directory there is a directory named power/ which contain two
// files for every device, dark_resume_active and dark_resume_source. Given the
// path to the device, we can get to these files to enable dark resume
// functionality for the device by appending |kPowerDir| then |kDarkResume...|
// to the path.
const char kDarkResumeActive[] = "dark_resume_active";
const char kDarkResumeSource[] = "dark_resume_source";
const char kPowerDir[] = "power/";

// Strings to write to sysfs files to enable/disable dark resume functionality
// on the kernel level.
const char kEnabled[] = "enabled";
const char kDisabled[] = "disabled";

}  // namespace

DarkResumePolicy::DarkResumePolicy()
    : power_supply_(NULL),
      prefs_(NULL),
      battery_shutdown_threshold_(0.0),
      battery_suspend_level_(0.0),
      thresholds_set_(false) {
}

DarkResumePolicy::~DarkResumePolicy() {
  SetStates(dark_resume_sources_, kDisabled);
  SetStates(dark_resume_devices_, kDisabled);
}

void DarkResumePolicy::Init(system::PowerSupply* power_supply,
                            PrefsInterface* prefs) {
  power_supply_ = power_supply;
  prefs_ = prefs;

  bool disable = false;
  enabled_ = (!prefs_->GetBool(kDisableDarkResumePref, &disable) || !disable) &&
              ReadSuspendDurationsPref() &&
              ReadBatteryMarginsPref();
  VLOG(1) << "Dark resume user space " << (enabled_ ? "enabled" : "disabled");
  GetFiles(&dark_resume_sources_, kDarkResumeSourcesPref, kDarkResumeSource);
  GetFiles(&dark_resume_devices_, kDarkResumeDevicesPref, kDarkResumeActive);
  SetStates(dark_resume_sources_, (enabled_ ? kEnabled : kDisabled));
  SetStates(dark_resume_devices_, (enabled_ ? kEnabled : kDisabled));
}

DarkResumePolicy::Action DarkResumePolicy::GetAction() {
  if (!enabled_)
    return SUSPEND_INDEFINITELY;

  power_supply_->RefreshImmediately();
  power_status_ = power_supply_->power_status();
  LOG(INFO) << "Current battery is " << power_status_.battery_percentage
            << "% with line power "
            << (power_status_.line_power_on ? "on" : "off");
  if (!thresholds_set_)
    SetThresholds();
  if (power_status_.battery_percentage < battery_shutdown_threshold_ &&
      !power_status_.line_power_on)
    return SHUT_DOWN;

  if (power_status_.battery_percentage > battery_suspend_level_)
    SetThresholds();

  return SUSPEND_FOR_DURATION;
}

base::TimeDelta DarkResumePolicy::GetSuspendDuration() {
  if (!enabled_)
    return base::TimeDelta();

  double battery = power_status_.battery_percentage;
  SuspendMap::iterator upper = suspend_durations_.upper_bound(battery);

  if (upper != suspend_durations_.begin())
    upper--;

  return upper->second;
}

bool DarkResumePolicy::CurrentlyInDarkResume() {
  if (!enabled_)
    return false;

  std::string buf;
  if (!base::ReadFileToString(base::FilePath(kDarkResumeStatePath), &buf)) {
    PLOG(ERROR) << "Unable to read " << kDarkResumeStatePath;
    return false;
  }
  base::TrimWhitespaceASCII(buf, base::TRIM_TRAILING, &buf);
  uint64 value = 0;
  return base::StringToUint64(buf, &value) && value;
}

void DarkResumePolicy::HandleResume() {
  battery_suspend_level_ = 0.0;
  battery_shutdown_threshold_ = 0.0;
  thresholds_set_ = false;
}

bool DarkResumePolicy::ExtractLines(const std::string& pref_name,
                                    std::vector<std::string>* lines) {
  std::string input_str;
  if (prefs_->GetString(pref_name, &input_str)) {
    base::SplitString(input_str, '\n', lines);
    return true;
  }
  return false;
}

bool DarkResumePolicy::ReadSuspendDurationsPref() {
  suspend_durations_.clear();
  std::vector<std::string> lines;
  if (!ExtractLines(kDarkResumeSuspendDurationsPref, &lines))
    return false;

  for (std::vector<std::string>::iterator iter = lines.begin();
       iter != lines.end(); ++iter) {
    std::vector<std::string> segments;
    base::SplitString(*iter, ' ', &segments);
    if (segments.size() != 2) {
      LOG(ERROR) << "Skipping line in dark resume suspend durations file:"
                 << *iter;
      return false;
    }

    double battery_level;
    int suspend_duration;
    if (!base::StringToDouble(segments[0], &battery_level) ||
        !base::StringToInt(segments[1],  &suspend_duration)) {
      LOG(ERROR) << "Failure in parse string: " << *iter << " -> ("
                 << segments[0] << ", "
                 << segments[1] << ")";
      return false;
    }

    if (suspend_duration % base::TimeDelta::FromDays(1).InSeconds() == 0) {
      LOG(ERROR) << "Cannot have suspend duration of 0 or a multiple of 86400"
                 << " (number of seconds in a day).";
      return false;
    }

    suspend_durations_[battery_level] =
        base::TimeDelta::FromSeconds(suspend_duration);
  }
  return !suspend_durations_.empty();
}

bool DarkResumePolicy::ReadBatteryMarginsPref() {
  battery_margins_.clear();
  std::vector<std::string> lines;
  if (!ExtractLines(kDarkResumeBatteryMarginsPref, &lines))
    return false;

  for (std::vector<std::string>::iterator iter = lines.begin();
       iter != lines.end(); ++iter) {
    std::vector<std::string> segments;
    base::SplitString(*iter, ' ', &segments);
    if (segments.size() != 2) {
      LOG(ERROR) << "Skipping line in dark resume battery margins file:"
                 << *iter;
      return false;
    }

    double battery_level;
    double margin;
    if (!base::StringToDouble(segments[0], &battery_level) ||
        !base::StringToDouble(segments[1], &margin)) {
      LOG(ERROR) << "Failure in parse string: " << *iter << " -> ("
                 << segments[0] << ", "
                 << segments[1] << ")";
      return false;
    }

    battery_margins_[battery_level] = margin;
  }
  return !battery_margins_.empty();
}

void DarkResumePolicy::GetFiles(std::vector<base::FilePath>* files,
                                const std::string& pref_name,
                                const std::string& base_file) {
  files->clear();
  std::vector<std::string> lines;
  if (!ExtractLines(pref_name, &lines))
    return;

  for (std::vector<std::string>::iterator iter = lines.begin();
       iter != lines.end(); ++iter) {
    base::FilePath path = base::FilePath(*iter);
    path = path.AppendASCII(kPowerDir);
    path = path.AppendASCII(base_file.c_str());
    files->push_back(path);
  }
}

void DarkResumePolicy::SetStates(const std::vector<base::FilePath>& files,
                                 const std::string& state) {
  for (std::vector<base::FilePath>::const_iterator iter = files.begin();
       iter != files.end(); ++iter) {
    base::WriteFile(*iter, state.c_str(), state.length());
  }
}

void DarkResumePolicy::SetThresholds() {
  double battery = power_status_.battery_percentage;
  MarginMap::iterator margin = battery_margins_.upper_bound(battery);

  if (margin != battery_margins_.begin())
    margin--;

  battery_shutdown_threshold_ = battery - margin->second;
  battery_suspend_level_ = battery;
  thresholds_set_ = true;
  LOG(INFO) << "Current threshold is " << battery_shutdown_threshold_;
}

}  // namespace policy
}  // namespace power_manager
