/*
 * Copyright 2015 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/session_driver.h"

#include "base/logging.h"
#include "cobalt/base/log_message_handler.h"

namespace cobalt {
namespace webdriver {
namespace {

const char kBrowserLog[] = "browser";

// Default page-load timeout.
const int kPageLoadTimeoutInSeconds = 30;

// Max retries for the "can_retry" CommandResult case.
const int kMaxRetries = 5;

protocol::LogEntry::LogLevel SeverityToLogLevel(int severity) {
  switch (severity) {
    case logging::LOG_INFO:
      return protocol::LogEntry::kInfo;
    case logging::LOG_WARNING:
    case logging::LOG_ERROR:
    case logging::LOG_ERROR_REPORT:
      return protocol::LogEntry::kWarning;
    case logging::LOG_FATAL:
      return protocol::LogEntry::kSevere;
  }
  return protocol::LogEntry::kInfo;
}

}  // namespace

SessionDriver::SessionDriver(
    const protocol::SessionId& session_id,
    const CreateWindowDriverCallback& create_window_driver_callback,
    const WaitForNavigationFunction& wait_for_navigation)
    : session_id_(session_id),
      capabilities_(protocol::Capabilities::CreateActualCapabilities()),
      create_window_driver_callback_(create_window_driver_callback),
      wait_for_navigation_(wait_for_navigation),
      next_window_id_(0),
      logging_callback_id_(0) {
  logging_callback_id_ = base::LogMessageHandler::GetInstance()->AddCallback(
      base::Bind(&SessionDriver::LogMessageHandler, base::Unretained(this)));
  window_driver_ = create_window_driver_callback_.Run(GetUniqueWindowId());
}

void SessionDriver::RefreshWindowDriver() {
  DCHECK(thread_checker_.CalledOnValidThread());
  window_driver_ =
      create_window_driver_callback_.Run(window_driver_->window_id());
}

SessionDriver::~SessionDriver() {
  // No more calls to LogMessageHandler will be made after this, so we can
  // safely be destructed.
  base::LogMessageHandler::GetInstance()->RemoveCallback(logging_callback_id_);
}

WindowDriver* SessionDriver::GetWindow(const protocol::WindowId& window_id) {
  DCHECK(thread_checker_.CalledOnValidThread());
  if (protocol::WindowId::IsCurrent(window_id) ||
      window_driver_->window_id() == window_id) {
    return window_driver_.get();
  } else {
    return NULL;
  }
}

util::CommandResult<void> SessionDriver::Navigate(const GURL& url) {
  int retries = 0;
  util::CommandResult<void> result;
  do {
    result = window_driver_->Navigate(url);
  } while (result.can_retry() && (retries++ < kMaxRetries));
  if (result.is_success()) {
    // TODO: Use timeout as specified by the webdriver client.
    wait_for_navigation_.Run(
        base::TimeDelta::FromSeconds(kPageLoadTimeoutInSeconds));
  }
  return result;
}

util::CommandResult<protocol::Capabilities> SessionDriver::GetCapabilities() {
  return util::CommandResult<protocol::Capabilities>(capabilities_);
}

util::CommandResult<protocol::WindowId>
SessionDriver::GetCurrentWindowHandle() {
  return util::CommandResult<protocol::WindowId>(window_driver_->window_id());
}

util::CommandResult<std::vector<protocol::WindowId> >
SessionDriver::GetWindowHandles() {
  typedef util::CommandResult<std::vector<protocol::WindowId> > CommandResult;
  // There is only one window, so just return a list of that.
  std::vector<protocol::WindowId> window_handles;
  window_handles.push_back(window_driver_->window_id());
  return CommandResult(window_handles);
}

util::CommandResult<std::vector<std::string> > SessionDriver::GetLogTypes() {
  DCHECK(thread_checker_.CalledOnValidThread());
  typedef util::CommandResult<std::vector<std::string> > CommandResult;

  std::vector<std::string> log_types;
  // Only "browser" log is supported.
  log_types.push_back(kBrowserLog);
  return CommandResult(log_types);
}

util::CommandResult<std::vector<protocol::LogEntry> > SessionDriver::GetLog(
    const protocol::LogType& type) {
  DCHECK(thread_checker_.CalledOnValidThread());
  typedef util::CommandResult<std::vector<protocol::LogEntry> > CommandResult;
  // Return an empty log vector for unsupported log types.
  CommandResult result((LogEntryVector()));
  if (type.type() == kBrowserLog) {
    base::AutoLock auto_lock(log_lock_);
    result = CommandResult(log_entries_);
    log_entries_.clear();
  }
  return result;
}

util::CommandResult<std::string> SessionDriver::GetAlertText() {
  return util::CommandResult<std::string>(
      protocol::Response::kNoAlertOpenError);
}

util::CommandResult<void> SessionDriver::SwitchToWindow(
    const protocol::WindowId& window_id) {
  DCHECK(thread_checker_.CalledOnValidThread());
  if (window_id == window_driver_->window_id()) {
    return util::CommandResult<void>(protocol::Response::kSuccess);
  } else {
    return util::CommandResult<void>(protocol::Response::kNoSuchWindow);
  }
}

protocol::WindowId SessionDriver::GetUniqueWindowId() {
  DCHECK(thread_checker_.CalledOnValidThread());
  std::string window_id = base::StringPrintf("window-%d", next_window_id_++);
  return protocol::WindowId(window_id);
}

bool SessionDriver::LogMessageHandler(int severity, const char* file, int line,
                                      size_t message_start,
                                      const std::string& str) {
  // Could be called from an arbitrary thread.
  base::Time log_time = base::Time::Now();
  protocol::LogEntry::LogLevel level = SeverityToLogLevel(severity);

  base::AutoLock auto_lock(log_lock_);
  log_entries_.push_back(protocol::LogEntry(log_time, level, str));
  // Don't capture this log entry - give other handlers a shot at it.
  return false;
}

}  // namespace webdriver
}  // namespace cobalt
