#include "farm_ng/calibration/visual_odometer.h"

#include <opencv2/highgui.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/video.hpp>

#include <Eigen/Geometry>

#include <ceres/ceres.h>

#include "farm_ng/blobstore.h"
#include "farm_ng/ipc.h"
#include "farm_ng/sophus_protobuf.h"

#include "farm_ng/calibration/camera_model.h"
#include "farm_ng/calibration/eigen_cv.h"
#include "farm_ng/calibration/kinematics.h"
#include "farm_ng/calibration/local_parameterization.h"

namespace farm_ng {
namespace {

void SavePly(std::string ply_path, const std::vector<Eigen::Vector3d>& points) {
  LOG(INFO) << ply_path << " npoints: " << points.size();
  std::ofstream out(ply_path);
  out << "ply\n";
  out << "format ascii 1.0\n";
  out << "element vertex " << points.size() << "\n";
  out << "property float x\n";
  out << "property float y\n";
  out << "property float z\n";
  out << "end_header\n";
  for (auto p : points) {
    out << float(p.x()) << " " << float(p.y()) << " " << float(p.z()) << "\n";
  }
  out.close();
}
struct ProjectionCostFunctor {
  ProjectionCostFunctor(const CameraModel& camera_model,
                        const Eigen::Vector2d& point_image)
      : camera_model_(camera_model), point_image_(point_image) {}

  template <class T>
  bool operator()(T const* const raw_camera_pose_world,
                  T const* const raw_point_world, T* raw_residuals) const {
    Eigen::Map<Sophus::SE3<T> const> const camera_pose_world(
        raw_camera_pose_world);

    Eigen::Map<Eigen::Matrix<T, 3, 1> const> const point_world(raw_point_world);
    Eigen::Map<Eigen::Matrix<T, 2, 1>> residuals(raw_residuals);
    residuals =
        ProjectPointToPixel<T>(camera_model_, camera_pose_world * point_world) -
        point_image_.cast<T>();
    return true;
  }
  const CameraModel& camera_model_;
  Eigen::Vector2d point_image_;
};

struct PoseCostFunctor {
  PoseCostFunctor(const Sophus::SE3d& camera_start_pose_camera_end)
      : camera_end_pose_camera_start_(camera_start_pose_camera_end.inverse()) {}

  template <class T>
  bool operator()(T const* const raw_camera_pose_world_start,
                  T const* const raw_camera_pose_world_end,
                  T* raw_residuals) const {
    Eigen::Map<Sophus::SE3<T> const> const camera_pose_world_start(
        raw_camera_pose_world_start);

    Eigen::Map<Sophus::SE3<T> const> const camera_pose_world_end(
        raw_camera_pose_world_end);

    auto camera_start_pose_camera_end_est =
        camera_pose_world_start * camera_pose_world_end.inverse();

    auto camera_end_pose_camera_end_est =
        camera_end_pose_camera_start_.cast<T>() *
        camera_start_pose_camera_end_est;

    Eigen::Map<Eigen::Matrix<T, 6, 1>> residuals(raw_residuals);
    residuals = T(100) * camera_end_pose_camera_end_est.log();
    return true;
  }
  Sophus::SE3d camera_end_pose_camera_start_;
};
}  // namespace
VisualOdometer::VisualOdometer(const CameraModel& camera_model,
                               const BaseToCameraModel& base_to_camera_model,
                               size_t max_history)
    : camera_model_(camera_model),
      flow_(camera_model, max_history),
      base_to_camera_model_(base_to_camera_model),
      odometry_pose_base_(Sophus::SE3d::rotX(0.0)) {
  ProtoToSophus(base_to_camera_model_.base_pose_camera().a_pose_b(),
                &base_pose_camera_);
}

void VisualOdometer::AddWheelMeasurements(
    const BaseToCameraModel::WheelMeasurement& measurements) {
  wheel_measurements_.insert(measurements);
}

VisualOdometerResult VisualOdometer::AddImage(
    cv::Mat image, google::protobuf::Timestamp stamp) {
  VisualOdometerResult result;
  if (const FlowImage* prev_flow_image = flow_.PreviousFlowImage()) {
    auto wheel_measurements =
        wheel_measurements_.find_range(prev_flow_image->stamp, stamp);

    Sophus::SE3d base_pose_basep = TractorStartPoseTractorEnd(
        base_to_camera_model_.wheel_radius(),
        base_to_camera_model_.wheel_baseline(), wheel_measurements.first,
        wheel_measurements.second);
    Sophus::SE3d odometry_pose_base_wheel_only =
        (base_pose_camera_ * prev_flow_image->camera_pose_world).inverse() *
        base_pose_basep;

    odometry_pose_base_ = odometry_pose_base_wheel_only;
    if ((true || base_pose_basep.log().norm() > 0.001) &&
        !wheel_measurements_.empty()) {
      auto start = MakeTimestampNow();

      flow_.AddImage(image, stamp,
                     odometry_pose_base_wheel_only * base_pose_camera_, true);
      debug_image_ = flow_.GetDebugImage();
      auto after_flow = MakeTimestampNow();

      SolvePose(true);
      odometry_pose_base_ =
          (base_pose_camera_ * flow_.PreviousFlowImage()->camera_pose_world)
              .inverse();

      wheel_measurements_.RemoveBefore(flow_.EarliestFlowImage()->stamp);
      auto after_solve = MakeTimestampNow();
      LOG_EVERY_N(INFO, 100)
          << "VO took: "
          << google::protobuf::util::TimeUtil::DurationToMilliseconds(
                 after_solve - start)
          << " ms flow: "
          << google::protobuf::util::TimeUtil::DurationToMilliseconds(
                 after_flow - start)
          << " ms solve: "
          << google::protobuf::util::TimeUtil::DurationToMilliseconds(
                 after_solve - after_flow);

      if (false && flow_.LastImageId() % 100 == 0) {
        DumpFlowPointsWorld("/tmp/flow_points_world." +
                            std::to_string(flow_.LastImageId()) + ".ply");
      }
    }

  } else {
    flow_.AddImage(image, stamp, odometry_pose_base_ * base_pose_camera_, true);
    debug_image_ = flow_.GetDebugImage();
  }

  if (goal_image_id_) {
    // TODO(ethanrublee) this is goal pose stuff here is a HACK, should be moved
    // somewhere else, tracking camera can produce some generic poses which can
    // be used for a variety of control and path following modes.
    //
    // Here the base_pose_goal is the start of the planned path (parameterized
    // as the x+ axis of this frame). For convenience downstream, we'll project
    // the tractor's goal (nearest point on this path + some reasonable
    // distance) onto this path.
    Sophus::SE3d base_pose_goal = base_pose_camera_ * camera_pose_base_goal_;
    // The path is the parameterized line passing through the origin of goal
    // frame and along the X axis.
    // This line is in the base frame.
    auto path_base = Eigen::ParametrizedLine<double, 3>::Through(
        base_pose_goal.translation(),
        base_pose_goal * Eigen::Vector3d(1.0, 0, 0));

    // Project the origin of the base frame onto the line, this is the closest
    // point on the path. Here we transform the point into the goal's reference
    // frame. We expect this point to be non zero in X, and zero in y,z as it
    // lies on the X-axis of the goal reference frame.
    Eigen::Vector3d closest_path_point_goal =
        base_pose_goal.inverse() *
        path_base.projection(Eigen::Vector3d(0, 0, 0));
    CHECK_NEAR(closest_path_point_goal.y(), 0.0, 1e-6);
    CHECK_NEAR(closest_path_point_goal.z(), 0.0, 1e-6);

    // Here we add 3 meters to the nearest point on the line.  Think of this
    // like a carrot on a stick hanging 3 meters front of the robot on the
    // planned path line.
    // NOTE this distance will effect the move to goal controller behavior.  If
    // its large, then the heading corrections will be less and the tractor will
    // gradually correct to get onto the path.  If its too small, the tractor
    // will pivot dramatically trying to stay on the line.

    Sophus::SE3d base_pose_goal_carrot =
        base_pose_goal *
        Sophus::SE3d::transX(closest_path_point_goal.x() + 10.0);
    SophusToProto(base_pose_goal_carrot,
                  result.base_pose_goal.mutable_a_pose_b());
    if (!debug_image_.empty()) {
      cv::circle(debug_image_,
                 EigenToCvPoint(ProjectPointToPixel(
                     camera_model_, base_pose_camera_.inverse() *
                                        base_pose_goal_carrot.translation())),
                 10, cv::Scalar(255, 0, 0), 3);
    }
  } else {
    SophusToProto(Sophus::SE3d::rotZ(0.0),
                  result.base_pose_goal.mutable_a_pose_b());
  }
  result.base_pose_goal.mutable_a_pose_b()->mutable_stamp()->CopyFrom(stamp);
  result.base_pose_goal.set_frame_a("tractor/base");
  result.base_pose_goal.set_frame_b("goal");

  SophusToProto(odometry_pose_base_,
                result.odometry_vo_pose_base.mutable_a_pose_b());
  result.odometry_vo_pose_base.mutable_a_pose_b()->mutable_stamp()->CopyFrom(
      stamp);
  result.odometry_vo_pose_base.set_frame_a("odometry/vo");
  result.odometry_vo_pose_base.set_frame_b("tractor/base");

  return result;
}

void VisualOdometer::AddFlowBlockToProblem(ceres::Problem* problem,
                                           const FlowBlock& flow_block) {
  ceres::CostFunction* cost_function1 =
      new ceres::AutoDiffCostFunction<ProjectionCostFunctor, 2,
                                      Sophus::SE3d::num_parameters, 3>(
          new ProjectionCostFunctor(
              camera_model_,
              flow_block.flow_point_image.point_image.cast<double>()));

  problem->AddParameterBlock(flow_block.flow_point_world->point_world.data(),
                             3);
  problem->AddResidualBlock(cost_function1, new ceres::CauchyLoss(2),
                            flow_block.flow_image->camera_pose_world.data(),
                            flow_block.flow_point_world->point_world.data());
}

void VisualOdometer::AddFlowImageToProblem(FlowImage* flow_image,
                                           ceres::Problem* problem,
                                           FlowBlocks* flow_blocks) {
  problem->AddParameterBlock(flow_image->camera_pose_world.data(),
                             Sophus::SE3d::num_parameters,
                             new LocalParameterizationSE3);

  for (const auto& id_flow_point : flow_image->flow_points) {
    const FlowPointImage& flow_point = id_flow_point.second;

    FlowPointWorld* flow_point_world =
        flow_.MutableFlowPointWorld(flow_point.id);
    if (flow_point_world->image_ids.size() < 5) {
      continue;
    }
    if (true) {  // flow_blocks->size() < 100 ||
                 // flow_blocks->count(flow_point_world->id)) {
      FlowBlock flow_block({flow_image, flow_point_world, flow_point});
      (*flow_blocks)[flow_point_world->id].push_back(flow_block);
      AddFlowBlockToProblem(problem, flow_block);
    }
  }
}
void VisualOdometer::SolvePose(bool debug) {
  ceres::Problem problem;

  std::set<uint64_t> flow_image_ids;
  FlowBlocks flow_blocks;
  {
    uint64_t image_id(flow_.LastImageId());
    if (image_id < 5) {
      return;
    }
    uint64_t begin_id =
        std::max(int(flow_.EarliestFlowImage()->id), int(image_id) - 50);
    flow_image_ids.insert(image_id);
    if (goal_image_id_) {
      if (int(image_id) - int(*goal_image_id_) < 50) {
        flow_image_ids.insert(*goal_image_id_);
      }
    }
    uint64_t skip = std::max(1, (int(image_id) - int(begin_id)) / 5);
    while (begin_id < image_id) {
      flow_image_ids.insert(begin_id);
      begin_id += skip;
    }
  }
  // debugging which images are used.
  if (false) {
    std::stringstream ss;
    for (auto id : flow_image_ids) {
      ss << " " << id;
    }
    LOG(INFO) << "Num images: " << flow_image_ids.size() << ss.str();
  }

  for (auto image_id : flow_image_ids) {
    FlowImage* flow_image = flow_.MutableFlowImage(image_id);
    AddFlowImageToProblem(flow_image, &problem, &flow_blocks);
  }

  for (auto start = flow_image_ids.begin(), end = ++flow_image_ids.begin();
       end != flow_image_ids.end(); ++start, ++end) {
    FlowImage* flow_image_start = flow_.MutableFlowImage(*start);
    FlowImage* flow_image_end = flow_.MutableFlowImage(*end);

    auto wheel_measurements = wheel_measurements_.find_range(
        flow_image_start->stamp, flow_image_end->stamp);
    VLOG(2) << std::distance(wheel_measurements.first,
                             wheel_measurements.second)
            << " Wheel measurements";

    Sophus::SE3d base_start_pose_base_end = TractorStartPoseTractorEnd(
        base_to_camera_model_.wheel_radius(),
        base_to_camera_model_.wheel_baseline(), wheel_measurements.first,
        wheel_measurements.second);

    Sophus::SE3d camera_start_pose_camera_end = base_pose_camera_.inverse() *
                                                base_start_pose_base_end *
                                                base_pose_camera_;
    ceres::CostFunction* cost_function1 =
        new ceres::AutoDiffCostFunction<PoseCostFunctor, 6,
                                        Sophus::SE3d::num_parameters,
                                        Sophus::SE3d::num_parameters>(
            new PoseCostFunctor(camera_start_pose_camera_end));

    problem.AddResidualBlock(cost_function1, new ceres::CauchyLoss(1.0),
                             flow_image_start->camera_pose_world.data(),
                             flow_image_end->camera_pose_world.data());
  }

  if (false && goal_image_id_ && flow_image_ids.count(*goal_image_id_)) {
    problem.SetParameterBlockConstant(
        flow_.MutableFlowImage(*goal_image_id_)->camera_pose_world.data());
  }

  // Set solver options (precision / method)
  ceres::Solver::Options options;
  // options.linear_solver_type = ceres::SPARSE_SCHUR;
  options.gradient_tolerance = 1e-4;
  options.function_tolerance = 1e-4;
  options.parameter_tolerance = 1e-4;
  // options.num_threads = 1;
  options.max_num_iterations = 30;

  // Solve
  ceres::Solver::Summary summary;
  //  options.logging_type = ceres::PER_MINIMIZER_ITERATION;
  options.minimizer_progress_to_stdout = false;
  ceres::Solve(options, &problem, &summary);
  LOG_EVERY_N(INFO, 100) << summary.BriefReport();
  if (!summary.IsSolutionUsable()) {
    LOG(INFO) << summary.FullReport();
  }

  double all_rmse = 0;
  double all_n = 0;
  for (auto id_blocks : flow_blocks) {
    uint64_t point_world_id = id_blocks.first;
    double rmse = 0;
    double n = 0;
    for (auto block : id_blocks.second) {
      Eigen::Vector3d point_camera = block.flow_image->camera_pose_world *
                                     block.flow_point_world->point_world;
      Eigen::Vector2d point_image_proj =
          ProjectPointToPixel(camera_model_, point_camera);

      if (point_camera.z() < 0) {
        flow_.RemoveBlock(block);
        continue;
      }

      if (point_camera.norm() > 5e2) {
        flow_.RemoveBlock(block);
        continue;
      }
      double err2 =
          (point_image_proj - block.flow_point_image.point_image.cast<double>())
              .squaredNorm();
      if (err2 > (4 * 4)) {
        flow_.RemoveBlock(block);
      } else {
        rmse += err2;
        n += 1;
      }
    }
    auto flow_point_world = flow_.MutableFlowPointWorld(point_world_id);
    if (flow_point_world->image_ids.size() < 5 ||
        flow_point_world->point_world.norm() > 1e3) {
      flow_.RemovePointWorld(point_world_id);
    } else {
      flow_.MutableFlowPointWorld(point_world_id)->rmse = std::sqrt(rmse / n);
      all_rmse += rmse;
      all_n += n;
    }
  }
  LOG_EVERY_N(INFO, 100) << "RMSE: "
                         << std::sqrt(all_rmse / std::max(all_n, 1.0))
                         << " N: " << all_n;

  FlowImage* flow_image = flow_.MutablePreviousFlowImage();

  if (goal_image_id_) {
    auto base_pose_world_goal =
        camera_pose_base_goal_.inverse() *
        flow_.MutableFlowImage(*goal_image_id_)->camera_pose_world;

    auto camera_pose_base_goal =
        flow_image->camera_pose_world * base_pose_world_goal.inverse();

    goal_image_id_ = flow_image->id;
    camera_pose_base_goal_ = camera_pose_base_goal;
  }

  if (debug) {
    cv::Mat reprojection_image = debug_image_;
    if (reprojection_image.empty()) {
      cv::cvtColor(*(flow_image->image), reprojection_image,
                   cv::COLOR_GRAY2BGR);
    }

    for (const auto& id_flow_point : flow_image->flow_points) {
      const auto& flow_point = id_flow_point.second;
      FlowPointWorld* flow_point_world =
          flow_.MutableFlowPointWorld(flow_point.id);
      if (flow_point_world->rmse == 0.0) {
        continue;
      }
      Eigen::Vector2d point_image_proj =
          ProjectPointToPixel(camera_model_, flow_image->camera_pose_world *
                                                 flow_point_world->point_world);
      cv::line(reprojection_image, EigenToCvPoint(flow_point.point_image),
               EigenToCvPoint(point_image_proj), flow_.Color(flow_point.id));

      cv::circle(reprojection_image, EigenToCvPoint(point_image_proj), 2,
                 flow_.Color(flow_point.id), -1);
      cv::circle(reprojection_image, EigenToCvPoint(flow_point.point_image), 5,
                 flow_.Color(flow_point.id));
    }
    if (goal_image_id_) {
      for (int i = 0; i < 1000; ++i) {
        Eigen::Vector3d p1 =
            camera_pose_base_goal_ * Eigen::Vector3d(0.1 * i, 0.0, 0.0);
        Eigen::Vector3d p2 =
            camera_pose_base_goal_ * Eigen::Vector3d(0.1 * (i + 1), 0.0, 0.0);
        if (p1.z() > 0.0 && p2.z() > 0.00) {
          cv::line(reprojection_image,
                   EigenToCvPoint(ProjectPointToPixel(camera_model_, p1)),
                   EigenToCvPoint(ProjectPointToPixel(camera_model_, p2)),
                   cv::Scalar(0, 255, 0), 3);
        }
      }
    }
    auto camera_pose_base = base_pose_camera_.inverse();
    for (int i = 0; i < 1000; ++i) {
      Eigen::Vector3d ap1 =
          camera_pose_base * Eigen::Vector3d(0.1 * i, 0.0, 0.0);
      Eigen::Vector3d ap2 =
          camera_pose_base * Eigen::Vector3d(0.1 * (i + 1), 0.0, 0.0);
      cv::line(reprojection_image,
               EigenToCvPoint(ProjectPointToPixel(camera_model_, ap1)),
               EigenToCvPoint(ProjectPointToPixel(camera_model_, ap2)),
               cv::Scalar(0, 0, 255), 1);
    }
    debug_image_ = reprojection_image;
  }
}

void VisualOdometer::DumpFlowPointsWorld(std::string ply_path) {
  std::vector<Eigen::Vector3d> points;
  for (auto it : flow_.FlowPointsWorld()) {
    if (it.second.image_ids.size() >= 5) {
      points.push_back(it.second.point_world);
    }
  }
  SavePly(ply_path, points);
}

void VisualOdometer::SetGoal() {
  if (flow_.LastImageId() < 10) {
    return;
  }
  goal_image_id_ = flow_.LastImageId();
  camera_pose_base_goal_ = base_pose_camera_.inverse();
}

void VisualOdometer::AdjustGoalAngle(double theta) {
  if (!goal_image_id_) {
    return;
  }
  camera_pose_base_goal_ = camera_pose_base_goal_ * Sophus::SE3d::rotZ(theta);
}

}  // namespace farm_ng


#include "pch.h"
#include "agent.h"
#include <stdlib.h>
#include <iostream>
#include <boost/geometry/algorithms/assign.hpp>
#include <SDL2_gfxPrimitives.h>
#include <boost/numeric/ublas/io.hpp>
#include "game_world.h"

using namespace std;
using namespace boost::geometry;
using namespace boost::numeric::ublas;

agent::agent()
{
	assign_values(position, (rand() % 300 + 1), (rand() % 300 + 1));
	model = new agent_model();
	is_active = false;
}

agent::~agent()
{
}

void wrap_around()
{
}

void agent::update_pos(float d)
{

	boost::numeric::ublas::vector<double> pos(position.x(), position.y());
	model->shape_matrix(0, 0) = pos[0] - 5;
	model->shape_matrix(0, 1) = pos[1] + 3;
	model->shape_matrix(1, 0) = pos[0] + 5;
	model->shape_matrix(1, 1) = pos[1] + 0.0;
	model->shape_matrix(2, 0) = pos[0] - 5;
	model->shape_matrix(2, 1) = pos[1] - 3;
}

void agent::update(float delta)
{
	if (!is_active) return;
	cout << "UPDATE!: " << delta << endl;
	update_pos(delta);
}

void agent::render(SDL_Renderer *renderer)
{
	if (!is_active) return;
	cout << "RENDER!" << model->shape_matrix;
	filledTrigonColor(renderer, model->shape_matrix(0, 0), model->shape_matrix(0, 1), model->shape_matrix(1, 0), model->shape_matrix(1, 1), model->shape_matrix(2, 0), model->shape_matrix(2, 1), 0xFF00FFFF);
}


#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE test_math
#include <boost/test/unit_test.hpp>

#include <ros/ros.h>
#include <geometry_utils/GeometryUtilsMath.h>

namespace gu = geometry_utils;
namespace gm = gu::math;

BOOST_AUTO_TEST_CASE(math) {
  srand(time(NULL));
  float rf = static_cast<float>(rand())/static_cast<float>(RAND_MAX);
  double rd = static_cast<double>(rand())/static_cast<double>(RAND_MAX);

  BOOST_CHECK_EQUAL(gm::cos<float>(rf), cosf(rf));
  BOOST_CHECK_EQUAL(gm::cos<float>(rf), gm::cos(rf));
  BOOST_CHECK_EQUAL(gm::cos<double>(rd), cos(rd));
  BOOST_CHECK_EQUAL(gm::cos<double>(rd), gm::cos(rd));

  BOOST_CHECK_EQUAL(gm::acos<float>(rf), acosf(rf));
  BOOST_CHECK_EQUAL(gm::acos<float>(rf), gm::acos(rf));
  BOOST_CHECK_EQUAL(gm::acos<double>(rd), acos(rd));
  BOOST_CHECK_EQUAL(gm::acos<double>(rd), gm::acos(rd));

  BOOST_CHECK_EQUAL(gm::sin<float>(rf), sinf(rf));
  BOOST_CHECK_EQUAL(gm::sin<float>(rf), gm::sin(rf));
  BOOST_CHECK_EQUAL(gm::sin<double>(rd), sin(rd));
  BOOST_CHECK_EQUAL(gm::sin<double>(rd), gm::sin(rd));

  BOOST_CHECK_EQUAL(gm::asin<float>(rf), asinf(rf));
  BOOST_CHECK_EQUAL(gm::asin<float>(rf), gm::asin(rf));
  BOOST_CHECK_EQUAL(gm::asin<double>(rd), asin(rd));
  BOOST_CHECK_EQUAL(gm::asin<double>(rd), gm::asin(rd));

  BOOST_CHECK_EQUAL(gm::tan<float>(rf), tanf(rf));
  BOOST_CHECK_EQUAL(gm::tan<float>(rf), gm::tan(rf));
  BOOST_CHECK_EQUAL(gm::tan<double>(rd), tan(rd));
  BOOST_CHECK_EQUAL(gm::tan<double>(rd), gm::tan(rd));

  BOOST_CHECK_EQUAL(gm::fabs<float>(rf), fabsf(rf));
  BOOST_CHECK_EQUAL(gm::fabs<float>(rf), gm::fabs(rf));
  BOOST_CHECK_EQUAL(gm::fabs<double>(rd), fabs(rd));
  BOOST_CHECK_EQUAL(gm::fabs<double>(rd), gm::fabs(rd));

  BOOST_CHECK_EQUAL(gm::sqrt<float>(rf), sqrtf(rf));
  BOOST_CHECK_EQUAL(gm::sqrt<float>(rf), gm::sqrt(rf));
  BOOST_CHECK_EQUAL(gm::sqrt<double>(rd), sqrt(rd));
  BOOST_CHECK_EQUAL(gm::sqrt<double>(rd), gm::sqrt(rd));

  float rf1 = static_cast<float>(rand())/static_cast<float>(RAND_MAX);
  float rf2 = static_cast<float>(rand())/static_cast<float>(RAND_MAX);
  double rd1 = static_cast<double>(rand())/static_cast<double>(RAND_MAX);
  double rd2 = static_cast<double>(rand())/static_cast<double>(RAND_MAX);

  BOOST_CHECK_EQUAL(gm::atan2<float>(rf1, rf2), atan2f(rf1, rf2));
  BOOST_CHECK_EQUAL(gm::atan2<float>(rf1, rf2), gm::atan2(rf1, rf2));
  BOOST_CHECK_EQUAL(gm::atan2<double>(rd1, rd2), atan2(rd1, rd2));
  BOOST_CHECK_EQUAL(gm::atan2<double>(rd1, rd2), gm::atan2(rd1, rd2));

  BOOST_CHECK_EQUAL(gm::hypot<float>(rf1, rf2), hypotf(rf1, rf2));
  BOOST_CHECK_EQUAL(gm::hypot<float>(rf1, rf2), gm::hypot(rf1, rf2));
  BOOST_CHECK_EQUAL(gm::hypot<double>(rd1, rd2), hypot(rd1, rd2));
  BOOST_CHECK_EQUAL(gm::hypot<double>(rd1, rd2), gm::hypot(rd1, rd2));
}


// Copyright (c) 2014 The Pebblecoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <cassert>

#include <boost/multiprecision/cpp_int.hpp>

#include "contract_grading.h"

namespace cryptonote
{
  uint64_t grade_amount(uint64_t full_amount, uint32_t grade, uint32_t fee_scale)
  {
    assert(grade <= GRADE_SCALE_MAX);
    assert(fee_scale <= GRADE_SCALE_MAX);

    // amount_left will be rounded down
    boost::multiprecision::uint128_t graded_amount = full_amount;
    graded_amount *= grade;
    graded_amount /= GRADE_SCALE_MAX;
    assert(graded_amount == (uint64_t)graded_amount);

    // calculate fee
    boost::multiprecision::uint128_t fee = graded_amount;
    fee *= fee_scale;
    fee /= GRADE_SCALE_MAX;
    assert(fee == (uint64_t)fee);
    // round fee taken up to prevent coins from being created via fee rounding
    while (fee_scale > 0 && fee * GRADE_SCALE_MAX / fee_scale < graded_amount)
    {
      fee += 1;
    }
    assert(fee <= graded_amount);

    boost::multiprecision::uint128_t amount_left = graded_amount - fee;
    assert(amount_left == amount_left.convert_to<uint64_t>());
    return amount_left.convert_to<uint64_t>();
  }

  uint64_t grade_contract_amount(uint64_t contract_amount, uint32_t grade, uint32_t fee_scale)
  {
    // coins resolve to the grade
    return grade_amount(contract_amount, grade, fee_scale);
  }

  uint64_t grade_backing_amount(uint64_t locked_amount, uint32_t grade, uint32_t fee_scale)
  {
    // the backing coins resolve to the other side of the contract
    assert(grade <= GRADE_SCALE_MAX);
    return grade_amount(locked_amount, GRADE_SCALE_MAX - grade, fee_scale);
  }

  uint64_t calculate_total_fee(uint64_t total_contract_coins, uint32_t fee_scale)
  {
    assert(fee_scale <= GRADE_SCALE_MAX);

    // round fee reward down
    boost::multiprecision::uint128_t fee = total_contract_coins;
    fee *= fee_scale;
    fee /= GRADE_SCALE_MAX;
    assert(fee == fee.convert_to<uint64_t>());

    return fee.convert_to<uint64_t>();
  }
}


#ifndef __COMMON_HPP__
#define __COMMON_HPP__

/******************************
      Author: Joel Veness
        Date: 2011
******************************/

#include <vector>
#include <cmath>

// boost includes
#include <boost/cstdint.hpp>
#include <boost/dynamic_bitset.hpp>

#include "Neighbours.hpp"

// define a bit type
typedef uint8_t bit_t;

// stores symbol occurrence counts
typedef float count_t;

// holds context weights
typedef double weight_t;

// describe a binary context
typedef std::vector<bit_t> context_t;

// describe a binary history
typedef Neighbours history_t;

/* given log(x) and log(y), compute log(x+y). uses the following identity:
   log(x + y) = log(x) + log(1 + y/x) = log(x) + log(1+exp(log(y)-log(x)))*/
inline double logAdd(double log_x, double log_y) {

    // ensure log_y >= log_x, can save some expensive log/exp calls
    if (log_x > log_y) {
        double t = log_x; log_x = log_y; log_y = t;
    }

    // only replace log(1+exp(log(y)-log(x))) with log(y)-log(x)
    // if the the difference is small enough to be meaningful
    double tmp = log_y - log_x;

    if (tmp < 100.0) {
        return std::log(1.0 + std::exp(tmp)) + log_x;
    } else {
        return log_y;
    }
}

// compressor interface
class Compressor {

    public:

        virtual ~Compressor() {}

        // the probability of seeing a particular symbol next
        virtual double prob(bit_t b) = 0;

        // the logarithm of the probability of all processed experience
        virtual double logBlockProbability() const = 0;

        // process a new piece of sensory experience
        virtual void update(bit_t b) = 0;

        // file extension
        virtual const char *fileExtension() const = 0;
};

#endif // __COMMON_HPP__


// Copyright (c) 2008-2016 Emil Dotchevski and Reverge Studios, Inc.

// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifndef UUID_3DCF6B90AE0E11DE9A315BE555D89593
#define UUID_3DCF6B90AE0E11DE9A315BE555D89593

#include <boost/qvm/inline.hpp>
#include <boost/qvm/mat_traits_array.hpp>
#include <boost/qvm/static_assert.hpp>

namespace boost {
namespace qvm {
namespace qvm_detail {
template <int N> struct det_size {};

template <class M>
BOOST_QVM_INLINE_TRIVIAL typename mat_traits<M>::scalar_type
determinant_impl_(M const &a, det_size<2>) {
  return mat_traits<M>::template read_element<0, 0>(a) *
             mat_traits<M>::template read_element<1, 1>(a) -
         mat_traits<M>::template read_element<1, 0>(a) *
             mat_traits<M>::template read_element<0, 1>(a);
}

template <class M, int N>
BOOST_QVM_INLINE_RECURSION typename mat_traits<M>::scalar_type
determinant_impl_(M const &a, det_size<N>) {
  typedef typename mat_traits<M>::scalar_type T;
  T m[N - 1][N - 1];
  T det = T(0);
  for (int j1 = 0; j1 != N; ++j1) {
    for (int i = 1; i != N; ++i) {
      int j2 = 0;
      for (int j = 0; j != N; ++j) {
        if (j == j1)
          continue;
        m[i - 1][j2] = mat_traits<M>::read_element_idx(i, j, a);
        ++j2;
      }
    }
    T d = determinant_impl_(m, det_size<N - 1>());
    if (j1 & 1)
      d = -d;
    det += mat_traits<M>::read_element_idx(0, j1, a) * d;
  }
  return det;
}

template <class M>
BOOST_QVM_INLINE_TRIVIAL typename mat_traits<M>::scalar_type
determinant_impl(M const &a) {
  BOOST_QVM_STATIC_ASSERT(mat_traits<M>::rows == mat_traits<M>::cols);
  return determinant_impl_(a, det_size<mat_traits<M>::rows>());
}
} // namespace qvm_detail
} // namespace qvm
} // namespace boost

#endif


/*
        Program is testing out a prototype for
        game tree solvers. Tick Tack Toe is
        especially nice as it's super simple,
        but has some interesting characteristsics
           - Game tree has many nodes
             which are invarant, ie one
             node can be represented by
             a rotation or mirror of
             another node, which means
             can have a system which "merges"
             nodes
           - We know a-prori that their is
             a solved solution, which we
             can visually check
           - We can create the static game
             tree, not need to worry about
             the complexity

        One thing to consider with these sorts
        or designs, is that we done want to
        have redendant data,

        <start> -- (0,0) -- (1,1) -- ...
                \- (1,0)
                ...
                \- (3,3) -- (1,1)

        Once we have this static game tree, we
        can then work backwards to figure
        out of an optmial strategy

 */

#include <iostream>
#include <tuple>
#include <map>
#include <cassert>
#include <sstream>
#include <random>
#include <algorithm>
#include <vector>
#include <set>
#include <bitset>
#include <boost/lexical_cast.hpp>

#define PRINT(X) do{ std::cout << #X << " = " << ( X ) << "\n"; }while(0)

/*
        Hero villian is arbitary,
        just convention, with Hero
        begin player who does the first
        move
 */
enum Player{
        Player_NotAPlayer,
        Player_Hero,         // first
        Player_Villian       // second
};
inline char PlayerToken(Player p){
        switch (p) {
        case Player_NotAPlayer:
                return ' ';
        case Player_Hero:
                return 'X';
        case Player_Villian:
                return 'O';
        }
}

template<class To, class From>
inline To Cast(From ptr){
        //PRINT( ptr->GetType() );
        //PRINT( std::remove_pointer_t<To>::__type__() );
        if( ptr->GetType() == std::remove_pointer_t<To>::__type__())
                return reinterpret_cast<To>(ptr);
        std::stringstream fmt;
        fmt << "casting " << ptr->GetType() << " to " << std::remove_pointer_t<To>::__type__();
        throw std::domain_error(fmt.str());
}

enum Eval{
        Eval_Win   = 0x01,
        Eval_Draw  = 0x02,
        Eval_Lose  = 0x04,
};
std::string EvalToString(Eval e) {
        switch (e) {
        case Eval_Win:
                return "Eval_Win";
        case Eval_Draw:
                return "Eval_Draw";
        case Eval_Lose:
                return "Eval_Lose";
        }
}

namespace Detail{
        struct PictureBox{
                PictureBox(){
                        lines_.emplace_back();
                }
                void NewLine(){
                        lines_.emplace_back();
                }
                void Append(std::string const& s){
                        lines_.back() += s;
                }
                void Append(char c){
                        lines_.back() += c;
                }
                void Display(){
                        for( size_t i=lines_.size();i!=0;){
                                --i;
                                std::cout << lines_[i] << "\n";
                        }
                }
                PictureBox& operator+=(PictureBox const& that){
                       for(; lines_.size() < that.lines_.size();)
                              NewLine();
                       for(size_t i=0;i!=std::min(lines_.size(), that.lines_.size());++i){
                               lines_[i] += that.lines_[i];
                       }
                       return *this;
                }
                static PictureBox Make(std::string const& s){
                        PictureBox result;
                        for( char c : s){
                                switch(c){
                                case '\n':
                                        result.NewLine();
                                        break;
                                default:
                                        result.Append(c);
                                        break;
                                }
                        }
                        return std::move(result);
                }
        private:
                std::vector<std::string> lines_;
        };
} // Detail

struct Board{
        /*
                For each pair of bits, we have

                +----+-----------+
                |Mask|    Data   |
                +----+-----------+
                | 00 | NotAPlayer|
                | 01 |  Hero     |
                | 10 | Villian   |
                +----+-----------+
         */
        Player GetTile(int x, int y)const{
                auto offset = Map_(x,y);
                return static_cast<Player>(( mask_ & ( 0x3 << offset ) ) >> offset);
        }
        void SetTile(int x, int y, Player p){
                assert( GetTile(x,y) == 0 && "Tile already set");
                auto offset = Map_(x,y);
                mask_ |= ( p << offset );
                assert( GetTile(x,y) == p  && "post condition failed");
        }

        friend std::ostream& operator<<(std::ostream& ostr, Board const& board){
                static const char* lineBreak = "+---+---+---+";
                for(int y=3;y!=0;){
                        --y;

                        if( y == 2 ){
                                ostr << lineBreak << "\n";
                        }

                        for(int x=0;x!=3;++x){
                                ostr << "| " << PlayerToken(board.GetTile(x,y)) << " ";
                                if( x == 2 )
                                        ostr << "|\n";
                        }
                        ostr << lineBreak;
                        if( y != 0 )
                                ostr << "\n";
                }
                return ostr;
        }
        std::string ToString()const{
                std::stringstream sstr;
                sstr << *this;
                return sstr.str();
        }
        auto GetMask()const{ return mask_; }

        auto GetInvariant()const{
                /*
                        a b c
                        d e f
                        g h i
                 */
                auto a = 0;
                auto b = 1;
                auto c = 2;
                auto d = 3;
                auto e = 4;
                auto f = 5;
                auto g = 6;
                auto h = 7;
                auto i = 8;

                std::vector<std::vector<int> > perms = {
                        /*
                        Normal Case (Rotate 0)
                         */
                        { a, b, c,
                          d, e, f,
                          g, h, i },
                        /*
                        Rotate 90
                         */
                        {  g, d, a,
                           h, e, b,
                           i, f, c },

                        /*
                        Rotate 180
                         */
                        {  i, h, g,
                           f, e, d,
                           c, b, a },
                        /*
                        Rotate 270
                         */
                        {  c, f, i,
                           b, e, h,
                           a, d, g },
                        /*
                        Mirror Above
                         */
                        {  g, h, i,
                           d, e, f,
                           a, b, c },

                        /*
                        Mirror Center
                         */
                        {  c, b, a,
                           f, e, d,
                           i, h, g }
                };

                std::vector<std::uint32_t> masks;
                for( auto const& p : perms ){
                        static std::vector<std::pair<int, int> > cord = {
                                { 0, 0},
                                { 1, 0},
                                { 2, 0},
                                { 0, 1},
                                { 1, 1},
                                { 2, 1},
                                { 0, 2},
                                { 1, 2},
                                { 2, 2}
                        };
                        Board aux;
                        for(size_t idx=0;idx!=9;++idx){
                                auto tok = GetTile(cord[idx].first, cord[idx].second);
                                aux.SetTile(cord[p[idx]].first, cord[p[idx]].second, tok);
                        }
                        masks.push_back(aux.GetMask());
                }
                return *std::min_element(masks.begin(), masks.end());
        }
private:
        static int Map_(int x, int y){
                return 2 * ( x * 3 + y );
        }
        std::uint32_t mask_ = 0;
};

/*
        Only one thing in the context, whos turn is it
        Obviously the Board is part of the context,
        but we have 2-tuples
                (B,C),
        to represent this
*/

enum GameCtrl{
        GameCtrl_Continue,
        GameCtrl_HeroWins,
        GameCtrl_VillianWins,
        GameCtrl_Draw
};
const char* GameCtrlToString(GameCtrl e) {
        switch (e) {
        case GameCtrl_Continue:
                return "GameCtrl_Continue";
        case GameCtrl_HeroWins:
                return "GameCtrl_HeroWins";
        case GameCtrl_VillianWins:
                return "GameCtrl_VillianWins";
        case GameCtrl_Draw:
                return "GameCtrl_Draw";
        }
}

struct GameContext{
        explicit GameContext(Board board = Board{}):board_{std::move(board)}{}
        explicit GameContext(Player active):active_{active}{}
        auto const& GetBoard()const{ return board_; }
        auto& GetBoard(){ return board_; }
        auto ActivePlayer()const{ return active_; }
        char ActivePlayerToken()const{
                return ( ActivePlayer() == 0 ? 'x' : 'o' );
        }
        void NextPlayer(){
                switch(active_){
                case Player_Hero:
                        active_ = Player_Villian;
                        break;
                case Player_Villian:
                        active_ = Player_Hero;
                        break;
                // stop compiler warning
                case Player_NotAPlayer:
                        break;
                }
        }
        auto GetCtrl()const{ return ctrl_; }
        auto SetCtrl(GameCtrl ctrl){ ctrl_ = ctrl; }
        friend bool operator<(GameContext const& lp, GameContext const& rp){
                #if 1
                return std::make_tuple(lp.board_.GetInvariant(), lp.ctrl_, lp.active_ )
                     < std::make_tuple(rp.board_.GetInvariant(), rp.ctrl_, rp.active_ );
                #else
                return std::make_tuple(lp.board_.GetMask(), lp.ctrl_, lp.active_ )
                     < std::make_tuple(rp.board_.GetMask(), rp.ctrl_, rp.active_ );
                #endif
        }
private:
        Board board_;
        GameCtrl ctrl_{ GameCtrl_Continue };
        Player active_{ Player_Hero };
};

struct TickTackToeLogic{
        GameContext Next(GameContext ctx, size_t x, size_t y){
                assert( ctx.GetCtrl()  == GameCtrl_Continue && "precondition failed");
                assert( ctx.GetBoard().GetTile(x,y)    == 0          && "precondition failed");

                ctx.GetBoard().SetTile(x,y, ctx.ActivePlayer() );

                // First need to check to see if someone has made a line
                auto triple = [&](auto x0, auto y0,
                                 auto x1, auto y1,
                                 auto x2, auto y2){
                        auto tok = ctx.GetBoard().GetTile(x0, y0);
                        if( tok == Player_NotAPlayer )
                                return false;
                        return
                                tok == ctx.GetBoard().GetTile(x1,y1) &&
                                tok == ctx.GetBoard().GetTile(x2,y2);
                };

                static std::vector< std::vector<size_t> > protos =
                {
                        { 0, 0, 0, 1, 0, 2},
                        { 1, 0, 1, 1, 1, 2},
                        { 2, 0, 2, 1, 2, 2},
                        { 0, 0, 1, 0, 2, 0},
                        { 0, 1, 1, 1, 2, 1},
                        { 0, 2, 1, 2, 2, 2},
                        { 0, 0, 1, 1, 2, 2},
                        { 0, 2, 1, 1, 2, 0}
                };

                for( auto const& p : protos){
                        if( triple( p[0], p[1], p[2], p[3], p[4], p[5]) ){
                                if( ctx.GetBoard().GetTile(p[0], p[1]) == Player_Hero){
                                        ctx.SetCtrl( GameCtrl_HeroWins );
                                } else {
                                        ctx.SetCtrl( GameCtrl_VillianWins );
                                }
                                return std::move(ctx);
                        }
                }

                // If we get here, their isn't a winner
                auto is_full = [&](){
                        for( size_t i=0;i!=3;++i){
                                for( size_t j=0;j!=3;++j){
                                        if( ctx.GetBoard().GetTile(i,j) == 0 )
                                                return false;

                                }
                        }
                        return true;
                };

                if( is_full() )
                        ctx.SetCtrl( GameCtrl_Draw );
                else
                        ctx.NextPlayer();
                return std::move(ctx);
        }
};

struct Node{
        enum Type{
                Type_Choice,
                Type_Payoff
        };
public:
        Type GetType()const{ return type_; }
        GameContext const& GetContext()const{ return ctx_; }
protected:
        explicit Node(Type type, GameContext ctx):
                type_{type},
                ctx_{std::move(ctx)}
        {}
private:
        Type type_;
        GameContext ctx_;
};

struct ChoiceNode : Node{
        explicit ChoiceNode(GameContext ctx):
                Node{Type_Choice, std::move(ctx)}
        {}
        // only when Choice
        void RegisterChild(Node* ptr){
                next_.push_back(ptr);
        }
        auto NumChildren()const{
                return next_.size();
        }
        auto begin()const{ return next_.begin(); }
        auto end()const{ return next_.end(); }
        static Type __type__(){ return Type_Choice; }
private:
        std::vector<Node*> next_;
};

struct PayoffNode : Node{
        explicit PayoffNode(GameContext ctx, Eval eval):
                Node{Type_Payoff, std::move(ctx)}
                ,eval_{eval}
        {}
        auto GetPayoff()const{ return eval_; }
        static Type __type__(){ return Type_Payoff; }
private:
        Eval eval_;
};

// TODO, rather than create a new graph, use this
struct NodeReference{
private:
        Node* ptr_;
        std::vector<Node*> next_;
};

struct GameTree{
        GameTree(Node* root):root_{root}{
                Register(root);
        }
        void AppendTerminal(Node* ptr){
                terminals_.push_back(ptr);
        }
        auto GetRoot()const{
                return root_;
        }
        auto const& GetTerminals()const{ return terminals_; }
        void Register(Node* ptr){
                world_.emplace(ptr->GetContext(), ptr);
                aux_.push_back(ptr);
        }
        Node const* Lookup(GameContext const& ctx)const{
                auto iter = world_.find(ctx);
                if( iter == world_.end())
                        return nullptr;
                return iter->second;
        }
        auto begin()const{ return aux_.begin(); }
        auto end()const{ return aux_.end(); }
private:
        Node* root_;
        std::vector<Node*> terminals_;
        std::map< GameContext, Node* > world_;
        std::vector<Node*> aux_;
};

/*
        Idea here, is that when creating a board
        which is invariant to anoher already
        created, we can return the reference
 */
struct NodeFactory{
        std::pair<bool, Node*> Make(GameContext ctx){
                auto iter = world_.find(ctx);
                if( iter != world_.end() )
                        return std::make_pair(false, iter->second);

                Node* ptr = nullptr;
                switch(ctx.GetCtrl()){
                case GameCtrl_Continue:
                        ptr = new ChoiceNode{ctx};
                        break;
                case GameCtrl_HeroWins:
                        ptr = new PayoffNode{ctx, Eval_Win};
                        break;
                case GameCtrl_VillianWins:
                        ptr = new PayoffNode{ctx, Eval_Lose};
                        break;
                case GameCtrl_Draw:
                        ptr = new PayoffNode{ctx, Eval_Draw};
                        break;
                }
                world_.emplace(ctx, ptr);
                return std::make_pair(true, ptr);
        }

private:
        std::map< GameContext, Node* > world_;
};

/*
        this is used to abstrauct the construction of
        the game tree
*/
struct GameTreeBuilder{
        void Generate(GameTree& tree, ChoiceNode* parent, GameContext ctx){
                static TickTackToeLogic logic;
                for( int x=0;x!=3;++x){
                        for( int y=0;y!=3;++y){
                                if( ctx.GetBoard().GetTile(x,y) == 0 ){

                                        auto nextCtx = logic.Next(ctx, x,y);

                                        auto makeRet = fac_.Make(nextCtx);
                                        auto ptr = makeRet.second;
                                        if( makeRet.first){
                                                // New node

                                                // First time here
                                                tree.Register(ptr);

                                                switch(nextCtx.GetCtrl()){
                                                case GameCtrl_Continue:
                                                        Generate(tree, Cast<ChoiceNode*>(ptr), nextCtx);
                                                        break;
                                                case GameCtrl_HeroWins:
                                                case GameCtrl_VillianWins:
                                                case GameCtrl_Draw:
                                                        tree.AppendTerminal(ptr);
                                                        break;
                                                }
                                        }
                                        parent->RegisterChild(ptr);
                                }
                        }
                }
        }
        GameTree Make(GameContext ctx){
                auto ptr = new ChoiceNode{ctx};
                GameTree tree{ptr};
                // Assume board isn't finished
                Generate(tree, ptr, ctx);
                return std::move(tree);
        }
private:
        NodeFactory fac_;
};

void test0(){
        GameContext ctx;
        Board board;
        TickTackToeLogic logic;

        std::vector< std::tuple<int, int> > todo = {
                { 0, 0 },
                { 1, 1 },
                { 0, 1 },
                { 0, 2 },
                { 1, 2 },
                { 2, 0 }
        };

        for( auto const& m : todo ){
                ctx = logic.Next(ctx, std::get<0>(m), std::get<1>(m) );
                PRINT(GameCtrlToString(ctx.GetCtrl()));
                //std::cout << board;
        }

}

void DisplayImpl(std::vector<Node*> history){
        if( history.size() == 0 )
                return;
        auto target = history.back();
        size_t indent_width = ( history.size() - 1 ) * 17;
        Detail::PictureBox indent;
        for(size_t i=7;i!=0;){
                --i;
                indent.Append(std::string(indent_width, ' ') );
                if( i != 0 )
                        indent.NewLine();
        }

        if( history.back()->GetType() == Node::Type_Payoff ){
                static auto spacer = [](){
                        Detail::PictureBox proto;
                        proto.Append("    ");
                        proto.NewLine();
                        proto.Append("    ");
                        proto.NewLine();
                        proto.Append("    ");
                        proto.NewLine();
                        proto.Append(" => ");
                        proto.NewLine();
                        proto.Append("    ");
                        proto.NewLine();
                        proto.Append("    ");
                        proto.NewLine();
                        proto.Append("    ");
                        return std::move(proto);
                }();

                Detail::PictureBox picture;
                #if 0
                picture += indent;
                picture += Detail::PictureBox::Make( history.back()->GetContext().GetBoard().ToString() );
                #endif
                for( auto ptr : history){
                        picture += Detail::PictureBox::Make( ptr->GetContext().GetBoard().ToString() );
                        picture += spacer;

                }
                picture += spacer;

                Detail::PictureBox leaf;
                leaf.NewLine();
                leaf.NewLine();
                leaf.NewLine();
                leaf.Append("Payoff " + boost::lexical_cast<std::string>(Cast<PayoffNode*>(target)->GetPayoff()));

                picture += leaf;
                picture.Display();

        } else {
                #if 0
                Detail::PictureBox picture;
                picture += indent;
                picture += Detail::PictureBox::Make( history.back()->GetContext().GetBoard().ToString() );
                picture.Display();
                #endif
                for( auto ptr : *Cast<ChoiceNode*>(target)){
                        history.push_back(ptr);
                        DisplayImpl(history);
                        history.pop_back();

                }
        }

}
void Display(Node* ptr){
        std::vector<Node*> history = {ptr};
        DisplayImpl(history);
}

/*
        Need to iterate the game tree, and evaluate each node.
        For nodes where it's the player, need to decide
        which is the best move by backwards induction

        From a payoff node, We find the most recent move the
        player made, and mark is a Never.

        Idea here is that for every move we do, we try to
        take the move with is gurenteed a win, else we take
        the move with a either a win or draw (depending on opp),
        then we take move with is only draw, then we take move
        which is win or lose, then take move with is win lose draw

        Note that in the game theory sense of a strategy, we
        need a move for every possible board, so this includeds
        taking a move we know will lose, even though we won't get
        their following out path.

        On nodes where it's the opponents move, we basically
        assume that he is going to take the optimum move, if their
        is a move we can take, which results in a node with
 */

struct EvalMetric{
        struct Result{
                unsigned Mask()const{ return mask_; }
                auto begin()const{ return next_.begin(); }
                auto end()const{ return next_.end(); }
        private:
                friend struct EvalMetric;
                unsigned mask_;
                std::vector<Node const*> next_;
        };
        static std::unique_ptr<EvalMetric> MakeForHero(GameTree const& tree){
                auto ptr = std::make_unique<EvalMetric>();
                ptr->Populate_(Player_Hero, tree.GetRoot());
                return std::move(ptr);
        }
        auto const& operator()(GameContext const& ctx)const{
                auto iter = eval_.find(ctx);
                if( iter == eval_.end()){
                        throw std::domain_error("not in tree");
                }
                return iter->second;
        }
private:

        unsigned Populate_(Player p, Node const* node){
                auto ctx = node->GetContext();
                if( eval_.count(ctx) != 0 )
                        return eval_[ctx].mask_;

                if( node->GetType() == Node::Type_Payoff ){
                        static std::map<Eval,Eval> invMap = {{Eval_Lose, Eval_Win}, {Eval_Draw, Eval_Draw}, {Eval_Win, Eval_Lose}};
                        auto payoff = Cast<PayoffNode const*>(node)->GetPayoff();
                        if( p  == Player_Villian ){
                                payoff = invMap[payoff];
                        }
                        eval_[ctx].mask_ = payoff;
                        return eval_[ctx].mask_;
                }

                using aggregator_t = std::function<Eval(std::vector<Eval>const&)>;

                aggregator_t hero_agg_ = [](std::vector<Eval> const& v){
                        return v.front();
                };

                auto choicePtr = Cast<ChoiceNode const*>(node);

                if(ctx.ActivePlayer() == p ){
                        [&](){
                                /*
                                        Want to find the path in this order,
                                        first we want to find nodes where we win,
                                        then win or draw (depending on opps move),
                                        etc
                                 */
                                static std::vector<unsigned> ticker = {
                                        Eval_Win,
                                        Eval_Win | Eval_Draw,
                                        Eval_Draw,
                                        Eval_Win | Eval_Lose,
                                        Eval_Win | Eval_Draw | Eval_Lose,
                                        Eval_Draw | Eval_Lose,
                                        Eval_Lose
                                };
                                for( auto t : ticker ){
                                        bool found = false;
                                        for( auto child : *choicePtr){
                                                if( Populate_(p, child) == t ){
                                                        // Their may be more than one
                                                        found = true;
                                                        eval_[ctx].mask_ = t;
                                                        eval_[ctx].next_.push_back(child);
                                                }
                                        }
                                        if( found )
                                                return;
                                }
                                assert( choicePtr->NumChildren() == 0 );
                        }();
                        return eval_[ctx].mask_;
                } else {
                        unsigned e = 0;
                        auto& ref = eval_[ctx];
                        for( auto child : *choicePtr){
                                e |= Populate_(p, child);
                                ref.next_.push_back(child);
                        }
                        ref.mask_ = e;
                        return e;
                }
        }
        std::map<GameContext, Result> eval_;
};

struct StrategyBuilder{
        GameTree Build(GameTree const& tree){
                NodeFactory fac;

                auto rootRet = fac.Make(tree.GetRoot()->GetContext());
                auto root = rootRet.second;

                GameTree stratTree{root};

                auto metric = EvalMetric::MakeForHero(tree);

                std::vector<Node*> stack;
                stack.push_back(root);
                for(;stack.size();){
                        auto ptr = stack.back();
                        stack.pop_back();

                        if( ptr->GetType() == Node::Type_Payoff)
                                continue;

                        auto choicePtr = Cast<ChoiceNode*>(ptr);

                        switch(ptr->GetContext().ActivePlayer()){
                        case Player_Hero:{

                                auto item = (*metric)(ptr->GetContext());

                                for( auto branch : item ){
                                        auto makeRet =fac.Make(branch->GetContext());
                                        auto next = makeRet.second;
                                        if( makeRet.first ){
                                                stratTree.Register(next);
                                                stack.push_back(next);
                                        }
                                        choicePtr->RegisterChild(next);
                                        break;
                                }
                                break;
                        }
                        /*
                                For villian we just need to copy
                                every possible move
                        */
                        case Player_Villian: {
                                auto aux = tree.Lookup(ptr->GetContext());
                                if( aux == nullptr ){
                                        std::cerr << "Can't find :(\n";
                                        break;
                                }
                                for( auto child : *Cast<ChoiceNode const*>(aux)){

                                        auto makeRet = fac.Make(child->GetContext());
                                        auto next = makeRet.second;
                                        if( makeRet.first ){
                                                stratTree.Register(next);
                                                stack.push_back(next);
                                        }
                                        choicePtr->RegisterChild(next);
                                }
                                break;
                        }
                        default:
                                break;
                        }
                }

                return std::move(stratTree);
        }
};

void RenderToDot(GameTree const& tree){
        std::cout << "digraph structs{\n";
        std::cout << "node [shape=record]\n";

        unsigned terminalMask = 0;

        auto tag = [](Node const* ptr){
                return "Node" + boost::lexical_cast<std::string>(ptr);
        };

        for( auto ptr : tree){
                auto t = tag(ptr);
                auto const& b = ptr->GetContext().GetBoard();
                std::cout
                        << t << " [shape=record,label=\""
                        << "{"
                                << "{"
                                << PlayerToken(b.GetTile(0,0)) << "|"
                                << PlayerToken(b.GetTile(1,0)) << "|"
                                << PlayerToken(b.GetTile(2,0))
                                << "}"
                        << "|"
                                << "{"
                                << PlayerToken(b.GetTile(0,1)) << "|"
                                << PlayerToken(b.GetTile(1,1)) << "|"
                                << PlayerToken(b.GetTile(2,1))
                                << "}"
                        << "|"
                                << "{"
                                << PlayerToken(b.GetTile(0,2)) << "|"
                                << PlayerToken(b.GetTile(1,2)) << "|"
                                << PlayerToken(b.GetTile(2,2))
                                << "}"
                        << "}\"];\n";
                if( ptr->GetType() == Node::Type_Choice ){
                        for( auto next : *Cast<ChoiceNode*>(ptr)){
                                std::cout << t << " -> " << tag(next) << ";\n";
                        }
                }

                if( ptr->GetType() == Node::Type_Payoff ){
                        auto payoff = Cast<PayoffNode*>(ptr)->GetPayoff();
                        std::cout << t << " -> " << EvalToString(payoff) << ";\n";
                        terminalMask |= payoff;
                }
        }

        std::cout << "}";
}

enum RenderOpt{
        RenderOpt_Solve,
};
void render(Player p, RenderOpt opt){

        TickTackToeLogic logic;
        GameTreeBuilder builder;
        GameContext ctx(p);
        auto tree = builder.Make(ctx);

        switch(opt){
        case RenderOpt_Solve:{
                StrategyBuilder sb;
                auto ret = sb.Build(tree);
                RenderToDot(ret);
        }
                break;
        }
}

void test2(){
        Detail::PictureBox first, second;
        first.Append("hello");
        first.NewLine();
        first.Append("world");
        second.Append(" oh ");
        second.NewLine();
        second.Append("yeah");
        first += second;
        first.Display();
}

void driver(){
        GameContext ctx{Player_Villian};
        GameTreeBuilder builder;
        TickTackToeLogic logic;
        auto tree = builder.Make(ctx);

        StrategyBuilder sb;
        auto strat = sb.Build(tree);

        std::random_device gen;
        std::uniform_int_distribution<int> dist(0,666);

        for(;ctx.GetCtrl() == GameCtrl_Continue;){
                std::cout << ctx.GetBoard() << "\n";

                switch(ctx.ActivePlayer()){
                case Player_Hero: {
                        auto move = Cast<ChoiceNode const*>(strat.Lookup(ctx));

                        assert( !! move );

                        // dedeuce move
                        auto randomOffset = dist(gen) % move->NumChildren();
                        auto nextMove = *std::next(move->begin(), randomOffset );
                        PRINT(move->NumChildren());
                        auto t = [&](){
                                for(size_t i=0;i!=3;++i){
                                        for(size_t j=0;j!=3;++j){
                                                if(     move->GetContext().GetBoard().GetTile(i,j) !=
                                                    nextMove->GetContext().GetBoard().GetTile(i,j) ){
                                                        return std::make_tuple(i,j);
                                                }

                                        }
                                }
                                throw std::domain_error("not move");
                        }();

                        ctx = logic.Next(ctx, std::get<0>(t), std::get<1>(t));
                        break;
                }
                case Player_Villian: {
                        char x_s, y_s;
                        std::cin >> x_s >> y_s;
                        do{
                                if(! ( std::isdigit(x_s) && std::isdigit(y_s))){
                                        std::cerr << "Invalid Move\n";
                                        break;
                                }
                                int x = x_s - '0';
                                int y = y_s - '0';
                                if( ctx.GetBoard().GetTile(x,y) != Player_NotAPlayer ){
                                        std::cerr << "Invalid Move\n";
                                        break;
                                }
                                ctx = logic.Next(ctx, x - '0', y - '0');
                        }while(0);
                        break;
                }
                default:
                        break;
                }
        }
        std::cout << ctx.GetBoard() << "\n";
        switch(ctx.GetCtrl()){
        case GameCtrl_Continue:
                break;
        case GameCtrl_HeroWins:
                std::cout << "Computer Won\n";
                break;
        case GameCtrl_VillianWins:
                std::cout << "You Won\n";
                break;
        case GameCtrl_Draw:
                std::cout << "Draw\n";
                break;
        default:
                return;
        }
}

int main(int argc, char* argv[]){
        try{
                switch(argc){
                case 1:
                        driver();
                        break;
                case 2: {
                        std::string arg = argv[1];
                        if( arg == "--hero" ){
                                render(Player_Hero, RenderOpt_Solve);
                        } else if(arg == "--villian"){
                                render(Player_Villian, RenderOpt_Solve);
                        } else if(arg == "--driver"){
                                driver();
                        } else{
                        }
                        break;
                }
                default:
                        std::cerr  << "unknown args\n";
                        return EXIT_FAILURE;
                }
        } catch(std::exception const& e){
                std::cerr << e.what() << "\n";
                return EXIT_FAILURE;
        }
}


// Copyright 2010-2014, D. E. Shaw Research.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt )

#ifndef BOOST_RANDOM_DETAIL_ROTL_HPP
#define BOOST_RANDOM_DETAIL_ROTL_HPP

#include <boost/static_assert.hpp>
#include <limits>

namespace boost{
namespace random{
namespace detail{
template <typename Uint>
static Uint rotl(Uint x, unsigned s){
    // Non-binary types would be a huge headache.  Sign-extension of
    // right-shift would not give the intended result.  These should
    // never come up, so it's not worth the trouble to try to handle
    // them "correctly".  But just in case they do, let's blow an
    // assertion rather than generating incorrect code.
    BOOST_STATIC_ASSERT(std::numeric_limits<Uint>::is_specialized);
    BOOST_STATIC_ASSERT(std::numeric_limits<Uint>::radix == 2);
    BOOST_STATIC_ASSERT(!std::numeric_limits<Uint>::is_signed);
    return (x<<s) | (x>>(std::numeric_limits<Uint>::digits-s));
}
}
}
}

#endif


// Copyright John Maddock 2008.

// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_MATH_DISTRIBUTIONS_DETAIL_MODE_HPP
#define BOOST_MATH_DISTRIBUTIONS_DETAIL_MODE_HPP

#include <boost/math/tools/minima.hpp> // function minimization for mode
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/distributions/fwd.hpp>

namespace boost{ namespace math{ namespace detail{

template <class Dist>
struct pdf_minimizer
{
   pdf_minimizer(const Dist& d)
      : dist(d) {}

   typename Dist::value_type operator()(const typename Dist::value_type& x)
   {
      return -pdf(dist, x);
   }
private:
   Dist dist;
};

template <class Dist>
typename Dist::value_type generic_find_mode(const Dist& dist, typename Dist::value_type guess, const char* function, typename Dist::value_type step = 0)
{
   BOOST_MATH_STD_USING
   typedef typename Dist::value_type value_type;
   typedef typename Dist::policy_type policy_type;
   //
   // Need to begin by bracketing the maxima of the PDF:
   //
   value_type maxval;
   value_type upper_bound = guess;
   value_type lower_bound;
   value_type v = pdf(dist, guess);
   if(v == 0)
   {
      //
      // Oops we don't know how to handle this, or even in which
      // direction we should move in, treat as an evaluation error:
      //
      policies::raise_evaluation_error(
         function,
         "Could not locate a starting location for the search for the mode, original guess was %1%", guess, policy_type());
   }
   do
   {
      maxval = v;
      if(step != 0)
         upper_bound += step;
      else
         upper_bound *= 2;
      v = pdf(dist, upper_bound);
   }while(maxval < v);

   lower_bound = upper_bound;
   do
   {
      maxval = v;
      if(step != 0)
         lower_bound -= step;
      else
         lower_bound /= 2;
      v = pdf(dist, lower_bound);
   }while(maxval < v);

   boost::uintmax_t max_iter = policies::get_max_root_iterations<policy_type>();

   value_type result = tools::brent_find_minima(
      pdf_minimizer<Dist>(dist),
      lower_bound,
      upper_bound,
      policies::digits<value_type, policy_type>(),
      max_iter).first;
   if(max_iter >= policies::get_max_root_iterations<policy_type>())
   {
      return policies::raise_evaluation_error<value_type>(
         function,
         "Unable to locate solution in a reasonable time:"
         " either there is no answer to the mode of the distribution"
         " or the answer is infinite.  Current best guess is %1%", result, policy_type());
   }
   return result;
}
//
// As above,but confined to the interval [0,1]:
//
template <class Dist>
typename Dist::value_type generic_find_mode_01(const Dist& dist, typename Dist::value_type guess, const char* function)
{
   BOOST_MATH_STD_USING
   typedef typename Dist::value_type value_type;
   typedef typename Dist::policy_type policy_type;
   //
   // Need to begin by bracketing the maxima of the PDF:
   //
   value_type maxval;
   value_type upper_bound = guess;
   value_type lower_bound;
   value_type v = pdf(dist, guess);
   do
   {
      maxval = v;
      upper_bound = 1 - (1 - upper_bound) / 2;
      if(upper_bound == 1)
         return 1;
      v = pdf(dist, upper_bound);
   }while(maxval < v);

   lower_bound = upper_bound;
   do
   {
      maxval = v;
      lower_bound /= 2;
      if(lower_bound < tools::min_value<value_type>())
         return 0;
      v = pdf(dist, lower_bound);
   }while(maxval < v);

   boost::uintmax_t max_iter = policies::get_max_root_iterations<policy_type>();

   value_type result = tools::brent_find_minima(
      pdf_minimizer<Dist>(dist),
      lower_bound,
      upper_bound,
      policies::digits<value_type, policy_type>(),
      max_iter).first;
   if(max_iter >= policies::get_max_root_iterations<policy_type>())
   {
      return policies::raise_evaluation_error<value_type>(
         function,
         "Unable to locate solution in a reasonable time:"
         " either there is no answer to the mode of the distribution"
         " or the answer is infinite.  Current best guess is %1%", result, policy_type());
   }
   return result;
}

}}} // namespaces

#endif // BOOST_MATH_DISTRIBUTIONS_DETAIL_MODE_HPP


/*
   Boneh, Di Crescenzo, Ostrovsky & Persiano
   Public Key Encryption with keyword Search

   See http://eprint.iacr.org/2003/195.pdf
   Section 3.1

   (From reading the protocol to a working implementation - 10 minutes!)

   Compile with modules as specified below

   For MR_PAIRING_CP curve
   cl /O2 /GX peks.cpp cp_pair.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib

   For MR_PAIRING_MNT curve
   cl /O2 /GX peks.cpp mnt_pair.cpp zzn6a.cpp ecn3.cpp zzn3.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib

   For MR_PAIRING_BN curve
   cl /O2 /GX peks.cpp bn_pair.cpp zzn12a.cpp ecn2.cpp zzn4.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib

   For MR_PAIRING_KSS curve
   cl /O2 /GX peks.cpp kss_pair.cpp zzn18.cpp zzn6.cpp ecn3.cpp zzn3.cpp big.cpp zzn.cpp ecn.cpp miracl.lib

   For MR_PAIRING_BLS curve
   cl /O2 /GX peks.cpp bls_pair.cpp zzn24.cpp zzn8.cpp zzn4.cpp zzn2.cpp ecn4.cpp big.cpp zzn.cpp ecn.cpp miracl.lib

   Test program
*/
#include <cstring>
#include "big.h"
#include <ctime>
#include <string>
#include <set>
#include <fstream>
#include <iostream>
#include <stdlib.h>
#include <assert.h>
#include "zzn.h"
#include <boost/algorithm/string/trim.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <sstream>
#include "params-peks.h"
#include <zmq.hpp>

using namespace std;

//********* choose just one of these pairs **********
//#define MR_PAIRING_CP      // AES-80 security
//#define AES_SECURITY 80

//#define MR_PAIRING_MNT	// AES-80 security
//#define AES_SECURITY 80

//#define MR_PAIRING_BN    // AES-128 or AES-192 security
//#define AES_SECURITY 128
//#define AES_SECURITY 192

//#define MR_PAIRING_KSS    // AES-192 security
//#define AES_SECURITY 192

//#define MR_PAIRING_BLS    // AES-256 security
//#define AES_SECURITY 256
//*********************************************
#include "pairing_3.h"
#include "ecn.h"
#include "miracl.h"

PFC pfc(AES_SECURITY);  // initialise pairing-friendly curve

void keyGen(string path,G1	&g, Big &alpha, G1& h );
void boneh_Peks(G1 g,G1 h, G1 &PA, Big &PB,string keyword);
void boneh_Trapdoor(Big alpha,G2 &TW, string keyword);
bool boneh_Test(G2 TW, G1 PA, Big PB);
//==========================================================================================================
string to_string(int i)
{
    stringstream ss;
    ss << i;
    return ss.str();
}

const char* const delimiter = "`-=[]\\;\',./~!@#$%^&*()+{}|:\"<>? \n\t\v\b\r\f\a";
bool is_word(std::string& s){
	bool flagd =true, flagc = false;  int count = 0;
	std::string::iterator it = s.begin();
    for (it = s.begin();it != s.end(); ++it)  {
		count++;
		if (std::isalpha(*it)){}
		else{
			flagd = false;
			}
		if (count > 2)  flagc = true;
	}

    return (flagd && flagc);
}
int extractWords_using_find_first_of(TYPE_KEYWORD_DICTIONARY &rKeywordsDictionary,
		TYPE_COUNTER *pKeywordNum,
		ifstream &rFin){

	bool capture = false;
	string line, word;
	while(getline(rFin, line))
    {
		int counter = 0;
		size_t prev = 0, pos;
		boost::trim(line);
		while ((pos = line.find_first_of(delimiter, prev)) != std::string::npos)
		{
			if (pos > prev)
            {
				word = line.substr(prev, pos-prev);
				boost::trim(word);
                //convert the word to lower case
                std::transform(word.begin(),word.end(),word.begin(),::tolower);
				//if (word == "dfossum")
				capture=true;
				if (is_word(word) && capture &&   rKeywordsDictionary.size()<numOfKeywords){
                rKeywordsDictionary.insert(word);
				*pKeywordNum = *pKeywordNum + 1;
				}
			}

			prev = pos+1;
		}
		if (prev < line.length()){
			word = line.substr(prev, std::string::npos);
			boost::trim(word);

            //convert the word to lower case
            std::transform(word.begin(),word.end(),word.begin(),::tolower);
			if (word == "dfossum") capture=true;
			if (is_word(word)&& capture && rKeywordsDictionary.size()<numOfKeywords){
				rKeywordsDictionary.insert(word);
				*pKeywordNum = *pKeywordNum + 1;
			}
		}

	}

	return 0;
}
int extractKeywords(TYPE_KEYWORD_DICTIONARY &rKeywordsDictionary,
		string file_name ,string path)
{
	TYPE_COUNTER keyword_num = 0;
	string fname_with_path;

	// create a file-reading object
	ifstream fin;

	fname_with_path.append(path);
	fname_with_path.append(file_name);
	//fname_with_path.append(".txt");

	// open a file
	fin.open(fname_with_path.c_str(),std::fstream::in);
	if (!fin.good()){
		cout << "No such file exist"<<endl; // exit if file not found
	}
	// Extract keywords from a file
	extractWords_using_find_first_of(rKeywordsDictionary, &keyword_num, fin);

	fin.close();

	return 0;
}
// Function gets the file info and a set of keywords and writes them on the file for the future use.
void writeKeywords(TYPE_KEYWORD_DICTIONARY keywordSet, string file_name, string path){

	string fname_with_path;
	set<string>::iterator it;

	fname_with_path.append(path);
	fname_with_path.append(file_name);
	fname_with_path.append("kw");
	// Opening file to write the keywords on it.
	ofstream myfile;
	myfile.open (fname_with_path.c_str(), ios::out | ios::binary);
	for (it=keywordSet.begin(); it!=keywordSet.end(); ++it){
		myfile << ' ' << *it;
	}
	myfile.close();

}
// Function to read keywords from file
void extractKeywordFile(string *keywordExtracted, int &keywordCounter, string file_name, string path)
{
    ifstream ifile;
	string fname_with_path;
	fname_with_path.append(path);
	fname_with_path.append(file_name);
	fname_with_path.append("kw");
	// Opening file to read the keywords from it.
    ifile.open(fname_with_path.c_str());
    if (!ifile.is_open())
		{cout << "No such file exist"<<endl;}
	string word;
	keywordCounter = 0;
    while (ifile >> word)
    {
		keywordExtracted[keywordCounter] = word;
		keywordCounter++;
     }
	for (int key = 0;key<numOfKeywords;key++)
		cout << file_name << "   "<< keywordExtracted[key]<<endl;
	ifile.close();
}

// Stores the PEKS obtained from the function below in the file.

void writePEKStoFile(string file_name, string path, G1  PA, Big PB){

	char testing[200];
	cout << "PA = " << PA.g << endl;

	Big x = 1;
	Big y = 1;
	PA.g.getxy(x,y);

	string fname_with_path;
	//recreate the file name
	fname_with_path.append(path);
	fname_with_path.append(file_name);
	fname_with_path.append("sc");

	ofstream ofile;
	ofile.open (fname_with_path.c_str(), ios_base::app | ios::binary);
	ofile<<x ;
	testing << x;
	ofile<<endl;
	ofile << y << endl;

	ofile << PB;
	ofile<<endl;
	ofile.close();
}

//Function to encrypt keywords and store them in file using writePEKStoFile function

void KeywordstoPEKS(G1  PA, Big PB,string file_name, string path, G1 g, G1 h, string keywordExtracted[numOfKeywords], int  keywordCounter)
	{
	string keyword;
	for (int i = 0; i < numOfKeywords; i++){
			keyword = keywordExtracted[i];
			boneh_Peks(g, h, PA, PB, keyword);
		//	Finished Boneh Peks, writing PEKS to file";
			writePEKStoFile(file_name,path,PA, PB);

	}

}

//void boneh_Trapdoor(Big alpha,G2 &TW, string keyword)
void myTrapdoorGenerator(Big alpha,G2 &TW, string& keyword){

	string word;
	cout << endl<<"Please keyin the keyword you would like to be searched: ";
	cin >> keyword;
	boneh_Trapdoor(alpha, TW, keyword);

}

void findFileByKeywords(TYPE_KEYWORD_DICTIONARY & listOfFiles, string file_name, string path, G2 TW){
	cout << "We are in Find FILE BY KEYWORD now: "<<endl<<endl;
	int rep;
	bool flagvalid = false;

	int counter = 0;

    string line1 = "";
    string line2 = "";
	string temp1,temp2="",fileNameforList="", fname_with_path;
	fstream ifile;

	for (int filecount = 1; filecount < numOfFiles; filecount++)
	{
		string line1 = "";string line0 = "";
		string line2 = "";
		string line3 = "";

		fstream ifile;
		fname_with_path = "";
		fname_with_path.append(path);
		file_name = "";
		file_name.append("/");
		temp1 = std::to_string(filecount);

		file_name.append(temp1);
		fileNameforList.append(file_name);
		//fileNameforList.append(".");
		file_name.append("sc");
		fname_with_path.append(file_name);

		ifile.open(fname_with_path.c_str());
		if (!ifile.is_open()){cout << "The file "<<fname_with_path<< "is NOT fine \n"<<endl;}
		string word ="";
		string target = "";
		int i = 0;

		while (i < numOfKeywords){

			epoint *temp;

			Big x = 1;
			Big y = 1;

			Big  PB =1; G1 PA;

			ifile>>x;
			ifile>>y;

			ifile>>PB;

			ECn point;
			bool flag = point.set(x,y);
			if(flag == true)
			{
				cout<<"Good!"<<endl;
			}

			PA.g = point;

			i++;

			if (boneh_Test( TW, PA, PB)){
				listOfFiles.insert(file_name);
			}

		}

	}
	ifile.close();

}

void writekeystoFile( string path,const G1 g, const Big alpha, const G1 h){

	cout << "g = " << g.g << endl;
	cout << "h = " << h.g << endl;
	Big x = 1;
	Big y = 1;
	Big xx =1;
	Big yy =1;
	g.g.getxy(x,y);
	h.g.getxy(xx,yy);

	string fname_with_path;
	//recreate the file name
	fname_with_path.append(path);
	fname_with_path.append("/keyfile");
	cout << fname_with_path<<endl;
	ofstream ofile;
	ofile.open (fname_with_path.c_str(),  ios::binary);
	ofile << x ;

	//cout << "/n/n/n/"<< "Hi This is x -----> "<< testing<<endl;
	ofile<<endl;
	ofile << y << endl;
	ofile<< alpha<<endl;
	ofile << xx<<endl;
	ofile << yy<<endl;
	ofile.close();
}
void readKeyFromFile ( string path, G1& g, Big& alpha, G1& h){

		string fname_with_path_key;
		fstream ifile;
		fname_with_path_key = "";
		fname_with_path_key.append(path);

		fname_with_path_key.append("/keyfile");
		ifile.open(fname_with_path_key.c_str());

	epoint *temp;

	Big x = 1;
	Big y = 1;
	Big xx = 1;
	Big yy = 1;

	ifile>>x;
	ifile>>y;

	ifile>>alpha;
	ifile >> xx;
	ifile>>yy;
	ECn point1;
	bool flag = point1.set(x,y);
	if(flag == false)
	{
		cout<<"Error in loading keys!"<<endl;
	}

	g.g = point1;

	ECn point2;
	bool flag1 = point2.set(xx,yy);
	if(flag1 == false)
	{
		cout<<"Error in loading keys1!"<<endl;
	}
	h.g = point2;

	}
//= ===== write trapdoor to file

void writeTrapdoorFile(string fname_with_path,  G2 TW){

	ZZn3 x;
char a[2] = {'0','1'};
ZZn mya(a);
	ZZn3 y;
	ZZn atx;
	ZZn btx;
	ZZn ctx;
	ZZn aty;
	ZZn bty;
	ZZn cty;
	ECn3 mypoint;
	mypoint = TW.g;
	cout << "The value of mypoint is : "<<mypoint<<endl;
	cout << "The value of Trapdoor is : "<<TW.g<<endl;
	mypoint.get(x,y);
	cout << "The value of x is : "<<x<<endl;
	cout << "The value of y is : "<<y<<endl;
	x.get(atx,btx,ctx);
	cout << "The value of a is : "<<atx<<endl;
	cout << "The value of b is : "<<btx<<endl;
	cout << "The value of c is : "<<ctx	<<endl;
	x.get(atx,btx,ctx);
	cout << "The value of aaaa is : "<<a	<<endl;
	y.get(aty,bty,cty);

	//string fname_with_path;
	//recreate the file name

	fname_with_path.append("trapdoor");

	ofstream ofile;
	ofile.open (fname_with_path.c_str(),  ios::binary);
	ofile << atx <<endl<<btx <<endl<<ctx<<endl <<aty<<endl<<bty<<endl<<cty<<endl ;

	ofile.close();
}

void sendTrapdoorToServer(string file_name, string path){
    zmq::context_t context(1);
	zmq::socket_t socket(context,ZMQ_REQ);
	printf("   Connecting to server...");
	//socket.connect ("tcp://localhost:5559");
	socket.connect ("tcp://52.26.80.225:5559");
	printf("OK!\n");
	string line1 = "";
	string fname_with_path;
	size_t sizeLine1 = 0;
	auto start = time_now;
    auto end = time_now;
	float sum = 0.0;

	fstream ifile;
	fname_with_path = "";
	fname_with_path.append(path);
	//file_name = "";
	//file_name.append("/");
	fname_with_path.append(file_name);
	size_t size1;
	ifile.open(fname_with_path.c_str());
	if (!ifile.is_open()){cout << "The file "<<fname_with_path<< "is NOT fine \n"<<endl;}
		while(ifile >> line1){
			cout << "The lines in sendTrapdoor "<<line1<<endl;
			sizeLine1 = (size_t)line1.length();
			zmq::message_t request_line1(sizeLine1);
			memcpy (request_line1.data (), line1.c_str(), sizeLine1);

			start = time_now;
			socket.send (request_line1);
			zmq::message_t reply;
			socket.recv (&reply);
			end = time_now;
			sum += (float)(std::chrono::duration_cast<std::chrono::microseconds>(end-start).count());
		}

	cout<<	"Sending Trapdoor takes   "<<sum<<" microseconds"<<endl;

	ifile.close();
	socket.close();

	}

//=== Send data to server

void sendPeksToServer(string file_name, string serverPath){
    zmq::context_t context(1);
	zmq::socket_t socket(context,ZMQ_REQ);
	printf("   Connecting to server...");
	//socket.connect ("tcp://localhost:5560");
	socket.connect ("tcp://52.26.80.225:5560");
	printf("OK!\n");
	string line1 = "";
    string line2 = ""; string line3 = "";
	string fname_with_path;
	fstream ifile;
	size_t sizeLine1 = 0;
	size_t sizeLine2 = 0;
	size_t sizeLine3 = 0;
	auto start = time_now;
    auto end = time_now;
	float sum = 0.0;
	string line22 = "Hello there how are you0";
	for (int filecount = 1; filecount < numOfFiles; filecount++)
	{

		string temp1 = "";
		fstream ifile;
		fname_with_path = "";
		fname_with_path.append(serverPath);
		file_name = "";
		file_name.append("/");
		temp1 = std::to_string(filecount);
		file_name.append(temp1);
		file_name.append("sc");
		fname_with_path.append(file_name);
		size_t size1, size2,size3;
		ifile.open(fname_with_path.c_str());
		if (!ifile.is_open()){cout << "The file "<<fname_with_path<< "is NOT fine \n"<<endl;}
		int i = 0;
		while (i < numOfKeywords){

			line1 = "";line2 = "";line3 = "";
			ifile>>line1;
			ifile>>line2;
			ifile>>line3;
			sizeLine1 = (size_t)line1.length();
			zmq::message_t request_line1(sizeLine1);
			memcpy (request_line1.data (), line1.c_str(), sizeLine1);

			sizeLine2 = (size_t)line2.length();
			zmq::message_t request_line2(sizeLine2);
			memcpy (request_line2.data (), line2.c_str(), sizeLine2);

			sizeLine3 = (size_t)line3.length();
			zmq::message_t request_line3(sizeLine3);
			memcpy (request_line3.data (), line3.c_str(), sizeLine3);
			start = time_now;
			socket.send (request_line1);
			zmq::message_t reply;
			socket.recv (&reply);
	     	socket.send (request_line2);
			socket.recv (&reply);
			socket.send (request_line3);
			socket.recv (&reply);
			end = time_now;
			sum += (float)(std::chrono::duration_cast<std::chrono::microseconds>(end-start).count());
			i++;
		}

	}

	cout<<	"Sending PEKS, each file takes   "<<sum/(numOfFiles*numOfKeywords)<<" microseconds on average"<<endl;

	cout << "All files have been received and stored in "<< serverPath << "folder "<< endl;
	ifile.close();
	socket.close();

	}

// ================== SERVER SIDE
void writePEKStoFileServer(string fname_with_path, string fname,  string x, string y, string pb){

	//string fname_with_path;
	//recreate the file name

	fname_with_path.append(fname);

	ofstream ofile;
	ofile.open (fname_with_path.c_str(), ios_base::app | ios::binary);
	ofile << x ;

	ofile<<endl;
	ofile << y << endl;

	ofile << pb;
	ofile<<endl;
	ofile.close();
}

void writeTrapdoortoFileServer(string fname_with_path,  string x){

	//string fname_with_path;
	//recreate the file name

	fname_with_path.append("trapdoor");

	ofstream ofile;
	ofile.open (fname_with_path.c_str(), ios_base::app | ios::binary);
	ofile << x ;

	ofile<<endl;

	ofile.close();
}

void receivingPeksServer(string serverPath){

	zmq::context_t context (1);
    zmq::socket_t socket (context, ZMQ_REP);
    socket.bind ("tcp://*:5560");
	int counterKeywords;

	for (int filecount = 1; filecount < numOfFiles; filecount++)
	{

		string temp1 = "";
		ofstream ofile;
		string fname_with_path1 = "";
		fname_with_path1.append(serverPath);
		string file_name = "";
		file_name.append("/");
		temp1 = std::to_string(filecount);
		file_name.append(temp1);
		file_name.append("sc");
		fname_with_path1.append(file_name);
		size_t size1, size2,size3;
		ofile.open (fname_with_path1.c_str(),  ios::binary);

	counterKeywords = 0;
    while (counterKeywords < numOfKeywords) {

        zmq::message_t request1;
        socket.recv (&request1);
        string rpl1 = string(static_cast<char*>(request1.data()), request1.size());
        cout <<  rpl1<< endl;

		zmq::message_t reply1 (8);
        memcpy (reply1.data (), "World", 8);
        socket.send (reply1);

	//sleep(1);
		zmq::message_t request2;
		socket.recv (&request2);
        string rpl2 = string(static_cast<char*>(request2.data()), request2.size());
        cout <<  rpl2<< endl;

        zmq::message_t reply2 (8);
        memcpy (reply2.data (), "World", 8);
        socket.send (reply2);

	//sleep(1);
	//sleep(1);
		zmq::message_t request3;
		socket.recv (&request3);
        string rpl3 = string(static_cast<char*>(request3.data()), request3.size());
        cout <<  rpl3<< endl;

		zmq::message_t reply3 (8);
        memcpy (reply3.data (), "World", 8);
        socket.send (reply3);
		writePEKStoFileServer(serverPath ,file_name, rpl1, rpl2,rpl3);

		counterKeywords++;

        //  Do some 'work'

        //  Send reply back to client

    }
}

	cout << "All files have been received and stored in "<< serverPath << "folder "<< endl;
	socket.close();

}

void receivingTrapdoorServer(string serverPath){

	zmq::context_t context (1);
    zmq::socket_t socket (context, ZMQ_REP);
    socket.bind ("tcp://*:5559");

		ofstream ofile;
		string fname_with_path1 = "";
		fname_with_path1.append(serverPath);
		string file_name = "trapdoor";
		fname_with_path1.append(file_name);
		size_t size1;
		ofile.open (fname_with_path1.c_str(),  ios::binary);

	int numOfLinesTrapdoor = 0;
    while (numOfLinesTrapdoor < 6) {

        zmq::message_t request1;
        socket.recv (&request1);
        string rpl1 = string(static_cast<char*>(request1.data()), request1.size());
        cout <<  rpl1<< endl;

		zmq::message_t reply1 (8);
        memcpy (reply1.data (), "World", 8);
        socket.send (reply1);

		writeTrapdoortoFileServer(serverPath, rpl1);

		numOfLinesTrapdoor++;

    }

	cout << "All files have been received and stored in "<< serverPath << "folder "<< endl;
	socket.close();

}

void findFileByKeywordsServer(TYPE_KEYWORD_DICTIONARY & listOfFiles, string file_name, string path, string serverPath){

	G2 TW;
	string tdfname = "";
	tdfname.append(serverPath);
	tdfname.append("trapdoor");
	ZZn3 x; ZZn3 y;
	ECn3 point;
	Big aux1 = 1;	Big aux2 = 1;
	Big aux3 = 1;	Big aux4 = 1;
	Big aux5 = 1;	Big aux6 = 1;
	ifstream fileTrapdoor;
	fileTrapdoor.open(tdfname.c_str());
	fileTrapdoor >> aux1;fileTrapdoor >> aux2;
	fileTrapdoor >> aux3;fileTrapdoor >> aux4;
	fileTrapdoor >> aux5;fileTrapdoor >> aux6;
	ZZn atx(aux1);
	ZZn btx(aux2);
	ZZn ctx(aux3);
	ZZn aty(aux4);
	ZZn bty(aux5);
	ZZn cty(aux6);
	x.set(atx,btx,ctx);
	y.set(aty,bty,cty);
	point.set(x,y);
	TW.g = point;
	cout << "We are in THE TESTING FUNC and the value is "<<TW.g<<endl;
	sleep(3);
	fileTrapdoor.close();

	int rep;
	bool flagvalid = false;

	int counter = 0;

    string line1 = "";
    string line2 = "";
	string temp1,temp2="",fileNameforList="", fname_with_path;
	fstream ifile;

	for (int filecount = 1; filecount < numOfFiles; filecount++)
	{
		string line1 = "";string line0 = "";
		string line2 = "";
		string line3 = "";

		fstream ifile;
		fname_with_path = "";
		fname_with_path.append(path);
		file_name = "";
		file_name.append("/");
		temp1 = std::to_string(filecount);

		file_name.append(temp1);
		fileNameforList.append(file_name);
		//fileNameforList.append(".");
		file_name.append("sc");
		fname_with_path.append(file_name);

		ifile.open(fname_with_path.c_str());
		if (!ifile.is_open()){cout << "The file "<<fname_with_path<< "is NOT fine \n"<<endl;}
		string word ="";
		string target = "";
		int i = 0;

		while (i < numOfKeywords){

			epoint *temp;

			Big x = 1;
			Big y = 1;

			Big  PB =1; G1 PA;

			ifile>>x;
			ifile>>y;

			ifile>>PB;

			ECn point;
			bool flag = point.set(x,y);
			if(flag == true)
			{
				cout<<"Good!"<<endl;
			}

			PA.g = point;

			i++;

			if (boneh_Test(TW, PA, PB)){
				listOfFiles.insert(file_name);
			}

		}

	}
	ifile.close();

}

//=========================================================================================================

void mainMenu(){
	cout << "\n\n\n\n\n\n\n\n\n\n";
	cout << "Select one of the following: \n";
	cout << "(1) Sender\n";
	cout << "(2) Receiver\n";
	cout << "(3) Server\n";
	cout << "(4) Exit\n";

	cout << "Choice: ";

}
void senderMenu(string path, const bool flagEnc, int numOfFiles){
	//int choiceSender = 0;
	cout << "\n\n\n\n\n\n\n\n\n\n";
	cout << "The default path for the email files is: \n";
	cout << path<<endl;
	cout << "The  number of email files is: ";
	cout << numOfFiles <<endl;
	cout << "Select one of the following: \n";
	cout << "(1) Change the default path\n";
	cout << "(2) Change the default number of files\n";
	cout << "(3) Extract and encrypt keywords for each file "; if (flagEnc){ cout << "(Done)\n"; } else cout << "\n";
	cout << "(4) Send encrypted files to the server\n";
	cout << "(5) Return to the main menu\n";
	cout << "Choice: ";
}

void receiverMenu(const bool flagTrapdoor, string path){
	string filename = "/keyfile";
	string filename_with_path = "";
	filename_with_path.append(path);
	filename_with_path.append(filename);
	cout << filename_with_path<<endl;
	ifstream keyfile (filename_with_path.c_str());

	cout << "\n\n\n\n\n\n\n\n\n\n";
	cout << "Select one of the following: \n";
	cout << "(1) Generate keys ";  if (keyfile) { cout<< "(Done!) \n";} else cout <<"\n";
	cout << "(2) Generate trapdoor "; if (flagTrapdoor){ cout << "(Done!)\n"; } else cout << "\n";
	cout << "(3) Send Trapdoor to server (trapdoor should have been genrated first.)\n";
	cout << "(4) Find files by keyword (trapdoor should have been genrated first.)\n";
	cout << "(5) Return to the main menu\n";
	cout << "Choice: ";
}

void serverMenu(){
	cout << "\n\n\n\n\n\n\n\n\n\n";
	cout << "Select one of the following: \n";
	cout << "(1) Receive Trapdoor\n";
	cout << "(2) Receive PEKS\n";
	cout << "(3) Return to the main menu\n";

	cout << "Choice: ";

}

int main()
{

	bool flagEnc = false; bool flagTrapdoor = false;
	time_t seed;
	time(&seed);
    irand((long)seed);
    clock_t t1, t2;
	float diff;
	G1 g,h,PA,PA1;
	Big alpha,r,PB;
	GT t;
	G2 HW,TW;
	TYPE_KEYWORD_DICTIONARY listOfFiles;
	string keyword;
	const unsigned int nb_trdb = 100;
    const unsigned int nb_crypb = 100;
	unsigned int i;
	string path = "/home/bob/Desktop/80BonehPeks/80BonehPeks/textfiles";
	string file_name;
	int keywordCounter;
	int choiceMain, choiceSender,choiceReceiver,serverChoice;
	auto start = time_now;
    auto end = time_now;
	float sum = 0.0;
// This function is run by Alice, the reciever,  to generate pk and sk.

	labelMain: mainMenu( );
	string fname_with_path_key;
	fstream ifiles;
	fname_with_path_key = "";
	fname_with_path_key.append(path);

	fname_with_path_key.append("/keyfile");
	ifiles.open(fname_with_path_key.c_str());
	if (ifiles.is_open()){
	readKeyFromFile (path,g,alpha,h);
	}

	cin >> choiceMain;
	cout << "\n\n\n\n\n\n\n\n\n\n";

if (choiceMain == 1){
	labelSenderMenu:
	senderMenu( path,   flagEnc, numOfFiles);
	cin >> choiceSender;
	if (choiceSender == 1){
		cout << "Please keyin the new path: ";
		cin >> path;
		goto labelSenderMenu;
	}
	else if (choiceSender == 2){
		cout << "Please keyin the number of files: ";
		cin >> numOfFiles;
		goto labelSenderMenu;
	}
	else if (choiceSender == 3){

		for (int j = 1; j < numOfFiles; j++){

			string keywordExtracted[25];
			string temp;
			int rep[numOfKeywords] = {0};
			TYPE_KEYWORD_DICTIONARY myset;
			file_name = "/";
			temp = std::to_string(j);
			file_name.append(temp);
		//	file_name.append(".");
			extractKeywords(myset, file_name, path);
			writeKeywords(myset, file_name, path);
			extractKeywordFile(keywordExtracted, keywordCounter, file_name,path);
			start = time_now;
			KeywordstoPEKS(PA, PB,file_name, path,g,h, keywordExtracted, keywordCounter);
			end = time_now;
			sum += (float)(std::chrono::duration_cast<std::chrono::milliseconds>(end-start).count());
			cout << "Keywords have been successfully extracted and stored in .kw files. \n";
			cout << "Keywords have been encrypted for each file and stored in .sc files. \n";	cout << "\n\n\n\n\n\n\n\n\n\n";

		}
		cout<<"Generate PEKS, each file takes   "<<sum/numOfFiles<<" ms on average"<<endl;
		flagEnc = true;

	}
	else if (choiceSender == 4){
		sendPeksToServer(file_name,path);
		goto labelSenderMenu;
	}

	else if (choiceSender == 5){ goto labelMain;}
	sleep(1);
	goto labelSenderMenu;

}

if (choiceMain == 2){
	labelReceiverMenu:
	receiverMenu(flagTrapdoor,path);
	cin >> choiceReceiver;
	if (choiceReceiver == 1 ){
		keyGen(path, g, alpha,h);
		cout << "Keys have been succefully generated. \n";	cout << "\n\n\n\n\n\n\n\n\n\n";
		sleep (1);
		goto labelReceiverMenu;
	}

	if (choiceReceiver == 2 ){
		flagTrapdoor = true;
		myTrapdoorGenerator( alpha,TW, keyword);
		cout << "Trapdoor has been succefully generated. \n";	cout << "\n\n\n\n\n\n\n\n\n\n";
		sleep (1);
		goto labelReceiverMenu;
	}

	else if (choiceReceiver == 3){ sendTrapdoorToServer("trapdoor", "/home/bob/Desktop/80BonehPeks/80BonehPeks/textfiles/server/");  goto labelReceiverMenu;}

		else if (choiceReceiver == 4 ){
		//findFileByKeywords(listOfFiles,  file_name,  path,  TW);
		start = time_now;
		findFileByKeywordsServer( listOfFiles,  file_name,  "/home/bob/Desktop/80BonehPeks/80BonehPeks/textfiles/server", "/home/bob/Desktop/80BonehPeks/80BonehPeks/textfiles/server2/");
		end = time_now;

		cout<<"Search time    "<<std::chrono::duration_cast<std::chrono::milliseconds>(end-start).count()/numOfFiles<<" ms"<<endl;
		for (set<string>::iterator it = listOfFiles.begin(); it != listOfFiles.end(); ++it) {
			cout <<"The file name is" << *it <<endl<<endl;
		}
		if (listOfFiles.size() == 0) cout << "No email was found for the keyword: "<< keyword << "\n";
			cout << "\n\n\n\n\n\n\n\n\n\n";
			sleep(1);
			 goto labelMain;
	}

	else if (choiceReceiver == 5){ goto labelMain;}

}

if (choiceMain == 3){
	labelServerMenu:
	serverMenu();
	cin >> serverChoice;

	if (serverChoice == 1){
		receivingTrapdoorServer("/home/bob/Desktop/80BonehPeks/80BonehPeks/textfiles/server2/"); goto labelServerMenu;
	}
	else if (serverChoice == 2 ){
	receivingPeksServer("/home/bob/Desktop/80BonehPeks/80BonehPeks/textfiles/server"); goto labelServerMenu;
	}
	else if (serverChoice == 3) {goto labelMain;}
}

if (choiceMain == 4){exit(1);}

    return 0;
}

void keyGen(string path,G1& g, Big& alpha, G1& h) {
	auto start = time_now;
    auto end = time_now;
	start = time_now;
	pfc.random(g);
	pfc.precomp_for_mult(g);  // precompute on fixed g
	pfc.random(alpha);		  // private key
	h=pfc.mult(g,alpha);      // public key
	pfc.precomp_for_mult(h);
	end = time_now;

	cout<<"Key Generation took    "<<std::chrono::duration_cast<std::chrono::milliseconds>(end-start).count()<<" ms"<<endl;
	writekeystoFile(path,g,alpha,h);
}

void boneh_Peks(G1 g,G1 h, G1 &PA,Big &PB, string keyword)
{
	Big r;
	GT t;
	G2 HW;
	pfc.random(r);
	pfc.hash_and_map(HW,(char *)keyword.c_str());
	t=pfc.pairing(HW,pfc.mult(h,r));
	PA=pfc.mult(g,r);
	PB=pfc.hash_to_aes_key(t);    // [PA,PB] added to ciphertext
}

void boneh_Trapdoor(Big alpha,G2 &TW, string keyword)
{
	auto start = time_now;
    auto end = time_now;
	start = time_now;
	G2 HW;
	pfc.hash_and_map(HW,(char *)keyword.c_str()); // key word we are looking for
	TW=pfc.mult(HW,alpha);
	pfc.precomp_for_pairing(TW);

	end = time_now;

	cout<<"Trapdoor Generation took    "<<std::chrono::duration_cast<std::chrono::milliseconds>(end-start).count()<<" ms"<<endl;

	cout << "This is what you want in file  "<< TW.g<<endl;
	writeTrapdoorFile("/home/bob/Desktop/80BonehPeks/80BonehPeks/textfiles/server/",TW);
}
bool boneh_Test(G2 TW, G1 PA, Big PB)
{
	if (pfc.hash_to_aes_key(pfc.pairing(TW,PA))==PB){
		cout << "yes it does work" << endl;
		return true;
	}

	else{
		cout << "It did not work"<<endl;
		return false;
	}

}