////////////////////////////////////////////////////////////////
//
// This program loads in a mapping problem (same format and files as
// the assignment 3 support code), an image (generated by your
// assignment 3 code), and a world description (same as assignments 1
// and 2).
//
// You can write your own code in this file to determine how good your
// map is when compared to the real world.
// 
////////////////////////////////////////////////////////////////

#include <iostream>
#include <dolt.h>
#include "world.h"
#include "mapproblem.h"

#include <CGAL/Triangle_2_Triangle_2_intersection.h>

using namespace std;
using namespace dolt;

drawableImage *Map;
Bbox gridBbox;

World *W;
MapProblem *MP;

// this is the function that you'll probably end up using to measure
// the occupancy of a cell
// 
double intersection_area(const Bbox & b, const Polygon & p);



int main(int argc, char *argv[])
{
#ifdef RUNTESTS
  Bbox b(0,0,4,5);
  Polygon p;
  // test 1
//   p.push_back(Point(5,6));
//   p.push_back(Point(2,6));
//   p.push_back(Point(2,3));
//   p.push_back(Point(5,3));
  // test 2
  p.push_back(Point(8,2));
  p.push_back(Point(7,6));
  p.push_back(Point(4,7));
  p.push_back(Point(2,6));
  p.push_back(Point(2,3));
  p.push_back(Point(6,1));
  
  double a = intersection_area(b, p);
  cout << "The intersecion area is: " << a << endl;
  
  exit(0);
#endif

  // make sure there are enough arguments
  if (argc < 4) {
    cerr << "Usage: " << argv[0]
	 << " <image-fname> <problem-fname> <world-fname>"
	 << endl;
    exit(1);
  }

  ////////////////////////////////////////////////////////////////
  // this next bit of code is directly from assign3.cpp
  // it reads in the problem and calculates the image size

  MP = new MapProblem(argv[2]);
  
  const Bbox worldBbox = MP->boundary;
  cout << "Requested boundary is: " << MP->boundary << endl;
  double width = worldBbox.xmax() - worldBbox.xmin();
  double height = worldBbox.ymax() - worldBbox.ymin();
  cout << "Cell size will be: " << MP->cellSize << endl;
  int xcells = (int) ceil(width/MP->cellSize);
  int ycells = (int) ceil(height/MP->cellSize);
  // calculate the actual grid size using an integral number of cells
  double xmax = worldBbox.xmin()+xcells*MP->cellSize;
  double ymax = worldBbox.ymin()+ycells*MP->cellSize;
  gridBbox = Bbox(worldBbox.xmin(), worldBbox.ymin(), xmax, ymax);
  cout << "Actual grid bounds are: " << gridBbox << endl;

  Map = new drawableImage(gridBbox, xcells, ycells, drawableImage::BPP1);

  // read the image from a file.  actually, the above calculations
  // aren't really necessary because the loadPPM method will create a
  // new image according to the dimensions of the image in the file.
  // however, it's probably useful to have the same parameters as you
  // did in assign3.cpp
  // 
  if (!Map->loadPPM(argv[1])) {
    cerr << "Error reading image from file \"" << argv[argc-3] << "\"" 
	 << endl;
    exit(1);
  }

  ////////////////////////////////////////////////////////////////
  // now read in the world description
  
  W = new World(argv[3]);

}


double triIntersectArea(const Triangle & ta, const Triangle & tb)
{
  CGAL::Object result;
  Triangle t;
  vector<Point> v;
  
  result = intersection(ta, tb);
  if (assign(t, result)) {
//     cout << "intersection triangle is: " << t << endl;
    return t.area();
  }
  else if (assign(v, result)) {
//     cout << "intersection is a vector of points" << endl;
    double area = 0.0;
    for (unsigned int k=1; k+1<v.size(); ++k) {
      double a = CGAL::area(v[0], v[k], v[k+1]);
//       cout << "  area contribution is " << a << endl;
      area += a;
    }
    return area;
  }
  else {
//     cerr << "no intersection!" << endl;
    return 0.0;
  }
}


// returns the area of the intersection between a bounding box and a
// CONVEX polygon
//
// polygon intersection in CGAL is a little involved, so this breaks
// the bbox and the polygon down into triangles, and the intersection
// of all pairs of triangles is computed
// 
double intersection_area(const Bbox & b, const Polygon & p)
{
  const Point ll(b.xmin(), b.ymin());
  const Point lr(b.xmax(), b.ymin());
  const Point ul(b.xmin(), b.ymax());
  const Point ur(b.xmax(), b.ymax());
  Triangle bt1(ll,ur,ul);
  Triangle bt2(ll,lr,ur);

  cout << "bt1 is " << bt1 << endl
       << "bt2 is " << bt2 << endl;

  double area=0.0;
  Polygon::const_iterator apex = p.vertices_begin();
  Polygon::const_iterator ptA = apex;
  Polygon::const_iterator ptB = apex;
  ptA++; ptB++; ptB++;
  for (; ptB != p.vertices_end(); ptA++, ptB++) {
    const Triangle t(*apex, *ptA, *ptB);
//     cout << "checking intersection with triangle: " << t << endl;
    double ba1 = -triIntersectArea(bt1, t);
//     cout << "area from intersection with bt1 is " << ba1 << endl;
    double ba2 = -triIntersectArea(bt2, t);
//     cout << "area from intersection with bt2 is " << ba2 << endl << endl;
    area += ba1 + ba2;
  }

  return area;
}

