#include "cTriangle.h"
#include <math.h>
#include <iostream>
using namespace std;

cEdge::cEdge()
{
    f0_ = NULL;
    f1_ = NULL;
    v0_ = NULL;
    v1_ = NULL;
    hasBeenAddedToCollisionList_ = false;
}

cEdge::cEdge(cVertex* v0, cVertex* v1)
{
    f0_ = NULL;
    f1_ = NULL;
    v0_ = v0;
    v1_ = v1;
    hasBeenAddedToCollisionList_ = false;
}

cEdge::cEdge(const cEdge& toCopy)
{
    f0_ = toCopy.f0_;
    f1_ = toCopy.f1_;
    
    v0_ = toCopy.v0_;
    v1_ = toCopy.v1_;
    
    standardizedX_ = toCopy.standardizedX_;
    
    for(int i = 0; i < 16; ++i)
        edgeTransform_[i] = toCopy.edgeTransform_[i];
        
    hasBeenAddedToCollisionList_ = false;
}

void cEdge::setAvailableFace(cTriangle* face)
{
    if(f0_ == NULL && f1_ == NULL) 
    {
        f0_ = face;
        return;
    }
    else if(f0_ != NULL && f1_ == NULL)
    {
        f1_ = face;
        return;
    }
    else if( f0_ != NULL && f1_ != NULL)
        cout << "error: tried to give an edge more than two adjacent faces" << endl;
}
    

void cEdge::standardizeEdge()
{
    // create the new standardized face and 
    // properly set up all of its data fields
    cVector standardizedV0 = *v0_;
    cVector standardizedV1 = *v1_;
    
    // rotate our edge to align last edge with the x axis
    // first we find the axis of rotation v
    // then we find the angle through which we need to rotate phi
    float phi;		// angles of rotation
    cVector rotAxis;		// axis of rotation
    cVector xAxis(1, 0, 0);	// the x-axis
    
    glPushMatrix(); 		// save the current matrix
    
    // translate our edge so v0_ is at the origin
    standardizedV1 -= standardizedV0;
    standardizedV0 = cVector(0, 0, 0);
    
    // rotate our triangle to align last edge with the x axis
    // first we find the axis of rotation v
    // then we find the angle through which we need to rotate phi
    cVector w = standardizedV1;
    w.normalize();
    
    if(w != xAxis && w != -xAxis) // w is not on the x axis
    {
        rotAxis = w.cross(xAxis);
        rotAxis.normalize();
        
        // the angle of rotation is found by taking the arcos of
        // the dot product of w and x we then convert to degrees
            phi = (float) acos((double) w.dot(xAxis));
            phi *= 360.f/(2.0f*3.14159f);	
    }
    else // w is on the x axis
    {
        rotAxis = cVector(0, 1, 0);
        if(w == xAxis) phi = 0;
        else phi = 180;
    }
    
    // have open gl compute the transformation matrix to rotate the edge to the x-axis,
    // assuming it has already been translated to the origin.
    float myTransform[16];
    glLoadIdentity();
    glRotatef(phi, rotAxis.x_, rotAxis.y_, rotAxis.z_);
    glGetFloatv(GL_MODELVIEW_MATRIX, myTransform);

    // update the standardized v1
    standardizedV1 = standardizedV1.matrixMultiply(myTransform);
    standardizedX_ = standardizedV1.x_;
	
    // compute the transformation matrix that we will use to tranform the ball's
    // path into standard space in ege collision. this must rotate and account
    // for the translation to put the first vertex at the origin.
    glLoadIdentity();
    glRotatef(phi, rotAxis.x_, rotAxis.y_, rotAxis.z_);
    glTranslatef(-v0_->x_, -v0_->y_, -v0_->z_);
    glGetFloatv(GL_MODELVIEW_MATRIX, edgeTransform_);

    glPopMatrix(); // restore current matrix
}

float* cEdge::getStandardEdgeTransform() { return edgeTransform_; }

void cEdge::getSumForwardFacingNormal(cVector& incident, cVector& normal)
{
    normal = cVector();
    //int numForwardFaces = 0;
    
    if( f0_ != NULL && f0_->forwardFacing(incident))
    {
        normal += f0_->getNormal();
        //++numForwardFaces;
    }
    
    if(f1_ !=NULL && f1_->forwardFacing(incident))
    {
        normal += f1_->getNormal();
        //++numForwardFaces;
    }
}
