// ################################
// ## Fyzikalni vzorce a vztahy, ##
// ## prevody jednotek a podobne ##
// ################################

#pragma once
#ifndef PHYSICS_H
#define PHYSICS_H

#include "common.h"

#include "independent_constants.h"
#include "datetime.h"
#include "mathfunc.h"

// ################################
// ################################

unsigned long long forceToStopMovingObject(unsigned long long weight, unsigned long long speed, unsigned long long time);
unsigned long long consumptionToStopMovingObject(unsigned long long jetForce, unsigned long jetConsumption, unsigned long long weight, unsigned long long speed);

// --------------------------------

#define MAXIMAL_IMPULSE_DRIVE_SPEED     149896229

// --------------------------------

template<typename T>
class physicsConstants
{
public:
    static const T lightSpeed()
    {
        return (T) 299792458;
    }

    static const T ly() 
    {
        return (T)(((T) lightSpeed()) / ((T)1000) * ((T)31536000)); /* km */
    }
    
    static const T kappa()
    {
        return (T) (6.67384E-11L);
    }
};

// --------------------------------

template<typename T>
class unitsConversion
{
public:
    static inline T mToKm(T m /* m */) /* km */
    {
        return (m / (T)1000);
    }
    static inline T KmTom(T km) /* m */
    {
        return (km * (T)1000);
    }
    static inline T mPerSecondToKmPerSecond(T mPerSec /* m */) /* km/s */
    {
        return (mPerSec / (T)1000);
    }
    static inline T KmPerSecondTomPerSecond(T kmPerSec) /* m/s */
    {
        return (kmPerSec * (T)1000);
    }
    static inline T degreesToNanoDegrees(T degrees) /* nanodegrees */
    {
        return degrees * (T)1000000000;
    }
    static inline T radiansToDegrees(T radians) /* degrees */
    {
        return radians * (T)180 / (T)PI;
    }
    static inline T degreesToRadians(T degrees) /*radians */
    {
        return degrees * (T) PI / (T) 180;
    }
    static inline T nanoDegreesToDegrees(T nanodegrees) /* degrees */
    {
        return nanodegrees / (T)1000000000; 
    }
    static inline T TNewtonsToNewtons(T Teranewtons) /* newtons */
    {
        return Teranewtons * (T)1000000000000;
    }
    static inline T GNewtonsToNewtons(T Giganewtons) /* newtons */
    {
        return Giganewtons * (T)1000000000;
    }
    static inline T NewtonsToTNewtons(T newtons) /* teranewtons */
    {
        return newtons / (T)1000000000000;
    }
    static inline T NewtonsToGNewtons(T newtons) /*giganewtons */
    {
        return newtons / (T)1000000000;
    }
    static inline T speedCtoSpeedMS(T speedtoC /* relative speed to the c */) /* m/s */
    {
        return speedtoC * (T) 299792458;
    }
    static inline T TMtoKm(T terameters) /* km */
    {
        return terameters * (T)1000000000;
    }
};

// --------------------------------

double convertDatetimeToSeconds(const dv_time:: datetime dt /* regular date time */); /* seconds */
dv_time:: datetime convertSecondsToDatetime(const double seconds /* seconds */); /* datetime */

// --------------------------------

vector_dist_t updatePosition(vector_dist_t oldPos /* (km, km) */, vector_dbl_t course /* normed vector */,
                             double speed /* m/sec */, double acceleration /* m/sec */,
                             dv_time:: datetime deltaTime /* regular time */);
double updateSpeed(double speed /* m/sec */, double acceleration /* m/sec */, 
                               dv_time:: datetime deltaTime);
dv_time:: datetime computeTimeForTravelDistance(double distance /* km */, double speed /* m/s */); /* datetime */
dv_time:: datetime computeTimeForTravelDistance(double distance /* km */, double speed /* m/s */, double acceleration /* m/s^2 */);
vector_dist_t updatePositionOrbiting(vector_dist_t base /* (km, km) */, double distance /* km */,
                                     double angle /* nanodegrees */);

vector_dist_t updatePositionOrbiting(vector_dist_t base /* (km, km) */, double distance /* km */,
                                     double basicangle /* nanodegrees */, 
                                     double angularSpeed /* nanodegrees/s*/, dv_time:: datetime dt); /* (km, km) */
vector_dist_t updateWarpPosition(vector_dist_t oldPos /* (km, km) */, vector_dbl_t course /* normed vector */,
                             double speed /* m/sec */,
                             dv_time:: datetime deltaTime /* regular time */);

// --------------------------------

unsigned long long computeNormalizedNanodegrees(unsigned long long ndg /* nanodegrees */); /* nanodegrees */
double computeOrbitalSpeed(double distance /* km */, double weight /* kg */); /* m/s */
double computeAngularVelocity(double distance /* km */, double weight /* kg */); /* nanodegrees/s */
double computeBasicAngle(vector_dist_t position /* (km,km) */); /* nanodegrees */
double computeGravityAcceleration(double distance /* km */, double weight /* kg */); /* m/s^2 */
double computeTravelledDistance(double speed /* m/s */, dv_time:: datetime dt); /* km */
double computeAcceleration(double force /* GN */, double weight /* kg */); /* m/s */
double computeForceFromAcceleration(double gacceleration /* m/s^2 */, double weight /* kg */); /* GN */
double computeGravitationCircleRadius(double weight /* kg */, double speed /* m/s */); /* km */
vector_dbl_t computeComposedVectors(vector_dbl_t v1, vector_dbl_t v2, double norm1, double norm2);

// --------------------------------

// ################################
// ################################

#endif