using System;
using System.Runtime.InteropServices;

namespace Orbiter.Interfaces
{
    /// <summary>
    /// Set of values defining drag coefficient.
    /// </summary>
    /// <remarks>
    /// This is no native Orbiter structure.
    /// </remarks>
    public struct CW
    {
        public double ZPositive;
        public double ZNegative;
        public double X;
        public double Y;
        public CW(double zPositive, double zNegative, double x, double y)
        {
            ZPositive = zPositive;
            ZNegative = zNegative;
            X = x;
            Y = y;
        }
    }

    /// <summary>
    /// Set of values defining docking parameters.
    /// </summary>
    /// <remarks>
    /// This is no native Orbiter structure.
    /// </remarks>
    public struct DockParameters
    {
        public Vector3 Position;
        public Vector3 Direction;
        public Vector3 Rotation;
        public DockParameters(Vector3 position, Vector3 direction, Vector3 rotation)
        {
            Position = position;
            Direction = direction;
            Rotation = rotation;
        }
    }

    /// <summary>
    /// Set of values defining touch-down points.
    /// </summary>
    /// /// <remarks>
    /// This is no native Orbiter structure.
    /// </remarks>
    public struct TouchDownPoints
    {
        private Vector3[] points;
        public TouchDownPoints(Vector3 point1, Vector3 point2, Vector3 point3)
        {
            points = new Vector3[3];
            points[0] = point1;
            points[1] = point2;
            points[2] = point3;
        }
        public Vector3 this[int index]
        {
            get
            {
                if (points != null && index < points.Length) return points[index];
                return null;
            }
            set
            {
                if (points == null) points = new Vector3[3];
                if (index < points.Length) points[index] = value;
            }
        }
    }

    /// <summary>
    /// The managed representation of the native Orbiter structure HUDPAINTSPEC.
    /// </summary>
    /// <remarks>
    /// <note>This is marshalled directly inside the wrapper, therefore no class wrapping is needed.</note>
    /// </remarks>
    [StructLayout(LayoutKind.Sequential)]
    public struct HudPaintSpecification
    {
        public int W;
        public int H;
        public int CX;
        public int CY;
        public double Scale;
        public int Markersize;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct ParticleStreamSpecification
    {
        public int Flags;
        public double Size;
        public double CreationRate;
        public double Velocity;
        public double Spreading;
        public double LifeTime;
        public double GrowthRate;
        public double SlowDown;
        public LightType Light;
        public LevelMap Level;
        public double LevelMapLimitMin;
        public double LevelMapLimitMax;
        public AtmosphereMap Atmosphere;
        public double AtmosphereMapLimitMin;
        public double AtmosphereMapLimitMax;
        public IntPtr Texture;

        public enum LightType
        {
            Emissive,
            Diffuse,
        }

        public enum LevelMap
        {
            Flat,
            Linear,
            SquareRoot,
            LimitedLinear,
            LimitedSquareRoot,
        }

        public enum AtmosphereMap
        {
            Flat,
            LimitedLinear,
            LimitedLogarithmic,
        }

        public ParticleStreamSpecification(int flags, double size, double creationRate, double velocity, double spreading, double lifeTime, double growthRate, double slowDown, LightType light, LevelMap level, double levelMapLimitMin, double levelMapLimitMax, AtmosphereMap atmosphere, double atmosphereMapLimitMin, double atmosphereMapLimitMax, IntPtr texture)
        {
            Flags = flags;
            Size = size;
            CreationRate = creationRate;
            Velocity = velocity;
            Spreading = spreading;
            LifeTime = lifeTime;
            GrowthRate = growthRate;
            SlowDown = slowDown;
            Light = light;
            Level = level;
            LevelMapLimitMin = levelMapLimitMin;
            LevelMapLimitMax = levelMapLimitMax;
            Atmosphere = atmosphere;
            AtmosphereMapLimitMin = atmosphereMapLimitMin;
            AtmosphereMapLimitMax = atmosphereMapLimitMax;
            Texture = texture;
        }
    }
    
    public class DoublePointer
    {
        private IntPtr native;
        
        public double Level
        {
            get
            {
                double[] result=new double[1];
                Marshal.Copy(native, result, 0, 1);
                return result[0];
            }
            set
            {
                Marshal.Copy(new double[]{value}, 0, native, 1);
            }
        }

        public IntPtr Native
        {
            get { return native; }
        }

        public DoublePointer()
        {
            native = Marshal.AllocHGlobal(sizeof (double));
            Marshal.DestroyStructure(native, typeof(double));
        }
        
        ~DoublePointer()
        {
            Marshal.FreeHGlobal(native);
        }
    }
    
    /// <summary>
    /// Planetary atmospheric constants
    /// </summary>
    public struct AtmosphereConstants
    {
        /// <summary>
        /// pressure at mean radius ('sea level') [Pa]
        /// </summary>
        public double P0;
        /// <summary>
        /// density at mean radius
        /// </summary>
        public double Rho0;
        /// <summary>
        /// specific gas constant [J/(K kg)]
        /// </summary>
        public double R;
        /// <summary>
        /// ratio of specific heats, c_p/c_v
        /// </summary>
        public double Gamma;
        /// <summary>
        /// exponent for pressure equation (temporary)
        /// </summary>
        public double C;
        /// <summary>
        /// partial pressure of oxygen
        /// </summary>
        public double O2pp;
        /// <summary>
        /// atmosphere altitude limit [m]
        /// </summary>
        public double AltitudeLimit;
        /// <summary>
        /// radius limit (altlimit + mean radius)
        /// </summary>
        public double RadiusLimit;
        /// <summary>
        /// horizon rendering altitude
        /// </summary>
        public double HorizonAltitude;
        /// <summary>
        /// sky colour at sea level during daytime
        /// </summary>
        public Vector3 Color0;
        
        public AtmosphereConstants(double p0,double rho0,double r,double gamma,double c,double o2pp,double altitudeLimit,double radiusLimit,double horizonAltitude,Vector3 color0)
        {
            P0 = p0;
            Rho0 = rho0;
            R = r;
            Gamma = gamma;
            C = c;
            O2pp = o2pp;
            AltitudeLimit = altitudeLimit;
            RadiusLimit = radiusLimit;
            HorizonAltitude = horizonAltitude;
            Color0 = color0;
        }
    }

    /// <summary>
    /// *********************************************************************************************************************
    /// vessel beacon light parameters TODO: CREATE CLASSES INSTEAD OF STRUCTS IN ORDER TO ALLOW PROPERTY-MARSHALLING!!!!
    /// *********************************************************************************************************************
    /// </summary>
    public struct BeaconLightSpecification
    {
        public IntPtr Native;
        /// <summary>
        /// beacon texture identifier
        /// </summary>
        public uint Shape;   
        /// <summary>
        /// pointer to position in vessel coordinates
        /// </summary>
        public Vector3 Position;
        /// <summary>
        /// pointer to beacon RGB colour
        /// </summary>
        public Vector3 Color;
        /// <summary>
        /// beacon radius
        /// </summary>
        public double Size;
        /// <summary>
        /// distance falloff parameter
        /// </summary>
        public double FallOff;
        /// <summary>
        /// strobe period (0 for continuous)
        /// </summary>
        public double Period;
        /// <summary>
        /// strobe duration
        /// </summary>
        public double Duration;
        /// <summary>
        /// strobe time offset
        /// </summary>
        public double TimeOffset;
        /// <summary>
        /// beacon lit?
        /// </summary>
        public bool Active;

        public BeaconLightSpecification(uint shape, Vector3 position, Vector3 color, double size, double fallOff, double period, double duration, double timeOffset, bool active)
        {
            Native = IntPtr.Zero;
            Shape = shape;
            Position = position;
            Color = color;
            Size = size;
            FallOff = fallOff;
            Period = period;
            Duration = duration;
            TimeOffset = timeOffset;
            Active = active;
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct FuelEntry
    {
        public int idx;
        public double level;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct ThrusterEntry
    {
        public int idx;
        public double level;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct DockEntry
    {
        public int idx;
        public int ridx;
        public IntPtr rvessel;
    }

    public struct VesselStatus2
    {
        public int version;
        public int flag;
        public IntPtr rbody;
        public IntPtr tbase;
        public int port;
        public int status;
        public Vector3 rpos;
        public Vector3 rvel;
        public Vector3 vrot;
        public Vector3 arot;
        public double surf_lng;
        public double surf_lat;
        public double surf_hdg;
        public FuelEntry[] fuel;
        public ThrusterEntry[] thruster;
        public DockEntry[] dockinfo;
        public int xpdr;
    }

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate double LiftCoefficientDelegate(double angleOfAttack);

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void AirFoilCoefficientDelegate(double angleOfAttack, double mach, double reynolds, IntPtr liftCoefficientDoublePointer, IntPtr momentCoefficientDoublePointer, IntPtr dragCoefficientDoublePointer);

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void AirFoilCoefficientExDelegate(double angleOfAttack, double mach, double reynolds, IntPtr contextVoidPointer, IntPtr liftCoefficientDoublePointer, IntPtr momentCoefficientDoublePointer, IntPtr dragCoefficientDoublePointer);

    public enum ThrusterGroup
    {
        Main,
        Retro,
        Hover,
        PitchUp,
        PitchDown,
        YawLeft,
        YawRight,
        BankLeft,
        BankRight,
        Right,
        Left,
        Up,
        Down,
        Forward,
        Back,
        User = 0x40,
    }
    
    public enum AirFoilOrientation
    {
	    Vertical,
        Horizontal,
    }
    
    public enum ControlSurface
    {
        Elevator,
        Rudder,
        Aileron,
        Flap,
        ElevatorTrim,
        RudderTrim,
    }
    
    public enum CockpitMode
    {
        Generic = 1,
        Panels,
        Virtual,
    }
    
    public enum AttitudeMode
    {
        None,
        Rotation,
        Translation,
    }
}
