context: // Copyright (c) The University of Dundee 2018-2019
  // This file is part of the Research Data Management Platform (RDMP).
  // RDMP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
  // RDMP is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  // You should have received a copy of the GNU General Public License along with RDMP. If not, see <https://www.gnu.org/licenses/>.
  
  using System;
  using System.Collections.Generic;
  using System.Data.Common;
  using System.Linq;
  using FAnsi.Discovery;
  using MapsDirectlyToDatabaseTable;
  using MapsDirectlyToDatabaseTable.Attributes;
  using Rdmp.Core.Curation.Data;
  using Rdmp.Core.Curation.Data.Cohort;
  using Rdmp.Core.Curation.Data.Defaults;
  using Rdmp.Core.Curation.Data.Pipelines;
  using Rdmp.Core.Curation.FilterImporting;
  using Rdmp.Core.DataExport.DataExtraction.Pipeline.Sources;
  using Rdmp.Core.DataExport.DataRelease.Audit;
  using Rdmp.Core.Logging;
  using Rdmp.Core.Logging.PastEvents;
  using Rdmp.Core.QueryBuilding;
  using Rdmp.Core.Repositories;
  using ReusableLibraryCode;
  using ReusableLibraryCode.Annotations;
  using ReusableLibraryCode.DataAccess;
  
  namespace Rdmp.Core.DataExport.Data
  {
      /// <inheritdoc cref="IExtractionConfiguration"/>
      public class ExtractionConfiguration : DatabaseEntity, IExtractionConfiguration, ICollectSqlParameters,INamed,ICustomSearchString
      {
          #region Database Properties
          private DateTime? _dtCreated;
          private int? _cohort_ID;
          private string _requestTicket;
          private string _releaseTicket;
          private int _project_ID;
          private string _username;
          private string _separator;
          private string _description;
          private bool _isReleased;
          private string _name;
          private int? _clonedFrom_ID;
  
          private int? _defaultPipeline_ID;
          private int? _cohortIdentificationConfigurationID;
          private int? _cohortRefreshPipelineID;
  
          /// <inheritdoc/>
          public int? CohortRefreshPipeline_ID
          {
              get { return _cohortRefreshPipelineID; }
              set {  SetField(ref _cohortRefreshPipelineID , value); }
          }
  
          /// <inheritdoc/>
          public int? CohortIdentificationConfiguration_ID
          {
              get { return _cohortIdentificationConfigurationID; }
              set { SetField(ref _cohortIdentificationConfigurationID, value); }
          }
  
          /// <inheritdoc/>
          public int? DefaultPipeline_ID
          {
              get { return _defaultPipeline_ID; }
              set { SetField(ref _defaultPipeline_ID, value); }
          }
  
          /// <inheritdoc/>
          public DateTime? dtCreated
          {
              get { return _dtCreated; }
              set { SetField(ref _dtCreated, value); }
          }
  
          /// <inheritdoc/>
          public int? Cohort_ID
          {
              get { return _cohort_ID; }
              set { SetField(ref _cohort_ID, value); }
          }
  
          /// <inheritdoc/>
          public bool IsExtractable(out string reason)
          {
              if(IsReleased)
              {
                  reason = "ExtractionConfiguration is released so cannot be executed";
                  return false;
              }
  
              if(Cohort_ID == null)
              {
                  reason = "No cohort has been configured for ExtractionConfiguration";
                  return false;
              }
  
              if (!GetAllExtractableDataSets().Any())
              {
                  reason = "ExtractionConfiguration does not have an selected datasets";
                  return false;
              }
                  
              reason = null;
              return true;
          }
  
          /// <inheritdoc/>
          public string RequestTicket
          {
              get { return _requestTicket; }
              set { SetField(ref _requestTicket, value); }
          }
          /// <inheritdoc/>
          public string ReleaseTicket
          {
              get { return _releaseTicket; }
              set { SetField(ref _releaseTicket, value); }
          }
          /// <inheritdoc/>
          public int Project_ID
          {
              get { return _project_ID; }
              set { SetField(ref _project_ID, value); }
          }
          /// <inheritdoc/>
          public string Username
          {
              get { return _username; }
              set { SetField(ref _username, value); }
          }
          /// <inheritdoc/>
          public string Separator
          {
              get { return _separator; }
              set { SetField(ref _separator, value); }
          }
          /// <inheritdoc/>
          public string Description
          {
              get { return _description; }
              set { SetField(ref _description, value); }
          }
          /// <inheritdoc/>
          public bool IsReleased
          {
              get { return _isReleased; }
              set { SetField(ref _isReleased, value); }
          }
  
          /// <inheritdoc/>
          [NotNull]
          public string Name
          {
              get { return _name; }
              set { SetField(ref _name, value); }
          }
  
          /// <inheritdoc/>
          public int? ClonedFrom_ID
          {
              get { return _clonedFrom_ID; }
              set { SetField(ref _clonedFrom_ID, value); }
          }
  
          #endregion
          
          #region Relationships
          
          /// <inheritdoc/>
          [NoMappingToDatabase]
          public IProject Project
          {
              get { return Repository.GetObjectByID<Project>(Project_ID); }
          }
  
          /// <inheritdoc/>
          [NoMappingToDatabase]
          public ISqlParameter[] GlobalExtractionFilterParameters
          {
              get
              {
                  return
                      Repository.GetAllObjectsWithParent<GlobalExtractionFilterParameter>(this)
                          .Cast<ISqlParameter>().ToArray();
              }
          }
  
          /// <inheritdoc/>
          [NoMappingToDatabase]
          public IEnumerable<ICumulativeExtractionResults> CumulativeExtractionResults
          {
              get
              {
                  return Repository.GetAllObjectsWithParent<CumulativeExtractionResults>(this);
              }
          }
  
          /// <inheritdoc/>
          [NoMappingToDatabase]
          public IEnumerable<ISupplementalExtractionResults> SupplementalExtractionResults
          {
              get
              {
                  return Repository.GetAllObjectsWithParent<SupplementalExtractionResults>(this);
              }
          }
  
          /// <inheritdoc/>
          [NoMappingToDatabase]
          public IExtractableCohort Cohort
          {
              get
              {
                  return Cohort_ID == null ? null : Repository.GetObjectByID<ExtractableCohort>(Cohort_ID.Value);
              }
          }
  
          /// <inheritdoc/>
          [NoMappingToDatabase]
          public ISelectedDataSets[] SelectedDataSets
          {
              get
              {
                  return Repository.GetAllObjectsWithParent<SelectedDataSets>(this).Cast<ISelectedDataSets>().ToArray();
              }
          }
  
          /// <inheritdoc/>
          [NoMappingToDatabase]
          public IReleaseLog[] ReleaseLog
          {
              get { return CumulativeExtractionResults.Select(c => c.GetReleaseLogEntryIfAny()).Where(l => l != null).ToArray(); }
          }
  
          /// <inheritdoc cref="DefaultPipeline_ID"/>
          [NoMappingToDatabase]
          public IPipeline DefaultPipeline {
              get
              {
                  if (DefaultPipeline_ID == null)
                      return null;
  
                  return
                      ((DataExportRepository) Repository).CatalogueRepository.GetObjectByID<Pipeline>(DefaultPipeline_ID.Value);
              }}
  
  
          /// <inheritdoc cref="CohortIdentificationConfiguration_ID"/>
          [NoMappingToDatabase]
          public CohortIdentificationConfiguration CohortIdentificationConfiguration
          {
              get
              {
                  if (CohortIdentificationConfiguration_ID == null)
                      return null;
  
                  return
                      ((DataExportRepository)Repository).CatalogueRepository.GetObjectByID<CohortIdentificationConfiguration>(CohortIdentificationConfiguration_ID.Value);
              }
          }
  
          /// <inheritdoc cref="CohortRefreshPipeline_ID"/>
          [NoMappingToDatabase]
          public IPipeline CohortRefreshPipeline
          {
              get
              {
                  if (CohortRefreshPipeline_ID == null)
                      return null;
  
                  return
                      ((DataExportRepository)Repository).CatalogueRepository.GetObjectByID<Pipeline>(CohortRefreshPipeline_ID.Value);
              }
          }
  
          /// <summary>
          /// Returns a name suitable for describing the extraction of a dataset(s) from this configuration (in a <see cref="DataLoadInfo"/>)
          /// </summary>
          /// <returns></returns>
          public string GetLoggingRunName()
          {
              return Project.Name + " " + GetExtractionLoggingName();
          }
  
          private string GetExtractionLoggingName()
          {
              return "(ExtractionConfiguration ID=" + ID + ")";
          }
  
  
          #endregion
  
          /// <summary>
          /// Returns <see cref="Project.Name"/>
          /// </summary>
          [NoMappingToDatabase]
          [UsefulProperty]
          public string ProjectName{ get=>Project.Name;}
  
          /// <summary>
          /// Creates a new extraction configuration in the <paramref name="repository"/> database for the provided <paramref name="project"/>.
          /// </summary>
          /// <param name="repository"></param>
          /// <param name="project"></param>
          public ExtractionConfiguration(IDataExportRepository repository, IProject project)
          {
              Repository = repository;
  
              Repository.InsertAndHydrate(this, new Dictionary<string, object>
              {
                  {"dtCreated", DateTime.Now},
                  {"Project_ID", project.ID},
                  {"Username", Environment.UserName},
                  {"Description", "Initial Configuration"},
                  {"Name","New ExtractionConfiguration" + Guid.NewGuid() }
              });
          }
          /// <summary>
          /// Provides a short human readable representation of the <see cref="Project"/> to which this 
          /// <see cref="ExtractionConfiguration"/> is associated with
          /// </summary>
          /// <param name="shortString">True for a short representation.  False for a longer representation.</param>
          /// <returns></returns>
          public string GetProjectHint(bool shortString)
          {
              return 
                  shortString ? $"({ Project.ProjectNumber})" :
                  $"'{Project.Name}' (PNo. { Project.ProjectNumber})";
          }
  
          /// <summary>
          /// Reads an existing <see cref="IExtractionConfiguration"/> out of the  <paramref name="repository"/> database.
          /// </summary>
          /// <param name="repository"></param>
          /// <param name="r"></param>
          internal ExtractionConfiguration(IDataExportRepository repository, DbDataReader r)
              : base(repository, r)
          {
              Project_ID = int.Parse(r["Project_ID"].ToString());
  
              if (!string.IsNullOrWhiteSpace(r["Cohort_ID"].ToString()))
                  Cohort_ID = int.Parse(r["Cohort_ID"].ToString());
  
              RequestTicket = r["RequestTicket"].ToString();
              ReleaseTicket = r["ReleaseTicket"].ToString();
  
              object dt = r["dtCreated"];
  
  
gt:             if (dt == null || dt == DBNull.Value)