using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Core;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.ModelConfiguration;
using System.Data.Entity.ModelConfiguration.Conventions;
using System.Linq;
using EFDBContextDemos.Verbesserungen_DbContext;
using ITVisions;
using System.Data.Entity.Infrastructure.Interception;

namespace de.WWWings.CodeOnly
{



 public class Demos
 {

  // Optionaler ConnString, wenn nicht der aus Konfig-Datei verwendet werden soll.
  // string ConnString = @"Data Source=.\sqlexpress;Initial Catalog=meineDB;Integrated Security=True";

  public static void Init()
  {


   Console.WriteLine("----------- Datenbank erstellen");
   //System.Data.Entity.Database.SetInitializer<WWWingsCodeOnlyContext>(new System.Data.Entity.MigrateDatabaseToLatestVersion<WWWingsCodeOnlyContext, de.WWWings.CodeOnly.Migrations.WWWingsMigrationConfiguration>());

   System.Data.Entity.Database.SetInitializer<FluggesellschaftContext>(new System.Data.Entity.DropCreateDatabaseAlways<FluggesellschaftContext>());

   Console.WriteLine(System.Data.Entity.Database.DefaultConnectionFactory.GetType().FullName);
   //ConnString = "WWWings6CodeOnly";
   var ctx = new FluggesellschaftContext();
   Console.WriteLine(ctx.Database.Connection.ConnectionString);

   ctx.Database.Initialize(true); // ohne dies wird die DB erst beim ersten Zugriff angelegt!
   Console.WriteLine("Init fertig.");
  }


  public static void WWWingsLog(string s)
  {
   var FarbeVorher = Console.ForegroundColor;
   if (!s.StartsWith("-"))
   {
    Console.ForegroundColor = ConsoleColor.Yellow;
   }
   else
   {
    Console.ForegroundColor = ConsoleColor.Green;
   }

   Console.Write(s);
   Console.ForegroundColor = FarbeVorher;
  }



  public static void Befuellen_Fluege()
  {

   FluggesellschaftContext ctx = new FluggesellschaftContext();
   ctx.Database.Log = WWWingsLog;


   //ctx.Database.Log = Console.Write;


   foreach (var f in ctx.Fluege)
   {
    ctx.Fluege.Remove(f);
    ctx.SaveChanges();
   }

   Pilot pl = new Pilot();
   pl.Name = "Meier";
   pl.Vorname = "Max";
   pl.FlugscheinSeit = new DateTime(1970, 1, 1);
   ctx.Piloten.Add(pl);
   ctx.SaveChanges();

   for (int i = 1; i <= 3; i++)
   {
    Flug f = new Flug();

    f.Abflugort = "Essen/Mülheim";
    f.Zielort = "München";
    f.FreiePlaetze = 10;
    f.Plaetze = 210;
    f.Datum = new DateTime(2011, 8, 1);
    f.Pilot = pl;
    f.Copilot = pl;

    ctx.Fluege.Add(f);

    var errListe = ctx.GetValidationErrors();
    foreach (var err in errListe)
    {
     Console.WriteLine(err.Entry.Entity.ToString());
     foreach (var ve in err.ValidationErrors)
     {
      Console.WriteLine(ve.PropertyName + ": " + ve.ErrorMessage);
     }


    }

    ctx.SaveChanges();
    Console.WriteLine("Flug #" + f.FlugNr);
    f.Passagiere = new List<Passagier>();
    for (int p = 1; p <= 2; p++)
    {
     var pas = new Passagier();
     pas.Vorname = "Max" + p;
     pas.Name = "Mustermann" + p;
     pas.KundenStatus = "A";
     f.Passagiere.Add(pas);
    }

   }


   foreach (var flug in ctx.Fluege)
   {
    flug.FreiePlaetze--;
    ctx.SaveChanges();
   }

  }

  public static void Befuellen_kurz()
  {
   
   // Pilot anlegen
   Pilot pl = new Pilot();
   pl.Name = "Mustermann";
   pl.Vorname = "Max";
   pl.FlugscheinSeit = new DateTime(1970, 1, 1);
   // Copilot anlegen
   Pilot cpl = new Pilot();
   cpl.Name = "Musterfrau";
   cpl.Vorname = "Martina";
   cpl.FlugscheinSeit = new DateTime(1968, 1, 1);

   // Flug anlegen
   Flug f = new Flug();
   f.Abflugort = "Essen/Mülheim";
   f.Zielort = "Hannover";
   f.Plaetze = 150;
   f.Datum = new DateTime(2014, 8, 1);
   f.Pilot = cpl;
   f.Copilot = cpl;
   f.Passagiere = new List<Passagier>();

   // Zehn Passagiere anlegen
   for (int j = 1; j <= 10; j++)
   {
    Passagier p = new Passagier();
    p.Name = "Passagier #" + j;
    p.Vorname = "";
    p.KundenStatus = "C";
    f.Passagiere.Add(p);
    Console.WriteLine(p.Name);
   }
   
   // Kontext erzeugen und mit Datenbank interagieren
   using (FluggesellschaftContext ctx = new FluggesellschaftContext())
   {
    // Protokollierung auf die Konsole
    ctx.Database.Log = Console.WriteLine;

    // Das Hauptobjekt muss mit dem Kontext verbunden werden
    ctx.Fluege.Add(f);

    // Alle Objekte in einer Transaktion speichern
    var anz = ctx.SaveChanges();
    Console.WriteLine("Anzahl gespeicherter Datensätze: " + anz);
   }
  }


  //  var errListe = ctx.GetValidationErrors();
  //foreach (var err in errListe)
  //{
  // Console.WriteLine(err.Entry.Entity.ToString());
  // foreach (var ve in err.ValidationErrors)
  // {
  //  Console.WriteLine(ve.PropertyName + ": " + ve.ErrorMessage);
  // }
  //}

  public static void Befuellen()
  {
   // Kontextinstanz erzeugen
   using (FluggesellschaftContext ctx = new FluggesellschaftContext())
   {
    Console.WriteLine("----------- Datenbank befüllen");

    Pilot pl = new Pilot();
    pl.Name = "Meier";
    pl.Vorname = "Max";
    ctx.Piloten.Add(pl);
    ctx.SaveChanges();

    for (int i = 1; i <= 3; i++)
    {
     Flug f = new Flug();

     f.Abflugort = "Essen/Mülheim";
     f.Zielort = "München";
     f.FreiePlaetze = 10;
     f.Plaetze = 10;
     f.Datum = new DateTime(2011, 8, 1);
     f.Passagiere = new List<Passagier>();
     f.Pilot = pl; //  new List<Pilot>() { pl };
     ctx.Fluege.Add(f);

     for (int j = 1; j < 10; j++)
     {
      Passagier p = new Passagier();
      p.Name = "Passagier #" + i * j;
      p.Vorname = "";
      p.KundenStatus = "C";
      f.Passagiere.Add(p);
      Console.WriteLine(p.Name);
     }
    }
    ctx.SaveChanges();
   }


   Console.WriteLine("OK");
  }

  public static void Abfrage()
  {
   Console.WriteLine("----------- Abfragen");

   // Kontextinstanz erzeugen
   using (FluggesellschaftContext ctx = new FluggesellschaftContext())
   {
    // Abfrage definieren
    var flugAbfrage = (from f in ctx.Fluege.Include(f => f.Passagiere).Include(f => f.Pilot).Include(f => f.Copilot)
                       where f.Abflugort == "Essen/Mülheim" &&
                       f.Plaetze > f.Passagiere.Count && 
                       f.Passagiere.Any(p=>p.KundenStatus == "C") &&
                       f.Pilot != null && f.Copilot != null
                       orderby f.Datum descending
                       select f).Skip(10).Take(5);

    // Abfrage ausführen
    var flugListe = flugAbfrage.ToList();

    // Schleife über alle Flüge
    foreach (var f in flugAbfrage.ToList())
    {
     // Flug mit Pilot und Copilot ausgeben
     Console.WriteLine("Flug #" + f.FlugNr + " wird geflogen von " + f.Pilot.Name + " und " +   f.Copilot.Name);
     // Alle Passagiere ausgeben
     foreach (var p in f.Passagiere)
     {
      Console.WriteLine(" - " + p.Name);
     }
    }
   }
  }


  public static void PrintWhite(string s)
  {
   CUI.Print(s, ConsoleColor.White);

  }

  /// <summary>
  /// EF_Konflikt_BeiFlug
  /// </summary>
  public static void EF_Konflikt_BeiFlug()
  {

   Console.WriteLine("EFTest_Speichern/Beispiel4_Konflikt in Prozess ID=" + System.Diagnostics.Process.GetCurrentProcess().Id);


   // Kontext instanziieren unter Verwendung der Verbindungszeichenfolge aus Konfigurationsdatei
   using (FluggesellschaftContext modell = new FluggesellschaftContext())
   {
    modell.Database.Log = PrintWhite;

    int flugNr = modell.Fluege.OrderBy(x => x.FlugNr).FirstOrDefault().FlugNr;
    var f = modell.Fluege.Where(x => x.FlugNr == flugNr).SingleOrDefault();

    Console.WriteLine("Flug " + flugNr + ": " + DateTime.Now.ToLongTimeString() + ": Freie Plätze VORHER: " + f.FreiePlaetze);
    Console.WriteLine("Warte auf ENTER...");
    Console.ReadLine(); // Warten (zum Starten eines zweiten Prozesses!)

    // Änderung
    f.FreiePlaetze = (short)(new System.Random(DateTime.Now.Millisecond).Next(1, 100));
    Console.WriteLine(DateTime.Now.ToLongTimeString() + ": Freie Plätze NEU: " + f.FreiePlaetze);
    try
    {
     // Speicherversuch
     ValUtil.PrintValErrors(modell.GetValidationErrors());
     modell.SaveChanges();
    }


    catch (DbUpdateConcurrencyException ex)
    {
     Console.ForegroundColor = ConsoleColor.Red;
     Console.WriteLine(DateTime.Now.ToLongTimeString() + ": Fehler: Ein anderer Benutzer hat bereits geändert!");
     // Zeige aktuellen Wert aus DB
     var f2 = (Flug)ex.Entries.Single().GetDatabaseValues().ToObject();
     Console.WriteLine(DateTime.Now.ToLongTimeString() + ": Der andere Benutzer hat gespeichert: Freie Plätze=" + f2.FreiePlaetze);

     // Frage beim Benutzer nach
     Console.WriteLine("Möchten Sie den Wert des anderen Benutzers  übernehmen (Taste '1') oder überschreiben (Taste '2')?");
     ConsoleKeyInfo key = Console.ReadKey();
     if (key.Key == ConsoleKey.D1)
     {
      Console.WriteLine("Sie haben gewählt: Option 1: übernehmen");
      modell.Entry(f).Reload(); // wie RefreshMode.StoreWins bei ObjectContext
     }
     else
     {
      Console.WriteLine("Sie haben gewählt: Option 2: überschreiben");
      Console.ForegroundColor = ConsoleColor.Gray;
      modell.Entry(f).OriginalValues.SetValues(modell.Entry(f).GetDatabaseValues()); // wie RefreshMode.ClientWins bei ObjectContext
      EF_Util.PrintChangeInfo(modell);
      int anz = modell.SaveChanges();
      Console.WriteLine("SaveChanges: Gespeicherte Änderungen: " + anz);
     }
    }
    Console.WriteLine(DateTime.Now.ToLongTimeString() + ": Freie Plätze NACHHER: " + f.FreiePlaetze);
   } // Ende using-Block -> Dispose() wird aufgerufen
  }
 }
}
