// ========================================================================
//
// Copyright (C) 2016-2017 MARC CHEVALDONNE
//                         marc.chevaldonne.free.fr
//
// Module        : Nounours.cs
// Author        : Marc Chevaldonné
// Creation date : 2016-10-05
//
// ========================================================================

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;

namespace ex_038_001_DataContractSerializer_bases
{
    /// <summary>
    /// Pour que Nounours soit sérialisable/désérialisable avec DataContractSerializer, il faut décorer le type et ses membres à sérialiser avec des attributs
    /// 1) pour cela, il faut ajouter [DataContract] à la définition du type comme ci-dessous.
    /// Vous pouvez lui rajouter trois paramètres optionnels :
    /// - IsReference qui indique s'il faut conserver les données de références objets
    /// - Name permet de définir le texte qui sera utilisé dans la balise XML (par défaut, le nom du type)
    /// - Namespace permet de définir l'espace de noms utilisé (par défaut, aucun)
    /// 2) il faut ensuite ajouter [DataMember] devant la définition de chaque propriété à sérialiser
    /// Vous pouvez également rajouter des paramètres optionnels :
    /// - EmitDefaultValue indique si il faut quand même sérialiser la propriété si sa valeur est celle par défaut (null par exemple pour un type référence)
    /// - IsRequired indique si l'élément correspondant à cette propriété doit être obligatoirement présent ou non
    /// - Name
    /// - Order indique si l'élément doit toujours avoir la même position dans les sous-éléments du type
    ///
    /// Note : [DataMember] peut être attaché aux propriétés dont le type est :
    /// - un type primitif
    /// - un DateTime, TimeSpan, Guid, Uri, un enum
    /// - NullableType d'un des types précédents
    /// - un byte[] (sérialisé en XML au format base64)
    /// - n'importe quel type personnalisé décoré par [DataContract]
    /// - n'importe quelle collection (si les éléments de la collection vérifient la condition précédente)
    /// - n'importe quel type décoré avec [Serializable]
    /// - n'importe quel type implémentant IXmlSerializable

    /// </summary>
    [DataContract(Name = "nounours")]
    public class Nounours
    {
        [DataMember]
        public string Nom
        {
            get;
            set;
        }

        [DataMember(Name = "naissance")]
        public DateTime DateDeNaissance
        {
            get;
            set;
        }

        [DataMember]
        public int NbPoils
        {
            get;
            set;
        }

        [DataMember(EmitDefaultValue = false)]
        public List<Nounours> Amis
        {
            get;
            set;
        }

        public Nounours()
        {
            Amis = new List<Nounours>();
        }

        /// <summary>
        /// returns a hash code in order to use this class in hash table
        /// </summary>
        /// <returns>hash code</returns>
        public override int GetHashCode()
        {
            return Nom.GetHashCode();
        }

        /// <summary>
        /// checks if the "right" object is equal to this Nounours or not
        /// </summary>
        /// <param name="right">the other object to be compared with this Nounours</param>
        /// <returns>true if equals, false if not</returns>
        public override bool Equals(object right)
        {
            //check null
            if (object.ReferenceEquals(right, null))
            {
                return false;
            }

            if (object.ReferenceEquals(this, right))
            {
                return true;
            }

            if (this.GetType() != right.GetType())
            {
                return false;
            }

            return this.Equals(right as Nounours);
        }

        /// <summary>
        /// checks if this Nounours is equal to the other Nounours
        /// </summary>
        /// <param name="other">the other Nounours to be compared with</param>
        /// <returns>true if equals</returns>
        public bool Equals(Nounours other)
        {
            return (this.Nom.Equals(other.Nom) && this.DateDeNaissance == other.DateDeNaissance);
        }

        public override string ToString()
        {
            string amisStr = String.Empty;
            if (Amis.Count > 0)
            {
                amisStr = $", amis : {Amis.Select(nounours => nounours.Nom).Aggregate((noms, nom) => $"{noms} {nom}")}";
            }
            return $"{Nom} ({DateDeNaissance:dd/MM/yyyy}, {NbPoils} poils{amisStr})";
        }

    }
}
