using System;
using System.Drawing;

namespace InABox.Core
{
    public class UnitOfLength
    {
        public static UnitOfLength Kilometers = new UnitOfLength(1.609344);
        public static UnitOfLength NauticalMiles = new UnitOfLength(0.8684);
        public static UnitOfLength Miles = new UnitOfLength(1);

        private readonly double _fromMilesFactor;

        private UnitOfLength(double fromMilesFactor)
        {
            _fromMilesFactor = fromMilesFactor;
        }

        public double ConvertFromMiles(double input)
        {
            return input * _fromMilesFactor;
        }
    }

    public class Location : EnclosedEntity
    {
        [DoubleEditor(Editable = Editable.Hidden, Visible = Visible.Optional)]
        public double Longitude { get; set; }

        [DoubleEditor(Editable = Editable.Hidden, Visible = Visible.Optional)]
        public double Latitude { get; set; }

        [DateTimeEditor(Editable = Editable.Hidden, Visible = Visible.Optional)]
        public DateTime Timestamp { get; set; }

        [TextBoxEditor(Editable = Editable.Hidden, Visible = Visible.Optional)]
        public string Address { get; set; }

        public static double DistanceBetween(PointF from, PointF to, UnitOfLength unitOfLength)
        {
            var baseRad = Math.PI * from.Y / 180;
            var targetRad = Math.PI * to.Y / 180;
            var theta = from.X - to.X;
            var thetaRad = Math.PI * theta / 180;

            var dist =
                Math.Sin(baseRad) * Math.Sin(targetRad) + Math.Cos(baseRad) *
                Math.Cos(targetRad) * Math.Cos(thetaRad);
            dist = Math.Acos(dist);

            dist = dist * 180 / Math.PI;
            dist = dist * 60 * 1.1515;

            return unitOfLength.ConvertFromMiles(dist);
        }
        
        public double DistanceTo(Location location, UnitOfLength unitOfLength)
        {
            return DistanceBetween(
                new PointF((float)Longitude, (float)Latitude), 
                new PointF((float)location.Longitude, (float)location.Latitude),
                unitOfLength
            );
        }

        public void CopyFrom(Location location)
        {
            Longitude = location.Longitude;
            Latitude = location.Latitude;
            Timestamp = location.Timestamp;
            Address = location.Address;
        }
    }
}