#include "host_exchange_plan.hpp"

#include <iostream>
#include <stdexcept>

namespace {
void expect(hostxcode::PacketHeader actual, hostxcode::PacketHeader expected) {
  if (!(actual == expected))
    throw std::runtime_error("host packet encoding mismatch");
}
} // namespace

int main() try {
  using hostxcode::PacketHeader;
  expect(hostxcode::tileToHost(0, 0x40, 64),
         PacketHeader{0xa0000000, 0x00000011});
  expect(hostxcode::hostToTile(0, 0x50120, 0x40, 64),
         PacketHeader{0xec000209, 0x00000011});
  expect(hostxcode::tileToHost(0, 4, 4),
         PacketHeader{0x80000000, 0x00000011});
  expect(hostxcode::hostToTile(0, 0x50160, 4, 4),
         PacketHeader{0xcc00020b, 0x00000011});
  expect(hostxcode::hostToTile(0, 0x50120, 0x100, 256),
         PacketHeader{0xec000209, 0x00000044});
  expect(hostxcode::hostToTile(0, 0x50000, 0x400, 1024),
         PacketHeader{0xec000200, 0x00000100});
  expect(hostxcode::zeroByteRead(0, 0x50120),
         PacketHeader{0xcc000209, 0x00000000});

  // Logical tile 46 is physical tile 1409 on this C600. Both command words
  // carry its odd-tile bit; the remaining route value is physical >> 1.
  expect(hostxcode::tileToHost(1409, 0x40, 64),
         PacketHeader{0xa2c08000, 0x80000011});
  expect(hostxcode::hostToTile(1409, 0x50120, 0x40, 64),
         PacketHeader{0xeec08209, 0x80000011});

  bool rejected = false;
  try {
    (void)hostxcode::hostToTile(0, 0x50124, 0x40, 64);
  } catch (const std::invalid_argument &) {
    rejected = true;
  }
  if (!rejected)
    throw std::runtime_error("unaligned destination was accepted");
  rejected = false;
  try {
    (void)hostxcode::tileToHost(0x1000, 0x40, 64);
  } catch (const std::out_of_range &) {
    rejected = true;
  }
  if (!rejected)
    throw std::runtime_error("unencodable route was accepted");
  std::cout << "host_exchange_plan_tests: PASS\n";
  return 0;
} catch (const std::exception &error) {
  std::cerr << "host_exchange_plan_tests: " << error.what() << '\n';
  return 1;
}
