// 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/server.h"

#include <string>
#include <vector>

#include "base/bind.h"
#include "base/debug/trace_event.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/string_util.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
#include "net/base/tcp_listen_socket.h"
#include "net/server/http_server_request_info.h"

namespace cobalt {
namespace webdriver {
namespace {

const char kJsonContentType[] = "application/json;charset=UTF-8";
const char kTextPlainContentType[] = "text/plain";

WebDriverServer::HttpMethod StringToHttpMethod(const std::string& method) {
  if (LowerCaseEqualsASCII(method, "get")) {
    return WebDriverServer::kGet;
  } else if (LowerCaseEqualsASCII(method, "post")) {
    return WebDriverServer::kPost;
  } else if (LowerCaseEqualsASCII(method, "delete")) {
    return WebDriverServer::kDelete;
  }
  return WebDriverServer::kUnknownMethod;
}

std::string HttpMethodToString(WebDriverServer::HttpMethod method) {
  switch (method) {
    case WebDriverServer::kGet:
      return "GET";
    case WebDriverServer::kPost:
      return "POST";
    case WebDriverServer::kDelete:
      return "DELETE";
    case WebDriverServer::kUnknownMethod:
      return "UNKNOWN";
  }
  NOTREACHED();
  return "";
}

// Implementation of the ResponseHandler interface.
// A Delegate implementation will call the methods on this interface for
// successful, failed, and invalid requests.
// For each of these cases, prepare an appropriate Http Response according to
// the spec, and send it to the specified connection through the net::HttpServer
// instance.
class ResponseHandlerImpl : public WebDriverServer::ResponseHandler {
 public:
  ResponseHandlerImpl(const scoped_refptr<net::HttpServer>& server,
                      int connection_id)
      : server_message_loop_(base::MessageLoopProxy::current()),
        server_(server),
        connection_id_(connection_id) {}

  // https://code.google.com/p/selenium/wiki/JsonWireProtocol#Responses
  void Success(scoped_ptr<base::Value> value) override {
    DCHECK(value);
    std::string data;
    base::JSONWriter::Write(value.get(), &data);
    SendInternal(net::HTTP_OK, data, kJsonContentType);
  }

  // Failed commands map to a valid WebDriver command and contain the expected
  // parameters, but otherwise failed to execute for some reason. This should
  // send a 500 Internal Server Error.
  // https://code.google.com/p/selenium/wiki/JsonWireProtocol#Error_Handling
  void FailedCommand(scoped_ptr<base::Value> value) override {
    DCHECK(value);
    std::string data;
    base::JSONWriter::Write(value.get(), &data);
    SendInternal(net::HTTP_INTERNAL_SERVER_ERROR, data, kJsonContentType);
  }

  // A number of cases for invalid requests are explained here:
  // https://code.google.com/p/selenium/wiki/JsonWireProtocol#Invalid_Requests
  // The response type should be text/plain and the message body is an error
  // message

  // The command request is not mapped to anything.
  void UnknownCommand(const std::string& path) override {
    LOG(INFO) << "Unknown command: " << path;
    SendInternal(net::HTTP_NOT_FOUND, "Unknown command",
                 kTextPlainContentType);
  }

  // The command request is mapped to a valid command, but this WebDriver
  // implementation has not implemented it.
  void UnimplementedCommand(const std::string& path) override {
    LOG(INFO) << "Unimplemented command: " << path;
    SendInternal(net::HTTP_NOT_IMPLEMENTED, "Unimplemented command",
                 kTextPlainContentType);
  }

  // The request maps to a valid command, but the variable part of the path
  // does not map to a valid instance.
  void VariableResourceNotFound(const std::string& variable_name) override {
    SendInternal(net::HTTP_NOT_FOUND,
                 "Unknown variable resource: " + variable_name,
                 kTextPlainContentType);
  }

  // The request maps to a valid command, but with an unsupported Http method.
  void InvalidCommandMethod(WebDriverServer::HttpMethod requested_method,
                            const std::vector<WebDriverServer::HttpMethod>&
                                allowed_methods) override {
    DCHECK(!allowed_methods.empty());
    std::vector<std::string> allowed_method_strings;
    for (int i = 0; i < allowed_methods.size(); ++i) {
      allowed_method_strings.push_back(HttpMethodToString(allowed_methods[i]));
    }
    std::vector<std::string> headers;
    headers.push_back("Allow: " + JoinString(allowed_method_strings, ", "));
    SendInternal(net::HTTP_METHOD_NOT_ALLOWED,
                 "Invalid method: " + HttpMethodToString(requested_method),
                 kTextPlainContentType, headers);
  }

  // The POST command's JSON request body does not contain the required
  // parameters.
  void MissingCommandParameters(const std::string& message) override {
    SendInternal(net::HTTP_BAD_REQUEST, message, kTextPlainContentType);
  }

 private:
  static void SendToServer(const scoped_refptr<net::HttpServer>& server,
                           int connection_id, net::HttpStatusCode status,
                           const std::string& message,
                           const std::string& content_type,
                           const std::vector<std::string>& headers) {
    server->Send(connection_id, status, message, content_type, headers);
  }

  // Send response with no additional headers specified.
  void SendInternal(net::HttpStatusCode status, const std::string& message,
                    const std::string& content_type) {
    std::vector<std::string> headers;
    SendInternal(status, message, content_type, headers);
  }

  // Send a response on the Http Server's thread.
  void SendInternal(net::HttpStatusCode status, const std::string& message,
                    const std::string& content_type,
                    const std::vector<std::string>& headers) {
    if (base::MessageLoopProxy::current() == server_message_loop_) {
      SendToServer(server_, connection_id_, status, message, content_type,
                   headers);
    } else {
      base::Closure closure =
          base::Bind(&SendToServer, server_, connection_id_, status, message,
                     content_type, headers);
      server_message_loop_->PostTask(FROM_HERE, closure);
    }
  }

  scoped_refptr<base::MessageLoopProxy> server_message_loop_;
  scoped_refptr<net::HttpServer> server_;
  int connection_id_;
};
}  // namespace

WebDriverServer::WebDriverServer(int port, const std::string& listen_ip,
                                 const HandleRequestCallback& callback)
    : handle_request_callback_(callback),
      server_address_("Cobalt.Server.WebDriver",
                      "Address to communicate with WebDriver.") {
  // Create http server
  factory_.reset(new net::TCPListenSocketFactory(listen_ip, port));
  server_ = new net::HttpServer(*factory_, this);
  GURL address;
  int result = GetLocalAddress(&address);
  if (result == net::OK) {
    LOG(INFO) << "Starting WebDriver server on port " << port;
    server_address_ = address.spec();
  } else {
    LOG(WARNING) << "Could not start WebDriver server";
    server_address_ = "<NOT RUNNING>";
  }
}

void WebDriverServer::OnHttpRequest(int connection_id,
                                    const net::HttpServerRequestInfo& info) {
  TRACE_EVENT0("cobalt::webdriver", "WebDriverServer::OnHttpRequest()");

  DCHECK(thread_checker_.CalledOnValidThread());
  std::string path = info.path;
  size_t query_position = path.find("?");
  // Discard any URL variables from the path
  if (query_position != std::string::npos) {
    path.resize(query_position);
  }

  DLOG(INFO) << "Got request: " << path;
  // Create a new ResponseHandler that will send a response to this connection.
  scoped_ptr<ResponseHandler> response_handler(
      new ResponseHandlerImpl(server_, connection_id));

  scoped_ptr<base::Value> parameters;
  HttpMethod method = StringToHttpMethod(info.method);
  if (method == kPost) {
    base::JSONReader reader;
    parameters.reset(reader.ReadToValue(info.data));
    if (!parameters) {
      // Failed to parse request body as JSON.
      response_handler->MissingCommandParameters(reader.GetErrorMessage());
      return;
    }
  }

  // Call the HandleRequestCallback.
  handle_request_callback_.Run(StringToHttpMethod(info.method), path,
                               parameters.Pass(), response_handler.Pass());
}

int WebDriverServer::GetLocalAddress(GURL* out) const {
  net::IPEndPoint ip_addr;
  int result = server_->GetLocalAddress(&ip_addr);
  if (result == net::OK) {
    *out = GURL("http://" + ip_addr.ToString());
  }
  return result;
}

}  // namespace webdriver
}  // namespace cobalt
