using System;
using System.Collections.Generic;
using log4net;

namespace Orbiter.Multiplayer
{
    public class Time
    {
        private Dictionary<UInt16, SpaceTime> spaces;
        private UInt16 timeReference;
        private User leader;
        private double MJD;
        private double timestamp;
        private double acceleration;
        private Server server;
        private static readonly ILog log = LogManager.GetLogger("VISI");
        private const double secondsToDays = 60 * 60 * 24;

        public Time(Server server, User leader, StateInfoPacket pac)
        {
            spaces=new Dictionary<ushort, SpaceTime>();
            this.server = server;
            this.leader = leader;
            MJD = pac.MJD;
            timestamp = pac.Sent;
            acceleration = 1;
            UpdateSpaces(pac);
        }

        public Time(Server server)
        {
            spaces = new Dictionary<ushort, SpaceTime>();
            this.server = server;
        }

        private void UpdateSpaces(StateInfoPacket pac)
        {
            lock(this) if (!spaces.ContainsKey(pac.SpaceReference))
            {
                var map = server.Map.GlobalsById;
                lock (map)
                {
                    if (map.ContainsKey(pac.SpaceReference))
                    {
                        CelestialBody body = map[pac.SpaceReference] as CelestialBody;
                        if (body != null) spaces.Add(pac.SpaceReference, new SpaceTime(this, body));
                        else log.Error("'" + map[pac.SpaceReference].Name + "' is not a valid space reference object!");
                    }
                    else log.Error(pac.SpaceReference + " is not a valid global object id!");
                }
            }
        }

        public User Leader
        {
            get
            {
                return leader;
            }
        }

        public double Now
        {
            get
            {
                lock(this) return MJD + (server.NTP.Now.ToDouble - timestamp)/secondsToDays;
            }
        }

        public SpaceTime Update(User user, StateInfoPacket pac)
        {
            lock (this)
            {
                if (leader == user)
                {
                    MJD = pac.MJD;
                    timestamp = pac.Sent;
                    acceleration = 1;
                }
                UpdateSpaces(pac);
                return spaces[pac.SpaceReference];
            }
        }
    }
}