using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration;
using System.Data.Entity.ModelConfiguration.Configuration;
using System.Data.Entity.ModelConfiguration.Conventions;
using System.Linq;
using de.WWWings.CodeOnly.Modell2;
using de.WWWings.CodeOnly.Kontext;


namespace de.WWWings.CodeOnly
{
 public class FluggesellschaftContext : DbContext
 {

  // Konstruktoren mit Angabe des Connection Strings
  public FluggesellschaftContext() : base("DB_Fluggesellschaft") { }
  public FluggesellschaftContext(string Connstring) : base(Connstring) { }

  // Einsprungpunkte für Zugriff auf Entitätsklassen
  public DbSet<Flug> Fluege { get; set; }
  public DbSet<Pilot> Piloten { get; set; }
  public DbSet<Person> Personen { get; set; }
  //public DbSet<Mitarbeiter> Mitarbeiter { get; set; }
  public DbSet<Passagier> Passagiere { get; set; }
  //public DbSet<Gate> Gates { get; set; }
  //public DbSet<Flughafen> Flughafen { get; set; }


  /// <summary>
  /// Methode zur Aktivierung/Deaktivierung von Konventionen
  /// sowie zur manuellen Konfiguration per Fluent-API
  /// </summary>

  protected override void OnModelCreating(DbModelBuilder modelBuilder)
  {

   // Konventionen ausschalten: Keine Pluralisierung
   modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
   modelBuilder.Conventions.Remove<PluralizingEntitySetNameConvention>();

   // Eigene Konventionen: Table per Type statt Table per Hierarchie
   modelBuilder.Types().Configure(c => c.ToTable(c.ClrType.Name));
   
   // Konfiguration durch Fluent API: INSERT, UPDATE, DELETE über Stored Procedures
   modelBuilder.Entity<Flug>().MapToStoredProcedures();
   modelBuilder.Entity<Passagier>().MapToStoredProcedures();
   modelBuilder.Entity<Person>().MapToStoredProcedures();
   modelBuilder.Entity<Pilot>().MapToStoredProcedures();



   //modelBuilder.Conventions.Remove<TableAttributeConvention>();
   //modelBuilder.Conventions.Remove<AssociationInverseDiscoveryConvention>();

   // 2a. Custom Conventions
   //ApplyMyLightweigthConventions(modelBuilder);
   // 2b. Alternative: Convention Classes
   // modelBuilder.Conventions.Add<NrIsPKConvention>();
   //modelBuilder.Conventions.Add<DateTimeColumnTypeConvention>();
   //modelBuilder.Conventions.Add<TableNameConvention>();
   // 2c: Convention Classes mit Attribut
   //  modelBuilder.Conventions.AddBefore<DateTimeColumnTypeConvention>(new DBDateAttributeConvention()); // Reihenfolge wichtig!!!
   // 2d: Model based Conventions
   //modelBuilder.Conventions.Add<DecimalPrecisionAndScaleConvention>();
   //modelBuilder.Conventions.Add<ConcurrencyFixedConvention>();

   // 2. Fluent Configuration
   //FluentConfiguration(modelBuilder);

   // 3. Mapping Form (ab EF 6.0)
   //MapToSPs(modelBuilder);




   base.OnModelCreating(modelBuilder);
  }

  public void ApplyMyLightweigthConventions(DbModelBuilder modelBuilder)
  {

   // Konvention 1: In der Datenbank erhalten alle Tabellennamen das Suffix "_Table" 
   // Alpha war "Entities" statt "Types"
   modelBuilder.Types().Configure(c => c.ToTable(c.ClrType.Name + "_Table"));

   // Konvention 2: Alle Properties, die auf "Nr" enden, sind Primärschlüssel
   modelBuilder
     .Properties()
     .Where(p => p.Name.EndsWith("Nr"))
     .Configure(p => p.IsKey());

   // Konvention 3: Für DateTime wird in der Datenbank nicht DateTime, sondern DateTime2 genutzt
   modelBuilder.Properties<DateTime>()
              .Configure(c => c.HasColumnType("datetime2"));

   // Unsinn, aber kein Kompiler- oder Laufzeitfehler in Alpha. Jetzt gibt es Fehler!
   //modelBuilder
   //  .Properties<string>()
   //  .Configure(p => p.HasPrecision(2));

  }


  protected void FluentConfiguration(DbModelBuilder modelBuilder)
  {
   //Individuelle Konfiguration
   //N:1 Beziehung zwischen Flug und Pilot mit PilotID als Fremdschlüssel für die Beziehung zwischen 
   //modelBuilder.Entity<Flug>()
   //.HasRequired<Pilot>(f => f.Pilot)
   //.WithMany(p => p.Flug)
   //.HasForeignKey(f => f.PilotID).WillCascadeOnDelete(false);
   //Verbindung mit individueller Konfig-Klasse
   modelBuilder.Configurations.Add(new FlugConfiguration());

   // //Klasse Flug soll auf Tabelle "Fluege" abgebildet werden
   //modelBuilder.Entity<Flug>().ToTable("Fluege", "Main");
   // //Datum ist ein Pflichtfeld
   //modelBuilder.Entity<Flug>().Property(f => f.Datum).IsRequired();
   //// Datum bekommt einen anderen Namen
   //modelBuilder.Entity<Flug>().Property(f => f.Datum).HasColumnName("Abflugdatum");



   // //N:M Beziehung zwischen Flug und Passagier 
   //modelBuilder.Entity<Flug>()
   //.HasMany<Passagier>(f => f.Passagiere)
   //.WithMany(p => p.Flug);
  }


  protected void MapToSPs(DbModelBuilder modelBuilder)
  {

   // Einfache SP-Abbildungen
   modelBuilder.Entity<Flug>().MapToStoredProcedures();
   modelBuilder.Entity<Passagier>().MapToStoredProcedures();
   modelBuilder.Entity<Person>().MapToStoredProcedures();
   modelBuilder.Entity<Pilot>().MapToStoredProcedures();

   //// SP-Abbildungen mit Namensanpassungen
   //modelBuilder.Entity<Mitarbeiter>().MapToStoredProcedures(
   // s => s.Update(x => x.HasName("Update_Mitarbeiter")
   //          .Parameter(p => p.MitarbeiterNr, "Nr"))
   //        .Delete(x => x.HasName("Delete_Mitarbeiter"))
   //        .Insert(x => x.HasName("Insert_Mitarbeiter")
   //          .Parameter(p => p.MitarbeiterNr, "Nr"))
   // );

   //modelBuilder.Entity<Flug>().MapToStoredProcedures(
   // sp =>
   // {
   //  sp.Update(u => u.HasName("Flug_UpdateSP").Parameter(p => p.FlugNr, "FlugNummer"));
   //  sp.Delete(d => d.HasName("Flug_DeleteSP").Parameter(p => p.FlugNr, "FlugNummer"));
   // }
   //  );

   
   // modelBuilder.Entity<Flug>().MapToStoredProcedures(
   // sp =>
   // {
   //  sp.Update(u => u.HasName("Flug_UpdateV2").Parameter(p => p.FlugNr, "FlugNummer"));
   //  sp.Delete(d => d.HasName("Flug_DeleteV2").Parameter(p => p.FlugNr, "FlugNummer"));
   // }
   //);

   // Alternativ:

   //  modelBuilder.Entity<Flug>().MapToStoredProcedures(
   // sp =>
   // {
   //  sp.Update(u => u.HasName("Flug_UpdateV2").Parameter(p => p.FlugNr, "FlugNummer"))
   //  .Delete(d => d.HasName("Flug_DeleteV2").Parameter(p => p.FlugNr, "FlugNummer"));
   // }
   //);



   //  // Ungültig 1
   //  modelBuilder.Entity<Flug>().MapToStoredProcedures(
   //sp =>
   //{
   // sp.Update(u => u.HasName("Flug_UpdateV2"));
   // sp.Update(u => u.Parameter(p => p.FlugNr, "FlugNummer"));
   // sp.Delete(u => u.HasName("Flug_DeleteV2"));
   // sp.Delete(u => u.Parameter(p => p.FlugNr, "FlugNummer"));
   //}
   //);


   //  // Ungültig 2
   //  modelBuilder.Entity<Flug>().MapToStoredProcedures(
   //sp =>
   //{
   // sp.Update(u => u.HasName("Flug_UpdateV2")).Update(u => u.Parameter(p => p.FlugNr, "FlugNummer"));
   // sp.Delete(u => u.HasName("Flug_DeleteV2")).Delete(d => d.Parameter(p => p.FlugNr, "FlugNummer"));
   //}
   //);

  }


  public static void ExportEDMX()
  {
   //var modell = modelBuilder.Build(new System.Data.Entity.Infrastructure.DbProviderInfo("System.Data.SqlClient", "2008"));
   //var cmodell = modell.Compile();

   //DbConnection connection = ctx.Database.Connection;
   //XDocument document = modelBuilder.W .(connection);

   //// or using XmlWriter 
   //var swriter = new StringWriter();
   //var xwriter = new XmlTextWriter(swriter);
   //builder.WriteEdmx(connection, xwriter);

  }

 }

}