#include "PathADT.h"

#include "PointADT.h"
#include "LineADT.h"
#include "MapTypes.h"
#include "Exceptions.h"

#include <vector>

using std::vector;


PathT::PathT(PointT st, CompassT o, nat l)
{
  s.push_back(LineT(st, o, l));
}

void PathT::append(CompassT o, nat l)
{
  LineT newLn(adjPt(o), o, l);
  
  for(auto ln : s)
    if(intersects(newLn, ln))
      throw invalid_argument();
  
  s.push_back(newLn);
}

PointT PathT::strt() const
{
  return s.front().strt();
}

PointT PathT::end() const
{
  return s.back().end();
}

LineT PathT::line(nat i) const
{
  if(i >= s.size())
    throw outside_bounds();
  return s[i];
}

nat PathT::size() const
{
  return s.size();
}

nat PathT::len() const
{
  nat sum = 0;
  
  for(auto ln : s)
    sum += ln.len();
    
  return sum; 
}

PathT PathT::translate(int dx, int dy) const
{
  PathT newPath = *this;
  newPath.translatePriv(dx, dy);
  return newPath;
}



// private methods

void PathT::translatePriv(int dx, int dy)
{
  for(vector<LineT>::iterator it = s.begin(); it != s.end(); ++it)
    *it = (*it).translate(dx, dy);
}

vector<PointT> PathT::pointsInLine(LineT ln) const
{
  vector<PointT> pts;
  
  int xFactor = 0;
  int yFactor = 0;
  
  switch(ln.orient()){
    case N:
      yFactor = 1;
      break;
    case S:
      yFactor = -1;
      break;
    case E:
      xFactor = 1;
      break;
    case W:
      xFactor = -1;
      break;
  }
  
  for(nat i = 0; i < ln.len(); ++i)
    pts.push_back(ln.strt().translate(i*xFactor, i*yFactor));
  
  return pts;
}

PointT PathT::adjPt(CompassT o) const
{
  switch(o){
    case N:
      return end().translate(0, 1);
    case S:
      return end().translate(0, -1);
    case E:
      return end().translate(1, 0);
    case W:
      return end().translate(-1, 0);
  }
}

bool PathT::intersects(LineT a, LineT b) const
{
  vector<PointT> ptsA = pointsInLine(a);
  vector<PointT> ptsB = pointsInLine(b);
  
  for(auto pA : ptsA)
    for(auto pB : ptsB)
      if(pA == pB) return true;
    
  return false;
}