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.Drawing;
  using System.IO;
  using System.Linq;
  using System.Reflection;
  using System.Threading;
  using System.Threading.Tasks;
  using System.Windows.Forms;
  using FAnsi.Discovery;
  using MapsDirectlyToDatabaseTable;
  using MapsDirectlyToDatabaseTable.Revertable;
  using MapsDirectlyToDatabaseTable.Versioning;
  using Rdmp.Core;
  using Rdmp.Core.CohortCommitting.Pipeline;
  using Rdmp.Core.CommandExecution;
  using Rdmp.Core.CommandExecution.AtomicCommands;
  using Rdmp.Core.CommandLine.Interactive;
  using Rdmp.Core.CommandLine.Runners;
  using Rdmp.Core.Curation.Data;
  using Rdmp.Core.Curation.Data.Aggregation;
  using Rdmp.Core.Curation.Data.Cohort;
  using Rdmp.Core.Curation.Data.Dashboarding;
  using Rdmp.Core.Curation.Data.DataLoad;
  using Rdmp.Core.Curation.Data.Defaults;
  using Rdmp.Core.Curation.Data.ImportExport;
  using Rdmp.Core.Curation.Data.Pipelines;
  using Rdmp.Core.DataExport.Data;
  using Rdmp.Core.DataViewing;
  using Rdmp.Core.Icons.IconProvision;
  using Rdmp.Core.Logging;
  using Rdmp.Core.Providers;
  using Rdmp.Core.Repositories;
  using Rdmp.UI;
  using Rdmp.UI.AggregationUIs;
  using Rdmp.UI.CatalogueSummary.LoadEvents;
  using Rdmp.UI.CohortUI.ImportCustomData;
  using Rdmp.UI.Collections;
  using Rdmp.UI.Collections.Providers;
  using Rdmp.UI.CommandExecution;
  using Rdmp.UI.CommandExecution.AtomicCommands;
  using Rdmp.UI.Copying;
  using Rdmp.UI.DataViewing;
  using Rdmp.UI.ItemActivation;
  using Rdmp.UI.ItemActivation.Arranging;
  using Rdmp.UI.Logging;
  using Rdmp.UI.PipelineUIs.Pipelines;
  using Rdmp.UI.Refreshing;
  using Rdmp.UI.Rules;
  using Rdmp.UI.SimpleDialogs;
  using Rdmp.UI.SimpleDialogs.ForwardEngineering;
  using Rdmp.UI.SimpleDialogs.NavigateTo;
  using Rdmp.UI.SubComponents;
  using Rdmp.UI.TestsAndSetup.ServicePropogation;
  using Rdmp.UI.Theme;
  using Rdmp.UI.Versioning;
  using Rdmp.UI.Wizard;
  using ResearchDataManagementPlatform.WindowManagement.ContentWindowTracking.Persistence;
  using ResearchDataManagementPlatform.WindowManagement.WindowArranging;
  using ReusableLibraryCode;
  using ReusableLibraryCode.Checks;
  using ReusableLibraryCode.Comments;
  
  
  using WeifenLuo.WinFormsUI.Docking;
  
  namespace ResearchDataManagementPlatform.WindowManagement
  {
      /// <summary>
      /// Central class for RDMP main application, this class provides acceess to all the main systems in RDMP user interface such as Emphasis, the RefreshBus, Child 
      /// provision etc.  See IActivateItems for full details
      /// </summary>
      public class ActivateItems : BasicActivateItems, IActivateItems, IRefreshBusSubscriber
      {
          private readonly DockPanel _mainDockPanel;
          private readonly WindowManager _windowManager;
  
          public WindowFactory WindowFactory { get; private set; }
  
  
          public ITheme Theme { get; private set; }
  
          public RefreshBus RefreshBus { get; private set; }
          
          readonly UIObjectConstructor _constructor = new UIObjectConstructor();
  
          public IArrangeWindows WindowArranger { get; private set; }
          
          public override void Publish(IMapsDirectlyToDatabaseTable databaseEntity)
          {
              if(databaseEntity is DatabaseEntity de)
                  RefreshBus.Publish(this,new RefreshObjectEventArgs(de));
          }
  
          public override void Show(string title, string message)
          {
              WideMessageBox.Show(title,message,Environment.StackTrace,true,null,WideMessageBoxTheme.Help);
          }
  
          public ICombineableFactory CommandFactory { get; private set; }
          public ICommandExecutionFactory CommandExecutionFactory { get; private set; }
          public CommentStore CommentStore { get { return RepositoryLocator.CatalogueRepository.CommentStore; } }
          public HistoryProvider HistoryProvider { get; private set; }
  
          public List<IProblemProvider> ProblemProviders { get; private set; }
  
          public ActivateItems(ITheme theme,RefreshBus refreshBus, DockPanel mainDockPanel, IRDMPPlatformRepositoryServiceLocator repositoryLocator, WindowFactory windowFactory, WindowManager windowManager, ICheckNotifier globalErrorCheckNotifier):base(repositoryLocator,globalErrorCheckNotifier)
          {
              Theme = theme;
              InteractiveDeletes = true;
              WindowFactory = windowFactory;
              _mainDockPanel = mainDockPanel;
              _windowManager = windowManager;
              RefreshBus = refreshBus;
  
              RefreshBus.ChildProvider = CoreChildProvider;
              
              HistoryProvider = new HistoryProvider(repositoryLocator);
              
              WindowArranger = new WindowArranger(this,_windowManager,_mainDockPanel);
              
              CommandFactory = new RDMPCombineableFactory();
              CommandExecutionFactory = new RDMPCommandExecutionFactory(this);
  
              ProblemProviders = new List<IProblemProvider>();
              ProblemProviders.Add(new DataExportProblemProvider());
              ProblemProviders.Add(new CatalogueProblemProvider());
              RefreshProblemProviders();
  
              RefreshBus.Subscribe(this);
          }
  
          protected override ICoreChildProvider GetChildProvider()
          {
              var provider = base.GetChildProvider();
  
              if (RefreshBus != null)
              {
                  RefreshBus.ChildProvider = provider;
              }
  
              return provider;
          }
          
  
          public Form ShowWindow(Control singleControlForm, bool asDocument = false)
          {
              int width = singleControlForm.Size.Width + SystemInformation.BorderSize.Width;
              int height = singleControlForm.Size.Height + SystemInformation.BorderSize.Height;
  
              //use the .Text or fallback on .Name 
              string name = string.IsNullOrWhiteSpace(singleControlForm.Text)
                  ? singleControlForm.Name ?? singleControlForm.GetType().Name//or worst case scenario use the type name!
                  : singleControlForm.Text;
  
              if(singleControlForm is Form && asDocument)
                  throw new Exception("Control '" + singleControlForm + "' is a Form and asDocument was passed as true.  When asDocument is true you must be a Control not a Form e.g. inherit from RDMPUserControl instead of RDMPForm");
  
              var c = singleControlForm as RDMPUserControl;
              
              if(c != null)
                  c.SetItemActivator(this);
  
              var content = WindowFactory.Create(this,singleControlForm,name , null);
              
              if (asDocument)
                  content.Show(_mainDockPanel,DockState.Document);
              else
                  content.Show(_mainDockPanel,new Rectangle(0,0,width,height));
              
              return content;
          }
                  
          public override void RequestItemEmphasis(object sender, EmphasiseRequest request)
          {
              //ensure a relevant Toolbox is available
              var descendancy = CoreChildProvider.GetDescendancyListIfAnyFor(request.ObjectToEmphasise);
              object root = null;
  
              if (descendancy != null)
                  root = descendancy.Parents.FirstOrDefault();
              else
                  root = request.ObjectToEmphasise; //assume maybe o is a root object itself?
  
              if (root is CohortIdentificationConfiguration cic)
                  Activate<CohortIdentificationConfigurationUI, CohortIdentificationConfiguration>(cic);
              else
              if (root != null)
                  _windowManager.ShowCollectionWhichSupportsRootObjectType(root);
  
              //really should be a listener now btw since we just launched the relevant Toolbox if it wasn't there before
              //Look at assignments to Sender, the invocation list can change the Sender!
              var args = new EmphasiseEventArgs(request);
              base.OnEmphasise(this,args);
              
              //might be different than sender that was passed in
              if(args.Sender is DockContent content)
                  content.Activate();
  
              //user is being shown the given object so track it as a recent (e.g. GoTo etc)
              HistoryProvider.Add(args.Request.ObjectToEmphasise);
          }
  
          public override bool SelectEnum(DialogArgs args, Type enumType, out Enum chosen)
          {
              var selector = new SelectDialog<Enum>(args,this,Enum.GetValues(enumType).Cast<Enum>().ToArray(), false,false);
              
              if (selector.ShowDialog() == DialogResult.OK)
              {
                  chosen = selector.Selected;
                  return true;
              }
              
              chosen = default;
              return false;
          }
  
          public override bool SelectType(DialogArgs args, Type[] available,out Type chosen)
          {
              var dlg =  new SelectDialog<Type>(args,this,available, false,false);
  
              if (dlg.ShowDialog() == DialogResult.OK)
              {
                  chosen = dlg.Selected;
                  return true;
              }
  
  
              chosen = null;
              return false;
          }
  
          public override bool CanActivate(object target)
          {
              return CommandExecutionFactory.CanActivate(target);
          }
          protected override void ActivateImpl(object o)
          {
              if(CommandExecutionFactory.CanActivate(o))
                  CommandExecutionFactory.Activate(o);
          }
  
          public bool IsRootObjectOfCollection(RDMPCollection collection, object rootObject)
          {
              //if the collection an arbitrary one then it is definetly not the root collection for anyone
              if (collection == RDMPCollection.None)
                  return false;
  
              return _windowManager.GetCollectionForRootObject(rootObject) == collection;
          }
  
          /// <summary>
          /// Consults all currently configured IProblemProviders and returns true if any report a problem with the object
          /// </summary>
          /// <param name="model"></param>
          /// <returns></returns>
          public bool HasProblem(object model)
          {
              return ProblemProviders.Any(p => p.HasProblem(model));
          }
  
          /// <summary>
          /// Consults all currently configured IProblemProviders and returns the first Problem reported by any about the object or null
          /// if there are no problems reported.
          /// </summary>
          /// <param name="model"></param>
          /// <returns></returns>
          public string DescribeProblemIfAny(object model)
          {
              return ProblemProviders.Select(p => p.DescribeProblem(model)).FirstOrDefault(desc => desc != null);
          }
          
          public string GetDocumentation(Type type)
          {
              return RepositoryLocator.CatalogueRepository.CommentStore.GetTypeDocumentationIfExists(type);
          }
  
          public string CurrentDirectory { get { return Environment.CurrentDirectory; }}
          public DialogResult ShowDialog(Form form)
          {
              return form.ShowDialog();
          }
  
          public void KillForm(Form f, Exception reason)
          {
              f.Close();
              ExceptionViewer.Show("Window Closed",reason);
          }
          public void KillForm(Form f, string reason)
          {
              f.Close();
              ExceptionViewer.Show("Window Closed",reason);
          }
          public void OnRuleRegistered(IBinderRule rule)
          {
              //no special action required
          }
  
          /// <summary>
          /// Asks the user if they want to reload a fresh copy with a Yes/No message box.
          /// </summary>
          /// <param name="databaseEntity"></param>
          /// <returns></returns>
          public bool ShouldReloadFreshCopy(DatabaseEntity databaseEntity)
          {
              return YesNo(databaseEntity + " is out of date with database, would you like to reload a fresh copy?",
                             "Object Changed");
          }
  
          public T Activate<T, T2>(T2 databaseObject)
              where T : RDMPSingleDatabaseObjectControl<T2>, new()
              where T2 : DatabaseEntity
          {
              return Activate<T, T2>(databaseObject, (Bitmap)CoreIconProvider.GetImage(databaseObject));
          }
          
          public T Activate<T>(IPersistableObjectCollection collection)
  
gt:             where T: Control,IObjectCollectionControl,new()