// 
// Copyright (c) 2013-2016 Carsten Sonne Larsen <cs@innolan.dk>
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

using System;
using System.Net;
using Newtonsoft.Json;

// ReSharper disable UnusedMember.Global
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedAutoPropertyAccessor.Global

namespace Ntp.Analyzer.Objects
{
    public class ExactlyTimeServer : TimeServer
    {
        /// <summary>
        /// A link to the server information page at support.ntp.org.
        /// </summary>
        [JsonProperty("url")]
        public string Url { get; set; }

        /// <summary>
        /// The country code for where the server is located.
        /// </summary>
        [JsonProperty("iso")]
        public string Iso { get; set; }

        public override string Country => Iso;

        /// <summary>
        /// The physical location of the server, useful in selecting upstream servers.
        /// </summary>
        [JsonProperty("location")]
        public string LocationRaw { get; set; }

        public override string Location => LocationRaw;

        public override string DisplayLocation => Location.Substring(0, 60);

        /// <summary>
        /// The organization sponsoring the operation of the server.
        /// </summary>
        [JsonProperty("sponsor")]
        public string Sponsor { get; set; }

        public override string Organization => Sponsor;

        /// <summary>
        /// The region/area that the server is intended to serve. If you're outside that area,
        /// you probably shouldn't be using it, unless there is a shortage of servers in your
        /// area.
        /// </summary>
        [JsonProperty("service_area")]
        public string ServiceAreaRaw { get; set; }

        public override string ServiceArea => ServiceAreaRaw;

        [JsonProperty("access")]
        public string Access { get; set; }

        public override string AccessPolicy => Access;

        /// <summary>
        /// A 1 indicates the server operator would like to be notified, via the details in
        /// contact if you are using their server. A zero means they don't care, just happy
        /// to be of help.
        /// </summary>
        [JsonProperty("notify")]
        public string NotifyRaw { get; set; }

        public override bool ShouldNotify => NotifyRaw.Trim() == "1";

        /// <summary>
        /// A UNIX timestamp indicating the last time the server page was updated by the owner.
        /// </summary>
        /// <example>1102697989</example>
        [JsonProperty("modified")]
        public long ModifiedRaw { get; set; }

        /// <summary>
        /// Last time the server page was updated by the owner.
        /// </summary>
        public DateTime Modified => new DateTime(1970, 1, 1, 0, 0, 0, 0).AddSeconds(ModifiedRaw);

        public override DateTime Updated => Modified;

        /// <summary>
        /// The hostname to be used if usedns = 1.
        /// </summary>
        /// <example>ntp.cpsc.ucalgary.ca</example>
        [JsonProperty("hostname")]
        public string Hostname { get; set; }

        public override string Name => Hostname;

        /// <summary>
        /// IP (v4) address to be used if usedns = 0.
        /// </summary>
        /// <example>136.159.2.2</example>
        [JsonProperty("ipv4")]
        public string Ipv4 { get; set; }

        public override IPAddress Address
        {
            get
            {
                IPAddress ip;
                return IPAddress.TryParse(Ipv4, out ip) ? ip : null;
            }
        }

        /// <summary>
        /// If available, the IP (v6) address to be used if usedns = 0.
        /// </summary>
        [JsonProperty("ipv6")]
        public string Ipv6 { get; set; }

        public override string V6Address => Ipv6;

        /// <summary>
        /// Indicates that downstream servers should use the hostname, not DNS.
        /// </summary>
        [JsonProperty("usedns")]
        public string UseDns { get; set; }

        public override bool ShouldUseDns => UseDns.Trim() == "1";

        public override bool IsPoolMember => false;

        /// <summary>
        /// More information about the access granted, or notification requested.
        /// </summary>
        [JsonProperty("access_details")]
        public string AccessDetailsRaw { get; set; }

        public override string AccessDetails => AccessDetailsRaw;

        /// <summary>
        /// If notify = 1, use this information to contact the server operator.
        /// </summary>
        /// <example>Brad Arlt (timekeeper@cpsc.ucalgary.ca)</example>
        [JsonProperty("contact")]
        public string ContactRaw { get; set; }

        public override string Contact => ContactRaw;

        /// <summary>
        /// These are the IP addresses returned by a DNS query for IPv4 (A)
        /// records, should not be used directly, use the hostname. Only
        /// successful addresses are listed.
        /// </summary>
        [JsonProperty("dns_a")]
        public string[] DnsA { get; set; }

        /// <summary>
        /// These are the IP addresses returned by a DNS query for IPv6 (AAAA)
        /// records, should not be used directly, use the hostname.
        /// </summary>
        [JsonProperty("dns_aaaa")]
        public string[] DnsAaaa { get; set; }

        /// <summary>
        /// If this is an empty array, that is good. If there is stuff here,
        /// something is entered wrong on the server page, or misconfigured
        /// with DNS, or possibly only some addresses worked.
        /// </summary>
        [JsonProperty("status")]
        public string[] Status { get; set; }

        /// <summary>
        /// If the last test was successful, this tells you which test succeeded:
        /// hostname, IPv4, or IPv6.
        /// </summary>
        [JsonProperty("success")]
        public ExactlySuccess Success { get; set; }

        /// <summary>
        /// The numerical ID, as queried from the list at support.ntp.org.
        /// </summary>
        [JsonProperty("id")]
        public int IdRaw { get; set; }

        /// <summary>
        /// How many times we have successfully contacted this server.
        /// </summary>
        [JsonProperty("successes")]
        public int Successes { get; set; }

        /// <summary>
        /// How many times we have failed to contact thsi server.
        /// </summary>
        [JsonProperty("failures")]
        public int Failures { get; set; }

        /// <summary>
        /// Was the last attempt successful? 1 = Yes, 0 = No.
        /// </summary>
        [JsonProperty("up")]
        public int UpRaw { get; set; }

        /// <summary>
        /// Was the last attempt successful?
        /// </summary>
        public bool IsUp => UpRaw == 1;

        /// <summary>
        /// UNIX timestamp of the last time this server was successfully contacted.
        /// </summary>
        /// <example>1482208125</example>
        [JsonProperty("contacted")]
        public long ContactedRaw { get; set; }

        /// <summary>
        /// Last time this server was successfully contacted.
        /// </summary>
        public DateTime Contacted => new DateTime(1970, 1, 1, 0, 0, 0, 0).AddSeconds(ContactedRaw);

        public override int Stratum => 0;

        public override string Geo => string.Empty;

        public override string Server => string.Empty;

        public override string AutoKey => string.Empty;

        public override string SymKey => string.Empty;

        public override string SymUrl => string.Empty;

        public override string ProviderPage => string.Empty;

        public override string ProviderUrl => string.Empty;

        public void SetOrgId(int id)
        {
            SetId(id);
            NewObject = true;
        }
    }
}