/*
Enable-Migrations -ContextTypeName iSchedulerDB -MigrationsDirectory Migrations
Update-Database -TargetMigration $InitialDatabase
Add-Migration -name InitialDB -Force -Verbose
Update-Database -Verbose

Update-Database -TargetMigration InitialDB -Verbose -Force
Add-Migration -name UpdateDB_01 -Force -Verbose 

Update-Database -TargetMigration UpdateDB_01 -Verbose -Force
Add-Migration -name UpdateDB_02 -Force -Verbose 
*/
namespace Vrh.iScheduler
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Data.Entity;
    using System.Linq;
    using Vrh.XmlProcessing;

    /// <summary>
    /// Az ütemezésekhez szükséges adatmodell (DBContext).
    /// </summary>
    public class SchedulerDB : DbContext
    {
        #region Constructors
        /// <summary>
        /// A DBContext előállítása az alapértelmezett kapcsolati sztringgel.
        /// </summary>
        public SchedulerDB() : this(ConnectionStringStore.GetSQL(SchConst.DEFAULT_SQLCONNECTIONSTRINGNAME)) { }

        /// <summary>
        /// A DBContext előállítása <paramref name="connectionString"/> 
        /// paraméterben megadott kapcsolati sztringgel.
        /// </summary>
        /// <param name="connectionString">Szabványos és szabályos SQL kapcsolati sztring. (Nem megnevezés!)</param>
        public SchedulerDB(string connectionString) : base(connectionString)
        {
            // migráció ellenőrzése
            System.Data.Entity.Database.SetInitializer(new System.Data.Entity.MigrateDatabaseToLatestVersion<SchedulerDB, Vrh.iScheduler.Migrations.Configuration>(true));
        }
        #endregion Constructors

        #region DbSets
        /// <summary>
        /// Az ütemezendő ojektumokat tartalmazó táblázat.
        /// </summary>
        public virtual DbSet<ScheduleObject> ScheduleObjects { get; set; }

        /// <summary>
        /// Az ütemezendő ojektumokon végezhető műveleteket tartalmazó táblázat.
        /// </summary>
        public virtual DbSet<ScheduleOperation> ScheduleOperations { get; set; }

        /// <summary>
        /// Az ütemezéseket tartalmazó táblázat.
        /// </summary>
        public virtual DbSet<Schedule> Schedules { get; set; }

        /// <summary>
        /// Sorozat ütemezések azonosítói és típusai.
        /// </summary>
        public virtual DbSet<ScheduleSeriesOne> ScheduleSeries { get; set; }
        #endregion DbSets

        #region OnModelCreating
        /// <summary>
        /// A EF CodeFirst-ben nem elvégezhető vagy módosítandó dolgokat ebben
        /// az eseményben kell elvégezni.
        /// </summary>
        /// <param name="modelBuilder"></param>
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            //modelBuilder.HasDefaultSchema("GoodBill");

            //WA20160124: Sajnos az EF a kötelező idegen kulcsnál alapértelmezésként cascadeDelete értékét true-ra állítja, 
            //            ami sok esetben nem megfelelő (nem is értem, miért true a default :(( )
            //            Ahol ez előfordul, ott a ForeignKey-eket itt kell definiálni.
            //            HasRequired   = many oldal virtual property 
            //            WithMany      = ha a one oldalon lett definiálva ICollection a many-ra, akkor azt kell ide írni, egyébként üres
            //            HasForeignKey = many oldalon a foreign key mező

            modelBuilder.Entity<Schedule>().HasRequired(v => v.ScheduleObject)
                                           .WithMany(one => one.Schedules)
                                           .HasForeignKey(t => t.ScheduleObjectId)
                                           .WillCascadeOnDelete(false);
            modelBuilder.Entity<Schedule>().HasRequired(v => v.ScheduleOperation)
                                           .WithMany(one => one.Schedules)
                                           .HasForeignKey(t => t.ScheduleOperationId)
                                           .WillCascadeOnDelete(false);

            base.OnModelCreating(modelBuilder);
        }
        #endregion OnModelCreating

        public class SelectLists
        {
            public static void CreateSystemViews(string sqlconnectionstring)
            {
                const string createview = @"CREATE VIEW [iScheduler].[{0}] AS {1}";
                const string dropview = @"IF  EXISTS (SELECT * FROM sys.views WHERE object_id = OBJECT_ID(N'[iScheduler].[{0}]')) DROP VIEW [iScheduler].[{0}];";
                var sl = new Dictionary<string, string>();
                sl.Add("SelectList_Schedules", selecttxt_SelectList_Schedules);
                sl.Add("SelectList_SchedulesActive", selecttxt_SelectList_SchedulesActive);
                int numofall = 0, numofcreated = 0;
                using (var dbc = new SchedulerDB(sqlconnectionstring))
                {
                    foreach (var s in sl)
                    {
                        numofall++;
                        var dropviewtext = string.Format(dropview, s.Key);
                        var createviewtext = string.Format(createview, s.Key, s.Value);
                        dbc.Database.ExecuteSqlCommand(dropviewtext);
                        dbc.Database.ExecuteSqlCommand(createviewtext);
                    }
                    dbc.SaveChanges();
                }
            }
            #region systemviewtexts
            const string selecttxt_SelectList_Schedules = @"
SELECT TOP 100 
[iScheduler].[Schedules].[Id] AS IID,
convert(varchar(25), [iScheduler].[Schedules].[Id]) + ' (' + convert(varchar(25), [OperationTime], 120) + ',' 
+ [iScheduler].[ScheduleObjects].[ObjectType] + ',' 
+ [iScheduler].[ScheduleObjects].[ObjectName] + ',' 
+ [iScheduler].[ScheduleOperations].[OperationName] + ',' 
+ (CASE WHEN [iScheduler].[Schedules].[State] = 0 THEN 'Active' ELSE 'Passive' END) + ')' 
AS DDISPLAY
FROM [iScheduler].[Schedules]
INNER JOIN [iScheduler].[ScheduleObjects] ON [iScheduler].[Schedules].[ScheduleObjectId] = [iScheduler].[ScheduleObjects].[Id]
INNER JOIN [iScheduler].[ScheduleOperations] ON [iScheduler].[Schedules].[ScheduleOperationId] = [iScheduler].[ScheduleOperations].[Id]";
            const string selecttxt_SelectList_SchedulesActive = selecttxt_SelectList_Schedules + @" WHERE [iScheduler].[Schedules].[State] = 0";
            #endregion systemviewtexts
        }
    }


    #region ScheduleObject class
    /// <summary>
    /// Ütemezhető objektumokat tartalmazó táblázat.
    /// Egy típus alatt egyedinek kell lennie az azonosítónak.
    /// </summary>
    [Table("ScheduleObjects", Schema = "iScheduler")]
    public partial class ScheduleObject
    {
        #region Properties
        /// <summary>
        /// Az ütemezett objektum belső egyedi azonosítója.
        /// </summary>
        [Key]
        public int Id { get; set; }

        /// <summary>
        /// Ütemezett objektum típusa.
        /// </summary>
        [Required, MaxLength(100), Index("IX_ScheduleObject_ObjectTypeObjectId", 1, IsUnique = true)]
        public string ObjectType { get; set; }

        /// <summary>
        /// Ütemezett objektum azonosítója.
        /// </summary>
        [Required, MaxLength(100), Index("IX_ScheduleObject_ObjectTypeObjectId", 2, IsUnique = true)]
        public string ObjectId { get; set; }

        /// <summary>
        /// Az ütemezett objektum publikus megnevezése.
        /// </summary>
        [Required, MaxLength(200)]
        public string ObjectName { get; set; }

        /// <summary>
        /// Ütemezett objektumcsoport azonosítója.
        /// </summary>
        [Required, MaxLength(100)]
        public string ObjectGroupId { get; set; }

        /// <summary>
        /// Gyűjtemény, mely azokat az ütemezéseket tartalmazza,
        /// amelyekben az objektum szerepel.
        /// </summary>
        public virtual ICollection<Schedule> Schedules { get; set; }

        #endregion Properties

        #region Constructor
        /// <summary>
        /// A ScheduleObject alapértelmezett konstruktora,
        /// melyben inicializálódik a Schedules gyűjtemény.
        /// </summary>
        public ScheduleObject()
        {
            Schedules = new HashSet<Schedule>();
        }
        #endregion Constructor
    }
    #endregion ScheduleObject class

    #region ScheduleOperation class
    /// <summary>
    /// Ütemezhető objektumokon elvégezhető műveletek.
    /// Egy típus alatt egyedinek kell lennie az azonosítónak.
    /// </summary>
    [Table("ScheduleOperations", Schema = "iScheduler")]
    public partial class ScheduleOperation
    {
        #region Properties
        /// <summary>
        /// A művelet egyedi belső azonosítója.
        /// </summary>
        [Key]
        public short Id { get; set; }

        /// <summary>
        /// Ütemezett objektum típusa.
        /// </summary>
        [Required, MaxLength(100), Index("IX_ScheduleOperation_ObjectTypeOperationId", 1, IsUnique = true)]
        public string ObjectType { get; set; }

        /// <summary>
        /// Ütemezett objektumon végezhető művelet "távoli" azonosítója.
        /// </summary>
        [Required, MaxLength(100), Index("IX_ScheduleOperation_ObjectTypeOperationId", 2, IsUnique = true)]
        public string OperationId { get; set; }

        /// <summary>
        /// Ütemezett objektumon végezhető művelet "távoli" megnevezése.
        /// </summary>
        [Required, MaxLength(200)]
        public string OperationName { get; set; }

        /// <summary>
        /// Gyűjtemény, mely azokat az ütemezéseket tartalmazza,
        /// amelyekben a művelet szerepel.
        /// </summary>
        public virtual ICollection<Schedule> Schedules { get; set; }
        #endregion Properties

        #region Constructor
        /// <summary>
        /// A ScheduleOperation alapértelmezett konstruktora,
        /// melyben a Schedules gyűjtemény inicializálása történik.
        /// </summary>
        public ScheduleOperation()
        {
            Schedules = new HashSet<Schedule>();
        }
        #endregion Constructor
    }
    #endregion ScheduleOperation class

    #region Schedule class
    /// <summary>
    /// Ütemezéseket tartalmazó táblázat.
    /// </summary>
    [Table("Schedules", Schema = "iScheduler")]
    public partial class Schedule
    {
        #region Properties
        
        /// <summary>
        /// Az ütemezés egyedi belső azonosítója.
        /// </summary>
        [Key]
        public int Id { get; set; }

        /// <summary>
        /// Az adott (OperationTime) időpontban végrehajtandó művelet ezen objektumhoz kapcsolódik.
        /// </summary>
        public int ScheduleObjectId { get; set; }

        /// <summary>
        /// Az adott (OperationTime) időpontban végrehajtandó művelet azonosítója.
        /// </summary>
        public short ScheduleOperationId { get; set; }

        /// <summary>
        /// Ütemezés időpontja, amikor végre kell hajtani a jelölt műveletet a jelölt objektumon.
        /// </summary>
        public DateTime OperationTime { get; set; }

        /// <summary>
        /// Ütemezés állapota. Alapértelmezett értéke: ScheduleStates.Active (0)
        /// </summary>
        [Index(IsUnique = false)]
        public ScheduleStates State { get; set; }

        /// <summary>
        /// Annak a sorozat ütemezésnek az azonosítója, mely alapján az egyedi ütemezés létrejött.
        /// Ha nem sorozat ütemezés alapján (wizard) jön létre, akkor az értéke null.
        /// </summary>
        public int? ScheduleSeriesId { get; set; }

        /// <summary>
        /// Művelet végrehajtásakor visszakapott ReturnInfoJSON ReturnValue tulajdonság értékének tárolására.
        /// </summary>
        /// <remarks>Csak akkor kerül bele érték, ha az iSchedulerMonitor service hajtja végre ScheduleExecute akciót.</remarks>
        public int? ReturnValue { get; set; }

        /// <summary>
        /// Művelet végrehajtásakor visszakapott ReturnInfoJSON ReturnMessage tulajdonság értékének tárolására.
        /// </summary>
        /// <remarks>Csak akkor kerül bele érték, ha az iSchedulerMonitor service hajtja végre ScheduleExecute akciót.</remarks>
        public string ReturnMessage { get; set; }

        /// <summary>
        /// ScheduleObjectId idegen kulcshoz tartozó virtuális tulajdonság.
        /// </summary>
        [ForeignKey("ScheduleObjectId")]
        public virtual ScheduleObject ScheduleObject { get; set; }

        /// <summary>
        /// ScheduleOperationId idegen kulcshoz tartozó virtuális tulajdonság.
        /// </summary>
        [ForeignKey("ScheduleOperationId")]
        public virtual ScheduleOperation ScheduleOperation { get; set; }

        /// <summary>
        /// ScheduleSeriesId idegen kulcshoz tartozó virtuális tulajdonság.
        /// </summary>
        [ForeignKey("ScheduleSeriesId")]
        public virtual ScheduleSeriesOne ScheduleSeriesOne { get; set; }

        #endregion Properties

        #region Contructor
        /// <summary>
        /// A Schedule alapértelmezett konstruktora, melyben a State, és 
        /// ScheduleSeriesId mezők inicializálása történik meg.
        /// </summary>
        public Schedule()
        {
            State = ScheduleStates.Active;
            ScheduleSeriesId = null;
        }
        #endregion Contructor
    }
    #endregion Schedule class

    #region ScheduleSeriesOne class
    /// <summary>
    /// Sorozat ütemezéseket tartalmazó táblázat.
    /// </summary>
    /// <remarks>
    /// A név ütközött valami egyéb összetevővel, ezért a típus kapott egy "One" suffix-et.
    /// </remarks>
    [Table("ScheduleSeries", Schema = "iScheduler")]
    public partial class ScheduleSeriesOne
    {
        /// <summary>
        /// Sorozat egyedi belső azonosítója.
        /// </summary>
        [Key]
        public int Id { get; set; }

        /// <summary>
        /// Sorozat típusa.
        /// </summary>
        [Required, MaxLength(20)]
        public string SeriesType { get; set; }

        /// <summary>
        /// Sorozat megnevezése, amelyet meg is mutatunk a manager-ben összefűzve a típussal
        /// TT-nnnnnnnn (id).
        /// </summary>
        [Required, MaxLength(100)]
        public string SeriesName { get; set; }

        /// <summary>
        /// Sorozat színjelölése.
        /// </summary>
        [MaxLength(30)]
        public string SeriesColor { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public virtual ICollection<Schedule> Schedules { get; set; }
    }
    #endregion ScheduleSeriesOne class
}