#include "Engine/Level/Scene/SceneLightmapsData.h"
#include "Level.h"
#include "Actor.h"
#include "Engine/Serialization/JsonTools.h"
#include "Engine/Serialization/Serialization.h"

String SceneInfo::ToString() const
{
    return TEXT("SceneInfo");
}

const int32 lightmapAtlasSizes[] =
{
    32,
    64,
    128,
    256,
    512,
    1024,
    2048,
    4096
};
DECLARE_ENUM_8(LightmapAtlasSize, _32, _64, _128, _256, _512, _1024, _2048, _4096);

{
    for (int32 i = 0; i < LightmapAtlasSize_Count; i++)
    {
        if (lightmapAtlasSizes[i] == size)
            return (LightmapAtlasSize)i;
    }
    return LightmapAtlasSize::_1024;
}

void SceneInfo::Serialize(SerializeStream& stream, const void* otherObj)
{
    SERIALIZE_GET_OTHER_OBJ(SceneInfo);

    SERIALIZE(Title);
    SERIALIZE(Description);
    SERIALIZE(Copyright);

    if (Lightmaps.HasItems())
    {
        stream.JKEY("Lightmaps");
        stream.StartArray();
        const int32 lightmapsCount = Lightmaps.Count();
        for (int32 i = 0; i < lightmapsCount; i++)
        {
            auto& info = Lightmaps[i];

            stream.StartObject();

            stream.JKEY("Lightmap0");
            stream.Guid(info.Lightmap0);

            stream.JKEY("Lightmap1");
            stream.Guid(info.Lightmap1);

            stream.JKEY("Lightmap2");
            stream.Guid(info.Lightmap2);

            stream.EndObject();
        }
        stream.EndArray(lightmapsCount);
    }

    stream.JKEY("LightmapSettings");
    stream.Object(&LightmapSettings, nullptr);
}

void SceneInfo::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)
{
    Title = JsonTools::GetString(stream, "Title");
    Description = JsonTools::GetString(stream, "Description");
    Copyright = JsonTools::GetString(stream, "Copyright");

    auto lightmaps = stream.FindMember("Lightmaps");
    if (lightmaps != stream.MemberEnd() && lightmaps->value.IsArray())
    {
        auto& lightmapsArray = lightmaps->value;
        Lightmaps.Resize(lightmapsArray.Size(), false);

        for (int32 i = 0; i < Lightmaps.Count(); i++)
        {
            auto& lightmap = Lightmaps[i];
            auto& lightmapsData = lightmapsArray[i];

            lightmap.Lightmap0 = JsonTools::GetGuid(lightmapsData, "Lightmap0");
            lightmap.Lightmap1 = JsonTools::GetGuid(lightmapsData, "Lightmap1");
            lightmap.Lightmap2 = JsonTools::GetGuid(lightmapsData, "Lightmap2");
        }
    }

    auto lightmapSettings = stream.FindMember("LightmapSettings");
    if (lightmapSettings != stream.MemberEnd())
    {
        LightmapSettings.Deserialize(lightmapSettings->value, modifier);
    }
    else
    {
        // Clear settings
        ::LightmapSettings settings;
        LightmapSettings = settings;
    }
}


{
    for (int32 i = 0; i < LightmapAtlasSize_Count; i++)
    {
        if (lightmapAtlasSizes[i] == size)
            return (LightmapAtlasSize)i;
    }
    return LightmapAtlasSize::_1024;
}

#include "Engine/Level/Scene/SceneLightmapsData.h"
#include "Level.h"
#include "Actor.h"
#include "Engine/Serialization/JsonTools.h"
#include "Engine/Serialization/Serialization.h"

String SceneInfo::ToString() const
{
    return TEXT("SceneInfo");
}

const int32 lightmapAtlasSizes[] =
{
    32,
    64,
    128,
    256,
    512,
    1024,
    2048,
    4096
};
DECLARE_ENUM_8(LightmapAtlasSize, _32, _64, _128, _256, _512, _1024, _2048, _4096);

LightmapAtlasSize getLightmapAtlasSize(int32 size)

void SceneInfo::Serialize(SerializeStream& stream, const void* otherObj)
{
    SERIALIZE_GET_OTHER_OBJ(SceneInfo);

    SERIALIZE(Title);
    SERIALIZE(Description);
    SERIALIZE(Copyright);

    if (Lightmaps.HasItems())
    {
        stream.JKEY("Lightmaps");
        stream.StartArray();
        const int32 lightmapsCount = Lightmaps.Count();
        for (int32 i = 0; i < lightmapsCount; i++)
        {
            auto& info = Lightmaps[i];

            stream.StartObject();

            stream.JKEY("Lightmap0");
            stream.Guid(info.Lightmap0);

            stream.JKEY("Lightmap1");
            stream.Guid(info.Lightmap1);

            stream.JKEY("Lightmap2");
            stream.Guid(info.Lightmap2);

            stream.EndObject();
        }
        stream.EndArray(lightmapsCount);
    }

    stream.JKEY("LightmapSettings");
    stream.Object(&LightmapSettings, nullptr);
}

void SceneInfo::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)
{
    Title = JsonTools::GetString(stream, "Title");
    Description = JsonTools::GetString(stream, "Description");
    Copyright = JsonTools::GetString(stream, "Copyright");

    auto lightmaps = stream.FindMember("Lightmaps");
    if (lightmaps != stream.MemberEnd() && lightmaps->value.IsArray())
    {
        auto& lightmapsArray = lightmaps->value;
        Lightmaps.Resize(lightmapsArray.Size(), false);

        for (int32 i = 0; i < Lightmaps.Count(); i++)
        {
            auto& lightmap = Lightmaps[i];
            auto& lightmapsData = lightmapsArray[i];

            lightmap.Lightmap0 = JsonTools::GetGuid(lightmapsData, "Lightmap0");
            lightmap.Lightmap1 = JsonTools::GetGuid(lightmapsData, "Lightmap1");
            lightmap.Lightmap2 = JsonTools::GetGuid(lightmapsData, "Lightmap2");
        }
    }

    auto lightmapSettings = stream.FindMember("LightmapSettings");
    if (lightmapSettings != stream.MemberEnd())
    {
        LightmapSettings.Deserialize(lightmapSettings->value, modifier);
    }
    else
    {
        // Clear settings
        ::LightmapSettings settings;
        LightmapSettings = settings;
    }
}


#include "Engine/Level/Scene/SceneLightmapsData.h"
#include "Level.h"
#include "Actor.h"
#include "Engine/Serialization/JsonTools.h"
#include "Engine/Serialization/Serialization.h"

String SceneInfo::ToString() const
{
    return TEXT("SceneInfo");
}

const int32 lightmapAtlasSizes[] =
{
    32,
    64,
    128,
    256,
    512,
    1024,
    2048,
    4096
};
DECLARE_ENUM_8(LightmapAtlasSize, _32, _64, _128, _256, _512, _1024, _2048, _4096);

LightmapAtlasSize getLightmapAtlasSize(int32 size)
{
    for (int32 i = 0; i < LightmapAtlasSize_Count; i++)
    {
        if (lightmapAtlasSizes[i] == size)
            return (LightmapAtlasSize)i;
    }
    return LightmapAtlasSize::_1024;
}

void SceneInfo::Serialize(SerializeStream& stream, const void* otherObj)
{
    SERIALIZE_GET_OTHER_OBJ(SceneInfo);

    SERIALIZE(Title);
    SERIALIZE(Description);
    SERIALIZE(Copyright);

    if (Lightmaps.HasItems())
    {
        stream.JKEY("Lightmaps");
        stream.StartArray();
        const int32 lightmapsCount = Lightmaps.Count();
        for (int32 i = 0; i < lightmapsCount; i++)
        {
            auto& info = Lightmaps[i];

            stream.StartObject();

            stream.JKEY("Lightmap0");
            stream.Guid(info.Lightmap0);

            stream.JKEY("Lightmap1");
            stream.Guid(info.Lightmap1);

            stream.JKEY("Lightmap2");
            stream.Guid(info.Lightmap2);

            stream.EndObject();
        }
        stream.EndArray(lightmapsCount);
    }

    stream.JKEY("LightmapSettings");
    stream.Object(&LightmapSettings, nullptr);
}

void SceneInfo::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)
{
    Title = JsonTools::GetString(stream,

    Description = JsonTools::GetString(stream, "Description");
    Copyright = JsonTools::GetString(stream, "Copyright");

    auto lightmaps = stream.FindMember("Lightmaps");
    if (lightmaps != stream.MemberEnd() && lightmaps->value.IsArray())
    {
        auto& lightmapsArray = lightmaps->value;
        Lightmaps.Resize(lightmapsArray.Size(), false);

        for (int32 i = 0; i < Lightmaps.Count(); i++)
        {
            auto& lightmap = Lightmaps[i];
            auto& lightmapsData = lightmapsArray[i];

            lightmap.Lightmap0 = JsonTools::GetGuid(lightmapsData, "Lightmap0");
            lightmap.Lightmap1 = JsonTools::GetGuid(lightmapsData, "Lightmap1");
            lightmap.Lightmap2 = JsonTools::GetGuid(lightmapsData, "Lightmap2");
        }
    }

    auto lightmapSettings = stream.FindMember("LightmapSettings");
    if (lightmapSettings != stream.MemberEnd())
    {
        LightmapSettings.Deserialize(lightmapSettings->value, modifier);
    }
    else
    {
        // Clear settings
        ::LightmapSettings settings;
        LightmapSettings = settings;
    }
}


/*
 *
 */
#include <glog/logging.h>
#include <signal.h>
#include <unistd.h>

#include <fstream>
#include <future>
#include <iostream>
#include <memory>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <thread>
#include <vitis/base/dpu/time_measure.hpp>

#include "../include/benchmark.hpp"
#include "./image_list.hpp"
#include "./stat_samples.hpp"
using namespace std;

int g_num_of_threads = 1;
int g_num_of_seconds = 30;
string g_list_name = "image.list";
string g_output_dir = "";
string g_model_name = "";

string g_report_file_name = "";
string g_run_mode = "accuracy";
long g_total = 0;
double g_e2e_mean = 0.0;
double g_dpu_mean = 0.0;
bool g_stop = false;

static int main_accuracy();

static int main_performance();
static void signal_handler(int signal) { g_stop = true; }

{
  cout << "usage: env DEEPHI_DPU_CONSUMING_TIME=1 dpbenchmark -r <run_mode> -t "
          "<num_of_threads> -s <num_of_seconds> "
          " -m <model name>"
          " <image list file> "
       << endl;
}

static void parse_opt(int argc, char *argv[]) {
  int opt = 0;

  while ((opt = getopt(argc, argv, "r:t:s:l:m:p:")) != -1) {
    switch (opt) {
      case 't':
        g_num_of_threads = std::stoi(optarg);
        break;
      case 's':
        g_num_of_seconds = std::stoi(optarg);
        break;
      case 'm':
        g_model_name = optarg;
        break;
      case 'l':
        g_report_file_name = optarg;
        break;
      case 'p':
        g_output_dir = optarg;
        break;
      case 'r':
        g_run_mode = optarg;
        if (g_run_mode == "performance" || g_run_mode == "accuracy") {
        } else {
          LOG(FATAL) << "run mode must be 'accuracy' or 'performance'";
        }
        break;

      default:
        usage();
        exit(1);
    }
  }
  if (optind >= argc) {
    cerr << "Expected argument after options\n";
    exit(EXIT_FAILURE);
  }
  if (g_model_name.empty()) {
    cerr << "model name is unknown, please use -m to specify a model name"
         << endl;
    exit(EXIT_FAILURE);
  }
  g_list_name = argv[optind];
  return;
}

BenchMarkResult thread_main(const ImageList *image_list,
                            unique_ptr<vitis::benchmark::Benchmark> &&model) {
  long ret = 0;
  StatSamples e2e_stat_samples(10000);
  StatSamples dpu_stat_samples(10000);
  for (ret = 0; !g_stop; ++ret) {
    vitis::base::TimeMeasure::getThreadLocalForDpu().reset();
    auto start = std::chrono::steady_clock::now();
    model->run_performance((*image_list)[ret]);
    auto end = std::chrono::steady_clock::now();
    auto end2endtime =
        int(std::chrono::duration_cast<std::chrono::microseconds>(end - start)
                .count());
    auto dputime = vitis::base::TimeMeasure::getThreadLocalForDpu().get();

    e2e_stat_samples.addSample(end2endtime);
    dpu_stat_samples.addSample(dputime);
    /*std::cout << "end2endtime "  << end2endtime << " " //
              << "dputime "  << dputime << " " //
              << std::endl;*/
  }
  /*std::cout << "ret " << ret << " " //
            << "e2e mean " << e2e_stat_samples.getMean() << " "
            << "dpu mean " << dpu_stat_samples.getMean() << " "
            << "e2e stdvar " << e2e_stat_samples.getStdVar() << " "
            << "dpu stdvar " << dpu_stat_samples.getStdVar() << " "
            << std::endl;
  */
  return BenchMarkResult{ret, std::move(e2e_stat_samples),
                         std::move(dpu_stat_samples)};
}

static void report(ostream *p_out) {
  ostream &out = *p_out;
  float fps = ((float)g_total) / ((float)g_num_of_seconds);
  out << "FPS=" << fps << "\n";
  out << "E2E_MEAN=" << g_e2e_mean << "\n";
  out << "DPU_MEAN=" << g_dpu_mean << "\n";
  out << flush;
  return;
}

static void report_for_mt(std::ostream *p_out) {
  std::ostream &out = *p_out;
  float sec = (float)act_time / 1000000.0;
  float fps = ((float)g_total) / sec;
  out << "FPS=" << fps << "\n";
  out << std::flush;
  return;
}
int main(int argc, char *argv[]) {
  parse_opt(argc, argv);
  if (g_run_mode == "performance") {
    return main_performance();
  } else if (g_run_mode == "accuracy") {
    return main_accuracy();
  }
  return 0;
}

static int main_performance() {
  auto lazy_load_image = false;
  auto image_list =
      std::unique_ptr<ImageList>(new ImageList(g_list_name, lazy_load_image));
  if (image_list->empty()) {
    LOG(FATAL) << "list of images are empty [" << image_list->to_string()
               << "]";
  }
  auto model = vitis::benchmark::create(g_model_name);
  auto width = model->getInputWidth();
  auto height = model->getInputHeight();
  image_list->resize_images(width, height);
  vector<std::future<BenchMarkResult>> results;
  results.reserve(g_num_of_threads);

  for (int i = 0; i < g_num_of_threads; ++i) {
    // every thread should have its own model object.
    if (i == 0) {
      // the first thread reuse the model which is already created.
      results.emplace_back(
          std::async(thread_main, image_list.get(), std::move(model)));
    } else {
      results.emplace_back(std::async(thread_main, image_list.get(),
                                      vitis::benchmark::create(g_model_name)));
    }
  }
  signal(SIGALRM, signal_handler);
  alarm(g_num_of_seconds);

  for (int i = 0; i < g_num_of_seconds; i = i + 5) {
    LOG(INFO) << "waiting for " << i << "/" << g_num_of_seconds << " seconds, "
              << g_num_of_threads << " threads running";
    std::this_thread::sleep_for(std::chrono::milliseconds(5000));
  }
  LOG(INFO) << "waiting for threads terminated";
  long total = 0;

  StatSamples e2eStatSamples(0);
  StatSamples dpuStatSamples(0);
  for (auto &r : results) {
    auto result = r.get();
    total = total + result.ret;
    /*
    std::cout << "r.get().e2eSamples " << e2eSamples.getMean() << " " //
              << "r.get().dpuSamples " << dpuSamples.getMean() << " " //
              << std::endl;
    */
    e2eStatSamples.merge(result.e2eSamples);
    dpuStatSamples.merge(result.dpuSamples);
  }

  /*std::cout << "E2E_MEAN=" << e2eStatSamples.getMean() << " "
           << std::endl;
 std::cout << "DPU_MEAN=" << dpuStatSamples.getMean() << " " << std::endl;
 */
  g_e2e_mean = e2eStatSamples.getMean();
  g_dpu_mean = dpuStatSamples.getMean();

  g_total = total;
  ostream *report_fs = &std::cout;
  auto fs = std::unique_ptr<ostream>{};
  if (!g_report_file_name.empty()) {
    LOG(INFO) << "writing report to " << g_report_file_name;
    fs = std::unique_ptr<ostream>{
        new std::ofstream(g_report_file_name.c_str(), std::ofstream::out)};
    report_fs = fs.get();
  } else {
    LOG(INFO) << "writing report to <STDOUT>";
  }
  if (g_num_of_threads==1){
    report(report_fs);
  }else{
    report_for_mt(report_fs);
  }
  return 0;
}

static int main_accuracy() {
  auto lazy_load_image = true;
  auto image_list =
      std::unique_ptr<ImageList>(new ImageList(g_list_name, lazy_load_image));
  if (image_list->empty()) {
    LOG(FATAL) << "list of images are empty [" << image_list->to_string()
               << "]";
  }
  ostream *report_fs = &std::cout;
  auto fs = std::unique_ptr<ostream>{};
  if (!g_report_file_name.empty()) {
    fs = std::unique_ptr<ostream>{
        new std::ofstream(g_report_file_name.c_str(), std::ofstream::out)};
    report_fs = fs.get();
    LOG(INFO) << "writing report to " << g_report_file_name;
  } else {
    LOG(INFO) << "writing report to <STDOUT>";
  }
  auto model = vitis::benchmark::create(g_model_name);
  for (auto i = 0u; i < image_list->size(); ++i) {
    model->run_accuracy(image_list->getName(i), (*image_list)[i], *report_fs);
  }
  return 0;
}


{
  std::ostream &out = *p_out;
  float sec = (float)act_time / 1000000.0;
  float fps = ((float)g_total) / sec;
  out << "FPS=" << fps << "\n";
  out << std::flush;
  return;
}

/*
 *
 */
#include <glog/logging.h>
#include <signal.h>
#include <unistd.h>

#include <fstream>
#include <future>
#include <iostream>
#include <memory>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <thread>
#include <vitis/base/dpu/time_measure.hpp>

#include "../include/benchmark.hpp"
#include "./image_list.hpp"
#include "./stat_samples.hpp"
using namespace std;

int g_num_of_threads = 1;
int g_num_of_seconds = 30;
string g_list_name = "image.list";
string g_output_dir = "";
string g_model_name = "";

string g_report_file_name = "";
string g_run_mode = "accuracy";
long g_total = 0;
double g_e2e_mean = 0.0;
double g_dpu_mean = 0.0;
bool g_stop = false;

static int main_accuracy();

static int main_performance();
static void signal_handler(int signal) { g_stop = true; }

static void usage() {
  cout << "usage: env DEEPHI_DPU_CONSUMING_TIME=1 dpbenchmark -r <run_mode> -t "
          "<num_of_threads> -s <num_of_seconds> "
          " -m <model name>"
          " <image list file> "
       << endl;
}

static void parse_opt(int argc, char *argv[]) {
  int opt = 0;

  while ((opt = getopt(argc, argv, "r:t:s:l:m:p:")) != -1) {
    switch (opt) {
      case 't':
        g_num_of_threads = std::stoi(optarg);
        break;
      case 's':
        g_num_of_seconds = std::stoi(optarg);
        break;
      case 'm':
        g_model_name = optarg;
        break;
      case 'l':
        g_report_file_name = optarg;
        break;
      case 'p':
        g_output_dir = optarg;
        break;
      case 'r':
        g_run_mode = optarg;
        if (g_run_mode == "performance" || g_run_mode == "accuracy") {
        } else {
          LOG(FATAL) << "run mode must be 'accuracy' or 'performance'";
        }
        break;

      default:
        usage();
        exit(1);
    }
  }
  if (optind >= argc) {
    cerr << "Expected argument after options\n";
    exit(EXIT_FAILURE);
  }
  if (g_model_name.empty()) {
    cerr << "model name is unknown, please use -m to specify a model name"
         << endl;
    exit(EXIT_FAILURE);
  }
  g_list_name = argv[optind];
  return;
}

BenchMarkResult thread_main(const ImageList *image_list,
                            unique_ptr<vitis::benchmark::Benchmark> &&model) {
  long ret = 0;
  StatSamples e2e_stat_samples(10000);
  StatSamples dpu_stat_samples(10000);
  for (ret = 0; !g_stop; ++ret) {
    vitis::base::TimeMeasure::getThreadLocalForDpu().reset();
    auto start = std::chrono::steady_clock::now();
    model->run_performance((*image_list)[ret]);
    auto end = std::chrono::steady_clock::now();
    auto end2endtime =
        int(std::chrono::duration_cast<std::chrono::microseconds>(end - start)
                .count());
    auto dputime = vitis::base::TimeMeasure::getThreadLocalForDpu().get();

    e2e_stat_samples.addSample(end2endtime);
    dpu_stat_samples.addSample(dputime);
    /*std::cout << "end2endtime "  << end2endtime << " " //
              << "dputime "  << dputime << " " //
              << std::endl;*/
  }
  /*std::cout << "ret " << ret << " " //
            << "e2e mean " << e2e_stat_samples.getMean() << " "
            << "dpu mean " << dpu_stat_samples.getMean() << " "
            << "e2e stdvar " << e2e_stat_samples.getStdVar() << " "
            << "dpu stdvar " << dpu_stat_samples.getStdVar() << " "
            << std::endl;
  */
  return BenchMarkResult{ret, std::move(e2e_stat_samples),
                         std::move(dpu_stat_samples)};
}

static void report(ostream *p_out) {
  ostream &out = *p_out;
  float fps = ((float)g_total) / ((float)g_num_of_seconds);
  out << "FPS=" << fps << "\n";
  out << "E2E_MEAN=" << g_e2e_mean << "\n";
  out << "DPU_MEAN=" << g_dpu_mean << "\n";
  out << flush;
  return;
}

static void report_for_mt(std::ostream *p_out)

int main(int argc, char *argv[]) {
  parse_opt(argc, argv);
  if (g_run_mode == "performance") {
    return main_performance();
  } else if (g_run_mode == "accuracy") {
    return main_accuracy();
  }
  return 0;
}

static int main_performance() {
  auto lazy_load_image = false;
  auto image_list =
      std::unique_ptr<ImageList>(new ImageList(g_list_name, lazy_load_image));
  if (image_list->empty()) {
    LOG(FATAL) << "list of images are empty [" << image_list->to_string()
               << "]";
  }
  auto model = vitis::benchmark::create(g_model_name);
  auto width = model->getInputWidth();
  auto height = model->getInputHeight();
  image_list->resize_images(width, height);
  vector<std::future<BenchMarkResult>> results;
  results.reserve(g_num_of_threads);

  for (int i = 0; i < g_num_of_threads; ++i) {
    // every thread should have its own model object.
    if (i == 0) {
      // the first thread reuse the model which is already created.
      results.emplace_back(
          std::async(thread_main, image_list.get(), std::move(model)));
    } else {
      results.emplace_back(std::async(thread_main, image_list.get(),
                                      vitis::benchmark::create(g_model_name)));
    }
  }
  signal(SIGALRM, signal_handler);
  alarm(g_num_of_seconds);

  for (int i = 0; i < g_num_of_seconds; i = i + 5) {
    LOG(INFO) << "waiting for " << i << "/" << g_num_of_seconds << " seconds, "
              << g_num_of_threads << " threads running";
    std::this_thread::sleep_for(std::chrono::milliseconds(5000));
  }
  LOG(INFO) << "waiting for threads terminated";
  long total = 0;

  StatSamples e2eStatSamples(0);
  StatSamples dpuStatSamples(0);
  for (auto &r : results) {
    auto result = r.get();
    total = total + result.ret;
    /*
    std::cout << "r.get().e2eSamples " << e2eSamples.getMean() << " " //
              << "r.get().dpuSamples " << dpuSamples.getMean() << " " //
              << std::endl;
    */
    e2eStatSamples.merge(result.e2eSamples);
    dpuStatSamples.merge(result.dpuSamples);
  }

  /*std::cout << "E2E_MEAN=" << e2eStatSamples.getMean() << " "
           << std::endl;
 std::cout << "DPU_MEAN=" << dpuStatSamples.getMean() << " " << std::endl;
 */
  g_e2e_mean = e2eStatSamples.getMean();
  g_dpu_mean = dpuStatSamples.getMean();

  g_total = total;
  ostream *report_fs = &std::cout;
  auto fs = std::unique_ptr<ostream>{};
  if (!g_report_file_name.empty()) {
    LOG(INFO) << "writing report to " << g_report_file_name;
    fs = std::unique_ptr<ostream>{
        new std::ofstream(g_report_file_name.c_str(), std::ofstream::out)};
    report_fs = fs.get();
  } else {
    LOG(INFO) << "writing report to <STDOUT>";
  }
  if (g_num_of_threads==1){
    report(report_fs);
  }else{
    report_for_mt(report_fs);
  }
  return 0;
}

static int main_accuracy() {
  auto lazy_load_image = true;
  auto image_list =
      std::unique_ptr<ImageList>(new ImageList(g_list_name, lazy_load_image));
  if (image_list->empty()) {
    LOG(FATAL) << "list of images are empty [" << image_list->to_string()
               << "]";
  }
  ostream *report_fs = &std::cout;
  auto fs = std::unique_ptr<ostream>{};
  if (!g_report_file_name.empty()) {
    fs = std::unique_ptr<ostream>{
        new std::ofstream(g_report_file_name.c_str(), std::ofstream::out)};
    report_fs = fs.get();
    LOG(INFO) << "writing report to " << g_report_file_name;
  } else {
    LOG(INFO) << "writing report to <STDOUT>";
  }
  auto model = vitis::benchmark::create(g_model_name);
  for (auto i = 0u; i < image_list->size(); ++i) {
    model->run_accuracy(image_list->getName(i), (*image_list)[i], *report_fs);
  }
  return 0;
}


/*
 *
 */
#include <glog/logging.h>
#include <signal.h>
#include <unistd.h>

#include <fstream>
#include <future>
#include <iostream>
#include <memory>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <thread>
#include <vitis/base/dpu/time_measure.hpp>

#include "../include/benchmark.hpp"
#include "./image_list.hpp"
#include "./stat_samples.hpp"
using namespace std;

int g_num_of_threads = 1;
int g_num_of_seconds = 30;
string g_list_name = "image.list";
string g_output_dir = "";
string g_model_name = "";

string g_report_file_name = "";
string g_run_mode = "accuracy";
long g_total = 0;
double g_e2e_mean = 0.0;
double g_dpu_mean = 0.0;
bool g_stop = false;

static int main_accuracy();

static int main_performance();
static void signal_handler(int signal) { g_stop = true; }

static void usage() {
  cout << "usage: env DEEPHI_DPU_CONSUMING_TIME=1 dpbenchmark -r <run_mode> -t "
          "<num_of_threads> -s <num_of_seconds> "
          " -m <model name>"
          " <image list file> "
       << endl;
}

static void parse_opt(int argc, char *argv[]) {
  int opt = 0;

  while ((opt = getopt(argc, argv, "r:t:s:l:m:p:")) != -1) {
    switch (opt) {
      case 't':
        g_num_of_threads = std::stoi(optarg);
        break;
      case 's':
        g_num_of_seconds = std::stoi(optarg);
        break;
      case 'm':
        g_model_name = optarg;
        break;
      case 'l':
        g_report_file_name = optarg;
        break;
      case 'p':
        g_output_dir = optarg;
        break;
      case 'r':
        g_run_mode = optarg;
        if (g_run_mode == "performance" || g_run_mode == "accuracy") {
        } else {
          LOG(FATAL) << "run mode must be 'accuracy' or 'performance'";
        }
        break;

      default:
        usage();
        exit(1);
    }
  }
  if (optind >= argc) {
    cerr << "Expected argument after options\n";
    exit(EXIT_FAILURE);
  }
  if (g_model_name.empty()) {
    cerr << "model name is unknown, please use -m to specify a model name"
         << endl;
    exit(EXIT_FAILURE);
  }
  g_list_name = argv[optind];
  return;
}

BenchMarkResult thread_main(const ImageList *image_list,
                            unique_ptr<vitis::benchmark::Benchmark> &&model) {
  long ret = 0;
  StatSamples e2e_stat_samples(10000);
  StatSamples dpu_stat_samples(10000);
  for (ret = 0; !g_stop; ++ret) {
    vitis::base::TimeMeasure::getThreadLocalForDpu().reset();
    auto start = std::chrono::steady_clock::now();
    model->run_performance((*image_list)[ret]);
    auto end = std::chrono::steady_clock::now();
    auto end2endtime =
        int(std::chrono::duration_cast<std::chrono::microseconds>(end - start)
                .count());
    auto dputime = vitis::base::TimeMeasure::getThreadLocalForDpu().get();

    e2e_stat_samples.addSample(end2endtime);
    dpu_stat_samples.addSample(dputime);
    /*std::cout << "end2endtime "  << end2endtime << " " //
              << "dputime "  << dputime << " " //
              << std::endl;*/
  }
  /*std::cout << "ret " << ret << " " //
            << "e2e mean " << e2e_stat_samples.getMean() << " "
            << "dpu mean " << dpu_stat_samples.getMean() << " "
            << "e2e stdvar " << e2e_stat_samples.getStdVar() << " "
            << "dpu stdvar " << dpu_stat_samples.getStdVar() << " "
            << std::endl;
  */
  return BenchMarkResult{ret, std::move(e2e_stat_samples),
                         std::move(dpu_stat_samples)};
}

static void report(ostream *p_out) {
  ostream &out = *p_out;
  float fps = ((float)g_total) / ((float)g_num_of_seconds);
  out << "FPS=" << fps << "\n";
  out << "E2E_MEAN=" << g_e2e_mean << "\n";
  out << "DPU_MEAN=" << g_dpu_mean << "\n";
  out << flush;
  return;
}

static void report_for_mt(std::ostream *p_out) {
  std::ostream &out = *p_out;
  float sec = (float)act_time / 1000000.0;
  float fps = ((float)g_total) / sec;
  out << "FPS=" << fps << "\n";
  out << std::flush;
  return;
}
int main(int argc, char *argv[]) {
  parse_opt(argc, argv);
  if (g_run_mode == "performance") {
    return main_performance();
  } else if (g_run_mode == "accuracy") {
    return main_accuracy();
  }
  return 0;
}

static int main_performance() {
  auto lazy_load_image = false;
  auto image_list =
      std::unique_ptr<ImageList>(new ImageList(g_list_name, lazy_load_image));
  if (image_list->empty()) {
    LOG(FATAL) << "list of images are empty [" << image_list->to_string()
               << "]";
  }
  auto model = vitis::benchmark::create(g_model_name);
  auto width = model->getInputWidth();
  auto height = model->getInputHeight();
  image_list->resize_images(width, height);
  vector<std::future<BenchMarkResult>> results;
  results.reserve(g_num_of_threads);

  for (int i = 0; i < g_num_of_threads; ++i) {
    // every thread should have its own model object.
    if (i == 0) {
      // the first thread reuse the model which is already created.
      results.emplace_back(
          std::async(thread_main, image_list.get(), std::move(model)));
    } else {
      results.emplace_back(std::async(thread_main, image_list.get(),
                                      vitis::benchmark::create(g_model_name)));
    }
  }
  signal(SIGALRM, signal_handler);
  alarm(g_num_of_seconds);

  for (int i = 0; i < g_num_of_seconds; i = i + 5) {
    LOG(INFO) << "waiting for " << i << "/" << g_num_of_seconds << " seconds, "
              << g_num_of_threads << " threads running";
    std::this_thread::sleep_for(std::chrono::milliseconds(5000));
  }
  LOG(INFO) << "waiting for threads terminated";
  long total = 0;

  StatSamples e2eStatSamples(0);
  StatSamples dpuStatSamples(0);
  for (auto &r : results) {
    auto result = r.get();
    total = total + result.ret;
    /*
    std::cout << "r.get().e2eSamples " << e2eSamples.getMean() << " " //
              << "r.get().dpuSamples " << dpuSamples.getMean() << " " //
              << std::endl;
    */
    e2eStatSamples.merge(result.e2eSamples);
    dpuStatSamples.merge(result.dpuSamples);
  }

  /*std::cout << "E2E_MEAN=" << e2eStatSamples.getMean() << " "
           << std::endl;
 std::cout << "DPU_MEAN=" << dpuStatSamples.getMean() << " " << std::endl;
 */
  g_e2e_mean = e2eStatSamples.getMean();
  g_dpu_mean = dpuStatSamples.getMean();

  g_total = total;
  ostream *report_fs = &std::cout;
  auto fs = std::unique_ptr<ostream>{};
  if (!g_report_file_name.empty()) {
    LOG(INFO) << "writing report to " << g_report_file_name;
    fs = std::unique_ptr<ostream>{
        new std::ofstream(g_report_file_name.c_str(), std::ofstream::out)};
    report_fs = fs.get();
  } else {
    LOG(INFO) << "writing report to <STDOUT>";
  }
  if (g_num_of_threads==1){
    report(report_fs);
  }else{
    report_for_mt(report_fs);
  }
  return 0;
}

static int main_accuracy() {
  auto lazy_load_image = true;
  auto image_list =
      std::unique_ptr<ImageList>(new ImageList(g_list_name, lazy_load_image));
  if (image_list->empty()) {
    LOG(FATAL) << "list of images are empty [" << image_list->to_string()
               << "]";
  }
  ostream *report_fs = &std::cout;
  auto fs =

  if (!g_report_file_name.empty()) {
    fs = std::unique_ptr<ostream>{
        new std::ofstream(g_report_file_name.c_str(), std::ofstream::out)};
    report_fs = fs.get();
    LOG(INFO) << "writing report to " << g_report_file_name;
  } else {
    LOG(INFO) << "writing report to <STDOUT>";
  }
  auto model = vitis::benchmark::create(g_model_name);
  for (auto i = 0u; i < image_list->size(); ++i) {
    model->run_accuracy(image_list->getName(i), (*image_list)[i], *report_fs);
  }
  return 0;
}


/* +------------------------------------------------------------------------+
   |                     Mobile Robot Programming Toolkit (MRPT)            |
   |                          http://example.com                         |
   |                                                                        |
   | See: http://example.com - All rights reserved.               |
   +------------------------------------------------------------------------+ */

#include "rawlog-edit-declarations.h"

using namespace mrpt;
using namespace mrpt::obs;
using namespace mrpt::system;
using namespace mrpt::rawlogtools;
using namespace std;
using namespace mrpt::io;

//		op_list_timestamps

{
	class CRawlogProcessor_ListTimestamps
		: public CRawlogProcessorOnEachObservation
	{
	   protected:
		string m_out_file;
		std::ofstream m_out;

	   public:
		CRawlogProcessor_ListTimestamps(
			CFileGZInputStream& in_rawlog, TCLAP::CmdLine& cmdline,
			bool Verbose)
			: CRawlogProcessorOnEachObservation(in_rawlog, cmdline, Verbose)
		{
			getArgValue<std::string>(cmdline, "text-file-output", m_out_file);
			VERBOSE_COUT << "Writing list to: " << m_out_file << endl;

			m_out.open(m_out_file.c_str());

			if (!m_out.is_open())
				throw std::runtime_error(
					"list-timestamps: Cannot open output text file.");
		}

		bool processOneObservation(CObservation::Ptr& obs) override
		{
			m_out << std::fixed
				  << mrpt::system::timestampToDouble(obs->timestamp) << " "
				  << obs->sensorLabel << " "
				  << obs->GetRuntimeClass()->className << std::endl;
			return true;
		}
	};

	// Process
	CRawlogProcessor_ListTimestamps proc(in_rawlog, cmdline, verbose);
	proc.doProcessRawlog();

	// Dump statistics:
	VERBOSE_COUT << "Time to process file (sec)        : " << proc.m_timToParse
				 << "\n";
}


{
			getArgValue<std::string>(cmdline, "text-file-output", m_out_file);
			VERBOSE_COUT << "Writing list to: " << m_out_file << endl;

			m_out.open(m_out_file.c_str());

			if (!m_out.is_open())
				throw std::runtime_error(
					"list-timestamps: Cannot open output text file.");
		}

/* +------------------------------------------------------------------------+
   |                     Mobile Robot Programming Toolkit (MRPT)            |
   |                          http://example.com                         |
   |                                                                        |
   | See: http://example.com - All rights reserved.               |
   +------------------------------------------------------------------------+ */

#include "rawlog-edit-declarations.h"

using namespace mrpt;
using namespace mrpt::obs;
using namespace mrpt::system;
using namespace mrpt::rawlogtools;
using namespace std;
using namespace mrpt::io;

//		op_list_timestamps
DECLARE_OP_FUNCTION(op_list_timestamps)
{
	class CRawlogProcessor_ListTimestamps
		: public CRawlogProcessorOnEachObservation
	{
	   protected:
		string m_out_file;
		std::ofstream m_out;

	   public:
		CRawlogProcessor_ListTimestamps(
			CFileGZInputStream& in_rawlog, TCLAP::CmdLine& cmdline,
			bool Verbose)
			: CRawlogProcessorOnEachObservation(in_rawlog, cmdline, Verbose)

		bool processOneObservation(CObservation::Ptr& obs) override
		{
			m_out << std::fixed
				  << mrpt::system::timestampToDouble(obs->timestamp) << " "
				  << obs->sensorLabel << " "
				  << obs->GetRuntimeClass()->className << std::endl;
			return true;
		}
	};

	// Process
	CRawlogProcessor_ListTimestamps proc(in_rawlog, cmdline, verbose);
	proc.doProcessRawlog();

	// Dump statistics:
	VERBOSE_COUT << "Time to process file (sec)        : " << proc.m_timToParse
				 << "\n";
}


/* +------------------------------------------------------------------------+
   |                     Mobile Robot Programming Toolkit (MRPT)            |
   |                          http://example.com                         |
   |                                                                        |
   | See: http://example.com - All rights reserved.               |
   +------------------------------------------------------------------------+ */

#include "rawlog-edit-declarations.h"

using namespace mrpt;
using namespace mrpt::obs;
using namespace mrpt::system;
using namespace mrpt::rawlogtools;
using namespace std;
using namespace mrpt::io;

//		op_list_timestamps
DECLARE_OP_FUNCTION(op_list_timestamps)
{
	class CRawlogProcessor_ListTimestamps
		: public CRawlogProcessorOnEachObservation
	{
	   protected:
		string m_out_file;
		std::ofstream m_out;

	   public:
		CRawlogProcessor_ListTimestamps(
			CFileGZInputStream& in_rawlog, TCLAP::CmdLine& cmdline,
			bool Verbose)
			: CRawlogProcessorOnEachObservation(in_rawlog, cmdline, Verbose)
		{
			getArgValue<std::string>(cmdline, "text-file-output", m_out_file);
			VERBOSE_COUT << "Writing list to: " << m_out_file << endl;

			m_out.open(m_out_file.c_st

			if (!m_out.is_open())
				throw std::runtime_error(
					"list-timestamps: Cannot open output text file.");
		}

		bool processOneObservation(CObservation::Ptr& obs) override
		{
			m_out << std::fixed
				  << mrpt::system::timestampToDouble(obs->timestamp) << " "
				  << obs->sensorLabel << " "
				  << obs->GetRuntimeClass()->className << std::endl;
			return true;
		}
	};

	// Process
	CRawlogProcessor_ListTimestamps proc(in_rawlog, cmdline, verbose);
	proc.doProcessRawlog();

	// Dump statistics:
	VERBOSE_COUT << "Time to process file (sec)        : " << proc.m_timToParse
				 << "\n";
}


/**
    bespoke synth, a software modular synthesizer

**/
//  PitchDive.cpp
//  Bespoke
//  Created by Ryan Challinor on 12/27/15.

#include "PitchDive.h"
#include "OpenFrameworksPort.h"
#include "ModularSynth.h"

PitchDive::PitchDive()
: mStart(0)
, mStartSlider(nullptr)
, mTime(0)
, mTimeSlider(nullptr)
, mModulation(false)
{
}

PitchDive::~PitchDive()
{
}

{
   IDrawableModule::CreateUIControls();
   mStartSlider = new FloatSlider(this,"start",5,2,110,15,&mStart,-3,3);
   mTimeSlider = new FloatSlider(this,"time",5,20,110,15,&mTime,0,1000);

   mTimeSlider->SetMode(FloatSlider::kSquare);
}

void PitchDive::DrawModule()
{
   if (Minimized() || IsVisible() == false)
      return;
   mStartSlider->Draw();
   mTimeSlider->Draw();
}

void PitchDive::PlayNote(double time, int pitch, int velocity, int voiceIdx, ModulationParameters modulation)
{
   if (mEnabled && velocity > 0 && mStart != 0 && mTime != 0)
   {
      ComputeSliders(0);
      auto* pitchBend = mModulation.GetPitchBend(voiceIdx);
      pitchBend->RampValue(time, mStart, 0, mTime);
      pitchBend->AppendTo(modulation.pitchBend);
      modulation.pitchBend = pitchBend;
   }

   PlayNoteOutput(time, pitch, velocity, voiceIdx, modulation);
}

void PitchDive::FloatSliderUpdated(FloatSlider* slider, float oldVal)
{
}

void PitchDive::CheckboxUpdated(Checkbox* checkbox)
{
}

void PitchDive::LoadLayout(const ofxJSONElement& moduleInfo)
{
   mModuleSaveData.LoadString("target", moduleInfo);

   SetUpFromSaveData();
}

void PitchDive::SetUpFromSaveData()
{
   SetUpPatchCables(mModuleSaveData.GetString("target"));
}


{
   IDrawableModule::CreateUIControls();
   mStartSlider = new FloatSlider(this,"start",5,2,110,15,&mStart,-3,3);
   mTimeSlider = new FloatSlider(this,"time",5,20,110,15,&mTime,0,1000);

   mTimeSlider->SetMode(FloatSlider::kSquare);
}

/**
    bespoke synth, a software modular synthesizer

**/
//  PitchDive.cpp
//  Bespoke
//  Created by Ryan Challinor on 12/27/15.

#include "PitchDive.h"
#include "OpenFrameworksPort.h"
#include "ModularSynth.h"

PitchDive::PitchDive()
: mStart(0)
, mStartSlider(nullptr)
, mTime(0)
, mTimeSlider(nullptr)
, mModulation(false)
{
}

PitchDive::~PitchDive()
{
}

void PitchDive::CreateUIControls()

void PitchDive::DrawModule()
{
   if (Minimized() || IsVisible() == false)
      return;
   mStartSlider->Draw();
   mTimeSlider->Draw();
}

void PitchDive::PlayNote(double time, int pitch, int velocity, int voiceIdx, ModulationParameters modulation)
{
   if (mEnabled && velocity > 0 && mStart != 0 && mTime != 0)
   {
      ComputeSliders(0);
      auto* pitchBend = mModulation.GetPitchBend(voiceIdx);
      pitchBend->RampValue(time, mStart, 0, mTime);
      pitchBend->AppendTo(modulation.pitchBend);
      modulation.pitchBend = pitchBend;
   }

   PlayNoteOutput(time, pitch, velocity, voiceIdx, modulation);
}

void PitchDive::FloatSliderUpdated(FloatSlider* slider, float oldVal)
{
}

void PitchDive::CheckboxUpdated(Checkbox* checkbox)
{
}

void PitchDive::LoadLayout(const ofxJSONElement& moduleInfo)
{
   mModuleSaveData.LoadString("target", moduleInfo);

   SetUpFromSaveData();
}

void PitchDive::SetUpFromSaveData()
{
   SetUpPatchCables(mModuleSaveData.GetString("target"));
}


/**
    bespoke synth, a software modular synthesizer

**/
//  PitchDive.cpp
//  Bespoke
//  Created by Ryan Challinor on 12/27/15.

#include "PitchDive.h"
#include "OpenFrameworksPort.h"
#include "ModularSynth.h"

PitchDive::PitchDive()
: mStart(0)
, mStartSlider(nullptr)
, mTime(0)
, mTimeSlider(nullptr)
, mModulation(false)
{
}

PitchDive::~PitchDive()
{
}

void PitchDive::CreateUIControls()
{
   IDrawableModule::CreateUIControls();
   mStartSlider = new FloatSlider(this,"start",5,2,110,15,&mStart,-3,3);
   mTimeSlider = new FloatSlider(this,"time",5,20,110,15,&mTime,0,1000);

   mTimeSlid

}

void PitchDive::DrawModule()
{
   if (Minimized() || IsVisible() == false)
      return;
   mStartSlider->Draw();
   mTimeSlider->Draw();
}

void PitchDive::PlayNote(double time, int pitch, int velocity, int voiceIdx, ModulationParameters modulation)
{
   if (mEnabled && velocity > 0 && mStart != 0 && mTime != 0)
   {
      ComputeSliders(0);
      auto* pitchBend = mModulation.GetPitchBend(voiceIdx);
      pitchBend->RampValue(time, mStart, 0, mTime);
      pitchBend->AppendTo(modulation.pitchBend);
      modulation.pitchBend = pitchBend;
   }

   PlayNoteOutput(time, pitch, velocity, voiceIdx, modulation);
}

void PitchDive::FloatSliderUpdated(FloatSlider* slider, float oldVal)
{
}

void PitchDive::CheckboxUpdated(Checkbox* checkbox)
{
}

void PitchDive::LoadLayout(const ofxJSONElement& moduleInfo)
{
   mModuleSaveData.LoadString("target", moduleInfo);

   SetUpFromSaveData();
}

void PitchDive::SetUpFromSaveData()
{
   SetUpPatchCables(mModuleSaveData.GetString("target"));
}


/* This file is part of reckless logging
 *
 */
#include <reckless/policy_log.hpp>
#include <thread>   // sleep_for

#include "unreliable_writer.hpp"

unreliable_writer writer;

{
    reckless::policy_log<> log(&writer);

    std::this_thread::sleep_for(std::chrono::seconds(2));
    log.write("(2) Write by log");
    std::cout << "(1) Write by cout " << std::endl;

    std::this_thread::sleep_for(std::chrono::seconds(2));
    log.write("(3) Write by log, then flush");
    log.flush();
    std::cout << "(4) Write by cout after flush " << std::endl;

    std::this_thread::sleep_for(std::chrono::seconds(2));
    writer.error_code.assign(static_cast<int>(std::errc::no_space_on_device),
            get_error_category());
    std::cout <<"Simulating disk full" << std::endl;
    log.write("(6) Write by log, then flush");
    try {
        log.flush();
    } catch(reckless::writer_error const& e) {
        std::cout << "(5) Catch writer_error " << e.code() << " on flush"
            << std::endl;
    }
    std::this_thread::sleep_for(std::chrono::seconds(2));
    std::cout <<"Simulating disk no longer full" << std::endl;
    writer.error_code.clear();
    log.flush();

    std::this_thread::sleep_for(std::chrono::seconds(2));
    std::cout <<"Simulating disk full" << std::endl;
    writer.error_code.assign(static_cast<int>(std::errc::no_space_on_device),
            get_error_category());
    log.write("(8) Write by log, then flush");
    std::error_code error;
    log.flush(error);
    if(error) {
        std::cout << "(7) Obtain error code " << error << " on flush"
            << std::endl;
    }
    writer.error_code.clear();
    log.flush();

    return 0;
}


/* This file is part of reckless logging
 *
 */
#include <reckless/policy_log.hpp>
#include <thread>   // sleep_for

#include "unreliable_writer.hpp"

unreliable_writer writer;
int main()
{
    reckless::policy_log<> log(&writer);

    std::this_thread::sleep_for(std::chrono::seconds(2));
    log.write("(2) Write by log");
    std::cout << "(1) Write by cout " << std::endl;

    std::this_thread::sleep_for(std::chrono::seconds(2));
    log.write("(3) Write by log, then flush");
    log.flush();
    std::cout << "(4) Write by cout after flush " << std::endl;

    std::this_thread::sleep_for(std::chrono::seconds(2));
    writer.error_code.assign(static_cast<int>(std::errc::no_space_on_device),
            get_error_category());
    std::cout <<"Simulating disk full" << std::endl;
    log.write("(6) Write by log, then flush");
    try {
        log.flush();
    } catch(reckless::writer_error const& e) {
        std::cout << "(5) Catch writer_error " << e.code() << " on flush"
            << std::endl;
    }
    std::this_thread::sleep_for(std::chrono::seconds(2));
    std::cout <<"Simulating disk no longer full" << std::endl;
    writer.error_code.clear();
    l

    std::this_thread::sleep_for(std::chrono::seconds(2));
    std::cout <<"Simulating disk full" << std::endl;
    writer.error_code.assign(static_cast<int>(std::errc::no_space_on_device),
            get_error_category());
    log.write("(8) Write by log, then flush");
    std::error_code error;
    log.flush(error);
    if(error) {
        std::cout << "(7) Obtain error code " << error << " on flush"
            << std::endl;
    }
    writer.error_code.clear();
    log.flush();

    return 0;
}


try {
        log.flush();
    } catch(reckless::writer_error const& e) {
        std::cout << "(5) Catch writer_error " << e.code() << " on flush"
            << std::endl;
    }

/* This file is part of reckless logging
 *
 */
#include <reckless/policy_log.hpp>
#include <thread>   // sleep_for

#include "unreliable_writer.hpp"

unreliable_writer writer;
int main()
{
    reckless::policy_log<> log(&writer);

    std::this_thread::sleep_for(std::chrono::seconds(2));
    log.write("(2) Write by log");
    std::cout << "(1) Write by cout " << std::endl;

    std::this_thread::sleep_for(std::chrono::seconds(2));
    log.write("(3) Write by log, then flush");
    log.flush();
    std::cout << "(4) Write by cout after flush " << std::endl;

    std::this_thread::sleep_for(std::chrono::seconds(2));
    writer.error_code.assign(static_cast<int>(std::errc::no_space_on_device),
            get_error_category());
    std::cout <<"Simulating disk full" << std::endl;
    log.write("(6) Write by log, then flush");

    std::this_thread::sleep_for(std::chrono::seconds(2));
    std::cout <<"Simulating disk no longer full" << std::endl;
    writer.error_code.clear();
    log.flush();

    std::this_thread::sleep_for(std::chrono::seconds(2));
    std::cout <<"Simulating disk full" << std::endl;
    writer.error_code.assign(static_cast<int>(std::errc::no_space_on_device),
            get_error_category());
    log.write("(8) Write by log, then flush");
    std::error_code error;
    log.flush(error);
    if(error) {
        std::cout << "(7) Obtain error code " << error << " on flush"
            << std::endl;
    }
    writer.error_code.clear();
    log.flush();

    return 0;
}


int LLVMFuzzerTestOneInput(const uint8_t *data, std::size_t size)

/**
 */

#include "block_loader_fixture.hpp"

extern "C"

{
  static fuzzing::BlockLoaderFixture fixture;

  if (size < 1) {
    return 0;
  }

  iroha::network::proto::BlockRequest request;
  if (protobuf_mutator::libfuzzer::LoadProtoInput(true, data, size, &request)) {
    grpc::ServerContext context;
    iroha::protocol::Block response;
    fixture.block_loader_service_->retrieveBlock(&context, &request, &response);
  }

  return 0;
}


{
  static fuzzing::BlockLoaderFixture fixture;

  if (size < 1) {
    return 0;
  }

  iroha::network::proto::BlockRequest request;
  if (protobuf_mutator::libfuzzer::LoadProtoInput(true, data, size, &request)) {
    grpc::ServerContext context;
    iroha::protocol::Block response;
    fixture.block_loader_service_->retrieveBlock(&context, &request, &response);
  }

  return 0;
}

/**
 */

#include "block_loader_fixture.hpp"

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, std::size_t size)


/**
 */

#include "block_loader_fixture.hpp"

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, std::size_t size) {
  static fuzzing::BlockLoaderFixture fixture;

  if (size < 1) {
    return 0;
  }

  iroha::network::proto::BlockRequest reque

  if (protobuf_mutator::libfuzzer::LoadProtoInput(true, data, size, &request)) {
    grpc::ServerContext context;
    iroha::protocol::Block response;
    fixture.block_loader_service_->retrieveBlock(&context, &request, &response);
  }

  return 0;
}


const int n = 10000; // ALL INDICES START AT 1 WITH THIS CODE!!

// mode 1: update indices, read prefixes
void update_idx(int tree[], int i, int val) { // v[i] += val
  for (; i <= n; i += i & -i) tree[i] += val;
}
int read_prefix(int tree[], int i) { // get sum v[1..i]
  int sum = 0;
  for (; i > 0; i -= i & -i) sum += tree[i];
  return sum;
}
int kth(int k) { // find kth element in tree (1-based index)
  int ans = 0;
  for (int i = maxl; i >= 0; --i) // maxl = largest i s.t. (1<<i) <= n
    if (ans + (1<<i) <= N && tree[ans + (1<<i)] < k) {
      ans += 1<<i;
      k -= tree[ans];
    }
  return ans+1;
}

// mode 2: update prefixes, read indices
void update_prefix(int tree[], int i, int val) { // v[1..i] += val
  for (; i > 0; i -= i & -i) tree[i] += val;
}
int read_idx(int tree[], int i) { // get v[i]
  int sum = 0;
  for (; i <= n; i += i & -i) sum += tree[i];
  return sum;
}

// mode 3: range-update range-query (using point-wise of linear functions)
const int maxn = 100100;
int n;
ll mul[maxn], add[maxn];

void update_idx(ll tree[], int x, ll val) {
  for (int i = x; i <= n; i += i & -i) tree[i] += val;
}
void update_prefix(int x, ll val) { // v[x] += val
  update_idx(mul, 1, val);
  update_idx(mul, x + 1, -val);
  update_idx(add, x + 1, x * val);
}

{ // get sum v[1..x]
  ll a = 0, b = 0;
  for (int i = x; i > 0; i -= i & -i) a += mul[i], b += add[i];
  return a * x + b;
}
void update_range(int l, int r, ll val) { // v[l..r] += val
  update_prefix(l - 1, -val);
  update_prefix(r, val);
}
ll read_range(int l, int r) { // get sum v[l..r]
  return read_prefix(r) - read_prefix(l - 1);
}


{ // find kth element in tree (1-based index)
  int ans = 0;
  for (int i = maxl; i >= 0; --i) // maxl = largest i s.t. (1<<i) <= n
    if (ans + (1<<i) <= N && tree[ans + (1<<i)] < k) {
      ans += 1<<i;
      k -= tree[ans];
    }
  return ans+1;
}

const int n = 10000; // ALL INDICES START AT 1 WITH THIS CODE!!

// mode 1: update indices, read prefixes
void update_idx(int tree[], int i, int val) { // v[i] += val
  for (; i <= n; i += i & -i) tree[i] += val;
}
int read_prefix(int tree[], int i) { // get sum v[1..i]
  int sum = 0;
  for (; i > 0; i -= i & -i) sum += tree[i];
  return sum;
}
int kth(int k)

// mode 2: update prefixes, read indices
void update_prefix(int tree[], int i, int val) { // v[1..i] += val
  for (; i > 0; i -= i & -i) tree[i] += val;
}
int read_idx(int tree[], int i) { // get v[i]
  int sum = 0;
  for (; i <= n; i += i & -i) sum += tree[i];
  return sum;
}

// mode 3: range-update range-query (using point-wise of linear functions)
const int maxn = 100100;
int n;
ll mul[maxn], add[maxn];

void update_idx(ll tree[], int x, ll val) {
  for (int i = x; i <= n; i += i & -i) tree[i] += val;
}
void update_prefix(int x, ll val) { // v[x] += val
  update_idx(mul, 1, val);
  update_idx(mul, x + 1, -val);
  update_idx(add, x + 1, x * val);
}
ll read_prefix(int x) { // get sum v[1..x]
  ll a = 0, b = 0;
  for (int i = x; i > 0; i -= i & -i) a += mul[i], b += add[i];
  return a * x + b;
}
void update_range(int l, int r, ll val) { // v[l..r] += val
  update_prefix(l - 1, -val);
  update_prefix(r, val);
}
ll read_range(int l, int r) { // get sum v[l..r]
  return read_prefix(r) - read_prefix(l - 1);
}


const int n = 10000; // ALL INDICES START AT 1 WITH THIS CODE!!

// mode 1: update indices, read prefixes
void update_idx(int tree[], int i, int val) { // v[i] += val
  for (; i <= n; i += i & -i) tree[i] += val;
}
int read_prefix(int tree[], int i) { // get sum v[1..i]
  int sum = 0;
  for (; i > 0; i -= i & -i) sum += tree[i];
  return sum;
}
int kth(int k) { // find kth element in tree (1-based index)
  int ans = 0;
  for (int i = maxl; i >= 0; --i) // maxl = largest i s.t. (1<<i) <= n
    if (ans + (1<<i) <= N && tree[ans + (1<<i)] < k) {
      ans += 1<<i;
      k -= tree[ans];
    }
  return ans+1;
}

// mode 2: update prefixes, read indices
void update_prefix(int tree[], int i, int val) { // v[1..i] += val
  for (; i > 0; i -= i & -i) tree[i] += val;
}
int read_idx(int tree[], int i) { // get v[i]
  int sum = 0;
  for (; i <= n; i += i & -i) sum += tree[i];
  return sum;
}

// mode 3: range-update range-query (using point-wise of linear functions)
const int maxn = 100100;
int n;
ll mul[maxn], add[maxn];

void update_idx(ll tree[], int x, ll val) {
  for (int i = x; i <= n; i += i & -i) tree[i] += val;
}
void update_prefix(int x, ll val) { // v[x] += val
  update_idx(mul, 1, val);
  update_idx(mul, x + 1, -val);
  update_idx(add, x + 1, x * val);
}
ll read_prefix(int x) { // get sum v[1..x]
  ll a = 0, b = 0;
  for (int i = x; i > 0; i -= i & -i) a += mul[i], b += add[i];
  return a * x + b;
}
void update_range(int l, int r, ll val) { // v[l..r] += val
  update_prefix(l - 1, -val);
  update_prefix(r, val);
}
ll read_range(int l, int r) { // get sum v[l..r]
  return read_prefix(r) - read_


void update_idx(int tree[], int i, int val) { // v[i] += val
  for (; i <= n; i += i & -i) tree[i] += val;
}

const int n = 10000; // ALL INDICES START AT 1 WITH THIS CODE!!

// mode 1: update indices, read prefixes

int read_prefix(int tree[], int i) { // get sum v[1..i]
  int sum = 0;
  for (; i > 0; i -= i & -i) sum += tree[i];
  return sum;
}
int kth(int k) { // find kth element in tree (1-based index)
  int ans = 0;
  for (int i = maxl; i >= 0; --i) // maxl = largest i s.t. (1<<i) <= n
    if (ans + (1<<i) <= N && tree[ans + (1<<i)] < k) {
      ans += 1<<i;
      k -= tree[ans];
    }
  return ans+1;
}

// mode 2: update prefixes, read indices
void update_prefix(int tree[], int i, int val) { // v[1..i] += val
  for (; i > 0; i -= i & -i) tree[i] += val;
}
int read_idx(int tree[], int i) { // get v[i]
  int sum = 0;
  for (; i <= n; i += i & -i) sum += tree[i];
  return sum;
}

// mode 3: range-update range-query (using point-wise of linear functions)
const int maxn = 100100;
int n;
ll mul[maxn], add[maxn];

void update_idx(ll tree[], int x, ll val) {
  for (int i = x; i <= n; i += i & -i) tree[i] += val;
}
void update_prefix(int x, ll val) { // v[x] += val
  update_idx(mul, 1, val);
  update_idx(mul, x + 1, -val);
  update_idx(add, x + 1, x * val);
}
ll read_prefix(int x) { // get sum v[1..x]
  ll a = 0, b = 0;
  for (int i = x; i > 0; i -= i & -i) a += mul[i], b += add[i];
  return a * x + b;
}
void update_range(int l, int r, ll val) { // v[l..r] += val
  update_prefix(l - 1, -val);
  update_prefix(r, val);
}
ll read_range(int l, int r) { // get sum v[l..r]
  return read_prefix(r) - read_prefix(l - 1);
}


void trans_warp_magnifier::transform(double* x, double* y) const

// Contact: example@nnthink.com
//          example@nnthink.com

#include <math.h>
#include "agg_trans_warp_magnifier.h"

namespace agg
{

{
        double dx = *x - m_xc;
        double dy = *y - m_yc;
        double r = sqrt(dx * dx + dy * dy);
        if(r < m_radius)
        {
            *x = m_xc + dx * m_magn;
            *y = m_yc + dy * m_magn;
            return;
        }

        double m = (r + m_radius * (m_magn - 1.0)) / r;
        *x = m_xc + dx * m;
        *y = m_yc + dy * m;
    }

    void trans_warp_magnifier::inverse_transform(double* x, double* y) const
    {
        // New version by Andrew Skalkin
        double dx = *x - m_xc;
        double dy = *y - m_yc;
        double r = sqrt(dx * dx + dy * dy);

        if(r < m_radius * m_magn)
        {
            *x = m_xc + dx / m_magn;
            *y = m_yc + dy / m_magn;
        }
        else
        {
            double rnew = r - m_radius * (m_magn - 1.0);
            *x = m_xc + rnew * dx / r;
            *y = m_yc + rnew * dy / r;
        }

        // Old version
    }

}


{
        // New version by Andrew Skalkin
        double dx = *x - m_xc;
        double dy = *y - m_yc;
        double r = sqrt(dx * dx + dy * dy);

        if(r < m_radius * m_magn)
        {
            *x = m_xc + dx / m_magn;
            *y = m_yc + dy / m_magn;
        }
        else
        {
            double rnew = r - m_radius * (m_magn - 1.0);
            *x = m_xc + rnew * dx / r;
            *y = m_yc + rnew * dy / r;
        }

        // Old version
    }

// Contact: example@nnthink.com
//          example@nnthink.com

#include <math.h>
#include "agg_trans_warp_magnifier.h"

namespace agg
{

    void trans_warp_magnifier::transform(double* x, double* y) const
    {
        double dx = *x - m_xc;
        double dy = *y - m_yc;
        double r = sqrt(dx * dx + dy * dy);
        if(r < m_radius)
        {
            *x = m_xc + dx * m_magn;
            *y = m_yc + dy * m_magn;
            return;
        }

        double m = (r + m_radius * (m_magn - 1.0)) / r;
        *x = m_xc + dx * m;
        *y = m_yc + dy * m;
    }

    void trans_warp_magnifier::inverse_transform(double* x, double* y) const


// Contact: example@nnthink.com
//          example@nnthink.com

#include <math.h>
#include "agg_trans_warp_magnifier.h"

namespace agg
{

    void trans_warp_magnifier::transform(double* x, double* y) const
    {
        doub

        double dy = *y - m_yc;
        double r = sqrt(dx * dx + dy * dy);
        if(r < m_radius)
        {
            *x = m_xc + dx * m_magn;
            *y = m_yc + dy * m_magn;
            return;
        }

        double m = (r + m_radius * (m_magn - 1.0)) / r;
        *x = m_xc + dx * m;
        *y = m_yc + dy * m;
    }

    void trans_warp_magnifier::inverse_transform(double* x, double* y) const
    {
        // New version by Andrew Skalkin
        double dx = *x - m_xc;
        double dy = *y - m_yc;
        double r = sqrt(dx * dx + dy * dy);

        if(r < m_radius * m_magn)
        {
            *x = m_xc + dx / m_magn;
            *y = m_yc + dy / m_magn;
        }
        else
        {
            double rnew = r - m_radius * (m_magn - 1.0);
            *x = m_xc + rnew * dx / r;
            *y = m_yc + rnew * dy / r;
        }

        // Old version
    }

}


nsresult ATTRIBUTE_USED
    PrepareAndDispatch(nsXPTCStubBase* self, uint32_t methodIndex, uint32_t* args)

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 */

/* Implement shared vtbl methods. */

#include "xptcprivate.h"
#include "xptiprivate.h"

extern "C" {

{
#define PARAM_BUFFER_COUNT     16

        nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
        nsXPTCMiniVariant* dispatchParams = nullptr;
        const nsXPTMethodInfo* info;
        uint8_t paramCount;
        uint8_t i;
        nsresult result = NS_ERROR_FAILURE;

        NS_ASSERTION(self,"no self");

        self->mEntry->GetMethodInfo(uint16_t(methodIndex), &info);
        NS_ASSERTION(info,"no method info");

        paramCount = info->GetParamCount();

        // setup variant array pointer
        if(paramCount > PARAM_BUFFER_COUNT)
            dispatchParams = new nsXPTCMiniVariant[paramCount];
        else
            dispatchParams = paramBuffer;
        NS_ASSERTION(dispatchParams,"no place for params");

        uint32_t* ap = args;
        for(i = 0; i < paramCount; i++, ap++)
        {
            const nsXPTParamInfo& param = info->GetParam(i);
            const nsXPTType& type = param.GetType();
            nsXPTCMiniVariant* dp = &dispatchParams[i];

            if(param.IsOut() || !type.IsArithmetic())
            {
                dp->val.p = (void*) *ap;
                continue;
            }

            switch(type)
            {
            // the 8 and 16 bit types will have been promoted to 32 bits before
            // being pushed onto the stack. Since the 68k is big endian, we
            // need to skip over the leading high order bytes.
            case nsXPTType::T_I8     : dp->val.i8  = *(((int8_t*) ap) + 3);  break;
            case nsXPTType::T_I16    : dp->val.i16 = *(((int16_t*) ap) + 1); break;
            case nsXPTType::T_I32    : dp->val.i32 = *((int32_t*) ap);       break;
            case nsXPTType::T_I64    : dp->val.i64 = *((int64_t*) ap); ap++; break;
            case nsXPTType::T_U8     : dp->val.u8  = *(((uint8_t*) ap) + 3); break;
            case nsXPTType::T_U16    : dp->val.u16 = *(((uint16_t*)ap) + 1); break;
            case nsXPTType::T_U32    : dp->val.u32 = *((uint32_t*)ap);       break;
            case nsXPTType::T_U64    : dp->val.u64 = *((uint64_t*)ap); ap++; break;
            case nsXPTType::T_FLOAT  : dp->val.f   = *((float*)   ap);       break;
            case nsXPTType::T_DOUBLE : dp->val.d   = *((double*)  ap); ap++; break;
            case nsXPTType::T_BOOL   : dp->val.b   = *((uint32_t* ap);       break;
            case nsXPTType::T_CHAR   : dp->val.c   = *(((char*)   ap) + 3);  break;
            case nsXPTType::T_WCHAR  : dp->val.wc  = *((wchar_t*) ap);       break;
            default:
                NS_ERROR("bad type");
                break;
            }
        }

        result = self->mOuter->CallMethod((uint16_t)methodIndex, info, dispatchParams);

        if(dispatchParams != paramBuffer)
            delete [] dispatchParams;

        return result;
    }
}

#define STUB_ENTRY(n) \
nsresult nsXPTCStubBase::Stub##n() \
{ \
  void *frame = __builtin_frame_address(0); \
  return PrepareAndDispatch(this, n, (uint32_t*)frame + 3); \
}

#define SENTINEL_ENTRY(n) \
nsresult nsXPTCStubBase::Sentinel##n() \
{ \
    NS_ERROR("nsXPTCStubBase::Sentinel called"); \
    return NS_ERROR_NOT_IMPLEMENTED; \
}

#include "xptcstubsdef.inc"


/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 */

/* Implement shared vtbl methods. */

#include "xptcprivate.h"
#include "xptiprivate.h"

extern "C" {
    nsresult ATTRIBUTE_USED
    PrepareAndDispatch(nsXPTCStubBase* self, uint32_t methodIndex, uint32_t* args)
    {
#define PARAM_BUFFER_COUNT     16

        nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
        nsXPTCMiniVar

        const nsXPTMethodInfo* info;
        uint8_t paramCount;
        uint8_t i;
        nsresult result = NS_ERROR_FAILURE;

        NS_ASSERTION(self,"no self");

        self->mEntry->GetMethodInfo(uint16_t(methodIndex), &info);
        NS_ASSERTION(info,"no method info");

        paramCount = info->GetParamCount();

        // setup variant array pointer
        if(paramCount > PARAM_BUFFER_COUNT)
            dispatchParams = new nsXPTCMiniVariant[paramCount];
        else
            dispatchParams = paramBuffer;
        NS_ASSERTION(dispatchParams,"no place for params");

        uint32_t* ap = args;
        for(i = 0; i < paramCount; i++, ap++)
        {
            const nsXPTParamInfo& param = info->GetParam(i);
            const nsXPTType& type = param.GetType();
            nsXPTCMiniVariant* dp = &dispatchParams[i];

            if(param.IsOut() || !type.IsArithmetic())
            {
                dp->val.p = (void*) *ap;
                continue;
            }

            switch(type)
            {
            // the 8 and 16 bit types will have been promoted to 32 bits before
            // being pushed onto the stack. Since the 68k is big endian, we
            // need to skip over the leading high order bytes.
            case nsXPTType::T_I8     : dp->val.i8  = *(((int8_t*) ap) + 3);  break;
            case nsXPTType::T_I16    : dp->val.i16 = *(((int16_t*) ap) + 1); break;
            case nsXPTType::T_I32    : dp->val.i32 = *((int32_t*) ap);       break;
            case nsXPTType::T_I64    : dp->val.i64 = *((int64_t*) ap); ap++; break;
            case nsXPTType::T_U8     : dp->val.u8  = *(((uint8_t*) ap) + 3); break;
            case nsXPTType::T_U16    : dp->val.u16 = *(((uint16_t*)ap) + 1); break;
            case nsXPTType::T_U32    : dp->val.u32 = *((uint32_t*)ap);       break;
            case nsXPTType::T_U64    : dp->val.u64 = *((uint64_t*)ap); ap++; break;
            case nsXPTType::T_FLOAT  : dp->val.f   = *((float*)   ap);       break;
            case nsXPTType::T_DOUBLE : dp->val.d   = *((double*)  ap); ap++; break;
            case nsXPTType::T_BOOL   : dp->val.b   = *((uint32_t* ap);       break;
            case nsXPTType::T_CHAR   : dp->val.c   = *(((char*)   ap) + 3);  break;
            case nsXPTType::T_WCHAR  : dp->val.wc  = *((wchar_t*) ap);       break;
            default:
                NS_ERROR("bad type");
                break;
            }
        }

        result = self->mOuter->CallMethod((uint16_t)methodIndex, info, dispatchParams);

        if(dispatchParams != paramBuffer)
            delete [] dispatchParams;

        return result;
    }
}

#define STUB_ENTRY(n) \
nsresult nsXPTCStubBase::Stub##n() \
{ \
  void *frame = __builtin_frame_address(0); \
  return PrepareAndDispatch(this, n, (uint32_t*)frame + 3); \
}

#define SENTINEL_ENTRY(n) \
nsresult nsXPTCStubBase::Sentinel##n() \
{ \
    NS_ERROR("nsXPTCStubBase::Sentinel called"); \
    return NS_ERROR_NOT_IMPLEMENTED; \
}

#include "xptcstubsdef.inc"


#include "Production/RTSProductionCostComponent.h"

#include "Economy/RTSResourceType.h"

URTSProductionCostComponent::URTSProductionCostComponent(const FObjectInitializer& ObjectInitializer /*= FObjectInitializer::Get()*/)
    : Super(ObjectInitializer)
{
	// Set reasonable default values.
	ProductionCostType = ERTSPaymentType::PAYMENT_PayImmediately;
	ProductionTime = 5.0f;
	RefundFactor = 0.5f;
}

{
    return ProductionCostType;
}

float URTSProductionCostComponent::GetProductionTime() const
{
    return ProductionTime;
}

TMap<TSubclassOf<URTSResourceType>, float> URTSProductionCostComponent::GetResources() const
{
    return Resources;
}

float URTSProductionCostComponent::GetRefundFactor() const
{
    return RefundFactor;
}

USoundCue* URTSProductionCostComponent::GetFinishedSound() const
{
    return FinishedSound;
}


#include "Production/RTSProductionCostComponent.h"

#include "Economy/RTSResourceType.h"

URTSProductionCostComponent::URTSProductionCostComponent(const FObjectInitializer& ObjectInitializer /*= FObjectInitializer::Get()*/)
    : Super(ObjectInitializer)
{
	// Set reasonable default values.
	ProductionCostType = ERTSPaymentType::PAYMENT_PayImmediately;
	ProductionTime = 5.0f;
	RefundFactor = 0.5f;
}

ERTSPaymentType URTSProductionCostComponent::GetProductionCostType() const
{
    return ProductionCostType;
}

float URTSProductionCostComponent::GetProductionTime() const

TMap<TSubclassOf<URTSResourceType>, float> URTSProductionCostComponent::GetResources() const
{
    return Resources;
}

float URTSProductionCostComponent::GetRefundFactor() const
{
    return RefundFactor;
}

USoundCue* URTSProductionCostComponent::GetFinishedSound() const
{
    return FinishedSound;
}


#include "Production/RTSProductionCostComponent.h"

#include "Economy/RTSResourceType.h"

URTSProductionCostComponent::URTSProductionCostComponent(const FObjectInitializer& ObjectInitializer /*= FObjectInitializer::Get()*/)
    : Super(ObjectInitializer)
{
	// Set reasonable default values.
	ProductionCostType = ERTSPaymentType::PAYMENT_PayImmediately;
	ProductionTime = 5.0f;
	RefundFactor = 0.5f;
}

ERTSPaymentType URTSProductionCostComponent::GetProductionCostType() const
{
    return Pr

}

float URTSProductionCostComponent::GetProductionTime() const
{
    return ProductionTime;
}

TMap<TSubclassOf<URTSResourceType>, float> URTSProductionCostComponent::GetResources() const
{
    return Resources;
}

float URTSProductionCostComponent::GetRefundFactor() const
{
    return RefundFactor;
}

USoundCue* URTSProductionCostComponent::GetFinishedSound() const
{
    return FinishedSound;
}


void LocalisedStrings::loadFromText (const String& fileContents, bool ignoreCase)

/*
  ==============================================================================

   This file is part of the juce_core module of the JUCE library.

   ------------------------------------------------------------------------------

   using any other modules, be sure to check that you also comply with their license.

   For more details, visit www.juce.com

  ==============================================================================
*/

LocalisedStrings::LocalisedStrings (const String& fileContents, bool ignoreCase)
{
    loadFromText (fileContents, ignoreCase);
}

LocalisedStrings::LocalisedStrings (const File& fileToLoad, bool ignoreCase)
{
    loadFromText (fileToLoad.loadFileAsString(), ignoreCase);
}

LocalisedStrings::LocalisedStrings (const LocalisedStrings& other)
    : languageName (other.languageName), countryCodes (other.countryCodes),
      translations (other.translations), fallback (createCopyIfNotNull (other.fallback.get()))
{
}

LocalisedStrings& LocalisedStrings::operator= (const LocalisedStrings& other)
{
    languageName = other.languageName;
    countryCodes = other.countryCodes;
    translations = other.translations;
    fallback = createCopyIfNotNull (other.fallback.get());
    return *this;
}

LocalisedStrings::~LocalisedStrings()
{
}

String LocalisedStrings::translate (const String& text) const
{
    if (fallback != nullptr && ! translations.containsKey (text))
        return fallback->translate (text);

    return translations.getValue (text, text);
}

String LocalisedStrings::translate (const String& text, const String& resultIfNotFound) const
{
    if (fallback != nullptr && ! translations.containsKey (text))
        return fallback->translate (text, resultIfNotFound);

    return translations.getValue (text, resultIfNotFound);
}

namespace
{
   #if JUCE_CHECK_MEMORY_LEAKS
    // By using this object to force a LocalisedStrings object to be created
    // before the currentMappings object, we can force the static order-of-destruction to
    // delete the currentMappings object first, which avoids a bogus leak warning.
    // (Oddly, just creating a LocalisedStrings on the stack doesn't work in gcc, it
    // has to be created with 'new' for this to work..)
    struct LeakAvoidanceTrick
    {
        LeakAvoidanceTrick()
        {
            const ScopedPointer<LocalisedStrings> dummy (new LocalisedStrings (String(), false));
        }
    };

    LeakAvoidanceTrick leakAvoidanceTrick;
   #endif

    SpinLock currentMappingsLock;
    ScopedPointer<LocalisedStrings> currentMappings;

    static int findCloseQuote (const String& text, int startPos)
    {
        juce_wchar lastChar = 0;
        String::CharPointerType t (text.getCharPointer() + startPos);

        for (;;)
        {
            const juce_wchar c = t.getAndAdvance();

            if (c == 0 || (c == '"' && lastChar != '\\'))
                break;

            lastChar = c;
            ++startPos;
        }

        return startPos;
    }

    static String unescapeString (const String& s)
    {
        return s.replace ("\\\"", "\"")
                .replace ("\\\'", "\'")
                .replace ("\\t", "\t")
                .replace ("\\r", "\r")
                .replace ("\\n", "\n");
    }
}

{
    translations.setIgnoresCase (ignoreCase);

    StringArray lines;
    lines.addLines (fileContents);

    for (int i = 0; i < lines.size(); ++i)
    {
        String line (lines[i].trim());

        if (line.startsWithChar ('"'))
        {
            int closeQuote = findCloseQuote (line, 1);

            const String originalText (unescapeString (line.substring (1, closeQuote)));

            if (originalText.isNotEmpty())
            {
                const int openingQuote = findCloseQuote (line, closeQuote + 1);
                closeQuote = findCloseQuote (line, openingQuote + 1);

                const String newText (unescapeString (line.substring (openingQuote + 1, closeQuote)));

                if (newText.isNotEmpty())
                    translations.set (originalText, newText);
            }
        }
        else if (line.startsWithIgnoreCase ("language:"))
        {
            languageName = line.substring (9).trim();
        }
        else if (line.startsWithIgnoreCase ("countries:"))
        {
            countryCodes.addTokens (line.substring (10).trim(), true);
            countryCodes.trim();
            countryCodes.removeEmptyStrings();
        }
    }

    translations.minimiseStorageOverheads();
}

void LocalisedStrings::addStrings (const LocalisedStrings& other)
{
    jassert (languageName == other.languageName);
    jassert (countryCodes == other.countryCodes);

    translations.addArray (other.translations);
}

void LocalisedStrings::setFallback (LocalisedStrings* f)
{
    fallback = f;
}

void LocalisedStrings::setCurrentMappings (LocalisedStrings* newTranslations)
{
    const SpinLock::ScopedLockType sl (currentMappingsLock);
    currentMappings = newTranslations;
}

LocalisedStrings* LocalisedStrings::getCurrentMappings()
{
    return currentMappings;
}

String LocalisedStrings::translateWithCurrentMappings (const String& text)  { return juce::translate (text); }
String LocalisedStrings::translateWithCurrentMappings (const char* text)    { return juce::translate (text); }

JUCE_API String translate (const String& text)       { return juce::translate (text, text); }
JUCE_API String translate (const char* text)         { return juce::translate (String (text)); }
JUCE_API String translate (CharPointer_UTF8 text)    { return juce::translate (String (text)); }

JUCE_API String translate (const String& text, const String& resultIfNotFound)
{
    const SpinLock::ScopedLockType sl (currentMappingsLock);

    if (const LocalisedStrings* const mappings = LocalisedStrings::getCurrentMappings())
        return mappings->translate (text, resultIfNotFound);

    return resultIfNotFound;
}


/*
  ==============================================================================

   This file is part of the juce_core module of the JUCE library.

   ------------------------------------------------------------------------------

   using any other modules, be sure to check that you also comply with their license.

   For more details, visit www.juce.com

  ==============================================================================
*/

LocalisedStrings::LocalisedStrings (const String& fileContents, bool ignoreCase)
{
    loadFromText (fileContents, ignoreCase);
}

LocalisedStrings::LocalisedStrings (const File& fileToLoad, bool ignoreCase)
{
    loadFromText (fileToLoad.loadFileAsString(), ignoreCase);
}

LocalisedStrings::LocalisedStrings (const LocalisedStrings& other)
    : languageName (other.languageName), countryCodes (other.countryCodes),
      translations (other.translations), fallback (createCopyIfNotNull (other.fallback.get()))
{
}

LocalisedStrings& LocalisedStrings::operator= (const LocalisedStrings& other)
{
    languageName = other.languageName;
    countryCodes = other.countryCodes;
    translations = other.translations;
    fallback = createCopyIfNotNull (other.fallback.get());
    return *this;
}

LocalisedStrings::~LocalisedStrings()
{
}

String LocalisedStrings::translate (const String& text) const
{
    if (fallback != nullptr && ! translations.containsKey (text))
        return fallback->translate (text);

    return translations.getValue (text, text);
}

String LocalisedStrings::translate (const String& text, const String& resultIfNotFound) const
{
    if (fallback != nullptr && ! translations.containsKey (text))
        return fallback->translate (text, resultIfNotFound);

    return translations.getValue (text, resultIfNotFound);
}

namespace
{
   #if JUCE_CHECK_MEMORY_LEAKS
    // By using this object to force a LocalisedStrings object to be created
    // before the currentMappings object, we can force the static order-of-destruction to
    // delete the currentMappings object first, which avoids a bogus leak warning.
    // (Oddly, just creating a LocalisedStrings on the stack doesn't work in gcc, it
    // has to be created with 'new' for this to work..)
    struct LeakAvoidanceTrick
    {
        LeakAvoidanceTrick()
        {
            const ScopedPointer<LocalisedStrings> dummy (new LocalisedStrings (String(), false));
        }
    };

    LeakAvoidanceTrick leakAvoidanceTrick;
   #endif

    SpinLock currentMappingsLock;
    ScopedPointer<LocalisedStrings> currentMappings;

    static int findCloseQuote (const String& text, int startPos)
    {
        juce_wchar lastChar = 0;
        String::CharPointerType t (text.getCharPointer() + startPos);

        for (;;)
        {
            const juce_wchar c = t.getAndAdvance();

            if (c == 0 || (c == '"' && lastChar != '\\'))
                break;

            lastChar = c;
            ++startPos;
        }

        return startPos;
    }

    static String unescapeString (const String& s)

}

void LocalisedStrings::loadFromText (const String& fileContents, bool ignoreCase)
{
    translations.setIgnoresCase (ignoreCase);

    StringArray lines;
    lines.addLines (fileContents);

    for (int i = 0; i < lines.size(); ++i)
    {
        String line (lines[i].trim());

        if (line.startsWithChar ('"'))
        {
            int closeQuote = findCloseQuote (line, 1);

            const String originalText (unescapeString (line.substring (1, closeQuote)));

            if (originalText.isNotEmpty())
            {
                const int openingQuote = findCloseQuote (line, closeQuote + 1);
                closeQuote = findCloseQuote (line, openingQuote + 1);

                const String newText (unescapeString (line.substring (openingQuote + 1, closeQuote)));

                if (newText.isNotEmpty())
                    translations.set (originalText, newText);
            }
        }
        else if (line.startsWithIgnoreCase ("language:"))
        {
            languageName = line.substring (9).trim();
        }
        else if (line.startsWithIgnoreCase ("countries:"))
        {
            countryCodes.addTokens (line.substring (10).trim(), true);
            countryCodes.trim();
            countryCodes.removeEmptyStrings();
        }
    }

    translations.minimiseStorageOverheads();
}

void LocalisedStrings::addStrings (const LocalisedStrings& other)
{
    jassert (languageName == other.languageName);
    jassert (countryCodes == other.countryCodes);

    translations.addArray (other.translations);
}

void LocalisedStrings::setFallback (LocalisedStrings* f)
{
    fallback = f;
}

void LocalisedStrings::setCurrentMappings (LocalisedStrings* newTranslations)
{
    const SpinLock::ScopedLockType sl (currentMappingsLock);
    currentMappings = newTranslations;
}

LocalisedStrings* LocalisedStrings::getCurrentMappings()
{
    return currentMappings;
}

String LocalisedStrings::translateWithCurrentMappings (const String& text)  { return juce::translate (text); }
String LocalisedStrings::translateWithCurrentMappings (const char* text)    { return juce::translate (text); }

JUCE_API String translate (const String& text)       { return juce::translate (text, text); }
JUCE_API String translate (const char* text)         { return juce::translate (String (text)); }
JUCE_API String translate (CharPointer_UTF8 text)    { return juce::translate (String (text)); }

JUCE_API String translate (const String& text, const String& resultIfNotFound)
{
    const SpinLock::ScopedLockType sl (currentMappingsLock);

    if (const LocalisedStrings* const mappings = LocalisedStrings::getCurrentMappings())
        return mappings->translate (text, resultIfNotFound);

    return resultIfNotFound;
}


/*
  ==============================================================================

   This file is part of the juce_core module of the JUCE library.

   ------------------------------------------------------------------------------

   using any other modules, be sure to check that you also comply with their license.

   For more details, visit www.juce.com

  ==============================================================================
*/

LocalisedStrings::LocalisedStrings (const String& fileContents, bool ignoreCase)
{
    loadFromText (fileContents, ignoreCase);
}

LocalisedStrings::LocalisedStrings (const File& fileToLoad, bool ignoreCase)
{
    loadFromText (f

}

LocalisedStrings::LocalisedStrings (const LocalisedStrings& other)
    : languageName (other.languageName), countryCodes (other.countryCodes),
      translations (other.translations), fallback (createCopyIfNotNull (other.fallback.get()))
{
}

LocalisedStrings& LocalisedStrings::operator= (const LocalisedStrings& other)
{
    languageName = other.languageName;
    countryCodes = other.countryCodes;
    translations = other.translations;
    fallback = createCopyIfNotNull (other.fallback.get());
    return *this;
}

LocalisedStrings::~LocalisedStrings()
{
}

String LocalisedStrings::translate (const String& text) const
{
    if (fallback != nullptr && ! translations.containsKey (text))
        return fallback->translate (text);

    return translations.getValue (text, text);
}

String LocalisedStrings::translate (const String& text, const String& resultIfNotFound) const
{
    if (fallback != nullptr && ! translations.containsKey (text))
        return fallback->translate (text, resultIfNotFound);

    return translations.getValue (text, resultIfNotFound);
}

namespace
{
   #if JUCE_CHECK_MEMORY_LEAKS
    // By using this object to force a LocalisedStrings object to be created
    // before the currentMappings object, we can force the static order-of-destruction to
    // delete the currentMappings object first, which avoids a bogus leak warning.
    // (Oddly, just creating a LocalisedStrings on the stack doesn't work in gcc, it
    // has to be created with 'new' for this to work..)
    struct LeakAvoidanceTrick
    {
        LeakAvoidanceTrick()
        {
            const ScopedPointer<LocalisedStrings> dummy (new LocalisedStrings (String(), false));
        }
    };

    LeakAvoidanceTrick leakAvoidanceTrick;
   #endif

    SpinLock currentMappingsLock;
    ScopedPointer<LocalisedStrings> currentMappings;

    static int findCloseQuote (const String& text, int startPos)
    {
        juce_wchar lastChar = 0;
        String::CharPointerType t (text.getCharPointer() + startPos);

        for (;;)
        {
            const juce_wchar c = t.getAndAdvance();

            if (c == 0 || (c == '"' && lastChar != '\\'))
                break;

            lastChar = c;
            ++startPos;
        }

        return startPos;
    }

    static String unescapeString (const String& s)
    {
        return s.replace ("\\\"", "\"")
                .replace ("\\\'", "\'")
                .replace ("\\t", "\t")
                .replace ("\\r", "\r")
                .replace ("\\n", "\n");
    }
}

void LocalisedStrings::loadFromText (const String& fileContents, bool ignoreCase)
{
    translations.setIgnoresCase (ignoreCase);

    StringArray lines;
    lines.addLines (fileContents);

    for (int i = 0; i < lines.size(); ++i)
    {
        String line (lines[i].trim());

        if (line.startsWithChar ('"'))
        {
            int closeQuote = findCloseQuote (line, 1);

            const String originalText (unescapeString (line.substring (1, closeQuote)));

            if (originalText.isNotEmpty())
            {
                const int openingQuote = findCloseQuote (line, closeQuote + 1);
                closeQuote = findCloseQuote (line, openingQuote + 1);

                const String newText (unescapeString (line.substring (openingQuote + 1, closeQuote)));

                if (newText.isNotEmpty())
                    translations.set (originalText, newText);
            }
        }
        else if (line.startsWithIgnoreCase ("language:"))
        {
            languageName = line.substring (9).trim();
        }
        else if (line.startsWithIgnoreCase ("countries:"))
        {
            countryCodes.addTokens (line.substring (10).trim(), true);
            countryCodes.trim();
            countryCodes.removeEmptyStrings();
        }
    }

    translations.minimiseStorageOverheads();
}

void LocalisedStrings::addStrings (const LocalisedStrings& other)
{
    jassert (languageName == other.languageName);
    jassert (countryCodes == other.countryCodes);

    translations.addArray (other.translations);
}

void LocalisedStrings::setFallback (LocalisedStrings* f)
{
    fallback = f;
}

void LocalisedStrings::setCurrentMappings (LocalisedStrings* newTranslations)
{
    const SpinLock::ScopedLockType sl (currentMappingsLock);
    currentMappings = newTranslations;
}

LocalisedStrings* LocalisedStrings::getCurrentMappings()
{
    return currentMappings;
}

String LocalisedStrings::translateWithCurrentMappings (const String& text)  { return juce::translate (text); }
String LocalisedStrings::translateWithCurrentMappings (const char* text)    { return juce::translate (text); }

JUCE_API String translate (const String& text)       { return juce::translate (text, text); }
JUCE_API String translate (const char* text)         { return juce::translate (String (text)); }
JUCE_API String translate (CharPointer_UTF8 text)    { return juce::translate (String (text)); }

JUCE_API String translate (const String& text, const String& resultIfNotFound)
{
    const SpinLock::ScopedLockType sl (currentMappingsLock);

    if (const LocalisedStrings* const mappings = LocalisedStrings::getCurrentMappings())
        return mappings->translate (text, resultIfNotFound);

    return resultIfNotFound;
}


LocalisedStrings::LocalisedStrings (const String& fileContents, bool ignoreCase)
{
    loadFromText (fileContents, ignoreCase);
}

LocalisedStrings::LocalisedStrings (const File& fileToLoad, bool ignoreCase)
{
    loadFromText (fileToLoad.loadFileAsString(), ignoreCase);
}

LocalisedStrings::LocalisedStrings (const LocalisedStrings& other)
    : languageName (other.languageName), countryCodes (other.countryCodes),
      translations (other.translations), fallback (createCopyIfNotNull (other.fallback.get()))
{
}

LocalisedStrings& LocalisedStrings::operator= (const LocalisedStrings& other)
{
    languageName = other.languageName;
    countryCodes = other.countryCodes;
    translations = other.translations;
    fallback = createCopyIfNotNull (other.fallback.get());
    return *this;
}

LocalisedStrings::~LocalisedStrings()
{
}

String LocalisedStrings::translate (const String& text) const
{
    if (fallback != nullptr && ! translations.containsKey (text))
        return fallback->translate (text);

    return translations.getValue (text, text);
}

String LocalisedStrings::translate (const String& text, const String& resultIfNotFound) const
{
    if (fallback != nullptr && ! translations.containsKey (text))
        return fallback->translate (text, resultIfNotFound);

    return translations.getValue (text, resultIfNotFound);
}

namespace
{
   #if JUCE_CHECK_MEMORY_LEAKS
    // By using this object to force a LocalisedStrings object to be created
    // before the currentMappings object, we can force the static order-of-destruction to
    // delete the currentMappings object first, which avoids a bogus leak warning.
    // (Oddly, just creating a LocalisedStrings on the stack doesn't work in gcc, it
    // has to be created with 'new' for this to work..)
    struct LeakAvoidanceTrick
    {
        LeakAvoidanceTrick()
        {
            const ScopedPointer<LocalisedStrings> dummy (new LocalisedStrings (String(), false));
        }
    };

    LeakAvoidanceTrick leakAvoidanceTrick;
   #endif

    SpinLock currentMappingsLock;
    ScopedPointer<LocalisedStrings> currentMappings;

    static int findCloseQuote (const String& text, int startPos)
    {
        juce_wchar lastChar = 0;
        String::CharPointerType t (text.getCharPointer() + startPos);

        for (;;)
        {
            const juce_wchar c = t.getAndAdvance();

            if (c == 0 || (c == '"' && lastChar != '\\'))
                break;

            lastChar = c;
            ++startPos;
        }

        return startPos;
    }

    static String unescapeString (const String& s)
    {
        return s.replace ("\\\"", "\"")
                .replace ("\\\'", "\'")
                .replace ("\\t", "\t")
                .replace ("\\r", "\r")
                .replace ("\\n", "\n");
    }
}

void LocalisedStrings::loadFromText (const String& fileContents, bool ignoreCase)
{
    translations.setIgnoresCase (ignoreCase);

    StringArray lines;
    lines.addLines (fileContents);

    for (int i = 0; i < lines.size(); ++i)
    {
        String line (lines[i].trim());

        if (line.startsWithChar ('"'))
        {
            int closeQuote = findCloseQuote (line, 1);

            const String originalText (unescapeString (line.substring (1, closeQuote)));

            if (originalText.isNotEmpty())
            {
                const int openingQuote = findCloseQuote (line, closeQuote + 1);
                closeQuote = findCloseQuote (line, openingQuote + 1);

                const String newText (unescapeString (line.substring (openingQuote + 1, closeQuote)));

                if (newText.isNotEmpty())
                    translations.set (originalText, newText);
            }
        }
        else if (line.startsWithIgnoreCase ("language:"))
        {
            languageName = line.substring (9).trim();
        }
        else if (line.startsWithIgnoreCase ("countries:"))
        {
            countryCodes.addTokens (line.substring (10).trim(), true);
            countryCodes.trim();
            countryCodes.removeEmptyStrings();
        }
    }

    translations.minimiseStorageOverheads();
}

void LocalisedStrings::addStrings (const LocalisedStrings& other)
{
    jassert (languageName == other.languageName);
    jassert (countryCodes == other.countryCodes);

    translations.addArray (other.translations);
}

void LocalisedStrings::setFallback (LocalisedStrings* f)
{
    fallback = f;
}

void LocalisedStrings::setCurrentMappings (LocalisedStrings* newTranslations)
{
    const SpinLock::ScopedLockType sl (currentMappingsLock);
    currentMappings = newTranslations;
}

LocalisedStrings* LocalisedStrings::getCurrentMappings()
{
    return currentMappings;
}

String LocalisedStrings::translateWithCurrentMappings (const String& text)  { return juce::translate (text); }
String LocalisedStrings::translateWithCurrentMappings (const char* text)    { return juce::translate (text); }

JUCE_API String translate (const String& text)       { return juce::translate (text, text); }
JUCE_API String translate (const char* text)         { return juce::translate (String (text)); }
JUCE_API String translate (CharPointer_UTF8 text)    { return juce::translate (String (text)); }

JUCE_API String translate (const String& text, const String& resultIfNotFound)
{
    const SpinLock::ScopedLockType sl (currentMappingsLock);

    if (const LocalisedStrings* const mappings = LocalisedStrings::getCurrentMappings())
        return mappings->translate (text, resultIfNotFound);

    return resultIfNotFound;
}


/*
 *
 * All source code herein is the property of Volition, Inc. You may not sell
 * or otherwise commercially exploit the source or things you created based on the
 * source.
 *
*/

#include "anim/animplay.h"
#include "anim/packunpack.h"
#include "cmdline/cmdline.h"
#include "ddsutils/ddsutils.h"
#include "globalincs/systemvars.h"
#include "gropenglbmpman.h"
#include "gropenglstate.h"
#include "gropengltexture.h"
#include "jpgutils/jpgutils.h"
#include "pcxutils/pcxutils.h"
#include "pngutils/pngutils.h"
#include "tgautils/tgautils.h"

#define BMPMAN_INTERNAL
#include "bmpman/bm_internal.h"

{
	int size, levels = 0;

	size = MAX(w, h);

	while (size > 0) {
		size >>= 1;
		levels++;
	}

	return (levels > 1) ? levels : 1;
}

/**
 * Anything API specific to freeing bm data
 */
void gr_opengl_bm_free_data(bitmap_slot* slot, bool release)
{
	if ( release )
		 opengl_free_texture_slot( slot );

	if ( (slot->entry.type == BM_TYPE_RENDER_TARGET_STATIC) || (slot->entry.type == BM_TYPE_RENDER_TARGET_DYNAMIC) )
		opengl_kill_render_target( slot );
}

/**
 * API specifics for creating a user bitmap
 */
void gr_opengl_bm_create(bitmap_slot* /*entry*/)
{
}

/**
 * API specific init instructions
 */
void gr_opengl_bm_init(bitmap_slot* slot)
{
	slot->gr_info = new tcache_slot_opengl;
}

/**
 * Specific instructions for setting up the start of a page-in session
 */
void gr_opengl_bm_page_in_start()
{
	opengl_preload_init();
}

extern bool opengl_texture_slot_valid(int n, int handle);

void gr_opengl_bm_save_render_target(int handle)
{
	if ( Cmdline_no_fbo ) {
		return;
	}

	bitmap_entry *be = bm_get_entry(handle);
	bitmap *bmp = &be->bm;

	size_t rc = opengl_export_render_target( handle, bmp->w, bmp->h, (bmp->true_bpp == 32), be->num_mipmaps, (ubyte*)bmp->data );

	if (rc != be->mem_taken) {
		Int3();
		return;
	}

	dds_save_image(bmp->w, bmp->h, bmp->true_bpp, be->num_mipmaps, (ubyte*)bmp->data, (bmp->flags & BMP_FLAG_CUBEMAP));
}

int gr_opengl_bm_make_render_target(int handle, int *width, int *height, int *bpp, int *mm_lvl, int flags)
{
	if ( Cmdline_no_fbo ) {
		return 0;
	}

	if ( (flags & BMP_FLAG_CUBEMAP) && (*width != *height) ) {
		MIN(*width, *height) = MAX(*width, *height);
	}

	if ( opengl_make_render_target(handle, width, height, bpp, mm_lvl, flags) ) {
		return 1;
	}

	return 0;
}

int gr_opengl_bm_set_render_target(int n, int face)
{
	if ( Cmdline_no_fbo ) {
		return 0;
	}

	if (n == -1) {
		opengl_set_render_target(-1);
		return 1;
	}

	auto entry = bm_get_entry(n);

	int is_static = (entry->type == BM_TYPE_RENDER_TARGET_STATIC);

	if ( opengl_set_render_target(n, face, is_static) ) {
		return 1;
	}

	return 0;
}

bool gr_opengl_bm_data(int  /*n*/, bitmap*  /*bm*/)
{
	// Do nothing here
	return true;
}


{
	int size, levels = 0;

	size = MAX(w, h);

	while (size > 0) {
		size >>= 1;
		levels++;
	}

	return (levels > 1) ? levels : 1;
}

/*
 *
 * All source code herein is the property of Volition, Inc. You may not sell
 * or otherwise commercially exploit the source or things you created based on the
 * source.
 *
*/

#include "anim/animplay.h"
#include "anim/packunpack.h"
#include "cmdline/cmdline.h"
#include "ddsutils/ddsutils.h"
#include "globalincs/systemvars.h"
#include "gropenglbmpman.h"
#include "gropenglstate.h"
#include "gropengltexture.h"
#include "jpgutils/jpgutils.h"
#include "pcxutils/pcxutils.h"
#include "pngutils/pngutils.h"
#include "tgautils/tgautils.h"

#define BMPMAN_INTERNAL
#include "bmpman/bm_internal.h"

int get_num_mipmap_levels(int w, int h)

/**
 * Anything API specific to freeing bm data
 */
void gr_opengl_bm_free_data(bitmap_slot* slot, bool release)
{
	if ( release )
		 opengl_free_texture_slot( slot );

	if ( (slot->entry.type == BM_TYPE_RENDER_TARGET_STATIC) || (slot->entry.type == BM_TYPE_RENDER_TARGET_DYNAMIC) )
		opengl_kill_render_target( slot );
}

/**
 * API specifics for creating a user bitmap
 */
void gr_opengl_bm_create(bitmap_slot* /*entry*/)
{
}

/**
 * API specific init instructions
 */
void gr_opengl_bm_init(bitmap_slot* slot)
{
	slot->gr_info = new tcache_slot_opengl;
}

/**
 * Specific instructions for setting up the start of a page-in session
 */
void gr_opengl_bm_page_in_start()
{
	opengl_preload_init();
}

extern bool opengl_texture_slot_valid(int n, int handle);

void gr_opengl_bm_save_render_target(int handle)
{
	if ( Cmdline_no_fbo ) {
		return;
	}

	bitmap_entry *be = bm_get_entry(handle);
	bitmap *bmp = &be->bm;

	size_t rc = opengl_export_render_target( handle, bmp->w, bmp->h, (bmp->true_bpp == 32), be->num_mipmaps, (ubyte*)bmp->data );

	if (rc != be->mem_taken) {
		Int3();
		return;
	}

	dds_save_image(bmp->w, bmp->h, bmp->true_bpp, be->num_mipmaps, (ubyte*)bmp->data, (bmp->flags & BMP_FLAG_CUBEMAP));
}

int gr_opengl_bm_make_render_target(int handle, int *width, int *height, int *bpp, int *mm_lvl, int flags)
{
	if ( Cmdline_no_fbo ) {
		return 0;
	}

	if ( (flags & BMP_FLAG_CUBEMAP) && (*width != *height) ) {
		MIN(*width, *height) = MAX(*width, *height);
	}

	if ( opengl_make_render_target(handle, width, height, bpp, mm_lvl, flags) ) {
		return 1;
	}

	return 0;
}

int gr_opengl_bm_set_render_target(int n, int face)
{
	if ( Cmdline_no_fbo ) {
		return 0;
	}

	if (n == -1) {
		opengl_set_render_target(-1);
		return 1;
	}

	auto entry = bm_get_entry(n);

	int is_static = (entry->type == BM_TYPE_RENDER_TARGET_STATIC);

	if ( opengl_set_render_target(n, face, is_static) ) {
		return 1;
	}

	return 0;
}

bool gr_opengl_bm_data(int  /*n*/, bitmap*  /*bm*/)
{
	// Do nothing here
	return true;
}


/*
 *
 * All source code herein is the property of Volition, Inc. You may not sell
 * or otherwise commercially exploit the source or things you created based on the
 * source.
 *
*/

#include "anim/animplay.h"
#include "anim/packunpack.h"
#include "cmdline/cmdline.h"
#include "ddsutils/ddsutils.h"
#include "globalincs/systemvars.h"
#include "gropenglbmpman.h"
#include "gropenglstate.h"
#include "gropengltexture.h"
#include "jpgutils/jpgutils.h"
#include "pcxutils/pcxutils.h"
#include "pngutils/pngutils.h"
#include "tgautils/tgautils.h"

#define BMPMAN_INTERNAL
#include "bmpman/bm_internal.h"

int get_num_mipmap_levels(int w, int h)
{
	int size, levels = 0;

	size = MAX(w, h);

	while (size > 0) {
		size >>= 1;
		levels++;
	}

	return (levels > 1) ? levels : 1;
}

/**
 * Anything API specific to freeing bm data
 */
void gr_opengl_bm_free_data(bitmap_slot* slot, bool release)
{
	if ( release )
		 opengl_free_texture_slot( slot );

	if ( (slot->entry.type == BM_TYPE_RENDER_TARGET_STATIC) || (slot->entry.type == BM_TYPE_RENDER_TARGET_DYNAMIC) )
		opengl_kill_render_target( slot );
}

/**
 * API specifics for creating a user bitmap
 */
void gr_opengl_bm_create(bitmap_slot* /*entry*/)
{
}

/**
 * API specific init instructions
 */
void gr_opengl_bm_init(bitmap_slot* slot)
{
	slot->gr_info = new tcache_slot_opengl;
}

/**
 * Specific instructions for setting up the start of a page-in session
 */
void gr_opengl_bm_page_in_start()
{
	opengl_preload_init();
}

extern bool opengl_texture_slot_valid(int n, int handle);

void gr_opengl_bm_save_render_target(int handle)
{
	if ( Cmdline_no_fbo ) {
		return;
	}

	bitmap_entry *be = bm_get_entry(handle);
	bitmap *bmp = &be->bm;

	size_t rc = opengl_export_render_target( handle, bmp->w, bmp->h, (bmp->true_bpp == 32), be->num_mipmaps, (ubyte*)bmp->data );

	if (rc != be->mem_taken) {
		Int3();
		return;
	}

	dds_save_image(bmp->w, bmp->h, bmp->true_bpp, be->num_mipmaps, (ubyte*)bmp->data, (bmp->flags & BMP_FLAG_CUBEMAP));
}

int gr_opengl_bm_make_render_target(int handle, int *width, int *height, int *bpp, int *mm_lvl, int flags)
{
	if ( Cmdline_no_fbo ) {
		return 0;
	}

	if ( (flags & BMP_FLAG_CUBEMAP) && (*width != *height) ) {
		MIN(*width, *height) = MAX(*width, *height);
	}

	if ( opengl_make_render_target(handle, width, height, bpp, mm_lvl, flags) ) {
		return 1;
	}

	return 0;
}

int gr_opengl_bm_set_render_target(int n, int face)
{
	if ( Cmdline_no_fbo ) {
		return 0;
	}

	if (n == -1) {
		opengl_set_render_target(-1);
		return 1;
	}

	auto entry = bm_get_entry(n);

	int is_static = (entry->type == BM_TYPE_RENDER_TARGET_STATIC);

	if ( opengl_set_render_target(n, face, is_static) ) {
		return 1;
	}

	retur

}

bool gr_opengl_bm_data(int  /*n*/, bitmap*  /*bm*/)
{
	// Do nothing here
	return true;
}