// Copyright 2013 The Flutter 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 FLUTTER_SHELL_COMMON_THREAD_HOST_H_
#define FLUTTER_SHELL_COMMON_THREAD_HOST_H_

#include <memory>
#include <optional>
#include <string>

#include "flutter/fml/macros.h"
#include "flutter/fml/thread.h"

namespace flutter {

using ThreadConfig = fml::Thread::ThreadConfig;
using ThreadConfigSetter = fml::Thread::ThreadConfigSetter;

/// The collection of all the threads used by the engine.
struct ThreadHost {
  enum Type {
    Platform = 1 << 0,
    UI = 1 << 1,
    RASTER = 1 << 2,
    IO = 1 << 3,
    Profiler = 1 << 4,
  };

  /// The collection of all the thread configures, and we create custom thread
  /// configure in engine to info the thread.
  struct ThreadHostConfig {
    explicit ThreadHostConfig(
        const ThreadConfigSetter& setter = fml::Thread::SetCurrentThreadName)
        : type_mask(0), config_setter(setter) {}

    ThreadHostConfig(
        const std::string& name_prefix,
        uint64_t mask,
        const ThreadConfigSetter& setter = fml::Thread::SetCurrentThreadName)
        : type_mask(mask), name_prefix(name_prefix), config_setter(setter) {}

    explicit ThreadHostConfig(
        uint64_t mask,
        const ThreadConfigSetter& setter = fml::Thread::SetCurrentThreadName)
        : ThreadHostConfig("", mask, setter) {}

    /// Check if need to create thread.
    bool isThreadNeeded(Type type) const { return type_mask & type; }

    /// Use the prefix and thread type to generator a thread name.
    static std::string MakeThreadName(Type type, const std::string& prefix);

    /// Specified the UI Thread Config, meanwhile set the mask.
    void SetUIConfig(const ThreadConfig&);

    /// Specified the Platform Thread Config, meanwhile set the mask.
    void SetPlatformConfig(const ThreadConfig&);

    /// Specified the IO Thread Config, meanwhile set the mask.
    void SetRasterConfig(const ThreadConfig&);

    /// Specified the IO Thread Config, meanwhile set the mask.
    void SetIOConfig(const ThreadConfig&);

    /// Specified the ProfilerThread  Config, meanwhile set the mask.
    void SetProfilerConfig(const ThreadConfig&);

    uint64_t type_mask;

    std::string name_prefix = "";

    const ThreadConfigSetter config_setter;

    std::optional<ThreadConfig> platform_config;
    std::optional<ThreadConfig> ui_config;
    std::optional<ThreadConfig> raster_config;
    std::optional<ThreadConfig> io_config;
    std::optional<ThreadConfig> profiler_config;
  };

  std::string name_prefix;
  std::unique_ptr<fml::Thread> platform_thread;
  std::unique_ptr<fml::Thread> ui_thread;
  std::unique_ptr<fml::Thread> raster_thread;
  std::unique_ptr<fml::Thread> io_thread;
  std::unique_ptr<fml::Thread> profiler_thread;

  ThreadHost();

  ThreadHost(ThreadHost&&);

  ThreadHost& operator=(ThreadHost&&) = default;

  ThreadHost(const std::string& name_prefix, uint64_t mask);

  explicit ThreadHost(const ThreadHostConfig& host_config);

  ~ThreadHost();

 private:
  std::unique_ptr<fml::Thread> CreateThread(
      Type type,
      std::optional<ThreadConfig> thread_config,
      const ThreadHostConfig& host_config) const;
};

}  // namespace flutter

#endif  // FLUTTER_SHELL_COMMON_THREAD_HOST_H_
