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

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Xml;
using static System.Console;

namespace ex_038_002_DataContract_subclassing
{
    class Program
    {
        /// <summary>
        /// Dans le Framework .NET, il était nécessaire de préciser le type des classes filles avec l'une des deux méthodes présentées dans l'exemple suivant. 
        /// Néanmoins, en .NET Core, cela ne semble plus nécessaire. Si on ne déclare pas les classes filles dans les sérialiseur, il s'en sort quand même !
        /// Voici néanmoins les explications.
        /// 
        /// Dans l'exemple suivant, trois classes (Chat, Chien et Oiseau) dérivent de la classe Animal. Animal, Chat et Chien sont décorées avec DataContract et DataMember.
        /// Nous avons trois variables de type Animal, mais l'une a été construite avec le constructeur d'Animal, la 2ème avec celui de Chat, et la 3ème avec celui de Chien.
        /// Nous sérialisons les trois variables de type Animal, et pourtant le sérialiseur sérialise un Animal, un Chat et un Chien.
        /// 
        /// Pour que cela soit possible, il faut utiliser l'une des deux solutions suivantes : 
        /// 1- dans la classe mère, on augmente l'attribut DataContract avec KnownType et on précise quelles sont les classes filles. 
        /// Par exemple, ici on a : [DataContract, KnownType(typeof(Chat)), KnownType(typeof(Chien))] class Animal { ... } (cf. Animal.cs)
        /// 2- dans la construction du sérialiseur, on donne les types fils qu'on peut avoir à sérialiser. Ceci est indispensable, si on ne connait pas à l'avance les classes filles
        /// au moment de l'écriture de la classe mère.
        /// 
        /// Comme expliqué ci-dessus, en .NET Core, il n'est plus nécessaire d'effectuer l'une des deux opérations précédentes.
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            Directory.SetCurrentDirectory(Path.Combine(Directory.GetParent(Directory.GetCurrentDirectory()).FullName, "ex_038_002_DataContract_subclassing", "XML"));

            Animal jojo = new Animal("jojo", "pfffff");
            Animal grosminet = new Chat("Grosminet", TimeSpan.FromHours(4.0));
            Animal idefix = new Chien("Idefix", 5);
            Animal titi = new Oiseau("Titi", TimeSpan.FromHours(12.0));

            //1- sérialiseur sans préciser quels sont les types fils
            //(en conséquence, seuls ceux qui sont déclarés en KnownType dans l'attribut DataContract de la classe mère sont reconnus
            var serializer = new DataContractSerializer(typeof(Animal));

            XmlWriterSettings settings = new XmlWriterSettings() { Indent = true };
            using (TextWriter tw = File.CreateText("animal.xml"))
            {
                using (XmlWriter writer = XmlWriter.Create(tw, settings))
                {
                    serializer.WriteObject(writer, jojo);
                }
            }

            using (TextWriter tw = File.CreateText("chat.xml"))
            {
                using (XmlWriter writer = XmlWriter.Create(tw, settings))
                {
                    serializer.WriteObject(writer, grosminet);
                }
            }

            using (TextWriter tw = File.CreateText("chien.xml"))
            using (XmlWriter writer = XmlWriter.Create(tw, settings))
            {
                serializer.WriteObject(writer, idefix);
            }

            //le type Oiseau n'est pas sérialisé
            try
            {
                using (TextWriter tw = File.CreateText("oiseau.xml"))
                using (XmlWriter writer = XmlWriter.Create(tw, settings))
                {
                    serializer.WriteObject(writer, titi);
                }
            }
            catch (Exception exc)
            {
                WriteLine(exc);
            }


            //2- on précise au sérialiseur qu'il peut tomber sur un type Oiseau
            var serializer2 = new DataContractSerializer(typeof(Animal), new Type[] { typeof(Oiseau) });
            using (TextWriter tw = File.CreateText("animal2.xml"))
            using (XmlWriter writer = XmlWriter.Create(tw, settings))
            {
                serializer2.WriteObject(writer, jojo);
            }

            using (TextWriter tw = File.CreateText("chat2.xml"))
            using (XmlWriter writer = XmlWriter.Create(tw, settings))
            {
                serializer2.WriteObject(writer, grosminet);
            }

            using (TextWriter tw = File.CreateText("chien2.xml"))
            using (XmlWriter writer = XmlWriter.Create(tw, settings))
            {
                serializer2.WriteObject(writer, idefix);
            }

            try
            {
                using (TextWriter tw = File.CreateText("oiseau2.xml"))
                using (XmlWriter writer = XmlWriter.Create(tw, settings))
                {
                    serializer2.WriteObject(writer, titi);
                }
            }
            catch (Exception exc)
            {
                WriteLine(exc);
            }
        }
    }
}
