/*
 *  spring.cpp
 *  simplespring
 *
 *  Created by Robert Tubb on 02/06/2011.
 *  Copyright 2011 __MyCompanyName__. All rights reserved.
 *
 */

#include "spring.h"
#include "lump.h"
#include "globalForces.h"

#include <iostream>
#include "globalUI.h"
extern GlobalForces globalForces;
extern GlobalUI globalUI;
// statics
int Spring::numSprings = 0;
double Spring::maxForce = 0.0;
double Spring::minForce = 0.0;
bool Spring::forcesOn = true;

//---------------------------------------------------------------
Spring::Spring(){
	//cout << "constructing a default spring" << endl;
	
	startPoint.setCoord(0.0,0.0); // dummy values - shouldn't get used
	endPoint.setCoord(0.0,0.0);
	
	springConst = 0.3; // not needed - assume it's one and use 1/c^2 for mass
    
	isInScanPath = false;
	
	startLumpPtr = 0;
	endLumpPtr = 0;
	restLength = 0.0;
	myIndex = Spring::numSprings++;
	maxForce = 0.005;
	minForce = -0.005;
	
	force.x = 0.0;
	force.y = 0.0;
	
	// width of a spring is proportional to how beefy it is
	//ofSetLineWidth(springConst*2);
	
}
//---------------------------------------------------------------
Spring::Spring(double aStartx, double aStarty, double aEndx, double aEndy, double aK){
	// hfsjsfhfshsgr


}
//---------------------------------------------------------------
void Spring::attachLump(Lump * aLump){
	// set position of spring start to mass position
	if(startLumpPtr == 0){
		startLumpPtr = aLump;
		
	}else if(endLumpPtr == 0){
		endLumpPtr = aLump;
		//cout << "----------------------------------------end point attached to " << endLumpPtr << endl;
		updateEndPoints(); // now both ends attached - set the spring start and end points to the relevant lumps
        setRestLength(); // the default length for the spring can be set
	}else{
		cerr << "PERROR can't attach lump to this spring cos it's already attached both ends" << endl;
	}
}
Lump * Spring::getLumpOnOtherEnd(Lump * alump){
    if (startLumpPtr == alump){
        return endLumpPtr;
        
    }else if (endLumpPtr == alump){
        return startLumpPtr;
    }
    cout << "getLumpOnOtherEnd: this should never happen" << endl;

    return NULL;
}
//---------------------------------------------------------------
void Spring::setRestLength(){

	//set rest length according to what the length is now
		TwoVector diff(startPoint.x - endPoint.x, startPoint.y - endPoint.y);
	
		restLength = diff.norm();	

		//restLength = 0.0;

}
	
void Spring::setRestLength(double aLength){
	restLength = aLength;
	
}
void Spring::setSpringConstant(double aK){
    springConst = aK;
}
double Spring::getLength(){
    return startPoint.distanceTo(endPoint);
}
//---------------------------------------------------------------
void Spring::updateEndPoints(){
	// tweak the end points eg: from mass move
	if (startLumpPtr ==0 || endLumpPtr == 0){
		cerr << "PERROR spring masses not attached!" << endl; 
	}else{
		startPoint = startLumpPtr->position;
		//cout << "start pt x = " << startPoint.x << ", y = " << startPoint.y << endl;
		endPoint = endLumpPtr->position;
	}
}
//---------------------------------------------------------------
void Spring::calculateForce(){

	if(!Spring::forcesOn){
		force.x = 0.0;
		force.y = 0.0;
        return;
	}
	// get force from the extension
	double xe = endPoint.x - startPoint.x;
    double ye = endPoint.y - startPoint.y;
	double extendedLength = sqrt(xe*xe + ye*ye);
	
    // doing this enables us to get away with only one division etc
    double FF = springConst*(restLength/extendedLength - 1.0);

    force.x = FF*xe;
    force.y = FF*ye;
  
}
//---------------------------------------------------------------
TwoVector Spring::getForce(Lump * aLump){ // pass in the lump that we want the force for
    
	// above force refers to force at END force at START negative of this...
	if(aLump ==  startLumpPtr){
        TwoVector rForce;
        rForce.setCoord(-force.x, -force.y);
        return rForce;
	}else if(aLump == endLumpPtr ){
        return force;
    }
    cout << "PERROR this lump is not attached to this spring\n";

	return force;
	
}


//---------------------------------------------------------------
void Spring::draw(){

	int sxpos = startPoint.x * ofGetHeight() + globalUI.borderSize; // TODO make this nicer
	int sypos = startPoint.y * ofGetHeight();
	//cout << "start position = " << sxpos << "," << sypos << endl;
	int expos = endPoint.x * ofGetHeight() + globalUI.borderSize;
	int eypos = endPoint.y*ofGetHeight();
	//cout << "end position = " << expos << "," << eypos << endl;

	if(isInScanPath){
        ofSetLineWidth(4);
		ofSetColor(0, 255, 0);
	}else{
        ofSetLineWidth(1);
		ofSetColor(0, 0, 255);
	}
    
	ofLine(sxpos, sypos, expos, eypos);
}
//---------------------------------------------------------------
double Spring::getForceMag(){
	return force.norm();
}
//---------------------------------------------------------------
void Spring::addToScanPath(){
	isInScanPath = true;
}
//---------------------------------------------------------------
void Spring::removeFromScanPath(){
	isInScanPath = false;
}
//---------------------------------------------------------------
/*
void Spring::checkStuff(){
	cout << "checking\n";
}
*/
PressureSpring::PressureSpring(){
    cout << "constructing a pressure spring for droplet mesh\n";
}

//---------------------------------------------------------------
TwoVector PressureSpring::getForce(Lump * aLump){ // pass in the lump that we want the force for
    
    // PRESSURE STUFF
    // by convention a positive pressure allways acts to the left as looking from start to end point
    // ie: Droplet MUST be constructed in clockwise fashion
    // we rotate the spring vector anti clockwise pi/2 radians this gives us the force vector
    // x = -y , y = x except damn y coordinate points downwards so handedness is reversed
    
    // conveniently this is proportional to length just as pressure would be
    //cout << "pressure spring get force\n";
    double xe = endPoint.x - startPoint.x;
    double ye = endPoint.y - startPoint.y;    
	// above force refers to force at END force at START negative of this...
	if(aLump ==  startLumpPtr){
        TwoVector rForce;
        rForce.setCoord(-force.x, -force.y);
        rForce.x += ye * globalForces.pressure * 0.5;
        rForce.y -= xe * globalForces.pressure * 0.5;
        return rForce;
	}else if(aLump == endLumpPtr ){
        TwoVector rForce;
        rForce.setCoord(force.x, force.y);
        rForce.x += ye * globalForces.pressure * 0.5;
        rForce.y -= xe * globalForces.pressure * 0.5;
        return rForce;
    }
    cout << "PERROR this lump is not attached to this spring\n";
    
	return force;
	
}