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

using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;

namespace ex_042_011_EF_CF_Many_to_Many_FluentAPI
{
    /// <summary>
    /// initialiseur de stratégies...
    /// </summary>
    public static class DbContextInitializer
    {
        //quelques dictionnaires pour aller plus vite dans la création du stub
        static Dictionary<string, Album> albums;
        static Dictionary<string, Artiste> artistes;
        static Dictionary<string, AlbumEF> albumsEF;
        static Dictionary<string, ArtisteEF> artistesEF;

        /// <summary>
        /// ajoute un couple album-artiste au context
        /// </summary>
        /// <param name="context"></param>
        /// <param name="album"></param>
        /// <param name="artiste"></param>
        static void AddArtisteAlbum(AlbumArtisteDBEntities context, string album, string artiste)
        {
            //met à jour les liens entre album et artiste
            albums[album].Artistes.Add(artistes[artiste]);
            artistes[artiste].Albums.Add(albums[album]);

            //récupère les procurateurs sur les album et artiste concernés
            AlbumEF albumEF = albumsEF[album];
            ArtisteEF artisteEF = artistesEF[artiste];
            //création d'une entité albumartiste pour la table d'association
            AlbumArtiste aa = new AlbumArtiste() { Album = albumEF, Artiste = artisteEF };
            //mise à jour des tables
            albumEF.AlbumsArtistes.Add(aa);
            artisteEF.ArtistesAlbums.Add(aa);
            context.Albums.Add(albumEF);
            context.Artistes.Add(artisteEF);
        }
        
        /// <summary>
        /// remplissage de la base avec des données stubbées.
        /// </summary>
        /// <param name="context">base à remplir</param>
        public static void Seed(AlbumArtisteDBEntities context)
        {
            SetInitializer(context, InitializationStrategies.DropCreateDatabaseAlways);

            albums = new Dictionary<string, Album>()
            {
                ["kindOfBlue"] = new Album { Titre = "Kind of Blue", DateDeSortie = new DateTime(1959, 8, 17) },
                ["somethinElse"] = new Album { Titre = "Somethin' Else", DateDeSortie = new DateTime(1958, 8, 1) }
            };
            artistes = new Dictionary<string, Artiste>()
            {
                ["milesDavis"] = new Artiste { Prénom = "Miles", Nom = "Davis", DateDeNaissance = new DateTime(1926, 5, 26), DateDeMort = new DateTime(1991, 9, 28) },
                ["johnColtrane"] = new Artiste { Prénom = "John", Nom = "Coltrane", DateDeNaissance = new DateTime(1926, 9, 23), DateDeMort = new DateTime(1967, 7, 11) },
                ["julianAdderley"] = new Artiste { Prénom = "Julian", Nom = "Adderley", DateDeNaissance = new DateTime(1928, 9, 15), DateDeMort = new DateTime(1975, 8, 8) },
                ["billEvans"] = new Artiste { Prénom = "Bill", Nom = "Evans", DateDeNaissance = new DateTime(1929, 8, 16), DateDeMort = new DateTime(1980, 9, 15) },
                ["wyntonKelly"] = new Artiste { Prénom = "Wynton", Nom = "Kelly", DateDeNaissance = new DateTime(1931, 12, 2), DateDeMort = new DateTime(1971, 4, 12) },
                ["paulChambers"] = new Artiste { Prénom = "Paul", Nom = "Chambers", DateDeNaissance = new DateTime(1935, 4, 22), DateDeMort = new DateTime(1969, 1, 4) },
                ["jimmyCobb"] = new Artiste { Prénom = "Jimmy", Nom = "Cobb", DateDeNaissance = new DateTime(1929, 1, 20) },
                ["hankJones"] = new Artiste { Prénom = "Hank", Nom = "Jones", DateDeNaissance = new DateTime(1918, 7, 31), DateDeMort = new DateTime(2010, 5, 16) },
                ["samJones"] = new Artiste { Prénom = "Sam", Nom = "Jones", DateDeNaissance = new DateTime(1924, 11, 12), DateDeMort = new DateTime(1981, 12, 15) },
                ["artBlakey"] = new Artiste { Prénom = "Art", Nom = "Blakey", DateDeNaissance = new DateTime(1919, 10, 11), DateDeMort = new DateTime(1990, 10, 16) }
            };

            albumsEF = albums.ToDictionary(kvp => kvp.Key, kvp => new AlbumEF { Album = kvp.Value });
            artistesEF = artistes.ToDictionary(kvp => kvp.Key, kvp => new ArtisteEF { Artiste = kvp.Value });

            //les artistes qui jouent sur Kind Of Blue sont reliés à l'album
            AddArtisteAlbum(context, "kindOfBlue", "milesDavis");
            AddArtisteAlbum(context, "kindOfBlue", "johnColtrane");
            AddArtisteAlbum(context, "kindOfBlue", "julianAdderley");
            AddArtisteAlbum(context, "kindOfBlue", "billEvans");
            AddArtisteAlbum(context, "kindOfBlue", "wyntonKelly");
            AddArtisteAlbum(context, "kindOfBlue", "paulChambers");
            AddArtisteAlbum(context, "kindOfBlue", "jimmyCobb");

            //les artistes qui jouent sur Somethin' Else sont reliés à l'album
            AddArtisteAlbum(context, "somethinElse", "julianAdderley");
            AddArtisteAlbum(context, "somethinElse", "milesDavis");
            AddArtisteAlbum(context, "somethinElse", "hankJones");
            AddArtisteAlbum(context, "somethinElse", "samJones");
            AddArtisteAlbum(context, "somethinElse", "artBlakey");

            context.SaveChanges();
        }

        /// <summary>
        /// les différentes stratégies de création de la base
        /// </summary>
        public enum InitializationStrategies
        {
            CreateDatabaseIfNotExists,
            DropCreateDatabaseIfModelChanges,
            DropCreateDatabaseAlways
        }
        public static void SetInitializer(DbContext context, InitializationStrategies strategy)
        {
            switch (strategy)
            {
                //par défaut : crée la base seulement si elle n'existe pas
                default:
                case InitializationStrategies.CreateDatabaseIfNotExists:
                    context.Database.EnsureCreated();
                    break;

                //recrée la base même si elle existe déjà
                case InitializationStrategies.DropCreateDatabaseAlways:
                    context.Database.EnsureDeleted();
                    context.Database.EnsureCreated();
                    break;

                //recrée la base seulement si le modèle change : impossible aujourd'hui en Entity Framework Core...
                case InitializationStrategies.DropCreateDatabaseIfModelChanges:
                    throw new NotImplementedException("Le mode DropCreateDatabaseIfModelChanges ne peut pas encore exister sous Entity Framework Core");
            }
        }
    }
}
