/***************************************************************************
 *   Copyright (C) 2008 by Peter Dahlberg				   *
 *   pdahlberg@gmail.com 						   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "graphicsellipseitem.h"
#include <QDrag>
#include <QGraphicsSceneMouseEvent>
#include <QMimeData>
#include <QPainterPath>
#include <QGraphicsPathItem>
#include <QDebug>
#include "simulscene.h"
#include "probechargewidget.h"
#include <cmath>
#include "constants.h"
#include <iostream>
#include <climits>
#include <QLocale>

GraphicsEllipseItem::GraphicsEllipseItem() {
	//setFlag(ItemIsMovable);
	//setFlag(ItemIsSelectable);
	setFlag(ItemIsFocusable);
	//setCacheMode(QGraphicsItem::DeviceCoordinateCache);
	//startTimer(100);
	myProbeChargeWidget = new ProbeChargeWidget(0,0,this);

	currProbePath = new QList<QPointF>;
	speedListX = new QList<double>;
	speedListY = new QList<double>;
	elapsedTimeList= new QList<double>;
	setupVars();

}
void  GraphicsEllipseItem::setupVars () {
	setMasse(9.10938188e-31);
	setCharge(-1.6e-19);
	setStartSpeedX(0);
	setStartSpeedY(0);
	setPos(0,0);
	setAdaptiveStepLength(0.01);
	setAdaptiveStepControl(true);
}

QList<QVariant> GraphicsEllipseItem::getSaveDataList(){
	QList<QVariant> list;
	list << getMasse(0);
	list << getCharge();
	list << getStartSpeedX();
	list << getStartSpeedY();
	list << scenePos();
	list << getAdaptiveStepLength();
	list << isAdaptiveStepControlEnabled();
	return list;
}
void GraphicsEllipseItem::setSaveDataList(QList<QVariant> list) {
	setMasse(list[0].toDouble());
	setCharge(list[1].toDouble());
	setStartSpeedX(list[2].toDouble());
	setStartSpeedY(list[3].toDouble());
	setPos(list[4].toPointF());
	setAdaptiveStepLength(list[5].toDouble());
	setAdaptiveStepControl(list[6].toBool());
}

void  GraphicsEllipseItem::resetProbe() {
	setupVars();
}

void  GraphicsEllipseItem::timerEvent ( QTimerEvent * event ) {
	static double vx;
	vx++;
	//moveBy(vx/20.0,vx/20.0*vx/20.0);
}

GraphicsEllipseItem::~GraphicsEllipseItem() {
}

void GraphicsEllipseItem::mousePressEvent ( QGraphicsSceneMouseEvent *event ) {
	//QGraphicsEllipseItem::mousePressEvent(event);
}

void GraphicsEllipseItem::handleSceneChange(const QList<QRectF> & /*region*/) {
	if (myScenePos != scenePos()) {
		myScenePos = scenePos();
		emit ScenePosChanged(myScenePos);
		emit ScenePosXChanged(myScenePos.x());
		emit ScenePosYChanged(myScenePos.y());
	}

}

void GraphicsEllipseItem::updateScenePosLabels() {
	SimulScene* myScene = dynamic_cast<SimulScene*>(scene());
		if (myScene != 0) {
			QString ScenePosPxStringX(QLocale().toString(myScenePos.x(),'g',3));
			ScenePosPxStringX.append(" px");
			QString ScenePosPxStringY(QLocale().toString(myScenePos.y(),'g',3));
			ScenePosPxStringY.append(" px");
			QString ScenePosMStringX(QLocale().toString(myScenePos.x()*myScene->getMeterPerPx(),'g',3));
			ScenePosMStringX.append(" m");
			QString ScenePosMStringY(QLocale().toString(myScenePos.y()*myScene->getMeterPerPx(),'g',3));
			ScenePosMStringY.append(" m");
			emit ScenePosXChangedPixel(ScenePosPxStringX);
			emit ScenePosYChangedPixel(ScenePosPxStringY);
			emit ScenePosXChangedMeter(ScenePosMStringX);
			emit ScenePosYChangedMeter(ScenePosMStringY);
		}
}

/*!
    \fn GraphicsEllipseItem::calculateProbePath()
 */
void GraphicsEllipseItem::calculateProbePath(QPointF startPoint) {

	double startSpeedX = getStartSpeedX();
	double startSpeedY = getStartSpeedY();
	SimulScene* myScene = dynamic_cast<SimulScene*>(scene());
	//wenn noch zu keiner scene gehoerend abbruch
	if (myScene == 0) return;
	//parameter der scene in lokale variablen uebernehmen
	double timePerStep = myScene->getTimePerStep();
	int steps = myScene->getSteps();
	double meterPerPx = myScene->getMeterPerPx();

	//listen leeren
	currProbePath->clear();
	speedListX->clear();
	speedListY->clear();
	elapsedTimeList->clear();
	//startwerte in die listen setzen
	currProbePath->append(startPoint);
	speedListX->append(startSpeedX);
	speedListY->append(startSpeedY);
	elapsedTimeList->append(0);

	//startpunkt in den Pfad setzen
	flightPath = QPainterPath(startPoint);

	for(int i = 1; i< steps;++i) {
		//Geschwindigkeit (gesamt)
		double combinedSpeed = sqrt( speedListX->at(i-1)*speedListX->at(i-1) + speedListY->at(i-1)*speedListY->at(i-1) );

		double myMasse = getMasse(combinedSpeed);
		//qDebug()<< myMasse;

		double powerX = myScene->getPowerAt(currProbePath->at(i-1), charge, speedListX->at(i-1),speedListY->at(i-1), 'x');
		double powerY = myScene->getPowerAt(currProbePath->at(i-1), charge, speedListX->at(i-1),speedListY->at(i-1), 'y');
		double combinedPower = sqrt(powerX*powerX+powerY*powerY);

		//automatische Zeitschrittanpassung
 		//if (isAdaptiveStepControlEnabled()&&combinedSpeed != 0) timePerStep = getAdaptiveStepLength()/(combinedSpeed/meterPerPx);
 		//if (isAdaptiveStepControlEnabled() && combinedPower !=0) {
 		//	timePerStep = fabs((-combinedSpeed + sqrt(combinedSpeed*combinedSpeed + 2*(combinedPower/myMasse)*getAdaptiveStepLength()*meterPerPx)) / (combinedPower/myMasse));
 		//}
		if (isAdaptiveStepControlEnabled() && (combinedPower !=0||combinedSpeed != 0)) {
			timePerStep = getAdaptiveStepLength()*meterPerPx/sqrt(2*(combinedPower/myMasse)*getAdaptiveStepLength()*meterPerPx+combinedSpeed*combinedSpeed);
		}
		//qDebug()<<timePerStep;

		double deltaSpeedX =  (powerX/myMasse * timePerStep);
		double deltaSpeedY = (powerY/myMasse * timePerStep);

		double newspeedX = speedListX->at(i-1) + deltaSpeedX;
		double newspeedY = speedListY->at(i-1) + deltaSpeedY;
		
		//double deltaDistX = (newspeedX * timePerStep);
		//double deltaDistY = (newspeedY * timePerStep);
		double deltaDistX = speedListX->at(i-1)* timePerStep + 0.5 * powerX/myMasse* timePerStep* timePerStep;
		double deltaDistY = speedListY->at(i-1)* timePerStep + 0.5 * powerY/myMasse* timePerStep* timePerStep;
		
		//qDebug() << deltaDistY;
		
		QPointF newPoint(currProbePath->at(i-1).x() + deltaDistX/meterPerPx ,currProbePath->at(i-1).y() + deltaDistY/meterPerPx);

		//Scrollbar int Probleme vermeiden
		if (newPoint.x() + 10 > INT_MAX || newPoint.x() - 10 < INT_MIN) break;
		if (newPoint.y() + 10 > INT_MAX || newPoint.y() - 10 < INT_MIN) break;

		if (myScene->stopsHere(currProbePath->at(i-1),newPoint)) break;

		currProbePath->append(newPoint);
		speedListX->append(newspeedX);
					speedListY->append(newspeedY);

		elapsedTimeList->append(elapsedTimeList->at(i-1) + timePerStep);
	}

	int path_entry_step = currProbePath->count()/5000.0; //jeder entry_step(te) step wird eingetragen
	if (path_entry_step == 0) path_entry_step = 1;
	for (int i = 1; i< currProbePath->count();++i) {
		if (i%path_entry_step == 0 || i==currProbePath->count()) flightPath.lineTo(currProbePath->at(i));
	}

	//qDebug()<< "Probe Path: " <<*currProbePath;
	//qDebug()<< "speed x: "<<*speedListX;
	//qDebug()<< "speed y: "<<*speedListY;
	//qDebug()<<speedListY->at(12);
	//qDebug()<<"power x: "<< (double)myScene->getPowerAt(QPointF(0,0), charge, 'x');
	//qDebug()<<"power y: " << (double)myScene->getPowerAt(QPointF(0,0), charge, 'y');
	//qDebug()<< getMasse(5e+20);

}
QList<double> *GraphicsEllipseItem::getElapsedTimeList() {
	return elapsedTimeList;
}


double GraphicsEllipseItem::getMasse(double speed) {
	//damit kein inf oder nan entsteht
	if(speed > (SPEED_OF_LIGHT - 3e-8)) speed = SPEED_OF_LIGHT - 3e-8; //fuer v>=c nehme v (etwas)<c an
	if(speed < SPEED_OF_LIGHT/10.0) return masse;
	
	return masse / (sqrt(1- ( (speed/SPEED_OF_LIGHT)*(speed/SPEED_OF_LIGHT))));


}


void GraphicsEllipseItem::setMasse ( const double& theValue ) {
	if (masse == theValue) return;
	masse = theValue;
	emit masseChanged(theValue);
}


double GraphicsEllipseItem::getCharge() const {
	return charge;
}


void GraphicsEllipseItem::setCharge ( const double& theValue ) {
	if (charge == theValue) return;
	charge = theValue;
	emit chargeChanged(theValue);
}

QWidget * GraphicsEllipseItem::getDockWidget() const
{
    return myProbeChargeWidget;
}

QList<QPointF> * GraphicsEllipseItem::getCurrProbePath() {
	return currProbePath;
}

double GraphicsEllipseItem::getStartSpeedX() const {
	return startSpeedX;
}


void GraphicsEllipseItem::setStartSpeedX ( double theValue ) {
	if (startSpeedX == theValue) return;
	startSpeedX = theValue;
	emit startSpeedXChanged(theValue);
}


double GraphicsEllipseItem::getStartSpeedY() const {
	return startSpeedY;
}


void GraphicsEllipseItem::setStartSpeedY ( double theValue ) {
	if (startSpeedY == theValue) return;
	startSpeedY = theValue;
	emit startSpeedYChanged(theValue);
}


/*!
    \fn GraphicsEllipseItem::setScenePosY(double posY)
 */
void GraphicsEllipseItem::setScenePosY(double newPosY)
{
   	moveBy(0, newPosY - scenePos().y());
}


/*!
    \fn GraphicsEllipseItem::setScenePosX(double posX)
 */
void GraphicsEllipseItem::setScenePosX(double newPosX)
{
        moveBy(newPosX - scenePos().x(),0 );
}


QPainterPath GraphicsEllipseItem::getFlightPath() const {
	return flightPath;
}


void GraphicsEllipseItem::setFlightPath ( const QPainterPath& theValue ) {
	if (flightPath==theValue) return;
	flightPath = theValue;
}





bool GraphicsEllipseItem::isAdaptiveStepControlEnabled() const {
	return adaptiveStepControlEnabled;
}


void GraphicsEllipseItem::setAdaptiveStepControl ( bool theValue ) {
	if (adaptiveStepControlEnabled == theValue) return;
	adaptiveStepControlEnabled = theValue;
	emit adaptiveStepControlChanged(theValue);
}


double GraphicsEllipseItem::getAdaptiveStepLength() const {
	return adaptiveStepLength;
}


void GraphicsEllipseItem::setAdaptiveStepLength ( double theValue ) {
	if (adaptiveStepLength == theValue) return;
	adaptiveStepLength = theValue;
	emit adaptiveStepLengthChanged(theValue);
}


QList< double >* GraphicsEllipseItem::getSpeedListX() const {
	return speedListX;
}


QList< double >* GraphicsEllipseItem::getSpeedListY() const {
	return speedListY;
}
