public static bool AreValueEqual(Hatfield.EnviroData.DataProfile.WQ.Models.LabReportSample model, Hatfield.EnviroData.Core.Action domain)
        {
            var observationResult = domain.FeatureActions.FirstOrDefault()
                                    .Results.FirstOrDefault()
                                    .MeasurementResult;

            var observationResultValue = observationResult.MeasurementResultValues.FirstOrDefault();
            var unitOfDomain = observationResult.Unit;
            var analyteOfDomain = observationResult.Result.Variable;
            var siteOfDomain = observationResult.Result.FeatureAction.SamplingFeature.Site;

            //var personOfDomain = observationResult.Result.;
            //var labOfDomain = domain;
            
            

            return model.Value == observationResultValue.DataValue && //value are equal
                    model.DateTime == observationResultValue.ValueDateTime && //result time are equal
                    AreValueEqual(model.Site, siteOfDomain) && //site are equal
                    AreValueEqual(model.Unit, unitOfDomain) && //unit are equal
                    //AreValueEqual(model.ImportBy, personOfDomain) && //importer person are equal
                    //AreValueEqual(model.Lab, labOfDomain) && //lab are equal
                    AreValueEqual(model.Analyte, analyteOfDomain);//analyte are equal
                    
        }
        public static IEnumerable<ChemistryDataEditViewModel> MapActionToChemistryFileEditViewModel(Hatfield.EnviroData.Core.Action source, IDataVersioningHelper versioningHelper)
        {
            var relatedChemistryAction = source.RelatedActions.Where(x => x.CV_RelationshipType.Name == "Is related to");
            var results = new List<ChemistryDataEditViewModel>();

            if (relatedChemistryAction == null || !relatedChemistryAction.Any())
            {
                return null;
            }

            foreach (var relationAction in relatedChemistryAction)
            {
                var latestRelationAction = versioningHelper.GetLatestVersionActionData(relationAction.Action1);
                var featureActions = latestRelationAction.FeatureActions;

                if (featureActions != null)
                {
                    foreach (var featureAction in featureActions)
                    {
                        var measurementResults = from result in featureAction.Results
                                                 from measurementResultValue in result.MeasurementResult.MeasurementResultValues
                                                 select new ChemistryDataEditViewModel { Id = relationAction.Action1.ActionID, 
                                                                                         ChemistryDataValue = MapChemistryFileData(relationAction.Action1, result, measurementResultValue)
                                                                                       };

                        results.AddRange(measurementResults);
                    }
                }
            }

            return results;
        }
        public static IEnumerable<SampleFileData> MapActionToSampleFileData(Hatfield.EnviroData.Core.Action source)
        {
            var result = new List<SampleFileData> { };

            foreach (var featureAction in source.FeatureActions)
            {
                var samplingActionResults = featureAction.Results;

                if (samplingActionResults != null)
                {
                    foreach (var samplingActionResult in samplingActionResults)
                    {
                        var sampleFileData = MapSampleFileData(featureAction.Action, samplingActionResult);

                        if (sampleFileData != null)
                        {
                            result.Add(sampleFileData);
                        }
                    }

                }

            }
            return result;
        }
        public void GetProcessingLevelTest(Hatfield.EnviroData.DataProfile.WQ.Models.ProcessingLevel levelToTest, string actualLevelCode)
        { 
            var context = MockDbContext();
            var foundProcessingLevel = ProcessingLevelHelper.GetOdm2ProcessingLevel(levelToTest, context);

            Assert.NotNull(foundProcessingLevel);
            Assert.AreEqual(actualLevelCode, foundProcessingLevel.ProcessingLevelCode);
        }
        public static bool AreValueEqual(Hatfield.EnviroData.DataProfile.WQ.Models.Unit model, Hatfield.EnviroData.Core.Unit domain)
        {
            if (model == null || domain == null)
            {
                return false;
            }

            return model.Name == domain.UnitsName;
        }
        public static bool AreValueEqual(Hatfield.EnviroData.DataProfile.WQ.Models.Lab model, Hatfield.EnviroData.Core.Organization domain)
        {
            if (model == null || domain == null)
            {
                return false;
            }

            return string.Equals(model.Name, domain.OrganizationName, StringComparison.InvariantCulture);
        }
        public static bool AreValueEqual(Hatfield.EnviroData.DataProfile.WQ.Models.Analyte model, Hatfield.EnviroData.Core.Variable domain)
        {
            if (model == null || domain == null)
            {
                return false;
            }

            return string.Equals(model.Name, domain.VariableCode, StringComparison.InvariantCulture);
        }
        public static ProcessingLevel GetOdm2ProcessingLevel(Hatfield.EnviroData.DataProfile.WQ.Models.ProcessingLevel level, ODM2Entities dbContext)
        {
            var foundLevel = dbContext.ProcessingLevels.FirstOrDefault(x => x.ProcessingLevelCode == level.ToString());

            if(foundLevel == null)
            {
                throw new KeyNotFoundException(string.Format("System can not find matched processing level for {0}", level));
            }

            return foundLevel;
        }
        public static bool AreValueEqual(Hatfield.EnviroData.DataProfile.WQ.Models.Person model, Hatfield.EnviroData.Core.Person domain)
        {
            if (model == null || domain == null)
            {
                return false;
            }

            return string.Equals(model.FirstName, domain.PersonFirstName, StringComparison.InvariantCulture) &&
                    string.Equals(model.MiddleName, domain.PersonMiddleName, StringComparison.InvariantCulture) &&
                    string.Equals(model.LastName, domain.PersonLastName, StringComparison.InvariantCulture);
        }
        public static bool AreValueEqual(Hatfield.EnviroData.DataProfile.WQ.Models.Site model, Hatfield.EnviroData.Core.Site domain)
        {
            if(model == null || domain == null)
            {
                return false;
            }

            var dataAreTheSame = (domain.Latitude == model.Latitude) &&
                                (domain.Longitude == model.Longitude) &&
                                (domain.SamplingFeature != null) &&
                                (domain.SamplingFeature.SamplingFeatureName == model.Name);

            return dataAreTheSame;
        }
        public int GetSubVersionCountOfAction(Hatfield.EnviroData.Core.Action originVersionActionData)
        {
            var numberOfVersion = 1;

            var childVersion = GetNextVersionActionData(originVersionActionData);

            while (childVersion != null)
            {
                numberOfVersion++;
                childVersion = GetNextVersionActionData(childVersion);
            }

            return numberOfVersion;
            
        }
        private IQualityCheckingResult GenerateCorrectSampleMatrixTypeDataNewVersion(Hatfield.EnviroData.Core.Action sampleActionData,
                                                                                     StringCompareCheckingRule rule)
        {
            var newVersionOfData = CorrectSampleMatrixTypeData(sampleActionData, rule);


            var relationActionOfNewVersion = new RelatedAction();
            relationActionOfNewVersion.Action = sampleActionData;
            relationActionOfNewVersion.Action1 = newVersionOfData;
            relationActionOfNewVersion.RelationshipTypeCV = QualityAssuranceConstants.SubVersionRelationCVType;
            var relationShipCV = _relationShipTypeCVRepository.GetAll()
                                    .Where(x => x.Name == QualityAssuranceConstants.SubVersionRelationCVType)
                                    .FirstOrDefault();
            relationActionOfNewVersion.CV_RelationshipType = relationShipCV;

            sampleActionData.RelatedActions.Add(relationActionOfNewVersion);

            return new QualityCheckingResult("Create new version for correction data.", false, QualityCheckingResultLevel.Info);
        }
        public Hatfield.EnviroData.Core.Action CloneActionData(Hatfield.EnviroData.Core.Action previousVersionAction)
        {
            var clonedAction = new Hatfield.EnviroData.Core.Action();

            //clone value in the root action object
            clonedAction.ActionTypeCV = previousVersionAction.ActionTypeCV;
            clonedAction.CV_ActionType = previousVersionAction.CV_ActionType;
            clonedAction.MethodID = previousVersionAction.MethodID;
            clonedAction.Method = previousVersionAction.Method;
            clonedAction.BeginDateTime = previousVersionAction.BeginDateTime;
            clonedAction.BeginDateTimeUTCOffset = previousVersionAction.BeginDateTimeUTCOffset;
            clonedAction.EndDateTime = previousVersionAction.EndDateTime;
            clonedAction.EndDateTimeUTCOffset = previousVersionAction.EndDateTimeUTCOffset;
            clonedAction.ActionDescription = previousVersionAction.ActionDescription;
            clonedAction.ActionFileLink = previousVersionAction.ActionFileLink;
            clonedAction.ActionBies = CloneActionBies(previousVersionAction, clonedAction);

            clonedAction.FeatureActions = CloneFeatureActions(previousVersionAction, clonedAction);

            return clonedAction;
        }
        public DomainBuildResult Build(Hatfield.EnviroData.DataProfile.WQ.Models.WQProfileEntity entity, Hatfield.EnviroData.Core.ODM2Entities dbContext)
        {
            var data = (Hatfield.EnviroData.DataProfile.WQ.Models.Site)entity;
            Hatfield.EnviroData.Core.Site domain = null;
            System.Data.Entity.EntityState state = EntityState.Unchanged;

            if(data == null)
            {
                throw new NullReferenceException("System fail to build domain on null entity.");
            }

            if (data.Id > 0)
            {
                domain = dbContext.Sites.Where(x => x.SamplingFeatureID == data.Id).FirstOrDefault();
            }

            //data has not change, return the data in the database
            if (!IsDataDirty(data, domain))
            {
                return new DomainBuildResult(true, domain, EntityState.Unchanged);
            }

            //data is dirty
            if (domain == null)
            {
                domain = new Core.Site();
                state = EntityState.Added;
            }
            else
            {
                state = EntityState.Modified;
            }

            domain.Latitude = data.Latitude.HasValue ? data.Latitude.Value : domain.Latitude;
            domain.Longitude = data.Longitude.HasValue ? data.Longitude.Value : domain.Longitude;
            domain.SamplingFeature.SamplingFeatureName = data.Name;
            var result = new DomainBuildResult(true, domain, state);
            return result;
        }
        private static SampleFileData MapSampleFileData(Hatfield.EnviroData.Core.Action actionData, Result sampleResultDomain)
        {
            if (sampleResultDomain != null)
            {

                var sampleFileData = new SampleFileData();
                sampleFileData.SampledDateTime = sampleResultDomain.ResultDateTime;

                try
                {
                    sampleFileData.LabName = actionData.Method.Organization.OrganizationName;
                }
                catch (NullReferenceException)
                {
                    sampleFileData.LabName = null;
                }

                //Map data from extension properties
                sampleFileData = MapFromExtensionProperties(sampleFileData, sampleResultDomain.ResultExtensionPropertyValues);

                return sampleFileData;


            }
            else
            {
                return null;
            }
        }
        private ICollection<FeatureAction> CloneFeatureActions(Hatfield.EnviroData.Core.Action previousVersionAction, 
                                                               Hatfield.EnviroData.Core.Action newVersionAction)
        {
            if (previousVersionAction.FeatureActions == null)
            {
                return null;
            }
            else
            {
                var newVersionFeatureActions = new List<FeatureAction>();

                foreach(var featureAction in previousVersionAction.FeatureActions)
                {
                    var newFeatureAction = new FeatureAction();
                    newFeatureAction.Action = newVersionAction;
                    newFeatureAction.SamplingFeatureID = featureAction.SamplingFeatureID;
                    newFeatureAction.SamplingFeature = featureAction.SamplingFeature;
                    newFeatureAction.Results = CloneResults(featureAction, newFeatureAction);

                    newVersionFeatureActions.Add(newFeatureAction);
                }

                return newVersionFeatureActions;
            }
        }
        private ICollection<ActionBy> CloneActionBies(Hatfield.EnviroData.Core.Action previousVersionAction,
                                                    Hatfield.EnviroData.Core.Action newVersionAction)
        {
            if (previousVersionAction.ActionBies == null)
            {
                return null;
            }
            else
            {
                var clonedNewActionBies = new List<ActionBy>();
                foreach(var actionByInPreviousVersion in previousVersionAction.ActionBies)
                {
                    var newActionBy = new ActionBy();

                    newActionBy.Action = newVersionAction;
                    newActionBy.Affiliation = actionByInPreviousVersion.Affiliation;
                    newActionBy.AffiliationID = actionByInPreviousVersion.AffiliationID;
                    newActionBy.IsActionLead = actionByInPreviousVersion.IsActionLead;
                    newActionBy.RoleDescription = actionByInPreviousVersion.RoleDescription;

                    clonedNewActionBies.Add(newActionBy);
                }

                return clonedNewActionBies;
            }
        }
        private static ChemistryFileData MapChemistryFileData(Hatfield.EnviroData.Core.Action action, Result result, MeasurementResultValue measurementResultValue)
        {
            var chemistryFileData = new ChemistryFileData();

            chemistryFileData.ExtractionDate = action.BeginDateTime;
            chemistryFileData.AnalysedDate = action.EndDateTime.HasValue ? action.EndDateTime.Value : DateTime.MinValue;
            chemistryFileData.Result = measurementResultValue.DataValue;
            chemistryFileData.ResultUnit = result.MeasurementResult.Unit.UnitsName;
            chemistryFileData.OriginalChemName = result.Variable.VariableDefinition;
            chemistryFileData.ChemCode = result.Variable.VariableCode;
            chemistryFileData.MethodName = action.Method.MethodName;
            chemistryFileData.MethodType = action.Method.MethodDescription;

            var propertyValueDictionary = result.ResultExtensionPropertyValues.ToDictionary(x => x.ExtensionProperty.PropertyName, x => x.PropertyValue);

            chemistryFileData.SampleCode = propertyValueDictionary.ContainsKey(ESDATChemistryConstants.ResultExtensionPropertyValueKeySampleCode) ?
                                            propertyValueDictionary[ESDATChemistryConstants.ResultExtensionPropertyValueKeySampleCode] :
                                            string.Empty;

            chemistryFileData.Prefix = propertyValueDictionary.ContainsKey(ESDATChemistryConstants.ResultExtensionPropertyValueKeyPrefix) ?
                                            propertyValueDictionary[ESDATChemistryConstants.ResultExtensionPropertyValueKeyPrefix] :
                                            string.Empty;

            chemistryFileData.TotalOrFiltered = propertyValueDictionary.ContainsKey(ESDATChemistryConstants.ResultExtensionPropertyValueKeyTotalOrFiltered) ?
                                                    propertyValueDictionary[ESDATChemistryConstants.ResultExtensionPropertyValueKeyTotalOrFiltered] :
                                                    string.Empty;

            chemistryFileData.ResultType = propertyValueDictionary.ContainsKey(ESDATChemistryConstants.ResultExtensionPropertyValueKeyResultType) ?
                                                propertyValueDictionary[ESDATChemistryConstants.ResultExtensionPropertyValueKeyResultType] :
                                                string.Empty;

            chemistryFileData.EQL = propertyValueDictionary.ContainsKey(ESDATChemistryConstants.ResultExtensionPropertyValueKeyEQL) ?
                                        MappingHelper.ToNullableDouble(propertyValueDictionary[ESDATChemistryConstants.ResultExtensionPropertyValueKeyEQL]) :
                                        null;

            chemistryFileData.EQLUnits = propertyValueDictionary.ContainsKey(ESDATChemistryConstants.ResultExtensionPropertyValueKeyEQLUnits) ?
                                            propertyValueDictionary[ESDATChemistryConstants.ResultExtensionPropertyValueKeyEQLUnits] :
                                            string.Empty;

            chemistryFileData.Comments = propertyValueDictionary.ContainsKey(ESDATChemistryConstants.ResultExtensionPropertyValueKeyComments) ? propertyValueDictionary[ESDATChemistryConstants.ResultExtensionPropertyValueKeyComments] : string.Empty;
            chemistryFileData.UCL = propertyValueDictionary.ContainsKey(ESDATChemistryConstants.ResultExtensionPropertyValueKeyUCL) ? MappingHelper.ToNullableDouble(propertyValueDictionary[ESDATChemistryConstants.ResultExtensionPropertyValueKeyUCL]) : null;
            chemistryFileData.LCL = propertyValueDictionary.ContainsKey(ESDATChemistryConstants.ResultExtensionPropertyValueKeyLCL) ? MappingHelper.ToNullableDouble(propertyValueDictionary[ESDATChemistryConstants.ResultExtensionPropertyValueKeyLCL]) : null;

            return chemistryFileData;
        }
 public WaterQualityDataProfile(Hatfield.EnviroData.Core.ODM2Entities dbContext)
 {
     _dbContext = dbContext;
 }
        private Hatfield.EnviroData.Core.Action CorrectSampleMatrixTypeData(Hatfield.EnviroData.Core.Action sampleActionData,
                                                                            StringCompareCheckingRule rule)
        {
            var newVersionOfData = _dataVersioningHelper.CloneActionData(sampleActionData);

            foreach (var featureAction in newVersionOfData.FeatureActions)
            {
                foreach(var result in featureAction.Results)
                {
                    foreach(var extension in result.ResultExtensionPropertyValues)
                    {
                        if (extension.ExtensionProperty.PropertyName == ESDATSampleCollectionConstants.ResultExtensionPropertyValueKeyMatrixType)
                        {
                            extension.PropertyValue = rule.CorrectionValue;
                        }
                    }
                }
            }

            return newVersionOfData;
        }
        private IQualityCheckingResult IsSampleMatrixTypeDataMeetQualityCheckingRule(Hatfield.EnviroData.Core.Action sampleActionData, 
                                                                                     StringCompareCheckingRule rule)
        {
            if (sampleActionData == null || sampleActionData.FeatureActions == null || !sampleActionData.FeatureActions.Any())
            {
                return new QualityCheckingResult("No results found for the sample action.", false, QualityCheckingResultLevel.Info);
            }

            var sampleResults = from featureAction in sampleActionData.FeatureActions
                                from result in featureAction.Results
                                where featureAction.SamplingFeature.SamplingFeatureTypeCV == QualityAssuranceConstants.SiteSampleFeatureTypeCV
                                select result;

            if (sampleResults == null || !sampleResults.Any())
            {
                return new QualityCheckingResult("No results found for the sample action.", false, QualityCheckingResultLevel.Info);
            }

            var resultStringBuilder = new StringBuilder();
            var needCorrection = false;

            foreach(var result in sampleResults)
            {
                var sampleMatrixExtension = result.ResultExtensionPropertyValues
                                                    .Where(x => x.ExtensionProperty.PropertyName == 
                                                           ESDATSampleCollectionConstants.ResultExtensionPropertyValueKeyMatrixType)
                                                    .FirstOrDefault();

                if (sampleMatrixExtension == null)
                {
                    resultStringBuilder.AppendLine("Sample Result: " + ResultToString(result) + " does not contain sample matrix data.");
                }
                else
                {
                    var stringCompareOption = rule.IsCaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase;

                    if (string.Equals(sampleMatrixExtension.PropertyValue, rule.ExpectedValue, stringCompareOption))
                    {
                        resultStringBuilder.AppendLine(
                            string.Format(validSampleMatrixResultFormat, ResultToString(result))
                        );
                    }
                    else
                    {
                        resultStringBuilder.AppendLine(
                            string.Format(invalidSampleMatrixResultFormat, 
                                          ResultToString(result), 
                                          sampleMatrixExtension.PropertyValue, 
                                          rule.ExpectedValue)
                        );
                        needCorrection = true;
                    }
                }
            }

            var qcResult = new QualityCheckingResult(resultStringBuilder.ToString(), needCorrection, QualityCheckingResultLevel.Info);
            return qcResult;
        }