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

using ex_023_019_ReadOnlyDictionary_and_values_dll;
using System.Text;
using static System.Console;

namespace ex_023_019_ReadOnlyDictionary_and_values_exe
{
    class Program
    {
        /// <summary>
        /// L'exemple suivant montre comment encapsuler un dictionnaire dans les cas suivants :
        /// => les clés et/ou valeurs sont mutables, c'est-à-dire qu'on peut modifier leur état interne en appelant leurs méthodes ou propriétés
        ///     => MonLit possède un dictionnaire de paire clé (string)- valeur (Nounours) privée mNounoursDico où Nounours est mutable
        /// Comment encapsuler correctement un dictionnaire de ce type ?
        /// Dans l'exemple suivant, nous voulons protéger le dictionnaire contre :
        /// - les modifications du dictionnaire (ajout ou suppression d'éléments),
        /// - la modification du dictionnaire lui-même (on ne doit pas pouvoir faire de new)
        /// - la modification de chaque valeur du dictionnaire : on ne doit pas pouvoir faire de new, ni appeler des méthodes ou propriétés mutables.
        /// 
        /// En résumé, nous cherchons à rendre publique en lecture seule, le dictionnaire privé, tout en protégeant les valeurs.
        /// 
        /// Il n'est pas possible d'utiliser une solution similaire à celle que nous avons utiliser pour les collections simples,
        ///     car les interfaces IDictionary ou IReadOnlyDictionary ne sont pas covariantes.
        ///     
        /// La meilleure solution consiste à :
        /// - rendre le type interne (Nounours)
        ///     c'est la raison pour laquelle cet exemple est sur deux assemblages :
        ///         . une bibliothèque de classes contenant le type interne et une classe contenant un dictionnaire privé avec ce type en valeur ;
        ///         . un exécutable consommant la classe contenant le dictionaire à encapsuler.
        /// - faire une façade immuable publique de ce type (INounours)
        ///     cette façade immuable ne contient que des propriétés et méthodes en lecture seule
        /// - utiliser un indexeur en lecture seule pour accéder aux valeurs du dictionnaire :
        ///     utilisez la clé dans l'indexeur
        ///     par exemple, pour encapsuler le dictionnaire Dictionary<string, Nounours>
        ///                  utilisez un indexeur : public INounours this[string key]
        ///                  soit dans le cas général, si vous voulez encapsuler le dictionaire privé : private Dictionary<TKey, TValue> dico;
        ///                  utilisez l'indexeur : public ITValue this[string key] => dico[key]; (où ITValue est une façade immuable de TValue)
        ///                  dans ce cas, l'indexeur ne possède qu'un getteur, qui rend la valeur associée à la clé key, et castée en sa façade immuable (ITValue)
        /// - on peut donner accès aux clés du dictionnaire en rendant une collection en lecture seule des clés.
        ///</summary>
        static void Main(string[] args)
        {
            OutputEncoding = Encoding.Unicode;

            MonLit monlit = new MonLit();

            //on peut parcourir les clés du dictionnaire :
            WriteLine("paires clé-valeur du dictionnaire");
            foreach (var key in monlit.Keys)
            {
                WriteLine($"\tclé : {key} ; valeur : {monlit[key]}");
            }


            //tentatives de modification
            //            monlit["Singe"].Nom = "Beluga"; //impossible, car on utilise la façade immuable INounours
            //            monlit["Singe"] = monlit["Beluga"]; //impossible car l'indexeur est en lecture seule
        }
    }
}
