/*
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "cobalt/webdriver/protocol/cookie.h"

#include "base/string_split.h"
#include "base/stringprintf.h"

namespace cobalt {
namespace webdriver {
namespace protocol {
namespace {
// The key for the JSON Cookie object in the parameters.
const char kCookieKey[] = "cookie";

// JSON Cookie object keys.
const char kNameKey[] = "name";
const char kValueKey[] = "value";
const char kDomainKey[] = "domain";
const char kPathKey[] = "path";
const char kSecureKey[] = "secure";
const char kHttpOnlyKey[] = "httpOnly";
const char kExpiryKey[] = "expiry";
}  // namespace

scoped_ptr<base::Value> Cookie::ToValue(const Cookie& cookie) {
  scoped_ptr<base::DictionaryValue> cookie_value(new base::DictionaryValue());
  cookie_value->SetString(kNameKey, cookie.name_);
  cookie_value->SetString(kValueKey, cookie.value_);
  return cookie_value.PassAs<base::Value>();
}

base::optional<Cookie> Cookie::FromValue(const base::Value* value) {
  // TODO: Malformed data should return an "unable to set cookie"
  // error, but the current implementation will return "invalid parameter".
  const base::DictionaryValue* dictionary_value;
  if (!value->GetAsDictionary(&dictionary_value)) {
    DLOG(INFO) << "Parameter is not a dictionary.";
    return base::nullopt;
  }

  const base::DictionaryValue* cookie_dictionary_value;
  if (!dictionary_value->GetDictionary(kCookieKey, &cookie_dictionary_value)) {
    DLOG(INFO) << StringPrintf("Value of key [%s] is not a JSON object.",
                               kCookieKey);
    return base::nullopt;
  }

  std::string cookie_name;
  std::string cookie_value;
  // Name and value are required.
  if (!cookie_dictionary_value->GetString(kNameKey, &cookie_name) ||
      !cookie_dictionary_value->GetString(kValueKey, &cookie_value)) {
    DLOG(INFO) << StringPrintf(
        "cookie.%s or cookie.%s either does not exist or is not a string",
        kNameKey, kValueKey);
    return base::nullopt;
  }

  Cookie new_cookie(cookie_name, cookie_value);

  std::string string_value;
  if (cookie_dictionary_value->HasKey(kDomainKey)) {
    if (cookie_dictionary_value->GetString(kDomainKey, &string_value)) {
      new_cookie.domain_ = string_value;
    } else {
      DLOG(INFO) << StringPrintf("cookie.%s is not a string", kDomainKey);
      return base::nullopt;
    }
  }
  if (cookie_dictionary_value->HasKey(kPathKey)) {
    if (cookie_dictionary_value->GetString(kPathKey, &string_value)) {
      new_cookie.path_ = string_value;
    } else {
      DLOG(INFO) << StringPrintf("cookie.%s is not a string", kPathKey);
      return base::nullopt;
    }
  }

  bool bool_value = false;
  if (cookie_dictionary_value->HasKey(kSecureKey)) {
    if (cookie_dictionary_value->GetBoolean(kSecureKey, &bool_value)) {
      new_cookie.secure_ = bool_value;
    } else {
      DLOG(INFO) << StringPrintf("cookie.%s is not a boolean", kSecureKey);
      return base::nullopt;
    }
  }
  if (cookie_dictionary_value->HasKey(kHttpOnlyKey)) {
    if (cookie_dictionary_value->GetBoolean(kHttpOnlyKey, &bool_value)) {
      new_cookie.http_only_ = bool_value;
    } else {
      DLOG(INFO) << StringPrintf("cookie.%s is not a boolean", kHttpOnlyKey);
      return base::nullopt;
    }
  }

  int timestamp_value = 0;
  if (cookie_dictionary_value->HasKey(kExpiryKey)) {
    if (cookie_dictionary_value->GetInteger(kExpiryKey, &timestamp_value)) {
      base::TimeDelta seconds_since_epoch =
          base::TimeDelta::FromSeconds(timestamp_value);
      new_cookie.expiry_time_ = base::Time::UnixEpoch() + seconds_since_epoch;
    } else {
      DLOG(INFO) << StringPrintf("cookie.%s is not an integer", kExpiryKey);
      return base::nullopt;
    }
  }
  return new_cookie;
}

void Cookie::ToCookieVector(const std::string& cookies_string,
                            std::vector<Cookie>* cookies) {
  std::vector<std::string> cookie_strings;
  base::SplitString(cookies_string, ';', &cookie_strings);
  for (size_t i = 0; i < cookie_strings.size(); ++i) {
    base::optional<Cookie> cookie = FromString(cookie_strings[i]);
    if (cookie) {
      cookies->push_back(*cookie);
    }
  }
}

base::optional<Cookie> Cookie::FromString(const std::string& cookie_as_string) {
  size_t pos = cookie_as_string.find('=');
  if (pos == std::string::npos) {
    return base::nullopt;
  }
  DCHECK(pos < cookie_as_string.size());
  return Cookie(cookie_as_string.substr(0, pos),
                cookie_as_string.substr(pos + 1));
}

std::string Cookie::ToCookieString(const std::string& current_domain) const {
  base::Time expiry_time;
  if (expiry_time_) {
    expiry_time = expiry_time_.value();
  } else {
    // If expiry was not set by the client, then the default is 20 years from
    // now.
    base::Time::Exploded exploded_now;
    base::Time::Now().UTCExplode(&exploded_now);
    exploded_now.year += 20;
    expiry_time = base::Time::FromUTCExploded(exploded_now);
  }

  // WebDriver protocol defines expiry as seconds since the Unix Epoch, but
  // the Max-Age attribute defines it as seconds from right now.
  base::TimeDelta max_age = expiry_time - base::Time::Now();

  std::string cookie_string =
      StringPrintf("%s=%s; Path=%s; Domain=%s; Max-Age=%d%s%s", name_.c_str(),
                   value_.c_str(), path_.value_or("/").c_str(),
                   domain_.value_or(current_domain).c_str(),
                   static_cast<int>(max_age.InSeconds()),
                   secure_.value_or(false) ? " ;Secure" : "",
                   http_only_.value_or(false) ? " ;HttpOnly" : "");
  return cookie_string;
}

}  // namespace protocol
}  // namespace webdriver
}  // namespace cobalt
