// Copyright (c) 2012 The Chromium 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 "chrome/test/chromedriver/session.h"

#include <list>

#include "base/lazy_instance.h"
#include "base/threading/thread_local.h"
#include "base/values.h"
#include "chrome/test/chromedriver/chrome/chrome.h"
#include "chrome/test/chromedriver/chrome/status.h"
#include "chrome/test/chromedriver/chrome/version.h"
#include "chrome/test/chromedriver/chrome/web_view.h"
#include "chrome/test/chromedriver/logging.h"

namespace {

base::LazyInstance<base::ThreadLocalPointer<Session> >
    lazy_tls_session = LAZY_INSTANCE_INITIALIZER;

}  // namespace

FrameInfo::FrameInfo(const std::string& parent_frame_id,
                     const std::string& frame_id,
                     const std::string& chromedriver_frame_id)
    : parent_frame_id(parent_frame_id),
      frame_id(frame_id),
      chromedriver_frame_id(chromedriver_frame_id) {}

const base::TimeDelta Session::kDefaultPageLoadTimeout =
    base::TimeDelta::FromMinutes(5);

Session::Session(const std::string& id)
    : id(id),
      quit(false),
      detach(false),
      force_devtools_screenshot(false),
      sticky_modifiers(0),
      mouse_position(0, 0),
      page_load_timeout(kDefaultPageLoadTimeout),
      auto_reporting_enabled(false) {}

Session::Session(const std::string& id, scoped_ptr<Chrome> chrome)
    : id(id),
      quit(false),
      detach(false),
      force_devtools_screenshot(false),
      chrome(chrome.Pass()),
      sticky_modifiers(0),
      mouse_position(0, 0),
      page_load_timeout(kDefaultPageLoadTimeout),
      auto_reporting_enabled(false) {}

Session::~Session() {}

Status Session::GetTargetWindow(WebView** web_view) {
  if (!chrome)
    return Status(kNoSuchWindow, "no chrome started in this session");

  Status status = chrome->GetWebViewById(window, web_view);
  if (status.IsError())
    status = Status(kNoSuchWindow, "target window already closed", status);
  return status;
}

void Session::SwitchToTopFrame() {
  frames.clear();
}

void Session::SwitchToParentFrame() {
  if (!frames.empty())
    frames.pop_back();
}

void Session::SwitchToSubFrame(const std::string& frame_id,
                               const std::string& chromedriver_frame_id) {
  std::string parent_frame_id;
  if (!frames.empty())
    parent_frame_id = frames.back().frame_id;
  frames.push_back(FrameInfo(parent_frame_id, frame_id, chromedriver_frame_id));
}

std::string Session::GetCurrentFrameId() const {
  if (frames.empty())
    return std::string();
  return frames.back().frame_id;
}

std::vector<WebDriverLog*> Session::GetAllLogs() const {
  std::vector<WebDriverLog*> logs;
  for (ScopedVector<WebDriverLog>::const_iterator log = devtools_logs.begin();
       log != devtools_logs.end();
       ++log) {
    logs.push_back(*log);
  }
  if (driver_log)
    logs.push_back(driver_log.get());
  return logs;
}

std::string Session::GetFirstBrowserError() const {
  for (ScopedVector<WebDriverLog>::const_iterator it = devtools_logs.begin();
       it != devtools_logs.end();
       ++it) {
    if ((*it)->type() == WebDriverLog::kBrowserType) {
      std::string message = (*it)->GetFirstErrorMessage();
      if (!message.empty())
        return message;
    }
  }
  return std::string();
}

Session* GetThreadLocalSession() {
  return lazy_tls_session.Pointer()->Get();
}

void SetThreadLocalSession(scoped_ptr<Session> session) {
  lazy_tls_session.Pointer()->Set(session.release());
}