#include <gmsh.h>
#include <set>
#include <iostream>

namespace factory = gmsh::model::geo;

int
main(int argc, char ** argv)
{
  gmsh::initialize();

  gmsh::option::setNumber("General.Terminal", 1);

  gmsh::model::add("square");

  double length = 2;
  double lc = .1;

  auto bottom_left_point = factory::addPoint(0, 0, 0, lc);
  auto bottom_right_point = factory::addPoint(length, 0, 0, lc);
  auto top_right_point = factory::addPoint(length, length, 0, lc);
  auto top_left_point = factory::addPoint(0, length, 0, lc);
  auto top = factory::addPoint(length / 2, length, 0, lc);
  auto bottom = factory::addPoint(length / 2, 0, 0, lc);

  // Generate the blocks

  auto right = factory::addLine(bottom_right_point, top_right_point);
  auto left = factory::addLine(top_left_point, bottom_left_point);

  auto bottom_left = factory::addLine(bottom_left_point, bottom);
  auto bottom_right = factory::addLine(bottom, bottom_right_point);
  auto top_left = factory::addLine(top, top_left_point);
  auto top_right = factory::addLine(top_right_point, top);

  auto left_interface = factory::addLine(bottom, top);
  auto right_interface = factory::addLine(top, bottom);

  auto left_curve_loop = factory::addCurveLoop({bottom_left, left_interface, top_left, left});
  auto left_surface = factory::addPlaneSurface({left_curve_loop});

  auto right_curve_loop = factory::addCurveLoop({bottom_right, right, top_right, right_interface});
  auto right_surface = factory::addPlaneSurface({right_curve_loop});

  // Add all the boundary ids and names

  size_t boundary_id_counter = 100;

  auto right_boundary_id = boundary_id_counter++;
  gmsh::model::addPhysicalGroup(1, {right}, right_boundary_id);
  gmsh::model::setPhysicalName(1, right_boundary_id, "right");

  auto left_boundary_id = boundary_id_counter++;
  gmsh::model::addPhysicalGroup(1, {left}, left_boundary_id);
  gmsh::model::setPhysicalName(1, left_boundary_id, "left");

  auto left_interface_boundary_id = boundary_id_counter++;
  gmsh::model::addPhysicalGroup(1, {left_interface}, left_interface_boundary_id);
  gmsh::model::setPhysicalName(1, left_interface_boundary_id, "master_interface");

  auto right_interface_boundary_id = boundary_id_counter++;
  gmsh::model::addPhysicalGroup(1, {right_interface}, right_interface_boundary_id);
  gmsh::model::setPhysicalName(1, right_interface_boundary_id, "slave_interface");

  // Add the subdomain ids and names

  size_t subdomain_id_counter = 10;

  auto left_subdomain_id = subdomain_id_counter++;
  gmsh::model::addPhysicalGroup(2, {left_surface}, left_subdomain_id);
  gmsh::model::setPhysicalName(2, left_subdomain_id, "left_block");

  auto right_subdomain_id = subdomain_id_counter++;
  gmsh::model::addPhysicalGroup(2, {right_surface}, right_subdomain_id);
  gmsh::model::setPhysicalName(2, right_subdomain_id, "right_block");

  factory::synchronize();

  gmsh::model::mesh::generate(2);

  gmsh::write("two-body.msh");

  gmsh::finalize();
  return 0;
}