#include "main_win.h"
#include <math.h>
#include <QGraphicsLineItem>

#define POCET_KROKU	10000

MainWin::MainWin(QWidget * p):QMainWindow(p),prev_scale(0) {
	setupUi(this);

	insertWin = new InsertWin(this);
	scene = new QGraphicsScene();
	graphicsView->setScene(scene);
	vysledekWin = new VysledekWin(this);;
	helpWin = new HelpWin(this);;

	graphicsView->setDragMode(QGraphicsView::ScrollHandDrag);

	connect(actionInsertData, SIGNAL(triggered()), insertWin, SLOT(resetAll()));
	connect(actionInsertData, SIGNAL(triggered()), insertWin, SLOT(show()));
	connect(insertWin, SIGNAL(accepted()), this, SLOT(calculate()));
	connect(actionVysledek, SIGNAL(triggered()), vysledekWin, SLOT(show()));
	connect(actionN_pov_da, SIGNAL(triggered()), helpWin, SLOT(show()));

	connect(action_ph, SIGNAL(triggered()), this, SLOT(zoom_ph()));
	connect(action_mh, SIGNAL(triggered()), this, SLOT(zoom_mh()));
	connect(action_pv, SIGNAL(triggered()), this, SLOT(zoom_pv()));
	connect(action_mv, SIGNAL(triggered()), this, SLOT(zoom_mv()));

	graphicsView->scale(10,3);
}

void MainWin::calculate() {
	int n = insertWin->n_spinBox->value();
	double L = insertWin->l_doubleSpinBox->value();

	bool *I = new bool[n+2];
	double *x,*SP,*alfa,*xp;
	x = new double[n+2];
	SP = new double[n+2];
	alfa = new double[n+2];
	xp = new double[POCET_KROKU+2];

	double N1[POCET_KROKU+2], T1[POCET_KROKU+2], MOY1[POCET_KROKU+2];
	double N[POCET_KROKU+2], T[POCET_KROKU+2], MOY[POCET_KROKU+2];

	double FAX,FAZ,Fbz,MA;

	bool prvni = insertWin->prvni_toolButton->isChecked();

	// init I, x, SP, alfa
	for (int i = 0; i < n; i++) {
		I[i+1] = insertWin->getPrvky()[i]->sila;
		x[i+1] = insertWin->getPrvky()[i]->x;
		SP[i+1] = insertWin->getPrvky()[i]->SP;
		alfa[i+1] = insertWin->getPrvky()[i]->alfa;
		//printf("I: %d x: %lf SP: %lf alfa: %lf\n", I[i+1]?1:-1, x[i+1], SP[i+1], alfa[i+1]);
	}

	// init xp
	xp[0] = 0.0;
	for (int i = 1; i < POCET_KROKU; i++) 
		xp[i] = (i-1)*(L/POCET_KROKU);
	xp[POCET_KROKU] = L;

	// calc N1, T1
	N1[0] = T1[0] = 0;
	for (int i = 1; i <= n; i++) {
		if (I[i] == SILA) {
			N1[i] = N1[i-1] - SP[i]*cos((alfa[i])*(M_PI/180));
			T1[i] = T1[i-1] - SP[i]*sin((alfa[i])*(M_PI/180));
			//printf("N1[%d] == %lf | T1[%d] == %lf\n", i, N1[i],i,T1[i]);
		}
		else { // MOMENT
			N1[i] = N1[i-1];
			T1[i] = T1[i-1];
		}
	}

	MOY1[0] = 0;
	I[n+1] = SILA;
	x[0] = 0;
	x[n+1] = L;
	// calc MOY1
	
	if (prvni) { // prvni
		for (int i = 1; i <= n+1; i++) 
			if (I[i] == SILA) {
				MOY1[i] = MOY1[i-1] + T1[i-1]*(x[i]-x[i-1]);
				//printf("MOY1[%d] == %lf\n", i,MOY1[i]);
			}
			else MOY1[i] = MOY1[i-1] + T1[i-1]*(x[i]-x[i-1]) - SP[i];
	
		// calc FAX, FAZ, Fbz
		FAX = N1[n];
		FAZ = +1 * MOY1[n+1]/x[n+1];
		Fbz = T1[n] - FAZ;
		//printf("n == %d | N1[n] == %lf | MOY1[n+1] == %lf | x[n+1] == %lf | T1[n] == %lf\n", n, N1[n], MOY1[n+1], x[n+1], T1[n]);
	}
	else { // druhe
		for (int i = 1; i <= n+1; i++) 
			if (I[i] == SILA) {
				MOY1[i] = MOY1[i-1] - SP[i]*sin((-1*alfa[i])*(M_PI/180))*(x[i]);
				//printf("MOY1[%d] == %lf\n", i,MOY1[i]);
			}
			else MOY1[i] = MOY1[i-1] - SP[i]*sin((-1*alfa[i])*(M_PI/180))*(x[i]) - SP[i];// T1[n-i]*(x[i]-x[i-1]) - SP[i];

		// calc FAX, FAZ, MA
		FAX = N1[n];
		FAZ = T1[n];
		MA =  MOY1[n+1];
		//printf("n == %d | N1[n] == %lf | MOY1[n+1] == %lf | x[n+1] == %lf | T1[n] == %lf\n", n, N1[n], MOY1[n+1], x[n+1], T1[n]);
	}

				
	// vypis FAX, FAZ, Fbz
	vysledekWin->listWidget->clear();
	vysledekWin->listWidget->addItem(QString("FAX = %1").arg(FAX,0,'g',3));
	vysledekWin->listWidget->addItem(QString("FAZ = %1").arg(FAZ,0,'g',3));
	if (prvni)
		vysledekWin->listWidget->addItem(QString("Fbz = %1").arg(Fbz,0,'g',3));
	else vysledekWin->listWidget->addItem(QString("MA = %1").arg(Fbz,0,'g',3));

	for (int i = 0; i < POCET_KROKU+2; i++) 
		N[i] = T[i] = MOY[i] = 0;

	if (prvni) { // prvni
		// calc N, T, MOY
		for (int j = 1; j <= POCET_KROKU; j++) {
			for (int i = 0; i <= n; i++) 
				if (xp[j] >= x[i] && xp[j] < x[i+1]) {
					N[j] = N1[i] - FAX;
					T[j] = T1[i] - FAZ;
					MOY[j] = MOY1[i] + T1[i]*(xp[j]-x[i]) - FAZ*xp[j];
				}

			vysledekWin->moreWin->listWidget_n->addItem(QString("%1 = %2").arg(xp[j]).arg(N[j]));
			vysledekWin->moreWin->listWidget_t->addItem(QString("%1 = %2").arg(xp[j]).arg(T[j]));
			vysledekWin->moreWin->listWidget_m->addItem(QString("%1 = %2").arg(xp[j]).arg(MOY[j]));
		}
	}
	else { // druhe
		// calc N, T, MOY
		for (int j = 1; j <= POCET_KROKU; j++) 
			for (int i = 0; i <= n; i++) 
				if (xp[j] >= x[i] && xp[j] < x[i+1]) {
					N[j] = N1[i] - FAX;
					T[j] = -T1[i] - FAZ;
					MOY[j] = -MOY1[i] + T1[n-i]*(xp[j]) + MA ;
					//printf("MOY[%d] == %lf\n", j, MOY[j]);
				}
	}
	
	graphicsView->centerOn(0, 0);
	QList <QGraphicsItem *> items = scene->items();

	for (int i = 0; i < items.size(); i++)
		scene->removeItem(items[i]);

	int i;
	double off;
	double min, max, max_x, min_x;
	double max_n, min_n, max_t, min_t, max_m, min_m;
	double l_x, l_y, n_x, n_y;

	// max N
	max = min = N[1];
	max_x = min_x = xp[1];
	for (int i = 2; i <= POCET_KROKU; i++) {
		if (N[i] > max) {
			max = N[i];
			max_x = xp[i];
		}
		if (N[i] < min) {
			min = N[i];
			min_x = xp[i];
		}
	}
	max_n = max;
	min_n = min;
	// test arg
	vysledekWin->listWidget->addItem(QString("max N: %1 v %2").arg(max,0,'g',3).arg(max_x,0,'g',3));
	vysledekWin->listWidget->addItem(QString("min N: %1 v %2").arg(min,0,'g',3).arg(min_x,0,'g',3));

	// draw N
	scene->addLine(QLineF(0,0,0,-FAX));
	scene->addLine(QLineF(0,-FAX,x[1],-FAX));
	scene->addLine(QLineF(x[1],-FAX,x[1],-FAX+N1[1]));
	l_x = x[1], l_y = -FAX+N1[1], n_x = x[2], n_y = -FAX+N1[1];
	for (i = 1; i < n; i++) {
		scene->addLine(QLineF(l_x, l_y, n_x, n_y));
		scene->addLine(QLineF(n_x, n_y, n_x, -FAX+N1[i+1]));
		l_x = n_x;
		l_y = -FAX+N1[i+1];
		n_x = x[i+2];
		n_y = -FAX+N1[i+1];
	} 
	i--;
	scene->addLine(QLineF(l_x, l_y, L, l_y));
	scene->addLine(QLineF(L, -FAX+N1[i+1], L, 0));
	// osy N
	scene->addLine(QLineF(-5, 0, L+5, 0));
	scene->addLine(QLineF(0, fabs(max_n)+5, 0, -fabs(min_n)-5));
	scene->addLine(QLineF(L, fabs(max_n)+5, L, -fabs(min_n)-5));

	// max T
	max = min = T[1];
	max_x = min_x = xp[1];
	for (int i = 2; i <= POCET_KROKU; i++) {
		if (T[i] > max) {
			max = T[i];
			max_x = xp[i];
		}
		if (T[i] < min) {
			min = T[i];
			min_x = xp[i];
		}
	}
	max_t = max;
	min_t = min;
	vysledekWin->listWidget->addItem(QString("max Tz: %1 v %2").arg(max,0,'g',3).arg(max_x,0,'g',3));
	vysledekWin->listWidget->addItem(QString("min Tz: %1 v %2").arg(min,0,'g',3).arg(min_x,0,'g',3));

	// draw T 
	off = fabs(FAX)+fabs(max_n)+fabs(min_t)+30;  // min N + max T

	scene->addLine(QLineF(0,off+0,0,off-FAZ));
	scene->addLine(QLineF(0,off-FAZ,x[1],off-FAZ));
	scene->addLine(QLineF(x[1],off-FAZ,x[1],off-FAZ+T1[1]));
	l_x = x[1], l_y = off-FAZ+T1[1], n_x = x[2], n_y = off-FAZ+T1[1];
	for (i = 1; i < n; i++) {
		scene->addLine(QLineF(l_x, l_y, n_x, n_y));
		scene->addLine(QLineF(n_x, n_y, n_x, off-FAZ+T1[i+1]));
		l_x = n_x;
		l_y = off-FAZ+T1[i+1];
		n_x = x[i+2];
		n_y = off-FAZ+T1[i+1];
	} 
	i--;
	scene->addLine(QLineF(l_x, l_y, L, l_y));
	scene->addLine(QLineF(L, off-FAZ+T1[i+1], L,off+0.0));
	// osy T
	scene->addLine(QLineF(-5, off+0, L+5, off+0));
	scene->addLine(QLineF(0, off+fabs(max_t)+5, 0, off-fabs(min_t)-5));
	scene->addLine(QLineF(L, off+fabs(max_t)+5, L, off-fabs(min_t)-5));

	// max MOY
	max = min = MOY[1];
	max_x = min_x = xp[1];
	for (int i = 2; i <= POCET_KROKU; i++) {
		if (MOY[i] > max) {
			max = MOY[i];
			max_x = xp[i];
		}
		if (MOY[i] < min) {
			min = MOY[i];
			min_x = xp[i];
		}
	}
	max_m = max;
	min_m = min;
	vysledekWin->listWidget->addItem(QString("max MOY: %1 v %2").arg(max,0,'g',3).arg(max_x,0,'g',3));
	vysledekWin->listWidget->addItem(QString("min MOY: %1 v %2").arg(min,0,'g',3).arg(min_x,0,'g',3));

	// draw MOY
	off += fabs(FAZ)+fabs(max_t)+fabs(min_m)+30; // min T + max MOY
	for (int i = 0; i < POCET_KROKU-1; i++)  
		scene->addLine(QLineF(xp[i],off+MOY[i],xp[i+1],off+MOY[i+1]));
	// osy moment
	scene->addLine(QLineF(-5, off+0, L+5, off+0));
	scene->addLine(QLineF(0, off+fabs(max_m)+5, 0, off-fabs(min_m)-5));
	scene->addLine(QLineF(L, off+fabs(max_m)+5, L, off-fabs(min_m)-5));

	graphicsView->fitInView(QRect(-10.0, max_n+10.0, L+20.0, off+fabs(max_n)+fabs(min_m)+20));

	delete [] I;
	delete [] x;
	delete [] SP;
	delete [] alfa;
}

void MainWin::zoom_ph() {
	graphicsView->scale(1.1, 1.0);
}

void MainWin::zoom_mh() {
	graphicsView->scale(0.9, 1.0);
}

void MainWin::zoom_pv() {
	graphicsView->scale(1.0, 1.1);
}

void MainWin::zoom_mv() {
	graphicsView->scale(1.0, 0.9);
}
