#include "line.h"

// constructors and desctructor 
line::line ( void ) {
}

line::line ( const line & xxx )
{
  is_vertical = xxx.vert();
  myslope = xxx.slope();
  end1 = xxx.point1();
  end2 = xxx.point2();
}

line::line ( const ratpoint & rp1, const ratpoint & rp2 )
{
  end1 = rp1;
  end2 = rp2;
  is_vertical = (rp1.x() == rp2.x());
  if (!is_vertical) {
    myslope = (rp1.y() - rp2.y()) / (rp1.x() - rp2.x());
  }
}

void line::makeline ( const ratpoint & rp1, const ratpoint & rp2 )
{
  end1 = rp1;
  end2 = rp2;
  is_vertical = (rp1.x() == rp2.x());
  if (!is_vertical) {
    myslope = (rp1.y() - rp2.y()) / (rp1.x() - rp2.x());
  }
}

line::~line ( )
{
}

// overloading of the assignment operator =
line & line::operator = ( const line & x )
{
  is_vertical = x.vert();
  myslope = x.slope();
  end1 = x.point1();
  end2 = x.point2();

  // return a reference to THIS object so that we
  // can write x =.y() = z = ...
  return *this;
}

// overloading of the output operator
ostream & operator << ( ostream & out , const line & x )
{
  out << "line that goes through " << x.end1 << " and " << x.end2;
}

bool line::hitpoint ( const ratpoint & x ) {
  if (is_vertical) {
    return (end1.x() == x.x());
  } else if (end1.x() == x.x()) {
    rational testslope;
    testslope = (x.y() - end2.y()) / (x.x() - end2.x());
    return (myslope == testslope);
  } else {
    rational testslope;
    testslope = (x.y() - end1.y()) / (x.x() - end1.x());
    return (myslope == testslope);
  }
}

bool line::intersect (const line & x) {
  if (is_vertical) {
    if (end1.y() == end2.y()) return false;
    return !(x.vert());
  } else if (x.vert()) {
    return true;
  } else {
    return !(myslope == x.slope());
  }
}

ratpoint line::intersection (const line & x) {
  rational my_x;
  rational my_y;
  if (is_vertical) {
    my_x = end1.x();
    if (my_x == x.point1().x())
      my_y = x.point2().y() - x.slope() * (x.point2().x() - my_x);
    else
      my_y = x.point1().y() - x.slope() * (x.point1().x() - my_x);
  } else if (x.vert()) {
    my_x = x.point1().x();
    if (my_x == end1.x())
      my_y = end2.y() - myslope * (end2.x() - my_x);
    else
      my_y = end1.y() - myslope * (end1.x() - my_x);
  } else {
    my_x = ((end1.x() * myslope - x.point1().x() * x.slope()) 
          + (x.point1().y() - end1.y()))
         / (myslope - x.slope());
    my_y = ((x.point1().y() * myslope - end1.y() * x.slope()) 
          + (end1.x() - x.point1().x())*myslope*x.slope())
         / (myslope - x.slope());
  }
  return ratpoint(my_x,my_y);
}

int line::side ( const ratpoint & x ) {
  rational d1;
  rational d2;
  rational m;
  int answer;
  if (is_vertical) {
    d1 = x.y() - end1.y();
    d2 = x.y() - end2.y();
  } else {
    d1 = x.x() - end1.x();
    d2 = x.x() - end2.x();
  }
  m = d1 - d2;
  d1 = d1 * m;  d2 = d2 * m;
  if (d1.numerator() <= 0) answer = 0;
  else if (d2.numerator() >= 0) answer = 2;
  else answer = 1;
  return answer;
}

bool line::between ( const ratpoint & x , const ratpoint & y ,
                     const ratpoint & z ) {
  rational checker; 
  if (is_vertical) {
    checker = (x.y() - y.y()) * (x.y() - z.y());
  } else {
    checker = (x.x() - y.x()) * (x.x() - z.x());
  }
  return (checker.numerator() <= 0);
}


