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

#ifndef CEF_LIBCEF_BROWSER_SERVER_IMPL_H_
#define CEF_LIBCEF_BROWSER_SERVER_IMPL_H_
#pragma once

#include <map>
#include <memory>

#include "include/cef_server.h"

#include "base/single_thread_task_runner.h"
#include "net/server/http_server.h"

namespace base {
class Thread;
};

class CefServerImpl : public CefServer, net::HttpServer::Delegate {
 public:
  explicit CefServerImpl(CefRefPtr<CefServerHandler> handler);

  void Start(const std::string& address, uint16 port, int backlog);

  // CefServer methods:
  CefRefPtr<CefTaskRunner> GetTaskRunner() override;
  void Shutdown() override;
  bool IsRunning() override;
  CefString GetAddress() override;
  bool HasConnection() override;
  bool IsValidConnection(int connection_id) override;
  void SendHttp200Response(int connection_id,
                           const CefString& content_type,
                           const void* data,
                           size_t data_size) override;
  void SendHttp404Response(int connection_id) override;
  void SendHttp500Response(int connection_id,
                           const CefString& error_message) override;
  void SendHttpResponse(int connection_id,
                        int response_code,
                        const CefString& content_type,
                        int64 content_length,
                        const HeaderMap& extra_headers) override;
  void SendRawData(int connection_id,
                   const void* data,
                   size_t data_size) override;
  void CloseConnection(int connection_id) override;
  void SendWebSocketMessage(int connection_id,
                            const void* data,
                            size_t data_size) override;

  void ContinueWebSocketRequest(int connection_id,
                                const net::HttpServerRequestInfo& request_info,
                                bool allow);

 private:
  void SendHttp200ResponseInternal(int connection_id,
                                   const CefString& content_type,
                                   std::unique_ptr<std::string> data);
  void SendRawDataInternal(int connection_id,
                           std::unique_ptr<std::string> data);
  void SendWebSocketMessageInternal(int connection_id,
                                    std::unique_ptr<std::string> data);

  // HttpServer::Delegate methods:
  void OnConnect(int connection_id) override;
  void OnHttpRequest(int connection_id,
                     const net::HttpServerRequestInfo& request_info) override;
  void OnWebSocketRequest(
      int connection_id,
      const net::HttpServerRequestInfo& request_info) override;
  void OnWebSocketMessage(int connection_id, const std::string& data) override;
  void OnClose(int connection_id) override;

  void StartOnUIThread(const std::string& address, uint16 port, int backlog);
  void StartOnHandlerThread(const std::string& address,
                            uint16 port,
                            int backlog);

  void ShutdownOnHandlerThread();
  void ShutdownOnUIThread();

  bool ValidateServer() const;

  struct ConnectionInfo;
  ConnectionInfo* CreateConnectionInfo(int connection_id);
  ConnectionInfo* GetConnectionInfo(int connection_id) const;
  void RemoveConnectionInfo(int connection_id);

  bool CurrentlyOnHandlerThread() const;

  // Safe to access from any thread.
  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
  std::string address_;

  // Only accessed on the UI thread.
  std::unique_ptr<base::Thread> thread_;

  // Only accessed on the server thread.
  CefRefPtr<CefServerHandler> handler_;
  std::unique_ptr<net::HttpServer> server_;

  // Map of connection_id to ConnectionInfo.
  using ConnectionInfoMap = std::map<int, std::unique_ptr<ConnectionInfo>>;
  ConnectionInfoMap connection_info_map_;

  IMPLEMENT_REFCOUNTING(CefServerImpl);
  DISALLOW_COPY_AND_ASSIGN(CefServerImpl);
};

#endif  // CEF_LIBCEF_BROWSER_SERVER_IMPL_H_