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

using static System.Console;

namespace ex_016_003_indexers
{
    class Nounours
    {
        //une propriété
        public string Nom
        {
            get
            {
                return mNom;
            }
            set
            {
                mNom = value;
            }
        }
        private string mNom;
    }

    //classe possédant des indexeurs
    class MonLit
    {
        Nounours[] mNounours;

        //constructeur
        public MonLit(int nombre)
        {
            mNounours = new Nounours[nombre];
        }

        //une propriété de plus
        public int NombreNounours
        {
            get
            {
                return mNounours.Length;
            }
        }

        /// <summary>
        /// indexeur permettant de récupérer ou d'écrire le (index)ième nounours dans le tableau mNounours
        /// </summary>
        /// <param name="index">index du nounours à récupérer ou écrire</param>
        /// <returns>rend le (index)ième nounours ou null si l'index n'est pas valide</returns>
        public Nounours this[int index]
        {
            get
            {
                if (index >= NombreNounours || index < 0)
                {
                    return null;
                }
                return mNounours[index];
            }
            set
            {
                if (index < NombreNounours && index >= 0)
                {
                    mNounours[index] = value;
                }
            }
        }

        /// <summary>
        /// indexeur en lecture seule permettant de récupérer un nounours dans le tableau mNounours à partir de son nom
        /// </summary>
        /// <param name="nom">nom du Nounours recherché</param>
        /// <returns>le nounours avec ce nom, ou null si le nom n'est pas reconnu</returns>
        public Nounours this[string nom]
        {
            get
            {
                foreach (Nounours n in mNounours)
                {
                    if (n.Nom == nom)
                    {
                        return n;
                    }
                }
                return null;
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            OutputEncoding = System.Text.Encoding.UTF8;

            WriteLine("Création d'un lit avec trois nounours");
            MonLit monlit = new MonLit(3);

            //utilisation de l'indexeur this[int] en écriture (set)
            monlit[0] = new Nounours { Nom = "zinzin" };
            monlit[1] = new Nounours { Nom = "rooooo" };
            monlit[2] = new Nounours { Nom = "argh" };

            WriteLine("contenu du 1er lit");
            for (int i = 0; i < monlit.NombreNounours; i++)
            {
                //utilisation de l'indexeur this[int] en lecture (get)
                WriteLine(monlit[i].Nom);
            }

            ReadLine();

            WriteLine("modification d'un nounours du lit avec l'indexeur");

            //utilisation de l'idexeur this[string]
            if (monlit["rooooo"] != null)
            {
                //utilisation de l'idexeur this[string]
                monlit["rooooo"].Nom = "zibaouin";
            }

            WriteLine("contenu du lit");
            for (int i = 0; i < monlit.NombreNounours; i++)
            {
                //utilisation de l'idexeur this[int] en lecture
                WriteLine(monlit[i].Nom);
            }

            ReadLine();
            WriteLine("création d'une maison avec deux lits : 1er lit = le précédent, 2ème lit de 4 nouveaux nounours");
            MaMaison maison = new MaMaison(2);
            //utilisation de l'indexeur simple de MaMaison this[int]
            maison[0] = monlit;
            maison[1] = new MonLit(4);
            //notez que maison[1, 0] = new Nounours(); ne compile pas, car l'indexeur n'a pas de 'set'
            //mais on peut accéder quand même à maison[1][0] car on accède à la référence maison[1] de type MonLit et de là, grâce à l'indexeur,
            //au nounours maison[1][0]... donc ... ATTENTION AUX REFERENCES PUBLIQUES DANS VOTRE API !

            //utilisation de l'indexeur this[int] de MaMaison puis de l'indexeur this[int] de MonLit
            maison[1][0] = new Nounours();
            //utilisation de l'indexeur double this[int, int] de MaMaison
            maison[1, 0].Nom = "Nigel";
            maison[1][1] = new Nounours();
            maison[1, 1].Nom = "David";
            maison[1][2] = new Nounours();
            maison[1, 2].Nom = "Derek";
            maison[1][3] = new Nounours();
            maison[1, 3].Nom = "Ian";
            WriteLine("contenu du lit");
            for (int i = 0; i < maison.NbreLits; i++)
            {
                WriteLine($"lit n°{(i + 1)}");
                for (int j = 0; j < maison[i].NombreNounours; j++)
                {
                    WriteLine(maison[i, j].Nom);
                }
                WriteLine();
            }
        }
    }

    //exemple d'indexeur à 2 variables
    class MaMaison
    {
        MonLit[] mLits;

        public MaMaison(int nombre)
        {
            mLits = new MonLit[nombre];
        }

        //une propriété en lecture seule
        public int NbreLits
        {
            get
            {
                return mLits.Length;
            }
        }


        /// <summary>
        /// un indexeur simple 
        /// </summary>
        /// <param name="lit">indice du lit à atteindre dans le tableau mLits</param>
        /// <returns></returns>
        public MonLit this[int lit]
        {
            get
            {
                if (lit >= NbreLits || lit < 0)
                {
                    return null;
                }
                return mLits[lit];
            }
            set
            {
                if (lit < NbreLits && lit >= 0)
                {
                    mLits[lit] = value;
                }
            }
        }

        /// <summary>
        /// un indexeur à double entrée
        /// </summary>
        /// <param name="lit">indice du lit à atteindre dans le tableau mLits</param>
        /// <param name="nounours">indice du nounours à atteindre dans le tableau mNounours de mLits[lit]</param>
        /// <returns></returns>
        public Nounours this[int lit, int nounours]
        {
            get
            {
                if (lit >= NbreLits || lit < 0 || nounours >= mLits[lit].NombreNounours || nounours < 0)
                {
                    return null;
                }
                return mLits[lit][nounours];
            }
        }
    }
}
