using System;
using System.Drawing;
using Orbiter.Interfaces;

namespace Orbiter.StockVessels
{
    public class ShuttlePB:Vessel2
    {
        private const Vessel2Callback callbacks=Vessel2Callback.SetClassCaps | Vessel2Callback.DrawHUD;
        private const double fuelMass = 750.0;
        private const double isp = 5e4;
        private const double maximumMainThrust = 3e4;
        private const double maximumHoverThrust = 1.5e4;
        private const double maximumRCSThrust = 2e2;
        private const int liftTableSize = 9;
        private static readonly double[] aoa = new double[liftTableSize]
            {   -180*Constants.Radiant,   -60*Constants.Radiant,
                -30*Constants.Radiant,    -1*Constants.Radiant,
                15*Constants.Radiant,     20*Constants.Radiant,
                25*Constants.Radiant,     60*Constants.Radiant, 180*Constants.Radiant};
        private static readonly double[] cl = new double[liftTableSize]
            {   0,      0,
                -0.1,   0,
                0.2,    0.25,
                0.2,    0,    0};
        private static readonly double[] scl = new double[liftTableSize]
            {   (cl[1]-cl[0])/(aoa[1]-aoa[0]), (cl[2]-cl[1])/(aoa[2]-aoa[1]),
                (cl[3]-cl[2])/(aoa[3]-aoa[2]), (cl[4]-cl[3])/(aoa[4]-aoa[3]),
                (cl[5]-cl[4])/(aoa[5]-aoa[4]), (cl[6]-cl[5])/(aoa[6]-aoa[5]),
                (cl[7]-cl[6])/(aoa[7]-aoa[6]), (cl[8]-cl[7])/(aoa[8]-aoa[7]), 0};
        private IntPtr[] rcsThrusters;
        
        public ShuttlePB()
        {
            rcsThrusters = new IntPtr[14];
        }
        
        /// <summary>
        /// Calculate lift coefficient [Cl] as a function of aoa (angle of attack) over -Pi ... Pi
        /// Implemented here as a piecewise linear function
        /// </summary>
        /// <param name="angleOfAttack">The angle of attack in radiants</param>
        /// <returns>Returns the lift coefficient</returns>
        private double LiftCoefficient(double angleOfAttack)
        {
            int i=0;
            while (i < liftTableSize - 1 && aoa[i + 1] < angleOfAttack) i++;
            return cl[i] + (angleOfAttack - aoa[i]) * scl[i];
        }
        
        private Vessel me;
        private Vessel2 myBase;

        public Vessel This
        {
            get { return me; }
            set { me = value; }
        }

        public Vessel2 Base
        {
            get { return myBase; }
            set { myBase = value; }
        }

        public Vessel2Callback CallbackSetting
        {
            get { return callbacks; }
        }

        public void SetClassCaps(IntPtr configuration)
        {
            IntPtr mainThruster;
            IntPtr hoverThruster;
            
            // physical specs
            This.Size=3.5;
            This.EmptyMass=500.0;
            This.CW=new CW(0.3, 0.3, 0.6, 0.9);
            This.WingAspect=0.7;
            This.WingEffectiveness=2.5;
            This.CrossSections=new Vector3(10.5,15.0,5.8);
            This.RotationalDrag=new Vector3(0.6,0.6,0.35);
            if (This.FlightModel >= 1)
            {
                This.PitchMomentScale=1e-4;
                This.BankMomentScale=1e-4;
            }
            This.PMI=new Vector3(2.28,2.31,0.79);
            This.TrimScale=0.05;
            This.CameraOffset=new Vector3(0,0.8,0);
            This.LiftCoefficient=LiftCoefficient;
            This.SetDockParameters(new DockParameters(new Vector3(0,1.3,-1), new Vector3(0,1,0), new Vector3(0,0,-1)));
            This.TouchDownPoints=new TouchDownPoints(new Vector3(0,-1.5,2), new Vector3(-1,-1.5,-1.5), new Vector3(1,-1.5,-1.5));
            
            // propellant resources
            IntPtr propellant = This.CreatePropellantResource (fuelMass);

            // ***************** thruster definitions *******************

            ParticleStreamSpecification mainContrail = new ParticleStreamSpecification(
                0, 5.0, 16.0, 200.0, 0.15, 1.0, 5.0, 3.0,
                ParticleStreamSpecification.LightType.Diffuse,
                ParticleStreamSpecification.LevelMap.LimitedSquareRoot, 0.0, 2.0,
                ParticleStreamSpecification.AtmosphereMap.LimitedLogarithmic, 1e-4, 1.0,
                IntPtr.Zero);
            ParticleStreamSpecification hoverContrail = new ParticleStreamSpecification(
                0, 5.0, 8.0, 200.0, 0.15, 1.0, 5.0, 3.0,
                ParticleStreamSpecification.LightType.Diffuse,
                ParticleStreamSpecification.LevelMap.LimitedSquareRoot, 0.0, 2.0,
                ParticleStreamSpecification.AtmosphereMap.LimitedLogarithmic, 1e-4, 1.0,
                IntPtr.Zero);
            ParticleStreamSpecification mainExhaust = new ParticleStreamSpecification(
                0, 2.0, 20.0, 200.0, 0.05, 0.1, 8.0, 1.0,
                ParticleStreamSpecification.LightType.Emissive,
                ParticleStreamSpecification.LevelMap.SquareRoot, 0.0, 1.0,
                ParticleStreamSpecification.AtmosphereMap.LimitedLogarithmic, 1e-5, 0.1,
                IntPtr.Zero);
            ParticleStreamSpecification hoverExhaust = new ParticleStreamSpecification(
                0, 2.0, 10.0, 200.0, 0.05, 0.05, 8.0, 1.0,
                ParticleStreamSpecification.LightType.Emissive,
                ParticleStreamSpecification.LevelMap.SquareRoot, 0.0, 1.0,
                ParticleStreamSpecification.AtmosphereMap.LimitedLogarithmic, 1e-5, 0.1,
                IntPtr.Zero);

            mainThruster = This.CreateThruster(new Vector3(0, 0, -4.35), new Vector3(0, 0, 1), maximumMainThrust, propellant, isp);
            This.CreateThrusterGroup(new IntPtr[] { mainThruster }, ThrusterGroup.Main);
            This.AddExhaust(mainThruster, 8, 1, new Vector3(0, 0.3, -4.35), new Vector3(0, 0, -1));

            hoverThruster = This.CreateThruster (new Vector3(0,-1.5,0), new Vector3(0,1,0), maximumHoverThrust, propellant, isp);
            This.CreateThrusterGroup (new IntPtr[]{hoverThruster}, ThrusterGroup.Hover);
            This.AddExhaust (hoverThruster, 8, 1, new Vector3(0,-1.5,1), new Vector3(0,-1,0));
            This.AddExhaust (hoverThruster, 8, 1, new Vector3(0,-1.5,-1), new Vector3(0,-1,0));

            This.AddExhaustStream(hoverThruster, new Vector3(0, -3, 1), hoverContrail);
            This.AddExhaustStream(hoverThruster, new Vector3(0, -3, -1), hoverContrail);
            This.AddExhaustStream(mainThruster, new Vector3(0, 0.3, -10), mainContrail);
            This.AddExhaustStream(hoverThruster, new Vector3(0, -2, 1), hoverExhaust);
            This.AddExhaustStream(hoverThruster, new Vector3(0, -2, -1), hoverExhaust);
            This.AddExhaustStream(mainThruster, new Vector3(0, 0.3, -5), mainExhaust);

            rcsThrusters[ 0] = This.CreateThruster (new Vector3( 1,0, 3), new Vector3(0, 1,0), maximumRCSThrust, propellant, isp);
            rcsThrusters[ 1] = This.CreateThruster (new Vector3( 1,0, 3), new Vector3(0,-1,0), maximumRCSThrust, propellant, isp);
            rcsThrusters[ 2] = This.CreateThruster (new Vector3(-1,0, 3), new Vector3(0, 1,0), maximumRCSThrust, propellant, isp);
            rcsThrusters[ 3] = This.CreateThruster (new Vector3(-1,0, 3), new Vector3(0,-1,0), maximumRCSThrust, propellant, isp);
            rcsThrusters[ 4] = This.CreateThruster (new Vector3( 1,0,-3), new Vector3(0, 1,0), maximumRCSThrust, propellant, isp);
            rcsThrusters[ 5] = This.CreateThruster (new Vector3( 1,0,-3), new Vector3(0,-1,0), maximumRCSThrust, propellant, isp);
            rcsThrusters[ 6] = This.CreateThruster (new Vector3(-1,0,-3), new Vector3(0, 1,0), maximumRCSThrust, propellant, isp);
            rcsThrusters[ 7] = This.CreateThruster (new Vector3(-1,0,-3), new Vector3(0,-1,0), maximumRCSThrust, propellant, isp);
            rcsThrusters[ 8] = This.CreateThruster (new Vector3( 1,0, 3), new Vector3(-1,0,0), maximumRCSThrust, propellant, isp);
            rcsThrusters[ 9] = This.CreateThruster (new Vector3(-1,0, 3), new Vector3( 1,0,0), maximumRCSThrust, propellant, isp);
            rcsThrusters[10] = This.CreateThruster (new Vector3( 1,0,-3), new Vector3(-1,0,0), maximumRCSThrust, propellant, isp);
            rcsThrusters[11] = This.CreateThruster (new Vector3(-1,0,-3), new Vector3( 1,0,0), maximumRCSThrust, propellant, isp);
            rcsThrusters[12] = This.CreateThruster (new Vector3( 0,0,-3), new Vector3(0,0, 1), maximumRCSThrust, propellant, isp);
            rcsThrusters[13] = This.CreateThruster (new Vector3( 0,0, 3), new Vector3(0,0,-1), maximumRCSThrust, propellant, isp);

            This.CreateThrusterGroup (MapRCS(0,2,5,7), ThrusterGroup.PitchUp);
            This.CreateThrusterGroup (MapRCS(1,3,4,6), ThrusterGroup.PitchDown);
            This.CreateThrusterGroup (MapRCS(0,4,3,7), ThrusterGroup.BankLeft);
            This.CreateThrusterGroup (MapRCS(1,5,2,6), ThrusterGroup.BankRight);
            This.CreateThrusterGroup (MapRCS(0,4,2,6), ThrusterGroup.Up);
            This.CreateThrusterGroup (MapRCS(1,5,3,7), ThrusterGroup.Down);
            This.CreateThrusterGroup (MapRCS(8, 11), ThrusterGroup.YawLeft);
            This.CreateThrusterGroup (MapRCS(9, 10), ThrusterGroup.YawRight);
            This.CreateThrusterGroup (MapRCS(8, 10), ThrusterGroup.Left);
            This.CreateThrusterGroup (MapRCS(9, 11), ThrusterGroup.Right);
            This.CreateThrusterGroup (MapRCS(12), ThrusterGroup.Forward);
            This.CreateThrusterGroup (MapRCS(13), ThrusterGroup.Back);

            // visual specs
            This.AddMesh("ShuttlePB");
        }

        public void SaveState(IntPtr scenario)
        {
            throw new NotImplementedException();
        }

        public void LoadStateEx(IntPtr scenario, IntPtr status)
        {
            throw new NotImplementedException();
        }

        public void SetStateEx(VesselStatus2 status)
        {
            throw new NotImplementedException();
        }

        public void PostCreation()
        {
            throw new NotImplementedException();
        }

        public void FocusChanged(bool getFocus, IntPtr newVessel, IntPtr oldVessel)
        {
            throw new NotImplementedException();
        }

        public void PreStep(double simt, double simdt, double mjd)
        {
            throw new NotImplementedException();
        }

        public void PostStep(double simt, double simdt, double mjd)
        {
            throw new NotImplementedException();
        }

        public bool PlaybackEvent(double simt, double event_t, string event_type, string event_name)
        {
            throw new NotImplementedException();
        }

        public void VisualCreated(IntPtr vis, int refCount)
        {
            throw new NotImplementedException();
        }

        public void VisualDestroyed(IntPtr vis, int refCount)
        {
            throw new NotImplementedException();
        }

        public void DrawHUD(int mode, HudPaintSpecification hps, IntPtr hDC)
        {
            //Uncomment and recompile this for demonstration of managed HUD painting
            Graphics MyHUD = Graphics.FromHdc(hDC);
            Font MyFont = new Font("Arial", 10.0F, FontStyle.Regular, GraphicsUnit.Pixel, (byte)(0));
            Brush MyBrush = Brushes.Red;
            MyHUD.DrawString(".NET Graphics Test (GDI+)", MyFont, MyBrush, 10, 250);
            Base.DrawHUD(mode, hps, hDC);
        }

        public void RCSMode(int mode)
        {
            throw new NotImplementedException();
        }

        public void ADCtrlMode(int mode)
        {
            throw new NotImplementedException();
        }

        public void HUDMode(int mode)
        {
            throw new NotImplementedException();
        }

        public void MFDMode(int mfd, int mode)
        {
            throw new NotImplementedException();
        }

        public void NavMode(int mode, bool active)
        {
            throw new NotImplementedException();
        }

        public void DockEvent(int dock, IntPtr mate)
        {
            throw new NotImplementedException();
        }

        public void Animate(double simt)
        {
            throw new NotImplementedException();
        }

        public int ConsumeDirectKey(IntPtr keyState)
        {
            throw new NotImplementedException();
        }

        public int ConsumeBufferedKey(int key, bool down, IntPtr keyState)
        {
            throw new NotImplementedException();
        }

        public bool LoadGenericCockpit()
        {
            throw new NotImplementedException();
        }

        public bool LoadPanel(int id)
        {
            throw new NotImplementedException();
        }

        public bool PanelMouseEvent(int id, int mouseEvent, int mx, int my)
        {
            throw new NotImplementedException();
        }

        public bool PanelRedrawEvent(int id, int mouseEvent, IntPtr surface)
        {
            throw new NotImplementedException();
        }

        public bool LoadVC(int id)
        {
            throw new NotImplementedException();
        }

        public bool VCMouseEvent(int id, int mouseEvent, Vector3 p)
        {
            throw new NotImplementedException();
        }

        public bool VCRedrawEvent(int id, int mouseEvent, IntPtr surface)
        {
            throw new NotImplementedException();
        }

        private IntPtr[] MapRCS(params int[] values)
        {
            IntPtr[] result=new IntPtr[values.Length];
            for(int i=0;i<values.Length;i++) result[i] = rcsThrusters[values[i]];
            return result;
        }

        public void DisposeThis()
        {
            //Do nothing
        }
    }
    
}
