#include <cstdint>
#include <fstream>
#include <iostream>
#include <vector>

#include <poplar/DeviceManager.hpp>
#include <poplar/Engine.hpp>
#include <poplar/Graph.hpp>
#include <poplar/Program.hpp>

int main(int argc, char **argv) try {
  if (argc != 2) {
    std::cerr << "usage: sdk_multi_host_read_oracle OUTPUT\n";
    return 2;
  }
  constexpr unsigned sourceTile = 514;
  constexpr unsigned firstTile = 111;
  constexpr unsigned secondTile = 1198;
  constexpr std::size_t words = 16;

  poplar::DeviceManager manager;
  auto devices = manager.getDevices(poplar::TargetType::IPU, 1);
  if (devices.empty() || !devices.front().attach())
    throw std::runtime_error("failed to attach one IPU");
  auto &device = devices.front();

  poplar::Graph graph(device.getTarget());
  auto source = graph.addVariable(poplar::UNSIGNED_INT, {words}, "source");
  auto first = graph.addVariable(poplar::UNSIGNED_INT, {words}, "first");
  auto second = graph.addVariable(poplar::UNSIGNED_INT, {words}, "second");
  graph.setTileMapping(source, sourceTile);
  graph.setTileMapping(first, firstTile);
  graph.setTileMapping(second, secondTile);
  graph.createHostWrite("source-write", source);
  graph.createHostRead("first-read", first);
  graph.createHostRead("second-read", second);

  poplar::program::Sequence program;
  program.add(poplar::program::Copy(source, first));
  program.add(poplar::program::Copy(source, second));
  poplar::OptionFlags options;
  options.set("debug.printHostExchangeSchedule", "0,111,514,1198");
  options.set("debug.dumpHostExchangePackets", "true");
  poplar::Engine engine(graph, program, options);
  std::ofstream output(argv[1], std::ios::binary);
  if (!output)
    throw std::runtime_error("cannot create output");
  engine.serializeExecutable(output);
  std::cout << "source=" << sourceTile << " destinations=" << firstTile << ','
            << secondTile << " words=" << words << '\n';
  return 0;
} catch (const std::exception &error) {
  std::cerr << "sdk_multi_host_read_oracle: " << error.what() << '\n';
  return 1;
}
