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

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

namespace ex_038_006_Binary_Serializable
{
    /// <summary>
    /// Pour que Nounours soit sérialisable/désérialisable avec un Binary Serializer, il faut décorer le type avec l'attribut [Serializable]
    /// 1) pour cela, il faut ajouter [Serializable] à la définition du type comme ci-dessous.
    /// 2) contrairement au DataContract Serializer, on ne rajoute pas d'attributs pour chaque membre à sérialiser. On n'en rajoute que pour ne pas sérialiser.
    /// L'attribut à ajouter dans ce cas est [NonSerialized]. Tous les autres membres publics ou privés sont sérialisés. 
    /// 
    /// Attention en conséquence aux propriétés automatiques : puisqu'un membre est créé par le compilateur, celui-ci est sérialisé, mais son nom peut changer à compilation. 
    /// Il faut donc éviter les propriétés automatiques qui doivent être sérialisées. 
    ///
    /// Il faut également faire attention aux membres de types collection (et en particulier aux types abstraits qui sont désérialisés en Array) comme pour les DataContractSerializers.
    /// 
    /// Enfin, comme pour le DataContractSerializer, on trouve les 4 hooks : [OnDeserializing], [OnDeserialized], [OnSerializing] et [OnSerialized]
    /// (enlevez l'attribut [OnDeserializing] devant la méthode Init pour constater les dégâts)
    /// </summary>
    [Serializable]
    public class Nounours
    {
        public string Nom
        {
            get { return nom; }
            set { nom = value; }
        }
        private string nom;

        public DateTime Naissance
        {
            get { return naissance; }
            set { naissance = value; }
        }
        private DateTime naissance;

        public int NbPoils
        {
            get;
            set;
        }

        [NonSerialized]
        private int entierQuiSertARienMaisQuOnNeVeutPasSerialiser = 42;

        public List<Nounours> Amis
        {
            get;
            set;
        }

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

        [OnDeserializing]
        void Init(StreamingContext sc = new StreamingContext())
        {
            entierQuiSertARienMaisQuOnNeVeutPasSerialiser = 42;
        }

        /// <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.Naissance == other.Naissance);
        }

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

    }
}
