#pragma once

#ifndef SolarSystem_H
#define SolarSystem_H

#include "PunktMaterialny.h"

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

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;
	Wektor położenieSłońca = Wektor((polozenieMax.X - polozenieMin.X) / 2, (polozenieMax.Y - polozenieMin.Y) / 2, (polozenieMax.Z - polozenieMin.Z) / 2);
	//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:
	
	Planeta** tablicaPlanet;
	double szybkoscPoczatkowaPocisku = 20.0;
	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;

	}
	
	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);
	}
	void Reset() {

		KontrolerTrzeciaPredkoscKosmiczna();
		//std::ofstream plik("pocisk", std::ios::app);
		//plik << "hahahaha" << std::endl;

	}

	double sumaPromieni() {

		double suma = 0;

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

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

		return suma;
	}

	void UstawPoprzedniePolozenia() {

		PunktMaterialny* Słońce = PobierzPunktMaterialny(0);
		Słońce->UstawPolozenie(Słońce->PoprzedniePolozenie());

		for (int i = 1; i < ilosc-1; ++i)
		{
			PunktMaterialny* punkt = PobierzPunktMaterialny(i);
			punkt->UstawPolozenie(punkt->PoprzedniePolozenie());
		}

		
	}

	void UstawieniePocisku(double szybkosc_pocisku) {

		PunktMaterialny* punkt = PobierzPunktMaterialny(ilosc - 1);
		PunktMaterialny* Ziemia = PobierzPunktMaterialny(3);
		punkt->UstawPolozenie(Ziemia->PoprzedniePolozenie() + Wektor(12756 + 200, 0, 0));
		punkt->UstawPredkosc(szybkosc_pocisku*Wektor(0,1,0));

	}

	void KontrolerTrzeciaPredkoscKosmiczna() {
		
		const int maxLiczbaProbek = 10;
		static int liczbaProbek = 0;
		static double predkosci[maxLiczbaProbek];
		double szybkoscPocisku = szybkoscPoczatkowaPocisku;
		bool start = true;

		if (liczbaProbek < maxLiczbaProbek) {

			if (start) {

				UstawPoprzedniePolozenia();
				UstawieniePocisku(szybkoscPocisku);
				start = false;

			}
			else {

				if (PociskZaNeptunem()) {

					predkosci[liczbaProbek] = szybkoscPocisku;
					szybkoscPocisku = szybkoscPoczatkowaPocisku;
					liczbaProbek++;
					start = true;
				}

				if (PociskSieCofa()) {

					UstawPoprzedniePolozenia();
					szybkoscPocisku += 10;
					UstawieniePocisku(szybkoscPocisku);
				}


			}

			
		}
		else {

			std::ofstream plik("pocisk", std::ios::app);
			plik << "Zarejestrowano nastepujace predkosci: " << std::endl;
			double sumaPredkosci = 0.0;

			for (int i = 0; i < liczbaProbek; ++i) {

				plik << predkosci[i] << std::endl;
				sumaPredkosci += predkosci[i];
			}
				

			plik << "Srednia predkosc wynosi: " << sumaPredkosci / liczbaProbek << std::endl;
		}

	}

	bool PociskZaNeptunem() {

		PunktMaterialny* pocisk = PobierzPunktMaterialny(ilosc - 1);
		PunktMaterialny* Neptun = PobierzPunktMaterialny(ilosc-2);
		PunktMaterialny* Słońce = PobierzPunktMaterialny(0);
		Wektor odlegloscPS = Roznica(pocisk->Polozenie(),Słońce->Polozenie());
		Wektor odlegloscNS = Roznica(Neptun->Polozenie(),Słońce->Polozenie());
		double od_PS = odlegloscPS.Dlugosc();
		double od_NS = odlegloscNS.Dlugosc();
		if (od_PS > od_NS) return true;

		return false;
	}

	bool PociskSieCofa() {

		static double poprzedniaOdlegloscOdSłońca = 0;
		if (poprzedniaOdlegloscOdSłońca == 0) return false;

		PunktMaterialny* pocisk = PobierzPunktMaterialny(ilosc - 1);
		PunktMaterialny* Słońce = PobierzPunktMaterialny(0);
		Wektor odlegloscPS = Roznica(pocisk->Polozenie(), Słońce->Polozenie());
		double od_PS = odlegloscPS.Dlugosc();

		if (poprzedniaOdlegloscOdSłońca > od_PS) {

			poprzedniaOdlegloscOdSłońca = 0;
			return true;
		} 

		poprzedniaOdlegloscOdSłońca = od_PS;
		return false;


	}

	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; ++i)
		{
		
			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);

		}

		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