/**************************************************
 *   File:     Object.cpp
 *   Author:   Dr. Dalton R. Hunkins     
 *   Date:     September 2008
**************************************************/
#include "Object.h"

#include <cmath>
using std::acos;
#include <GL/Utils/MathFunctions.h>

  Object::Object() { }

  Object::Object(float color[3], 
                 double scaleFactor,
                 double translateX,
                 double translateY) {
     for (int i=0; i<3; i++)
        Object::initialColor[i] = color[i];
           	  
     initialScaleFactor = scaleFactor;
     initialTranslateX  = translateX;
     initialTranslateY  = translateY;
           
     currentScale      = scaleFactor;
     currentTranslateX = translateX;
     currentTranslateY = translateY;
     for (int i=0; i<3; i++)
        currentColor[i] = initialColor[i];
     isCurrentObject = false;   
  }    
           
  void Object::setTranslation(double x, double y) {
      currentTranslateX = x;
      currentTranslateY = y;
  }
      
  void Object::incrementScale(double amount) {
  	  double temp = currentScale + amount;
  	  if (temp >= 0)
   	     currentScale = temp;
  } 	  
      	   
  void Object::setColor(float color[3]) {
      for (int i=0; i<3; i++)
   	      Object::currentColor[i] = color[i];
  }
  
  void Object::setAsCurrentObject(bool value) {
  	  isCurrentObject = value;
  } 	  
           
  void Object::draw() {}
  
  
  bool Object::isOver(double x, double y) { }
  
  void Object::reset() {
  	 currentTranslateX = initialTranslateX;
  	 currentTranslateY = initialTranslateY;
  	 currentScale      = initialScaleFactor;
  	 for (int i=0; i<3; i++)
  	    currentColor[i]= initialColor[i];
  	 isCurrentObject = false;
  	 glutPostRedisplay();
  }
  	            
  Square::Square(float color[3], 
           double scaleFactor,
           double translateX,
           double translateY) : Object(color, 
                                       scaleFactor,
                                       translateX,
                                       translateY) { }
                                       
  void Square::draw() {                                       
      glColor3fv(currentColor);
      	  
      glMatrixMode(GL_MODELVIEW);
      glPushMatrix();
      glTranslated(currentTranslateX, currentTranslateY, 0.0);
      glScaled(currentScale, currentScale, 0.0);
      glBegin(GL_POLYGON);
         glVertex3d(-1.0, -1.0, 0.0);
         glVertex3d( 1.0, -1.0, 0.0);
         glVertex3d( 1.0,  1.0, 0.0);
         glVertex3d(-1.0,  1.0, 0.0);
      glEnd();
      
      if (isCurrentObject) {
      	 glLineWidth(3.0);
      	 glColor3f(1.0, 1.0, 1.0);
         glBegin(GL_LINE_LOOP);
            glVertex3d(-1.0, -1.0, 0.0);
            glVertex3d( 1.0, -1.0, 0.0);
            glVertex3d( 1.0,  1.0, 0.0);
            glVertex3d(-1.0,  1.0, 0.0);
         glEnd();
      }	 
      glPopMatrix();
  }                         
   
                                      
  bool Square::isOver(double x, double y) {
  	 return ((-currentScale+currentTranslateX) <= x) && 
  	        (x <= (currentScale+currentTranslateX))  &&
  	        ((-currentScale+currentTranslateY) <= y) &&
  	        (y <= (currentScale+currentTranslateY));
  }
  

  Disk::Disk(float color[3], 
           double scaleFactor,
           double translateX,
           double translateY) : Object(color, 
                                       scaleFactor,
                                       translateX,
                                       translateY) { }
  void Disk::draw( ) {
     glColor3fv(currentColor);
      	  
     glMatrixMode(GL_MODELVIEW);
     glPushMatrix();
     glTranslated(currentTranslateX, currentTranslateY, 0.0);
     glScaled(currentScale, currentScale, 0.0);
     gluDisk(gluNewQuadric(), 0.0, 1.0, 72, 1);
     
     if (isCurrentObject) {
        glColor3f(1.0, 1.0, 1.0);
        gluDisk(gluNewQuadric(), 0.90, 1.0, 72, 1);
     }     
     glPopMatrix();	 
  }
  
  
  bool Disk::isOver(double x, double y) {
  	  return   ((currentTranslateX - x)*(currentTranslateX - x)
  	         + (currentTranslateY - y)*(currentTranslateY - y))
  	         <= currentScale*currentScale;
  }
  
  Triangle::Triangle(float color[3], 
           double scaleFactor,
           double translateX,
           double translateY) : Object(color, 
                                       scaleFactor,
                                       translateX,
                                       translateY) { }
   void Triangle::draw() {
       	  glColor3fv(currentColor);
      	  
      	  glMatrixMode(GL_MODELVIEW);
      	  glPushMatrix();
      	  glTranslated(currentTranslateX, currentTranslateY, 0.0);
      	  glScaled(currentScale, currentScale, 0.0);   	
          glBegin(GL_POLYGON);
            glVertex3d(-1.0, -1.0, 0.0);
            glVertex3d( 1.0, -1.0, 0.0);
            glVertex3d( 0.0,  1.0,    0.0);
          glEnd();
              
          if (isCurrentObject) {
           	  glColor3f(1.0, 1.0, 1.0);
           	  glLineWidth(3.0);
              glBegin(GL_LINE_LOOP);
                glVertex3d(-1.0, -1.0, 0.0);
                glVertex3d( 1.0, -1.0, 0.0);
                glVertex3d( 0.0,  1.0,    0.0);
              glEnd();
          } 	     
          glPopMatrix();	 
   }
   
  
   bool Triangle::isOver(double x, double y) {
   	   double vector1[] = {-1.0*currentScale+currentTranslateX - x,
   	   	                   -1.0*currentScale+currentTranslateY - y, 0.0};
       double vector2[] = { 1.0*currentScale+currentTranslateX - x,
   	   	                   -1.0*currentScale+currentTranslateY - y, 0.0}; 
       double vector3[] = { 0.0*currentScale+currentTranslateX - x,
   	   	                    1.0*currentScale+currentTranslateY - y, 0.0};   	   	                 
   	   double normalizedVector1[3];
   	   double normalizedVector2[3];
   	   double normalizedVector3[3];
   	   normalize(vector1, normalizedVector1);
   	   normalize(vector2, normalizedVector2);
   	   normalize(vector3, normalizedVector3);
   	   double angle1 = acos(dotProduct(normalizedVector1,
   	                                   normalizedVector2));
   	   double angle2 = acos(dotProduct(normalizedVector1, 
   	                                   normalizedVector3));
   	   double angle3 = acos(dotProduct(normalizedVector2, 
   	                                   normalizedVector3));   	                                   
   	   return !((angle1 + angle2 + angle3) < 2*PI);
}