/// <summary>
        /// The data set is initiated or redefined by
        /// using this method.
        /// Scope of the data set is defined by this
        /// species fact data set selection.
        /// At least one factor and one taxon must be specified
        /// in the species fact data set selection.
        /// </summary>
        /// <param name="userContext">
        /// Information about the user that makes this method call.
        /// </param>
        /// <param name="selection">
        /// Scope of the data set is defined by this
        /// species fact data set selection.
        /// </param>
        public virtual void UpdateSelection(IUserContext userContext,
                                            ISpeciesFactDataSetSelection selection)
        {
            IFactor factor;
            Int32   factorIndex;
            ISpeciesFactDataSetSelection workingSelection;
            ISpeciesFactSearchCriteria   searchCriteria;
            SpeciesFactList speciesFacts;

            // Check arguments.
            selection.CheckNotNull("selection");
            if (selection.Factors.IsEmpty() || selection.Taxa.IsEmpty())
            {
                // Reset species fact data set and end method.
                // Conditions to retrieve species facts are not fulfilled.
                Reset(selection);
                return;
            }

            // Add dependent factors to selection if necessary.
            workingSelection = (ISpeciesFactDataSetSelection)(selection.Clone());
            for (factorIndex = 0; factorIndex < workingSelection.Factors.Count; factorIndex++)
            {
                factor = workingSelection.Factors[factorIndex];
                workingSelection.Factors.Merge(factor.GetDependentFactors(userContext));
            }

            // Get species facts.
            searchCriteria         = new SpeciesFactSearchCriteria();
            searchCriteria.Factors = workingSelection.Factors;
            searchCriteria.Hosts   = workingSelection.Hosts;
            searchCriteria.IncludeNotValidHosts = true;
            searchCriteria.IncludeNotValidTaxa  = true;
            searchCriteria.IndividualCategories = workingSelection.IndividualCategories;
            searchCriteria.Periods    = workingSelection.Periods;
            searchCriteria.References = workingSelection.References;
            searchCriteria.Taxa       = workingSelection.Taxa;
            speciesFacts = CoreData.SpeciesFactManager.GetSpeciesFacts(userContext, searchCriteria);

            // Update species fact scope with new information.
            UpdateScope(userContext, workingSelection, speciesFacts);

            // Remove old species facts that are no longer
            // included in the species fact scope.
            RemoveSpeciesFactsNotInScope();

            // Merge old and new species facts to same list.
            MergeSpeciesFacts(speciesFacts);

            // Get missing species facts according to expanded
            // combinations of species fact data set selection.
            UpdateWithEmptySpeciesFacts(userContext);

            // Init automated calculation.
            InitAutomatedCalculations(userContext);

            // Save selection information.
            _selection     = (ISpeciesFactDataSetSelection)(selection.Clone());
            _selectionCopy = (ISpeciesFactDataSetSelection)(selection.Clone());
        }
 /// <summary>
 /// Create a species fact data set instance.
 /// </summary>
 public SpeciesFactDataSet()
 {
     Factors = new FactorList(true);
     Hosts   = new TaxonList(true);
     IndividualCategories = new IndividualCategoryList(true);
     Periods        = new PeriodList(true);
     References     = new ReferenceList(true);
     _selection     = new SpeciesFactDataSetSelection();
     _selectionCopy = new SpeciesFactDataSetSelection();
     SpeciesFacts   = new SpeciesFactList();
     Taxa           = new TaxonList(true);
 }
        /// <summary>
        /// Remove factors, hosts, individual categories, periods or
        /// taxa from current species fact data set scope.
        /// The species facts in the data set are updated
        /// to the new species fact data set scope.
        /// </summary>
        /// <param name="userContext">
        /// Information about the user that makes this method call.
        /// </param>
        /// <param name="selection">Changed scope of the data set.</param>
        public virtual void RemoveSelection(IUserContext userContext,
                                            ISpeciesFactDataSetSelection selection)
        {
            FactorList             factors;
            IndividualCategoryList individualCategories;
            PeriodList             periods;
            ReferenceList          references;
            TaxonList hosts, taxa;

            // Check arguments.
            selection.CheckNotNull("selection");

            // Update selection with existing scope.
            factors = new FactorList();
            factors.Merge(_selection.Factors);
            factors.Remove(selection.Factors);
            selection.Factors = factors;

            hosts = new TaxonList();
            hosts.Merge(_selection.Hosts);
            hosts.Remove(selection.Hosts);
            selection.Hosts = hosts;

            individualCategories = new IndividualCategoryList();
            individualCategories.Merge(_selection.IndividualCategories);
            individualCategories.Remove(selection.IndividualCategories);
            selection.IndividualCategories = individualCategories;

            periods = new PeriodList();
            periods.Merge(_selection.Periods);
            periods.Remove(selection.Periods);
            selection.Periods = periods;

            references = new ReferenceList();
            references.Merge(_selection.References);
            references.Remove(selection.References);
            selection.References = references;

            taxa = new TaxonList();
            taxa.Merge(_selection.Taxa);
            taxa.Remove(selection.Taxa);
            selection.Taxa = taxa;

            // Update species fact data set.
            UpdateSelection(userContext, selection);
        }
        /// <summary>
        /// Add factors, hosts, individual categories, periods or
        /// taxa to current species fact data set scope.
        /// The species facts in the data set are updated
        /// to the new species fact data set scope.
        /// </summary>
        /// <param name="userContext">
        /// Information about the user that makes this method call.
        /// </param>
        /// <param name="selection">Changed scope of the data set.</param>
        public virtual void AddSelection(IUserContext userContext,
                                         ISpeciesFactDataSetSelection selection)
        {
            // Check arguments.
            selection.CheckNotNull("selection");

            // Update selection with existing scope.
            selection.Factors.Merge(_selection.Factors);
            selection.Hosts.Merge(_selection.Hosts);
            selection.IndividualCategories.Merge(_selection.IndividualCategories);
            selection.Periods.Merge(_selection.Periods);
            selection.References.Merge(_selection.References);
            selection.Taxa.Merge(_selection.Taxa);

            // Update species fact data set.
            UpdateSelection(userContext, selection);
        }
        /// <summary>
        /// Reset species fact data set to no species facts.
        /// This method is used when species fact data set selection
        /// does not contain both factors and taxa.
        /// </summary>
        /// <param name="selection">
        /// Scope of the data set is defined by this
        /// species fact data set selection.
        /// </param>
        private void Reset(ISpeciesFactDataSetSelection selection)
        {
            Factors = new FactorList(true);
            Factors.Merge(selection.Factors);
            Hosts = new TaxonList(true);
            Hosts.Merge(selection.Hosts);
            IndividualCategories = new IndividualCategoryList(true);
            IndividualCategories.Merge(selection.IndividualCategories);
            Periods = new PeriodList(true);
            Periods.Merge(selection.Periods);
            References = new ReferenceList(true);
            References.Merge(selection.References);
            SpeciesFacts = new SpeciesFactList(true);
            Taxa         = new TaxonList();
            Taxa.Merge(selection.Taxa);

            // Save selection information.
            _selection     = (ISpeciesFactDataSetSelection)(selection.Clone());
            _selectionCopy = (ISpeciesFactDataSetSelection)(selection.Clone());
        }
        /// <summary>
        /// Update information about which factors, hosts,
        /// individual categories, periods, references and taxa
        /// that are used in the species facts.
        /// </summary>
        /// <param name="userContext">
        /// Information about the user that makes this method call.
        /// </param>
        /// <param name="selection">
        /// Scope of the data set is defined by this
        /// species fact data set selection.
        /// </param>
        /// <param name="speciesFacts">Species facts.</param>
        private void UpdateScope(IUserContext userContext,
                                 ISpeciesFactDataSetSelection selection,
                                 SpeciesFactList speciesFacts)
        {
            Factors = new FactorList(true);
            Factors.AddRange(selection.Factors);
            Hosts = new TaxonList(true);
            Hosts.AddRange(selection.Hosts);
            IndividualCategories = new IndividualCategoryList(true);
            IndividualCategories.AddRange(selection.IndividualCategories);
            Periods = new PeriodList(true);
            Periods.AddRange(selection.Periods);
            References = new ReferenceList(true);
            Taxa       = new TaxonList(true);
            Taxa.AddRange(selection.Taxa);

            if (speciesFacts.IsNotEmpty())
            {
                foreach (ISpeciesFact speciesFact in speciesFacts)
                {
                    Factors.Merge(speciesFact.Factor);
                    if (speciesFact.HasHost)
                    {
                        Hosts.Merge(speciesFact.Host);
                    }

                    IndividualCategories.Merge(speciesFact.IndividualCategory);
                    if (speciesFact.HasPeriod)
                    {
                        Periods.Merge(speciesFact.Period);
                    }

                    if (speciesFact.HasReference)
                    {
                        References.Merge(speciesFact.Reference);
                    }

                    Taxa.Merge(speciesFact.Taxon);
                }
            }

            // Set default values if no values are entered.
            if (Hosts.IsEmpty())
            {
                Hosts.Add(CoreData.TaxonManager.GetTaxon(userContext, TaxonId.Life));
            }

            if (IndividualCategories.IsEmpty())
            {
                IndividualCategories.Add(CoreData.FactorManager.GetDefaultIndividualCategory(userContext));
            }

            if (Periods.IsEmpty())
            {
                Periods.AddRange(CoreData.FactorManager.GetPeriods(userContext));
            }

            // Sort all lists.
            Factors.Sort();
            Hosts.Sort();
            IndividualCategories.Sort();
            Periods.Sort();
            References.Sort();
            Taxa.Sort();
        }