//Jacek Matulewski, e-mail: jacek@fizyka.umk.pl

#ifndef UKLADYPUNKTOWMATERIALNYCH3_H
#define UKLADYPUNKTOWMATERIALNYCH3_H

#include "PunktMaterialny.h"
//#include "UkladyPunktowMaterialnych2.h"

#define _USE_MATH_DEFINES
#include <math.h>
#include <time.h>
#include<fstream>

#include <vector>

class Planeta {

public:
	double skala_odleglosci =1.0;
	double KM_na_AU = 0.0000000066845;
	double odlegloscOdSlonca_AU;
	double średnicaRównikowa_AU;
	double masa;
	double czasObieguSłońca_s;
	double okresObrotu_s;
	double OdległośćOdSłońca() { return skala_odleglosci*odlegloscOdSlonca_AU; }

	Planeta(double odległość_od_Słońca_KM, double średnicaRównikowa_KM, double ile_mas_ziemi, double czasObiegu_d, double okresObrotu_h=0) {

		odlegloscOdSlonca_AU = KM_na_AU * odległość_od_Słońca_KM;
		średnicaRównikowa_AU = KM_na_AU * średnicaRównikowa_KM;
		masa = ile_mas_ziemi;
		czasObieguSłońca_s = czasObiegu_d *24* 3600;
		okresObrotu_s = okresObrotu_h * 3600;
	}
	double prędkośćKątowa() {

		return 2 * M_PI/czasObieguSłońca_s;
	}
	double PromieńPlanety() { return skala_odleglosci*średnicaRównikowa_AU / 2; }
};


class SolarSystem : public ZbiorPunktowMaterialnych {

	private:
		Wektor polozenieMin, polozenieMax;
		double G;
		//double masaSłońca = 333000;
		//double średnicaSłońca = 0.00928;
		//double średnicaRównikowa = 109;
		Wektor położenieSłońca = Wektor((polozenieMax.X - polozenieMin.X) / 2, (polozenieMax.Y - polozenieMin.Y) / 2, (polozenieMax.Z - polozenieMin.Z) / 2);
		//double masaPlanety[8] = {0.0552,0.8149 ,1.0,0.1074 ,317.8,95.1620,14.5360,17.1470 };
		//double odległośćOdSłońca[8] = { 0.3871, 0.7233, 1.0,1.5237, 5.2034,9.5371,19.1913, 30.0690 };
		//double średnicaRównikowa[8] = { 0.3825, 0.9489, 1.0, 0.5335, 11.2092, 9.4494, 4.0074, 3.8827 };
		//double średnicaPlanety[8] = {0.00003252, 0.00008069, 0.00008504,0.00004536,0.00095322,0.00080357,0.00034078,0.00033018};
		//double szer_dlu_sferyczne[8][2] = { {5.874,-8.523 },{ -3.391,-10.769}, {0,284.335},{1.681,114.894},{1.263,24.971},{1.256,83.283},{-0.584,25.099},{-0.899,-17.662} };
	
	public:
		bool pocisk = false;
		Planeta** tablicaPlanet;
		static void DanePocisk(TWektor<double> sila, TWektor<double> predkosc) {
		
			static unsigned int nr = 0;
			std::ofstream plik("pocisk", std::ios::app);
			plik << nr << "\t" << sila.Dlugosc() << "\t"<< predkosc.Dlugosc()<<std::endl;
			++nr;
		
		}
		//double odległośćOdSłońca[8] = { 0.3871, 0.7233, 1.0,1.5237, 5.2034,9.5371,19.1913, 30.0690 };
		//double predkosciKatowePhi[8] = { 0.0000008262,/*0.0000003234*/0.00000002992,0.0000001989,0.0000001058,0.0000000167,0.0000000067,0.0000000023,0.0000000012};
		SolarSystem(int liczbaPlanet, double stalaGrawitacji, Wektor polozenieMin, Wektor polozenieMax)
			:ZbiorPunktowMaterialnych(liczbaPlanet),G(stalaGrawitacji) {

			tablicaPlanet = new Planeta*[liczbaPlanet];
			tablicaPlanet[0] = new Planeta(0, 1392000, 332950, 0);
			tablicaPlanet[1] = new Planeta(57909170, 4879, 0.0552, 87969);
			tablicaPlanet[2] = new Planeta(108208926, 12104, 0.8149, 224, 701);
			tablicaPlanet[3] = new Planeta(152141051.079, 12756, 1.0, 365.256);
			tablicaPlanet[4] = new Planeta(227936637, 6805, 0.1074, 686.960);
			tablicaPlanet[5] = new Planeta(778412027, 142984, 317.8, 4333.287);
			tablicaPlanet[6] = new Planeta(1426725413, 120536, 95.1620, 10756.2);
			tablicaPlanet[7] = new Planeta(2870972220, 51118, 14.5360, 30707.490);
			tablicaPlanet[8] = new Planeta(4498252900, 49528, 17.1470, 60223.353);
			tablicaPlanet[9] = new Planeta(152141051.08, 0.00001, 1e-24, 0, 0);
			UstawieniePoczatkowe(polozenieMin, polozenieMax);
			std::ofstream plik("pocisk", std::ios::out);
		}
		double sumaPromieni() {

			double suma = 0;

			for (int i = 0; i < ilosc-1; ++i) {

				suma += tablicaPlanet[i]->PromieńPlanety();
			}

			return suma;
		}
		void UstawieniePoczatkowe(Wektor polozenieMin, Wektor polozenieMax) {

			double sumaP = sumaPromieni();
			PunktMaterialny* Słońce = PobierzPunktMaterialny(0);
			Słońce->UstawPolozenie(położenieSłońca);
			Słońce->UstawPredkosc(Wektor(0,0,0));
			Słońce->UstawMase(tablicaPlanet[0]->masa);
			Słońce->UstawPromien((0.3*tablicaPlanet[0]->PromieńPlanety())/sumaP);
			
			for (int i = 1; i < ilosc-1; ++i)
			{
				bool wynikTestuNakrywania = false;
				
				do
				{
					double polozenieX = tablicaPlanet[i]->OdległośćOdSłońca();
					double polozenieY = 0;
					double polozenieZ = 0;
					
					PunktMaterialny* punkt = PobierzPunktMaterialny(i);
					punkt->UstawPolozenie(Wektor(polozenieX, polozenieY, polozenieZ));
					
					Wektor r12 = Roznica(Słońce->Polozenie(), punkt->Polozenie());
					double odleglosc = r12.Dlugosc();
					double odleglosc2 = SQR(odleglosc);
					r12.Normuj();
					double szybkosc = sqrt(G*tablicaPlanet[0]->masa / odleglosc);
					punkt->UstawPredkosc(szybkosc*Wektor(sin(tablicaPlanet[i]->prędkośćKątowa()), cos(tablicaPlanet[i]->prędkośćKątowa()), 0));
					punkt->UstawMase(tablicaPlanet[i]->masa);
					punkt->UstawPromien(3*tablicaPlanet[i]->PromieńPlanety()/sumaP);
					punkt->UstawKolor(i / (float)ilosc, 1 - i / (float)ilosc, 1);

					wynikTestuNakrywania = false;
					for (int j = 0; j < i; ++j)
					{
						PunktMaterialny* punktJ = PobierzPunktMaterialny(j);
						if ((punkt->Polozenie() - punktJ->Polozenie()).Dlugosc() == 0) //oslabic warunek?
							wynikTestuNakrywania = true;
					}
				} while (wynikTestuNakrywania);

			}

			double polozenieX = tablicaPlanet[ilosc-1]->OdległośćOdSłońca();
			double polozenieY = 0;
			double polozenieZ = 0;

			PunktMaterialny* punkt = PobierzPunktMaterialny(ilosc-1);
			PunktMaterialny* Ziemia = PobierzPunktMaterialny(3);
			punkt->UstawPolozenie(Wektor(polozenieX, polozenieY, polozenieZ));

			Wektor r12 = Roznica(Ziemia->Polozenie(), punkt->Polozenie());
			double odleglosc = r12.Dlugosc();
			double odleglosc2 = SQR(odleglosc);
			r12.Normuj();
			double szybkosc = sqrt(2*G*tablicaPlanet[3]->masa / odleglosc);
			punkt->UstawPredkosc(szybkosc*Wektor(0, 1, 0));
			punkt->UstawMase(tablicaPlanet[ilosc-1]->masa);
			//punkt->UstawPromien(3 * tablicaPlanet[3]->PromieńPlanety() / sumaP);
			//punkt->UstawKolor(i / (float)ilosc, 1 - i / (float)ilosc, 1);

		}
		Wektor Roznica(Wektor p2, Wektor p1) const
		{
			Wektor roznica = p2 - p1;
			return roznica;
		}

		Wektor Sila(int indeks) const
		{
			PunktMaterialny* punkt = PobierzPunktMaterialny(indeks);
			Wektor sila;
			
			for (int i = 0; i < ilosc; ++i) {

				if (i != indeks)
				{
					PunktMaterialny* punktI = PobierzPunktMaterialny(i);
					Wektor r12 = Roznica(punktI->Polozenie(), punkt->Polozenie());
					double odleglosc2 = SQR(r12.Dlugosc());
					r12.Normuj();
					sila += (punkt->Masa()*punktI->Masa() / odleglosc2)*r12;

				}

			}
			if (indeks == ilosc - 1) {
				
				PunktMaterialny* pocisk = PobierzPunktMaterialny(ilosc-1);
				DanePocisk(G*sila,pocisk->Predkosc());
			}
			return G*sila;
		}
};

#endif