// Copyright 2013 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 "shell/context.h"

#include <vector>

#include "base/base_switches.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/lazy_instance.h"
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "mojo/common/trace_provider_impl.h"
#include "mojo/common/tracing_impl.h"
#include "mojo/edk/embedder/embedder.h"
#include "mojo/edk/embedder/simple_platform_support.h"
#include "mojo/public/cpp/application/application_connection.h"
#include "mojo/public/cpp/application/application_delegate.h"
#include "mojo/public/cpp/application/application_impl.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "mojo/services/tracing/public/interfaces/tracing.mojom.h"
#include "shell/application_manager/application_loader.h"
#include "shell/application_manager/application_manager.h"
#include "shell/background_application_loader.h"
#include "shell/command_line_util.h"
#include "shell/filename_util.h"
#include "shell/in_process_native_runner.h"
#include "shell/out_of_process_native_runner.h"
#include "shell/switches.h"
#include "shell/tracer.h"
#include "url/gurl.h"

#if !defined(OS_MACOSX)
#include "shell/url_response_disk_cache_loader.h"
#endif

using mojo::ServiceProvider;
using mojo::ServiceProviderPtr;

namespace shell {
namespace {

// Used to ensure we only init once.
class Setup {
 public:
  Setup() {
    // TODO(vtl): Use make_unique when C++14 is available.
    mojo::embedder::Init(std::unique_ptr<mojo::embedder::PlatformSupport>(
        new mojo::embedder::SimplePlatformSupport()));
  }

  ~Setup() {}

 private:
  DISALLOW_COPY_AND_ASSIGN(Setup);
};

ApplicationManager::Options MakeApplicationManagerOptions() {
  ApplicationManager::Options options;
  options.disable_cache = base::CommandLine::ForCurrentProcess()->HasSwitch(
      switches::kDisableCache);
  options.force_offline_by_default =
      base::CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kForceOfflineByDefault);
  return options;
}

bool ConfigureURLMappings(const base::CommandLine& command_line,
                          Context* context) {
  URLResolver* resolver = context->url_resolver();

  // Configure the resolution of unknown mojo: URLs.
  GURL base_url;
  if (command_line.HasSwitch(switches::kOrigin))
    base_url = GURL(command_line.GetSwitchValueASCII(switches::kOrigin));
  else
    // Use the shell's file root if the base was not specified.
    base_url = context->ResolveShellFileURL("");

  if (!base_url.is_valid())
    return false;

  resolver->SetMojoBaseURL(base_url);

  // The network service must be loaded from the filesystem.
  // This mapping is done before the command line URL mapping are processed, so
  // that it can be overridden.
  resolver->AddURLMapping(
      GURL("mojo:network_service"),
      context->ResolveShellFileURL("file:network_service.mojo"));

  // Command line URL mapping.
  std::vector<URLResolver::OriginMapping> origin_mappings =
      URLResolver::GetOriginMappings(command_line.argv());
  for (const auto& origin_mapping : origin_mappings)
    resolver->AddOriginMapping(GURL(origin_mapping.origin),
                               GURL(origin_mapping.base_url));

  if (command_line.HasSwitch(switches::kURLMappings)) {
    const std::string mappings =
        command_line.GetSwitchValueASCII(switches::kURLMappings);

    base::StringPairs pairs;
    if (!base::SplitStringIntoKeyValuePairs(mappings, '=', ',', &pairs))
      return false;
    using StringPair = std::pair<std::string, std::string>;
    for (const StringPair& pair : pairs) {
      const GURL from(pair.first);
      const GURL to = context->ResolveCommandLineURL(pair.second);
      if (!from.is_valid() || !to.is_valid())
        return false;
      resolver->AddURLMapping(from, to);
    }
  }
  return true;
}

void InitContentHandlers(ApplicationManager* manager,
                         const base::CommandLine& command_line) {
  // Default content handlers.
  manager->RegisterContentHandler("application/pdf", GURL("mojo:pdf_viewer"));
  manager->RegisterContentHandler("image/png", GURL("mojo:png_viewer"));
  manager->RegisterContentHandler("text/html", GURL("mojo:html_viewer"));

  // Command-line-specified content handlers.
  std::string handlers_spec =
      command_line.GetSwitchValueASCII(switches::kContentHandlers);
  if (handlers_spec.empty())
    return;

#if defined(OS_ANDROID)
  // TODO(eseidel): On Android we pass command line arguments is via the
  // 'parameters' key on the intent, which we specify during 'am shell start'
  // via --esa, however that expects comma-separated values and says:
  //   am shell --help:
  //     [--esa <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]]
  //     (to embed a comma into a string escape it using "\,")
  // Whatever takes 'parameters' and constructs a CommandLine is failing to
  // un-escape the commas, we need to move this fix to that file.
  ReplaceSubstringsAfterOffset(&handlers_spec, 0, "\\,", ",");
#endif

  std::vector<std::string> parts;
  base::SplitString(handlers_spec, ',', &parts);
  if (parts.size() % 2 != 0) {
    LOG(ERROR) << "Invalid value for switch " << switches::kContentHandlers
               << ": must be a comma-separated list of mimetype/url pairs."
               << handlers_spec;
    return;
  }

  for (size_t i = 0; i < parts.size(); i += 2) {
    GURL url(parts[i + 1]);
    if (!url.is_valid()) {
      LOG(ERROR) << "Invalid value for switch " << switches::kContentHandlers
                 << ": '" << parts[i + 1] << "' is not a valid URL.";
      return;
    }
    // TODO(eseidel): We should also validate that the mimetype is valid
    // net/base/mime_util.h could do this, but we don't want to depend on net.
    manager->RegisterContentHandler(parts[i], url);
  }
}

void InitNativeOptions(ApplicationManager* manager,
                       const base::CommandLine& command_line) {
  std::vector<std::string> force_in_process_url_list;
  base::SplitString(command_line.GetSwitchValueASCII(switches::kForceInProcess),
                    ',', &force_in_process_url_list);
  for (const auto& force_in_process_url : force_in_process_url_list) {
    GURL gurl(force_in_process_url);
    if (!gurl.is_valid()) {
      LOG(ERROR) << "Invalid value for switch " << switches::kForceInProcess
                 << ": '" << force_in_process_url << "'is not a valid URL.";
      return;
    }

    NativeRunnerFactory::Options options;
    options.force_in_process = true;
    manager->SetNativeOptionsForURL(options, gurl);
  }
}

class TracingServiceProvider : public ServiceProvider {
 public:
  TracingServiceProvider(Tracer* tracer,
                         mojo::InterfaceRequest<ServiceProvider> request)
      : tracer_(tracer), binding_(this, request.Pass()) {}
  ~TracingServiceProvider() override {}

  void ConnectToService(const mojo::String& service_name,
                        mojo::ScopedMessagePipeHandle client_handle) override {
    if (tracer_ && service_name == tracing::TraceProvider::Name_) {
      tracer_->ConnectToProvider(
          mojo::MakeRequest<tracing::TraceProvider>(client_handle.Pass()));
    }
  }

 private:
  Tracer* tracer_;
  mojo::StrongBinding<mojo::ServiceProvider> binding_;

  DISALLOW_COPY_AND_ASSIGN(TracingServiceProvider);
};

}  // namespace

Context::Context(Tracer* tracer)
    : tracer_(tracer),
      application_manager_(MakeApplicationManagerOptions(), this) {
  DCHECK(!base::MessageLoop::current());

  // By default assume that the local apps reside alongside the shell.
  // TODO(ncbray): really, this should be passed in rather than defaulting.
  // This default makes sense for desktop but not Android.
  base::FilePath shell_dir;
  PathService::Get(base::DIR_MODULE, &shell_dir);
  SetShellFileRoot(shell_dir);

  base::FilePath cwd;
  PathService::Get(base::DIR_CURRENT, &cwd);
  SetCommandLineCWD(cwd);
}

Context::~Context() {
  DCHECK(!base::MessageLoop::current());
}

// static
void Context::EnsureEmbedderIsInitialized() {
  static base::LazyInstance<Setup>::Leaky setup = LAZY_INSTANCE_INITIALIZER;
  setup.Get();
}

void Context::SetShellFileRoot(const base::FilePath& path) {
  shell_file_root_ = AddTrailingSlashIfNeeded(FilePathToFileURL(path));
}

GURL Context::ResolveShellFileURL(const std::string& path) {
  return shell_file_root_.Resolve(path);
}

void Context::SetCommandLineCWD(const base::FilePath& path) {
  command_line_cwd_ = AddTrailingSlashIfNeeded(FilePathToFileURL(path));
}

GURL Context::ResolveCommandLineURL(const std::string& path) {
  return command_line_cwd_.Resolve(path);
}

bool Context::Init() {
  base::FilePath shell_path = base::MakeAbsoluteFilePath(
      base::CommandLine::ForCurrentProcess()->GetProgram());
  base::FilePath shell_child_path =
      shell_path.DirName().AppendASCII("mojo_shell_child");
  return InitWithPaths(shell_child_path, nullptr);
}

bool Context::InitWithPaths(
    const base::FilePath& shell_child_path,
    mojo::URLResponseDiskCacheDelegate* url_response_disk_cache_delegate) {
  TRACE_EVENT0("mojo_shell", "Context::InitWithPaths");
  const base::CommandLine& command_line =
      *base::CommandLine::ForCurrentProcess();

  if (command_line.HasSwitch(switches::kWaitForDebugger))
    base::debug::WaitForDebugger(60, true);

  mojo_shell_child_path_ = shell_child_path;

  task_runners_.reset(
      new TaskRunners(base::MessageLoop::current()->message_loop_proxy()));

#if !defined(OS_MACOSX)
  application_manager()->SetLoaderForURL(
      make_scoped_ptr(new BackgroundApplicationLoader(
          make_scoped_ptr(
              new URLResponseDiskCacheLoader(task_runners_->blocking_pool(),
                                             url_response_disk_cache_delegate)),
          "url_response_disk_cache", base::MessageLoop::TYPE_DEFAULT)),
      GURL("mojo:url_response_disk_cache"));
#endif

  EnsureEmbedderIsInitialized();

  // TODO(vtl): Probably these failures should be checked before |Init()|, and
  // this function simply shouldn't fail.
  if (!shell_file_root_.is_valid())
    return false;
  if (!ConfigureURLMappings(command_line, this))
    return false;

  mojo::embedder::InitIPCSupport(
      mojo::embedder::ProcessType::MASTER, task_runners_->shell_runner(), this,
      task_runners_->io_runner(), mojo::embedder::ScopedPlatformHandle());

  scoped_ptr<NativeRunnerFactory> runner_factory;
  if (command_line.HasSwitch(switches::kEnableMultiprocess))
    runner_factory.reset(new OutOfProcessNativeRunnerFactory(this));
  else
    runner_factory.reset(new InProcessNativeRunnerFactory(this));
  application_manager_.set_blocking_pool(task_runners_->blocking_pool());
  application_manager_.set_native_runner_factory(runner_factory.Pass());

  InitContentHandlers(&application_manager_, command_line);
  InitNativeOptions(&application_manager_, command_line);

  // The mojo_shell --args-for command-line switch is handled specially because
  // it can appear more than once. The base::CommandLine class collapses
  // multiple occurrences of the same switch.
  base::CommandLine* current = base::CommandLine::ForCurrentProcess();
  for (size_t i = 1; i < current->argv().size(); ++i)
    ApplyApplicationArgs(this, current->argv()[i]);

  ServiceProviderPtr tracing_services;
  ServiceProviderPtr tracing_exposed_services;
  new TracingServiceProvider(tracer_, GetProxy(&tracing_exposed_services));
  application_manager_.ConnectToApplication(
      GURL("mojo:tracing"), GURL(""), GetProxy(&tracing_services),
      tracing_exposed_services.Pass(), base::Closure());

  if (command_line.HasSwitch(switches::kTraceStartup)) {
    DCHECK(tracer_);
    tracing::TraceCollectorPtr coordinator;
    auto coordinator_request = GetProxy(&coordinator);
    tracing_services->ConnectToService(tracing::TraceCollector::Name_,
                                       coordinator_request.PassMessagePipe());
    tracer_->StartCollectingFromTracingService(coordinator.Pass());
  }

  return true;
}

void Context::Shutdown() {
  TRACE_EVENT0("mojo_shell", "Context::Shutdown");
  DCHECK_EQ(base::MessageLoop::current()->task_runner(),
            task_runners_->shell_runner());
  mojo::embedder::ShutdownIPCSupport();
  // We'll quit when we get OnShutdownComplete().
  base::MessageLoop::current()->Run();
}

GURL Context::ResolveMappings(const GURL& url) {
  return url_resolver_.ApplyMappings(url);
}

GURL Context::ResolveMojoURL(const GURL& url) {
  return url_resolver_.ResolveMojoURL(url);
}

void Context::OnShutdownComplete() {
  DCHECK_EQ(base::MessageLoop::current()->task_runner(),
            task_runners_->shell_runner());
  base::MessageLoop::current()->Quit();
}

void Context::OnSlaveDisconnect(mojo::embedder::SlaveInfo slave_info) {
  // TODO(vtl): Do something, once we actually have |slave_info|.
}

void Context::Run(const GURL& url) {
  ServiceProviderPtr services;
  ServiceProviderPtr exposed_services;

  app_urls_.insert(url);
  application_manager_.ConnectToApplication(
      url, GURL(), mojo::GetProxy(&services), exposed_services.Pass(),
      base::Bind(&Context::OnApplicationEnd, base::Unretained(this), url));
}

void Context::OnApplicationEnd(const GURL& url) {
  if (app_urls_.find(url) != app_urls_.end()) {
    app_urls_.erase(url);
    if (app_urls_.empty() && base::MessageLoop::current()->is_running()) {
      DCHECK_EQ(base::MessageLoop::current()->task_runner(),
                task_runners_->shell_runner());
      base::MessageLoop::current()->Quit();
    }
  }
}

}  // namespace shell
