Option Strict Off

Imports EarthSoft.Common
Imports EarthSoft.EDP
Imports System
Imports System.Collections
Imports System.Linq
Imports Microsoft.VisualBasic
Imports System.Runtime.InteropServices
Imports System.Reflection
Imports ICSharpCode.SharpZipLib

<Assembly: AssemblyCompany("EarthSoft, Inc.")>
<Assembly: AssemblyProduct("EQuIS")>
<Assembly: AssemblyCopyright("Copyright © EarthSoft, Inc.")>
<Assembly: AssemblyTrademark("")>
<Assembly: AssemblyVersion("1.00.4")>

Public Class NPS_WQXHandler
  Inherits EarthSoft.EDP.EddCustomHandler

  Private Efd As EarthSoft.EDP.EddFormatDefinition
  Private _Log As log4net.ILog = EarthSoft.Common.log4net.GetLogger(GetType(NPS_WQXHandler))

  Private Organization As System.Data.DataTable
  Private Projects As System.Data.DataTable
  Private Locations As System.Data.DataTable
  Private Indices As System.Data.DataTable
  Private Activities As System.Data.DataTable
  Private Result As EddTable
  Private Metrics As EddTable
  Private Files As EddTable
  Private rt_analyte_detail As System.Data.DataTable = Nothing
  '9/28/2015 
  Private dtFacilities As System.Data.DataTable

  ''' <summary>These are used for checking for child rows</summary>
  Private Smp_Trs As EarthSoft.EDP.EddRelation
  Private Smp_Met As EarthSoft.EDP.EddRelation

  ''' <summary>Several checks lookup the sample/activity for a given test.  
  ''' Instead of looking it up over, and over,
  ''' we will cache each lookup in this variable so we don't have to look it up again.</summary>
  Private SampleActivityRow As System.Data.DataRow
#Disable Warning IDE0044 ' Add readonly modifier
    Private IsLoading As Boolean = False
#Enable Warning IDE0044 ' Add readonly modifier

  Private resultChecker As EarthSoft.EDP.Checks.Result
  Dim dsHelper As New EarthSoft.Common.Data.DataSetHelper
  Private dtCounty_State As New System.Data.DataTable("County")
  Private dtResultValue As New System.Data.DataTable("ResultValue")
  Private dtActivityType As New System.Data.DataTable("ActivityType")
  Private limitTypes As New System.Collections.Generic.List(Of String)
  Private dbCachedData As New System.Data.DataSet

  Private detectFlags As New Hashtable

  ' MS.199172: These objects improve performance (by not creating new DataViews within individual methods).
  '   We may get similar performance benefit from using the .DefaultView for each table, but the user may sort data in grids 
  '   and we do not want to rely on the DefaultView not being changed.
  Private rt_timezone As DataTable = Nothing
  Private vw_timezone As DataView = Nothing
  Private rt_county As DataTable = Nothing
  Private vw_county As DataView = Nothing
  Private rt_analyte As DataTable = Nothing
  Private vw_analyte As DataView = Nothing
  Private dt_sample As DataTable = Nothing
  Private vw_sample As DataView = Nothing
  Private dt_test As DataTable = Nothing
  Private vw_test As DataView = Nothing
  Private dv_Activities As DataView = Nothing
  Private rt_remap_detail As DataTable = Nothing
  Private vw_remap_detail As DataView = Nothing

  Public Sub New()
    ' call the base class constructor
    MyBase.New()
    limitTypes.Add("lower quantification limit")
    limitTypes.Add("upper quantification limit")
    limitTypes.Add("method detection level (mdl)")
    limitTypes.Add("lower reporting limit")
    limitTypes.Add("upper reporting limit")
    limitTypes.Add("lrl")
    limitTypes.Add("mdl")
    limitTypes.Add("lql")

    Me.resultChecker = New EarthSoft.EDP.Checks.Result(Me)

    'setup tables for ERR63
    Dim dt As New System.Data.DataTable("dt_task")
    Dim key1 As System.Data.DataColumn = dt.Columns.Add("facility_id", 1.GetType)
    Dim key2 As System.Data.DataColumn = dt.Columns.Add("task_code", "string".GetType)
    dt.Columns.Add("found", False.GetType)
    dt.PrimaryKey = New System.Data.DataColumn() {key1, key2}
    dbCachedData.Tables.Add(dt)

    dt = New System.Data.DataTable("dt_location")
    key1 = dt.Columns.Add("facility_id", 1.GetType)
    key2 = dt.Columns.Add("sys_loc_code", "string".GetType)
    dt.Columns.Add("found", False.GetType)
    dt.PrimaryKey = New System.Data.DataColumn() {key1, key2}
    dbCachedData.Tables.Add(dt)

    dt = New System.Data.DataTable("dt_sample")
    key1 = dt.Columns.Add("facility_id", 1.GetType)
    key2 = dt.Columns.Add("sys_sample_code", "string".GetType)
    dt.Columns.Add("found", False.GetType)
    dt.PrimaryKey = New System.Data.DataColumn() {key1, key2}
    dbCachedData.Tables.Add(dt)

    dt = New System.Data.DataTable("dt_facility")
    key1 = dt.Columns.Add("facility_id", 1.GetType)
    key2 = dt.Columns.Add("facility_code", "string".GetType)
    dt.Columns.Add("found", False.GetType)
    dt.PrimaryKey = New System.Data.DataColumn() {key1, key2}
    dbCachedData.Tables.Add(dt)
  End Sub

  Public Overrides Sub AddDataHandlers(ByRef efd As EarthSoft.EDP.EddFormatDefinition)
    Me.Efd = efd

    Me.Organization = efd.Tables.Item("Organization")
    Me.Locations = efd.Tables.Item("Locations")
    Me.Projects = efd.Tables.Item("Projects")
    Me.Indices = efd.Tables.Item("Indices")
    Me.Activities = efd.Tables.Item("Activities")
    Me.Result = CType(efd.Tables.Item("Results"), EddTable)
    Me.Metrics = CType(efd.Tables.Item("Metrics"), EddTable)
    Me.Files = CType(efd.Tables.Item("Files"), EddTable)

    ' MS.199172: set the sort order on the DefaultView so that the .Select method is faster (see ERR65, ERR92)
    Me.dv_Activities = New DataView(Me.Activities, String.Empty, "Activity_ID, Activity_Type", DataViewRowState.None)

    '9/28/2015 Get all of dt_facility so GetFacilityId method is faster.
    Dim ds As New System.Data.DataSet
    Dim qdft As String = String.Format("select facility_id, facility_code from dt_facility")
    If efd.package.Connection IsNot Nothing Then
      efd.package.Connection.Fill(ds, "dt_facility", New EarthSoft.Common.Data.SafeSqlString(qdft))
      Me.dtFacilities = ds.Tables("dt_facility")
      Me.dtFacilities.DefaultView.Sort = "facility_code"
    End If

    'AddHandler Organization.ColumnChanged, AddressOf Me.CheckOrganization
    'AddHandler Organization.RowChanged, AddressOf Me.Organization_RowChanged
    'AddHandler efd.Tables.Item("PrjMonitorLocationWeight").ColumnChanged, AddressOf Me.CheckPrjMonitorLocationWeight
    AddHandler Locations.ColumnChanged, AddressOf Me.CheckMonitoringLocation
    AddHandler Indices.ColumnChanged, AddressOf Me.CheckBiologicalHabitatIndex
    AddHandler Activities.ColumnChanged, AddressOf Me.CheckActivity
    AddHandler efd.Tables.Item("ActivitySites").ColumnChanged, AddressOf Me.CheckActivitySites
    AddHandler efd.Tables.Item("Metrics").ColumnChanged, AddressOf Me.CheckActMetric
    AddHandler Result.ColumnChanged, AddressOf Me.CheckResult
    'AddHandler efd.Tables.Item("ResDetectionQuantLimit").ColumnChanged, AddressOf Me.CheckResDetectionQuantLimit
    AddHandler Files.ColumnChanged, AddressOf CheckFiles

    AddHandler Result.AfterDataLoad, AddressOf AfterDataLoad

    If Me.Efd.package.Tables.Contains("rt_analyte_detail") Then
      Me.rt_analyte_detail = efd.package.Tables.Item("rt_analyte_detail")
    End If

    ' MS.199172: set the .DefaultView sort order to improve performance of the Remap method
    If Me.Efd.package.Tables.Contains("rt_remap_detail") Then
      Me.rt_remap_detail = efd.package.Tables("rt_remap_detail")
      Me.vw_remap_detail = New DataView(Me.rt_remap_detail, "REMAP_CODE = 'WQX'", "EXTERNAL_FIELD, EXTERNAL_VALUE", DataViewRowState.None)
    End If
    If Me.Efd.package.Tables.Contains("rt_timezone") Then
      Me.rt_timezone = efd.package.Tables("rt_timezone")
      Me.vw_timezone = New DataView(Me.rt_timezone, String.Empty, "timezone_code", DataViewRowState.None)
    End If
    If Me.Efd.package.Tables.Contains("rt_county") Then
      Me.rt_county = efd.package.Tables("rt_county")
      Me.vw_county = New DataView(Me.rt_county, String.Empty, "county_name, state_code", DataViewRowState.None)
    End If
    If Me.Efd.package.Tables.Contains("rt_analyte") Then
      Me.rt_analyte = efd.package.Tables("rt_analyte")
      Me.vw_analyte = New DataView(Me.rt_analyte, String.Empty, "chemical_name", DataViewRowState.None)
    End If
    If Me.Efd.package.Tables.Contains("dt_sample") Then
      Me.dt_sample = efd.package.Tables("dt_sample")
      Me.vw_sample = New DataView(Me.dt_sample, String.Empty, "sys_sample_code", DataViewRowState.None)
    End If
    If Me.Efd.package.Tables.Contains("dt_test") Then
      Me.dt_test = efd.package.Tables("dt_test")
      ' these columns need to exactly match (including order) the columns used in GetTestID and GetColumnNumber
      Me.vw_test = New DataView(Me.dt_test, String.Empty, "sample_id, analytic_method, analysis_date, fraction, column_number, test_type, biological_intent, taxon, unknown_species_identifier, basis, temp_basis, duration_basis, dilution_factor, custom_field_1", DataViewRowState.None)
    End If

    'ERR80 will listen to RowChanged of Activities so it can check for child rows
    AddHandler Activities.RowChanged, AddressOf Me.Activities_RowChanged
    'get the relation to find child rows
    Me.Smp_Trs = CType(Result, EddTable).ParentRelations.Item("FK_Result_Activity")
    Me.Smp_Met = CType(Metrics, EddTable).ParentRelations.Item("FK_Metrics_Activity")

    'Create state and county lookups from the county_code enumeration.
    dtCounty_State.Columns.Add("county_code")
    dtCounty_State.Columns.Add("state_code")
    'Create result value cross-check table from the result_value_code enumeration.
    dtResultValue.Columns.Add("result_code")
    dtResultValue.Columns.Add("characteristic_name")
    dtResultValue.DefaultView.Sort = "characteristic_name, result_code"
    'Create activities type cross-check table from the activity_type_code enumeration.
    dtActivityType.Columns.Add("activity_code")
    dtActivityType.Columns.Add("location_required")
    dtActivityType.Columns.Add("analytical_method_required")

    'Access enumerations in the WQX-enum.xml file
    For Each include As System.Xml.Schema.XmlSchemaObject In efd.Schema.Includes
      Dim enumSchema As System.Xml.Schema.XmlSchemaInclude = include
      If enumSchema.SchemaLocation.ToLower.Contains("-enum") Then
        For Each enumeration As System.Xml.Schema.XmlSchemaObject In enumSchema.Schema.Items
          Dim name As String = CType(enumeration, System.Xml.Schema.XmlSchemaSimpleType).Name
          If name = "county_code" Then
            'For Each value As System.Xml.Schema.XmlSchemaObject In CType(CType(enumeration, System.Xml.Schema.XmlSchemaSimpleType).Content, System.Xml.Schema.XmlSchemaSimpleTypeRestriction).Facets
            '  If value.GetType.Name = "XmlSchemaEnumerationFacet" Then
            '    Dim newRow As System.Data.DataRow = dtCounty_State.NewRow()

            '    newRow.Item("county_code") = CType(value, System.Xml.Schema.XmlSchemaEnumerationFacet).Value.Trim.Trim
            '    If CType(value, System.Xml.Schema.XmlSchemaEnumerationFacet).UnhandledAttributes.Length > 0 Then
            '      newRow.Item("state_code") = CType(value, System.Xml.Schema.XmlSchemaEnumerationFacet).UnhandledAttributes(0).Value.Trim
            '    End If

            '    dtCounty_State.Rows.Add(newRow)
            '  End If
            'Next
          ElseIf name = "result_value_code" Then
            For Each value As System.Xml.Schema.XmlSchemaObject In CType(CType(enumeration, System.Xml.Schema.XmlSchemaSimpleType).Content, System.Xml.Schema.XmlSchemaSimpleTypeRestriction).Facets
              If value.GetType.Name = "XmlSchemaEnumerationFacet" Then
                Dim newRow As System.Data.DataRow = dtResultValue.NewRow()

                newRow.Item("result_code") = CType(value, System.Xml.Schema.XmlSchemaEnumerationFacet).Value.Trim
                If CType(value, System.Xml.Schema.XmlSchemaEnumerationFacet).UnhandledAttributes.Length > 0 Then
                  newRow.Item("characteristic_name") = CType(value, System.Xml.Schema.XmlSchemaEnumerationFacet).UnhandledAttributes(0).Value.Trim
                End If

                dtResultValue.Rows.Add(newRow)
              End If
            Next
          ElseIf name = "activity_type_code" Then
            For Each value As System.Xml.Schema.XmlSchemaObject In CType(CType(enumeration, System.Xml.Schema.XmlSchemaSimpleType).Content, System.Xml.Schema.XmlSchemaSimpleTypeRestriction).Facets
              If value.GetType.Name = "XmlSchemaEnumerationFacet" Then
                Dim newRow As System.Data.DataRow = dtActivityType.NewRow()

                newRow.Item("activity_code") = CType(value, System.Xml.Schema.XmlSchemaEnumerationFacet).Value.Trim
                If CType(value, System.Xml.Schema.XmlSchemaEnumerationFacet).UnhandledAttributes.Length > 0 Then
                  newRow.Item("location_required") = CType(value, System.Xml.Schema.XmlSchemaEnumerationFacet).UnhandledAttributes(0).Value.Trim
                End If
                If CType(value, System.Xml.Schema.XmlSchemaEnumerationFacet).UnhandledAttributes.Length > 1 Then
                  newRow.Item("analytical_method_required") = CType(value, System.Xml.Schema.XmlSchemaEnumerationFacet).UnhandledAttributes(1).Value.Trim
                End If

                dtActivityType.Rows.Add(newRow)
              End If
            Next
          End If
        Next
      End If
    Next

    'Create the state and county lookups
    'CType(Me.Organization.Columns("State_Code"), EddColumn).Lookup = New EddLookup(Me.dsHelper.SelectDistinct(dtCounty_State.TableName, dtCounty_State, "state_code"), "state_code")
    'CType(Me.Organization.Columns("County_Code"), EddColumn).Lookup = New EddLookup(Me.dsHelper.SelectDistinct(dtCounty_State.TableName, dtCounty_State, "county_code"), "county_code")
  End Sub

  Public Overloads Overrides Function ErrorMessage(ByVal err As EddErrors) As String
    Select Case err
      Case EddErrors.CustomError1
        Return "Assemblage_Sampled_Name is required if Medium='Biological'."
      Case EddErrors.CustomError2
        Return "If Net_Type, Net_Surface_Area, Net_Surface_Area_Unit, Net_Mesh_Size or Net_Mesh_Size_Unit is populated, then the others are required."
      Case EddErrors.CustomError3
        Return "Boat_Speed is required if Net_Type='Net/Horizontal Tow'."
      Case EddErrors.CustomError4
        Return "If Activity_Depth is populated, then Activity_Upper_Depth and Activity_Lower_Depth cannot be populated."
      Case EddErrors.CustomError5
        Return "If Preparation_Method_ID, Preparation_Method_ID_Context, or Preparation_Method_Name is populated then either Chemical_Preservative or Thermal_Preservative must be populated."
      Case EddErrors.CustomError6
        Return "Source_Map_Scale_Numeric is required if Lat_Lon_Method='INTERPOLATION MAP'."
      Case EddErrors.CustomError7
        Return "If Result_Detection_Condition is 'Detected and Quantified', then Result_Text is required otherwise Result_Text must be empty."
      Case EddErrors.CustomError8
        Return "If Biological_Intent='GROUP SUMMARY', then Group_Summary_Count_or_Weight is required."
                'Case EddErrors.CustomError9
                '  Return "Activity_End_Time_Zone must be the same as Activity_Start_Time_Zone."
      Case EddErrors.CustomError10
        Return "Biological_Intent is required if any of the biological result fields are populated.  Biological result fields include Biological_Individual_ID to Frequency_Class_Upper_Bound_3."
      Case EddErrors.CustomError11
        Return "If Biological_Intent='Frequency Class', then Characteristic_Name must be 'Count'."
      Case EddErrors.CustomError12
        Return "If Biological_Intent='Population Census', then Characteristic_Name must be 'Count' or 'Total Sample Weight'."
      Case EddErrors.CustomError13
        Return "If Results.Biological_Intent or Activities.Medium='Tissue', then the other must also be 'Tissue' and Results.Tissue_Anatomy must be populated."
      Case EddErrors.CustomError14
        Return "If Results.Result_Detection_Condition='Not Detected', 'Present Below Quantification Limit', or 'Present Above Quantification Limit' then the associated Method_Detection_Limit, Lower_Quantification_Limit, or Upper_Quantification_Limit is required."
      Case EddErrors.CustomError15
        Return "If Activity_Upper_Depth or Activity_Lower_Depth is populated, then the other is required."
      Case EddErrors.CustomError16
        Return "If Activity_Type='Sample-Integrated Vertical Profile', then Activity_Upper_Depth and Activity_Lower_Depth are required."
      Case EddErrors.CustomError17
        Return "County code does not belong to the selected state code."
      Case EddErrors.CustomError18
        Return "If Characteristic_Name ends with the phrase 'Choice List', then Result_Text must match the domain list value."
      Case EddErrors.CustomError19
        Return "Maximum number of rows is 1."
      Case EddErrors.CustomError20
        Return "If Resource_Title_Name, File_Name_or_Resource_ID, or Resource_Date is populated, then the others are required."
      Case EddErrors.CustomError21
        Return "If Net_Type is populated, then Collection_Equipment_Name must be of the same type."
      Case EddErrors.CustomError22
        Return "If Activity_Type contains 'Sample', then Collection_Method_ID is required."
      Case EddErrors.CustomError23
        Return "Characteristic_Name indicates Filtered_Fraction is required, 'NA' cannot be used."
      Case EddErrors.CustomError24
        Return "If Activity_ID is populated then Activities.Location_ID must be populated."
      Case EddErrors.CustomError25
        Return "Field must be populated unless there is a remap for a null value in rt_remap_detail."
      Case EddErrors.CustomError26
        Return "If Activities.Activity_Type='Field Msr/Obs-Portable Data Logger' or 'Quality Control Field Replicate Portable Data Logger', then Data_Logger_Line_Name is required."
      Case EddErrors.CustomError27
        Return "If DetectionQuantitationLimitTypeName='Lower Quantitation Limit', 'Upper Quantitation Limit', 'Method Detection Level (MDL)', 'Lower Reporting Limit', 'Upper Reporting Limit', 'LRL', 'MDL', or 'LQL' then DetectionQuantitationLimitMeasureValue must be numeric."
      Case EddErrors.CustomError28
        Return "Limit_Comment must be empty unless Method_Detection_Limit, Lower_Quantification_Limit, or Upper_Quantification_Limit is populated."
      Case EddErrors.CustomError29
        Return "If Result_Text starts with '<' then Result_Detection_Condition must be 'Not Detected'."
      Case EddErrors.CustomError30
        Return "If Result_Text starts with '<' then Method_Detection_Limit must equal the value after the < symbol."
      Case EddErrors.CustomError31
        Return "If Result_Text starts with '>' then Result_Detection_Condition must be 'Present Above Quantification Limit'."
      Case EddErrors.CustomError32
        Return "If Result_Text starts with '>' then Upper_Quantification_Limit must equal the value after the > symbol."
      Case EddErrors.CustomError33
        Return "If Result_Text starts with '^' then Result_Detection_Condition must be 'Present Below Quantification Limit'."
      Case EddErrors.CustomError34
        Return "If Result_Text starts with '^' then Lower_Quantification_Limit must equal the value after the ^ symbol."
      Case EddErrors.CustomError35
        Return "Location_ID must begin with Park_Code followed by an underscore (i.e.'PARK_')."
      Case EddErrors.CustomError36
        Return "If Result_Detection_Condition is 'Not Detected', Method_Detection_Limit is required."
      Case EddErrors.CustomError37
        Return "If Result_Detection_Condition is 'Present Above Quantification Limit', Upper_Quantification_Limit is required."
      Case EddErrors.CustomError75
        Return "If Result_Detection_Condition is 'Present Below Quantification Limit', Lower_Quantification_Limit is required."
     'Case EddErrors.CustomError78
        'Return "Analysis_Start_Date and Analysis_Start_Time must precede Analysis_End_Date and Analysis_End_Time."
      Case EddErrors.CustomError79
        Return "Date and Time can't be before Activity_Start_Date and Activity_Start_Time"
      Case EddErrors.CustomError80
        Return "Sample/Activity must have related test/result."
      Case EddErrors.CustomError81
        Return "If Entered, Method_Detection_Limit must be < Lower_Quantification_Limit which must be < Upper_Quantification_Limit."
      Case EddErrors.CustomError82
        Return "Result_Text values must be >= Lower_Quantification_Limit and <= Upper_Quantification_Limit.  Result_Text values shouldn't be < Method_Detection or Lower_Quantification_Limit, or > Upper_Quantification_Limit."
      Case EddErrors.CustomError83
        Return "Activity_End_Date/Time can't occur before the Activity_Start_Date/Time."
      Case EddErrors.CustomError84
        Return "Activity_End_Time_Zone must be in the same geographic region as Activity_Start_Time_Zone."
      Case EddErrors.CustomError85
        Return "Activity_Depth or Activity_Upper_Depth and Activity_Lower_Depth are required if Activity_Depth_Unit is provided."
      Case EddErrors.CustomError86
        Return "This field should not be populated if there is no elevation entered."
      Case EddErrors.CustomError87
        Return "This field should not be populated if both Location latitude and longitude haven't been entered."
      Case EddErrors.CustomError88
        Return "This field should not be populated if both ActivitySite latitude and longitude haven't been entered."
      Case EddErrors.CustomError89
        Return "Result_Unit must be entered if a Method_Detection_Limit, Lower_Quantification_Limit, or Upper_Quantification_Limit has been entered."
      Case EddErrors.CustomError90
        Return "Characteristic_Name indicates Analytical_Method_ID must be entered."
      Case EddErrors.CustomError91
        Return "Characteristic_Name indicates Method_Speciation must be entered, 'None' cannot be used."
      Case EddErrors.CustomError92
        Return "If Activities.Medium='Biological' or 'Tissue', then Subject_Taxon is required."
      Case EddErrors.CustomError93
        Return "If Biological_Intent='Individual', then Biological_Individual_ID is required."

    End Select

    Return MyBase.ErrorMessage(err)
  End Function

  Public Sub AfterDataLoad(table As EddTable)
    For Each row As System.Data.DataRow In table.Rows
      'If Not IsCommentRow(row) AndAlso Not row.IsNull("Characteristic_Name") AndAlso Not row.IsNull("Result_Text") Then
      If Not IsCommentRow(row) AndAlso Not row.IsNull("Characteristic_Name") Then
        Dim chemicalName As String = row.Item("Characteristic_Name").ToString
        If Efd.package.Tables.Contains("rt_remap_detail") AndAlso Efd.package.Tables("rt_remap_detail").Rows.Count > 0 Then
          row.Item("Characteristic_Name") = Remap(row.Item("Characteristic_Name"), "Characteristic_Name", row, "Characteristic_Name", Efd.package.Tables("rt_remap_detail").Rows(0))
        End If

        If row.Item("Characteristic_Name").ToString.ToLower.Contains("(text)") Then
          If Not row.IsNull("Result_Text") AndAlso row.Item("Result_Text").ToString <> "*Text" AndAlso row.Item("Result_Text").ToString <> "See Remark" AndAlso row.Item("Result_Text").ToString <> "See Remark for TEXT" Then 'don't want to concatenate '*Text' to Result_Comment for records coming from STORET or 'See Remark' for records coming from NPSTORET
            If Not row.IsNull("Result_Comment") Then
              row.Item("Result_Comment") = row.Item("Result_Text") & vbCrLf & row.Item("Result_Comment")
            Else
              row.Item("Result_Comment") = row.Item("Result_Text")
            End If
            row.Item("Result_Text") = "See Remark for TEXT"
          End If
        End If
        'If row.Item("Biological_Intent").ToString.ToLower = "population census" OrElse row.Item("Biological_Intent").ToString.ToLower = "species density" OrElse row.Item("Biological_Intent").ToString.ToLower = "individual" OrElse row.Item("Biological_Intent").ToString.ToLower = "frequency class" OrElse row.Item("Biological_Intent").ToString.ToLower = "group summary" OrElse row.Item("Biological_Intent").ToString.ToLower = "tissue" Then
        UpdateDuplicateRowTime(table, row)
        'End If
      End If
    Next

    'Updates the line color
    table.Refresh()
  End Sub

  ' the Organizations section has been removed from the format
  'Private Sub CheckOrganization(ByVal sender As Object, ByVal e As System.Data.DataColumnChangeEventArgs)
  '  Select Case e.Column.ColumnName
  '    Case "ElectronicAddressText", "ElectronicAddressTypeName"
  '      ERR01(e, "ElectronicAddressTypeName", "ElectronicAddressText")        'If ElectronicAddressTypeName or ElectronicAddressText is populated then the other is required.
  '    Case "TelephoneNumberText", "TelephoneNumberTypeName"
  '      ERR01(e, "TelephoneNumberTypeName", "TelephoneNumberText")       'If TelephoneNumberTypeName or TelephoneNumberText is populated then the other is required.
  '    Case "AddressTypeName", "AddressText"
  '      ERR01(e, "AddressTypeName", "AddressText")         'If AddressTypeName or AddressText is populated then the other is required.
  '    Case "State_Code", "County_Code"
  '      ERR04(e)        'If County_Code is populated, then State_Code is required.
  '      ERR53(e)        'Checks if the county coded belongs to the selected state code

  '  End Select
  'End Sub

  'Private Sub Organization_RowChanged(ByVal sender As Object, ByVal e As System.Data.DataRowChangeEventArgs)
  '  ERR57(e)              'Adds error on row if more than one rows is in the Organization section
  'End Sub

  ' the PrjMonitorLocationWeight has been removed from the format
  'Private Sub CheckPrjMonitorLocationWeight(ByVal sender As Object, ByVal e As System.Data.DataColumnChangeEventArgs)
  '  Select Case e.Column.ColumnName
  '    Case "LocationWeightingFactorMeasureValue", "LocationWeightingFactorMeasureUnitCode"
  '      ERR05(e, "LocationWeightingFactorMeasureValue", "LocationWeightingFactorMeasureUnitCode")      'If LocationWeightingFactorMeasureValue or LocationWeightingFactorMeasureUnitCode is populated then the other is required.
  '    Case "Resource_Title_Name", "File_Name_or_Resource_ID", "Resource_Date"
  '      ERR58(e)    'If Resource_Title_Name, File_Name_or_Resource_ID, or Resource_Date is populated, then the others are required.
  '  End Select
  'End Sub

  Private Sub CheckMonitoringLocation(ByVal sender As Object, ByVal e As System.Data.DataColumnChangeEventArgs)
    Select Case e.Column.Ordinal
      Case Locations_.Location_ID, Locations_.Park_Code
                'Comment out for the SFAN network because of GOGA/PORE where PORE actually administers lands for GOGA
                ERR72(e)    '"Location_ID must begin with Park_Code followed by an underscore (i.e.'PARK_')."
            Case Locations_.Alternate_Location_ID, Locations_.Alternate_Location_ID_Context
                ERR07(e)        'If Alternate_Location_ID or Alternate_Location_ID_Context is populated then the other is required.
            Case Locations_.Source_Map_Scale_Numeric, Locations_.Lat_Lon_Method
                ERR08(e)        'If Lat_Lon_Method='INTERPOLATION MAP' then Source_Map_Scale_Numeric is required.
      Case Locations_.Elevation, Locations_.Elevation_Unit, Locations_.Elevation_Method, Locations_.Elevation_Datum
        ERR09(e)        'If Elevation is populated, then Elevation_Unit, Elevation_Method, and Elevation_Datum are required.
        ERR86(e)        'If Elevation not populated, then Elevation_Unit, Elevation_Method, and Elevation_Datum shouldn't be populated.
      Case Locations_.State_Code, Locations_.County_Code
        ERR04(e)        'If County_Code is populated, then State_Code is required.
        ERR53(e)        'Checks if the county coded belongs to the selected state code
      Case Locations_.Well_Type, Locations_.Aquifer_Name, Locations_.Formation_Type
        ERR10(e)        'If Aquifer_Name or Formation_Type is populated, then Well_Type is required.
      Case Locations_.Well_Hole_Depth, Locations_.Well_Hole_Depth_Unit
        ERR05(e, "Well_Hole_Depth", "Well_Hole_Depth_Unit") 'If Well_Hole_Depth or Well_Hole_Depth_Unit is populated then the other is required.
      Case Locations_.Contributing_Area, Locations_.Contributing_Area_Unit
        ERR05(e, "Contributing_Area", "Contributing_Area_Unit") 'If Contributing_Area or Contributing_Area_Unit is populated then the other is required.
      Case Locations_.Drainage_Area, Locations_.Drainage_Area_Unit
        ERR05(e, "Drainage_Area", "Drainage_Area_Unit") 'If Drainage_Area or Drainage_Area_Unit is populated then the other is required.
      Case Locations_.Lat_Lon_Accuracy, Locations_.Lat_Lon_Accuracy_Unit
        ERR05(e, "Lat_Lon_Accuracy", "Lat_Lon_Accuracy_Unit")   'If Lat_Lon_Accuracy or Lat_Lon_Accuracy_Unit is populated then the other is required.
        ERR87(e) 'If Latitude and Longitude aren't populated, shouldn't have Lat_Lon_Accuracy, Lat_Lon_Accuracy_Unit
      Case Locations_.Elevation_Accuracy, Locations_.Elevation_Accuracy_Unit
        ERR05(e, "Elevation_Accuracy", "Elevation_Accuracy_Unit")   'If Elevation_Accuracy or Elevation_Accuracy_Unit is populated then the other is required.
        ERR86(e)        'If Elevation not populated, then Elevation_Accuracy and Elevation_Accuracy_Unit shouldn't be populated.
      Case Locations_.Latitude, Locations_.Longitude
        ERR87(e) 'If Latitude and Longitude aren't populated, shouldn't have Lat_Lon_Accuracy, Lat_Lon_Accuracy_Unit
    End Select
  End Sub

  Private Sub CheckBiologicalHabitatIndex(ByVal sender As Object, ByVal e As System.Data.DataColumnChangeEventArgs)
    Select Case e.Column.Ordinal
      Case Indices_.Resource_Title_Name, Indices_.File_Name_or_Resource_ID, Indices_.Resource_Date
        ERR58(e)    'If Resource_Title_Name, File_Name_or_Resource_ID, or Resource_Date is populated, then the others are required.
      Case Indices_.Location_ID
        ERR60(e)        'If Location_ID is populated then a parent record must exist in the Locations section or in the database.
      Case Indices_.Project_ID
        ERR67(e)        'If Project_ID is populated then a parent record must exist in the Project section or in the database.
    End Select
  End Sub

  Private Sub CheckActivity(ByVal sender As Object, ByVal e As System.Data.DataColumnChangeEventArgs)
    Select Case e.Column.Ordinal
      Case Activities_.Container_Size
        ERR05(e, "Container_Size", "Container_Size_Unit")        'If Container_Size or Container_Size_Unit is populated, then the other is required.
      Case Activities_.Container_Size_Unit
        ERR05(e, "Container_Size", "Container_Size_Unit")        'If Container_Size or Container_Size_Unit is populated, then the other is required.
                'Case "Activity_Lower_Depth_Unit"
                '  ERR05(e, "Activity_Lower_Depth", "Activity_Lower_Depth_Unit")           'If Activity_Lower_Depth is populated, then Activity_Lower_Depth_Unit is required.
      Case Activities_.Activity_Upper_Depth
        'ERR05(e, "Activity_Upper_Depth", "Activity_Depth_Unit")          'If Activity_Upper_Depth is populated, then Activity_Upper_Depth_Unit is required.
        ERR02(e)        'If Activity_Depth is populated, then Activity_Upper_Depth and Activity_Lower_Depth cannot be populated.
        ERR50(e)        'If Activity_Upper_Depth or Activity_Lower_Depth is populated, then the other is required.
        ERR51(e)        'If Activity_Type='Sample-Integrated Vertical Profile', then Activity_Upper_Depth and Activity_Lower_Depth are required.
        ERR85(e) 'If Activity_Upper_Depth is populated, need Activity_Lower_Depth and Activity_Depth_Unit

                'Case "Activity_Upper_Depth_Unit"
                '  ERR05(e, "Activity_Upper_Depth", "Activity_Upper_Depth_Unit")          'If Activity_Upper_Depth is populated, then Activity_Upper_Depth_Unit is required.
      Case Activities_.Activity_Lower_Depth
        'ERR05(e, "Activity_Lower_Depth", "Activity_Depth_Unit")           'If Activity_Lower_Depth is populated, then Activity_Depth_Unit is required.
        ERR02(e)        'If Activity_Depth is populated, then Activity_Upper_Depth and Activity_Lower_Depth cannot be populated.
        ERR50(e)        'If Activity_Upper_Depth or Activity_Lower_Depth is populated, then the other is required.
        ERR51(e)        'If Activity_Type='Sample-Integrated Vertical Profile', then Activity_Upper_Depth and Activity_Lower_Depth are required.
        ERR85(e) 'If Activity_Lower_Depth is populated, need Activity_Upper_Depth and Activity_Depth_Unit
      Case Activities_.Activity_Depth
        ERR02(e)        'Only one of the following fields: Activity_Depth, Activity_Upper_Depth, Activity_Lower_Depth, can be populated.
        'ERR05(e, "Activity_Depth", "Activity_Depth_Unit")   'If Activity_Depth or Activity_Depth_Unit is populated, then the other is required.
        ERR85(e) 'If Activity_Depth is populated, need Activity_Depth_Unit
      Case Activities_.Activity_Depth_Unit
        ERR85(e)   'If Activity_Depth_Unit is populated, then must have Activity_Depth or Activity_Upper_Depth and Activity_Lower_Depth.
      Case Activities_.Activity_Start_Date
        ERR83(e) 'Activity_End_Date/Time can't precede Activity_Start_Date/Time
        ERR79(e, e.Column.ColumnName, "Activity_Start_Time", Me.Smp_Trs) 'Date and Time can't be before Activity_Start_Date and Activity_Start_Time
                'ERR12(e)        'If Activity_Start_Time_Zone or Activity_End_Date is populated, then Activity_Start_Time is required.
                'ERR13(e)        'If Activity_Start_Time or Activity_End_Date is populated, then Activity_Start_Time_Zone is required.
      Case Activities_.Activity_End_Date
        ERR83(e) 'Activity_End_Date/Time can't precede Activity_Start_Date/Time
        ERR79(e, "Activity_End_Time", e.Column.ColumnName, Me.Smp_Trs) 'Date and Time can't be before Activity_Start_Date and Activity_Start_Time
                'ERR12(e)        'If Activity_Start_Time_Zone or Activity_End_Date is populated, then Activity_Start_Time is required.
                'ERR13(e)        'If Activity_Start_Time or Activity_End_Date is populated, then Activity_Start_Time_Zone is required.
      Case Activities_.Activity_Start_Time
        ERR83(e) 'Activity_End_Date/Time can't precede Activity_Start_Date/Time
        'ERR12(e)        'If Activity_Start_Time_Zone or Activity_End_Date is populated, then Activity_Start_Time is required.
        'ERR13(e)        'If Activity_Start_Time or Activity_End_Date is populated, then Activity_Start_Time_Zone is required.
        ERR76(e)        'If Activity_Start_Time or Activity_Start_Time_Zone is populated then the other is required.
      Case Activities_.Activity_Start_Time_Zone
        ERR84(e) 'Activity_Start_Time_Zone and Activity_End_Time_Zone must be in same geographic region (e.g. Eastern, Mountain, etc.)
        'ERR12(e)        'If Activity_Start_Time_Zone or Activity_End_Date is populated, then Activity_Start_Time is required.
        'ERR13(e)        'If Activity_Start_Time or Activity_End_Date is populated, then Activity_Start_Time_Zone is required.
        ERR76(e)        'If Activity_Start_Time or Activity_Start_Time_Zone is populated then the other is required.
                'ERR44(e)        'Activity_End_Time_Zone must be the same as Activity_Start_Time_Zone.
      Case Activities_.Activity_End_Time '"Activity_Relative_Depth"
        ERR83(e) 'Activity_End_Date/Time can't precede Activity_Start_Date/Time
        'Removed ERR14 & ERR15 because Activity_Relative_Depth does not seem to be associated with the end date/time
        'ERR14(e)       'If Activity_End_Time_Zone or Activity_Relative_Depth is populated, then Activity_End_Time is required.
        'ERR15(e)       'If Activity_End_Time or Activity_Relative_Depth is populated, then Activity_End_Time_Zone is required.
        ERR61(e)        'If Activity_End_Time or Activity_End_Time_Zone is populated then the other is required.
      Case Activities_.Activity_End_Time_Zone
        ERR84(e) 'Activity_Start_Time_Zone and Activity_End_Time_Zone must be in same geographic region (e.g. Eastern, Mountain, etc.)
        'ERR14(e)       'If Activity_End_Time_Zone or Activity_Relative_Depth is populated, then Activity_End_Time is required.
        'ERR15(e)       'If Activity_End_Time or Activity_Relative_Depth is populated, then Activity_End_Time_Zone is required.
        'ERR44(e)        'Activity_End_Time_Zone must be the same as Activity_Start_Time_Zone.
        ERR61(e)        'If Activity_End_Time or Activity_End_Time_Zone is populated then the other is required.
      Case Activities_.Activity_ID
        ERR48(e)        'If Results.Biological_Intent or Activities.Medium='Tissue', then the other must also be 'Tissue' and Results.Tissue_Anatomy must be populated.
      Case Activities_.Medium
        ERR19(e)        'Assemblage_Sampled_Name is required if Medium="Biological".
        ERR48(e)        'If Results.Biological_Intent or Activities.Medium='Tissue', then the other must also be 'Tissue' and Results.Tissue_Anatomy must be populated.
      Case Activities_.Medium_Subdivision
        ERR64(e)        'Field must be populated unless there is a remap for a null value in rt_remap_detail.
      Case Activities_.Activity_Type
        ERR51(e)        'If Activity_Type='Sample-Integrated Vertical Profile', then Activity_Upper_Depth and Activity_Lower_Depth are required.
        ERR56(e)        'Check in enumeration activity_type_code to determine if Location_ID is required.
        ERR20(e)        'If Activity_Type contains 'Sample', then Sample_Prep_Method_ID is required.
      Case Activities_.Assemblage_Sampled_Name
        ERR19(e)        'Assemblage_Sampled_Name is required if Medium="Biological".
      Case Activities_.Boat_Speed, Activities_.Boat_Speed_Unit
        ERR05(e, "Boat_Speed", "Boat_Speed_Unit")      'If Boat_Speed or Boat_Speed_Unit is populated, then the other is required.
        ERR25(e)        'Boat_Speed is required if Net_Type='Net/Horizontal Tow'.
      Case Activities_.Chemical_Preservative, Activities_.Thermal_Preservative
        ERR17(e)        'If Preparation_Method_ID, Preparation_Method_ID_Context, or Preparation_Method_Name is populated then either Chemical_Preservative or Thermal_Preservative must be populated.
      Case Activities_.Collection_Duration, Activities_.Collection_Duration_Unit
        ERR05(e, "Collection_Duration", "Collection_Duration_Unit")         'If Collection_Duration or Collection_Duration_Unit is populated, then the other is required.
      Case Activities_.Current_Speed, Activities_.Current_Speed_Unit
        ERR05(e, "Current_Speed", "Current_Speed_Unit")        'If Current_Speed or Current_Speed_Unit is populated, then the other is required.
      Case Activities_.Location_ID
        ERR56(e)        'Check in enumeration activity_type_code to determine if Location_ID is required.
        ERR60(e)        'If Location_ID is populated then a parent record must exist in the Locations section or in the database.
      Case Activities_.Net_Surface_Area, Activities_.Net_Surface_Area_Unit, Activities_.Net_Mesh_Size, Activities_.Net_Mesh_Size_Unit
        ERR23(e)        'If Net_Type, Net_Surface_Area, Net_Surface_Area_Unit, Net_Mesh_Size or Net_Mesh_Size_Unit is populated, then the others are required.
      Case Activities_.Net_Type
        ERR23(e)        'If Net_Type, Net_Surface_Area, Net_Surface_Area_Unit, Net_Mesh_Size or Net_Mesh_Size_Unit is populated, then the others are required.
        ERR03(e)        'If Net_Type is populated, then Collection_Equipment_Name must have the same value.
      Case Activities_.Project_ID
        ERR67(e)        'If Project_ID is populated then a parent record must exist in the Project section or in the database.
      Case Activities_.Reach_Length, Activities_.Reach_Length_Unit
        ERR05(e, "Reach_Length", "Reach_Length_Unit")        'If Reach_Length or Reach_Length_Unit is populated, then the other is required.
      Case Activities_.Reach_Width, Activities_.Reach_Width_Unit
        ERR05(e, "Reach_Width", "Reach_Width_Unit")        'If Reach_Width or Reach_Width_Unit is populated, then the other is required.
      Case Activities_.Collection_Effort, Activities_.Collection_Effort_Gear_Type
        ERR05(e, "Collection_Effort", "Collection_Effort_Gear_Type")        'If Collection_Effort or Collection_Effort_Gear_Type is populated, then the other is required.
      Case Activities_.Collection_Equipment_Name
        ERR28(e)        'If Collection_Method_ID is populated, then Collection_Equipment_Name is required.
        ERR03(e)        'If Net_Type is populated, then Collection_Equipment_Name must have the same value.
      Case Activities_.Collection_Method_ID
        'ERR27(e)        'If Collection_Method_ID, Collection_Method_ID_Context or Collection_Method_Name is populated, then the others are required.
        ERR28(e)        'If Collection_Method_ID is populated, then Collection_Equipment_Name is required.
        ERR20(e)        'If Activity_Type contains 'Sample', then Collection_Method_ID is required.
      'Case Activities_.Collection_Method_ID_Context, Activities_.Collection_Method_Name
         'ERR27(e)        'If Collection_Method_ID, Collection_Method_ID_Context or Collection_Method_Name is populated, then the others are required.
      Case Activities_.Container_Type, Activities_.Container_Color, Activities_.Transport_Storage_Description
        ERR16(e)        'If Preparation_Method_ID is populated then Container_Type, Container_Color and Transport_Storage_Description are required.
      Case Activities_.Preparation_Method_ID
        'ERR11(e)        'If Preparation_Method_ID, Preparation_Method_ID_Context or Preparation_Method_Name is populated, then the others are required.
        ERR16(e)        'If Preparation_Method_ID is populated then Container_Type, Container_Color and Transport_Storage_Description are required.
        'Case Activities_.Preparation_Method_ID_Context, Activities_.Preparation_Method_Name
        'ERR11(e)        'If Preparation_Method_ID, Preparation_Method_ID_Context or Preparation_Method_Name is populated, then the others are required.
    End Select
  End Sub

  Private Sub CheckActivitySites(ByVal sender As Object, ByVal e As System.Data.DataColumnChangeEventArgs)
    Select Case e.Column.Ordinal
      Case ActivitySites_.Activity_ID
        ERR62(e)      'If Activity_ID is populated then Activities.Location_ID must be populated.
      Case ActivitySites_.Lat_Lon_Method
        ERR08(e)      'Source_Map_Scale_Numeric is required if Lat_Lon_Method='INTERPOLATION MAP'.
        ERR21(e)      'Lat_Lon_Method and Lat_Lon_Datum are required if Latitude or Longitude is populated.
        ERR88(e)      'No Lat_Lon_Method, Lat_Lon_Datum, Lat_Lon_Accuracy, Lat_Lon_Accuracy_Unit if Latitude and Longitude aren't entered
      Case ActivitySites_.Lat_Lon_Datum
        ERR21(e)      'Lat_Lon_Method and Lat_Lon_Datum are required if Latitude or Longitude is populated.
        ERR88(e)      'No Lat_Lon_Method, Lat_Lon_Datum, Lat_Lon_Accuracy, Lat_Lon_Accuracy_Unit if Latitude and Longitude aren't entered
      Case ActivitySites_.Latitude, ActivitySites_.Longitude
        ERR18(e)      'If Latitude or Longitude is populated, then the other is required.
        ERR21(e)      'Lat_Lon_Method and Lat_Lon_Datum are required if Latitude or Longitude is populated.
        ERR88(e)      'No Lat_Lon_Method, Lat_Lon_Datum, Lat_Lon_Accuracy, Lat_Lon_Accuracy_Unit if Latitude and Longitude aren't entered
      Case ActivitySites_.Source_Map_Scale_Numeric
        ERR08(e)      'Source_Map_Scale_Numeric is required if Lat_Lon_Method='INTERPOLATION MAP'.
      Case ActivitySites_.Lat_Lon_Accuracy, ActivitySites_.Lat_Lon_Accuracy_Unit
        ERR05(e, "Lat_Lon_Accuracy", "Lat_Lon_Accuracy_Unit")   'If Lat_Lon_Accuracy or Lat_Lon_Accuracy_Unit is populated then the other is required.
        ERR88(e)      'No Lat_Lon_Method, Lat_Lon_Datum, Lat_Lon_Accuracy, Lat_Lon_Accuracy_Unit if Latitude and Longitude aren't entered
      Case ActivitySites_.Elevation_Accuracy, ActivitySites_.Elevation_Accuracy_Unit
        ERR05(e, "Elevation_Accuracy", "Elevation_Accuracy_Unit")   'If Elevation_Accuracy or Elevation_Accuracy_Unit is populated then the other is required.
        ERR86(e)        'If Elevation not populated, then Elevation_Unit, Elevation_Method, Elevation_Datum, Elevation_Accuracy, and Elevation_Accuracy_Unit shouldn't be populated.
      Case ActivitySites_.Source_Map_Scale_Numeric, ActivitySites_.Lat_Lon_Method
        ERR08(e)        'If Lat_Lon_Method='INTERPOLATION MAP' then Source_Map_Scale_Numeric is required.
      Case ActivitySites_.Elevation, ActivitySites_.Elevation_Unit, ActivitySites_.Elevation_Method, ActivitySites_.Elevation_Datum, ActivitySites_.Elevation_Accuracy, ActivitySites_.Elevation_Accuracy_Unit
        ERR09(e)        'If Elevation is populated, then Elevation_Unit, Elevation_Method, and Elevation_Datum are required.
        ERR86(e)        'If Elevation not populated, then Elevation_Unit, Elevation_Method, Elevation_Datum, Elevation_Accuracy, and Elevation_Accuracy_Unit shouldn't be populated.
    End Select
  End Sub

  Private Sub CheckActMetric(ByVal sender As Object, ByVal e As System.Data.DataColumnChangeEventArgs)
    Select Case e.Column.Ordinal
      Case Metrics_.Index_ID
        ERR52(e)          'Metrics.Index_ID is a foreign key to Indices.Bio_Habitat_Index_ID.
      Case Metrics_.Metric_ID
        ERR06(e)          'Check if value has a remap or is a valid value.
      Case Metrics_.Metric_Value, Metrics_.Metric_Value_Unit
        ERR05(e, "Metric_Value", "Metric_Value_Unit")      'If Metric_Value or Metric_Value_Unit is populated, then the other is required.
      Case Metrics_.Resource_Title_Name, Metrics_.File_Name_or_Resource_ID, Metrics_.Resource_Date
        ERR58(e)    'If Resource_Title_Name, File_Name_or_Resource_ID, or Resource_Date is populated, then the others are required.
    End Select
  End Sub

  Private Sub CheckResult(ByVal sender As Object, ByVal e As System.Data.DataColumnChangeEventArgs)
    Dim columnOrdinal As Integer = e.Column.Ordinal
    If IsBiologicalResult(columnOrdinal) Then ERR45(e) 'Biological_Intent is required if any of the biological result fields are populated.

    Select Case columnOrdinal
      Case Results_.Activity_ID
        ERR48(e)    'If Biological_Intent='Tissue', then Tissue_Anatomy must be populated and Activities.Medium must be 'Tissue'.
        ERR55(e)    'Check in rt_sample_type to determine if Analytical_Method_ID is required.
        ERR65(e)    'If Activities.Activity_Type='Field Msr/Obs-Portable Data Logger' or 'Quality Control Field Replicate Portable Data Logger', then Data_Logger_Line_Name is required.
        ERR92(e)    'If Activities.Medium='Biological' or 'Tissue', then Subject_Taxon is required.
        ERR79(e, "Analysis_Start_Date", "Analysis_Start_Time", Me.Smp_Trs) 'Date and Time can't be before Activity_Start_Date and Activity_Start_Time
        ERR79(e, "Lab_Sample_Preparation_Start_Date", "Lab_Sample_Preparation_Start_Time", Me.Smp_Trs) 'Date and Time can't be before Activity_Start_Date and Activity_Start_Time
      'Case "Analysis_End_Date"
        'ERR78(e)    'Analysis_Start_Date and Analysis_Start_Time must precede Analysis_End_Date and Analysis_End_Time.
        'ERR38(e)    'Analysis_Start_Time_Zone is required if Analysis_Start_Time or Analysis_End_Date is populated.
      'Case "Analysis_End_Time"
        'ERR37(e)    'Analysis_Start_Time is required if Analysis_Start_Time_Zone or Analysis_End_Time is populated.
        'ERR39(e)    'If Analysis_End_Time or Analysis_End_Time_Zone is populated, then the other is required.
        'ERR78(e)    'Analysis_Start_Date and Analysis_Start_Time must preceded Analysis_End_Date and Analysis_End_Time.
      'Case "Analysis_End_Time_Zone"
        'ERR39(e)    'If Analysis_End_Time or Analysis_End_Time_Zone is populated, then the other is required.
      Case Results_.Analysis_Start_Date
        ' ERR78(e)    'Analysis_Start_Date and Analysis_Start_Time must precede Analysis_End_Date and Analysis_End_Time.
        ERR79(e, e.Column.ColumnName, "Analysis_Start_Time", Me.Smp_Trs) 'Date and Time can't be before Activity_Start_Date and Activity_Start_Time
      Case Results_.Analysis_Start_Time
        ERR77(e)    'If Analysis_Start_Time or Analysis_Start_Time_Zone is populated, then the other is required.
        'ERR78(e)    'Analysis_Start_Date and Analysis_Start_Time must preceded Analysis_End_Date and Analysis_End_Time.
        'ERR37(e)    'Analysis_Start_Time is required if Analysis_Start_Time_Zone or Analysis_End_Time is populated.
        ERR79(e, "Analysis_Start_Date", e.Column.ColumnName, Me.Smp_Trs) 'Date and Time can't be before Activity_Start_Date and Activity_Start_Time
      Case Results_.Analysis_Start_Time_Zone
        ERR77(e)    'If Analysis_Start_Time or Analysis_Start_Time_Zone is populated, then the other is required.
       'ERR37(e)    'Analysis_Start_Time is required if Analysis_Start_Time_Zone or Analysis_End_Time is populated.
       'ERR38(e)    'Analysis_Start_Time_Zone is required if Analysis_Start_Time or Analysis_End_Date is populated.
      Case Results_.Biological_Intent
        ERR29(e)    'If Biological_Intent='Group Summary', then Group_Summary_Count_or_Weight is required.
        ERR45(e)    'Biological_Intent is required if any of the biological result fields are populated.
        ERR46(e)    'If Biological_Intent='Frequency Class', then Characteristic_Name must be 'Count'.
        ERR47(e)    'If Biological_Intent='Population Census', then Characteristic_Name must be 'Count' or 'Total Sample Weight'.
        ERR48(e)    'If Biological_Intent='Tissue', then Tissue_Anatomy must be populated and Activities.Medium must be 'Tissue'.
        ERR93(e)    'If Biological_Intent='Individual', then Biological_Individual_ID is required.
     'Case "CAS_rn"
       'PopulateChemicalName(e)     'Auto-populated Characteristic_Name
       'ERR59(e)                    'If rt_analyte_detail.fraction_required_yn='Y' then Filtered_Fraction cannot equal 'N'.
      Case Results_.Characteristic_Name
        'PopulateCasRn(e) 'Auto-populated CAS_rn
        ERR46(e)    'If Biological_Intent='Frequency Class', then Characteristic_Name must be 'Count'.
        ERR47(e)    'If Biological_Intent='Population Census', then Characteristic_Name must be 'Count' or 'Total Sample Weight'.
        ERR54(e)    'If Characteristic_Name ends with the phrase 'Choice List', then Result_Text must match the domain list value.
        ERR59(e)    'If rt_analyte_detail.fraction_required_yn='Y' then Filtered_Fraction cannot equal 'NA'.
        ERR90(e)    'If rt_analyte_detail.method_required_yn='Y' then Analytical_Method_ID must be entered.
        ERR91(e)    'If rt_analyte_detail.speciation_required_yn='Y' then Method_Speciation must be entered.
      Case Results_.Data_Logger_Line_Name
        ERR65(e)    'If Activities.Activity_Type='Field Msr/Obs-Portable Data Logger' or 'Quality Control Field Replicate Portable Data Logger', then Data_Logger_Line_Name is required.
      Case Results_.Frequency_Class_Descriptor_1, Results_.Frequency_Class_Bounds_Unit_1, Results_.Frequency_Class_Lower_Bound_1, Results_.Frequency_Class_Upper_Bound_1
        ERR30(e)    'If Frequency_Class_Descriptor_1='Measured Characteristic', then Frequency_Class_Bounds_Unit_1, Frequency_Class_Lower_Bound_1, and Frequency_Class_Upper_Bound_1 are required.
        ERR33(e)    'Frequency_Class_Descriptor_1 is required if Frequency_Class_Bounds_Unit_1, Frequency_Class_Lower_Bound_1, or Frequency_Class_Upper_Bound_1 is populated.
      Case Results_.Frequency_Class_Descriptor_2, Results_.Frequency_Class_Bounds_Unit_2, Results_.Frequency_Class_Lower_Bound_2, Results_.Frequency_Class_Upper_Bound_2
        ERR31(e)    'If Frequency_Class_Descriptor_2='Measured Characteristic', then Frequency_Class_Bounds_Unit_2, Frequency_Class_Lower_Bound_2, and Frequency_Class_Upper_Bound_2 are required.
        ERR34(e)    'Frequency_Class_Descriptor_2 is required if Frequency_Class_Bounds_Unit_2, Frequency_Class_Lower_Bound_2, or Frequency_Class_Upper_Bound_2 is populated.
      Case Results_.Frequency_Class_Descriptor_3, Results_.Frequency_Class_Bounds_Unit_3, Results_.Frequency_Class_Lower_Bound_3, Results_.Frequency_Class_Upper_Bound_3
        ERR32(e)    'If Frequency_Class_Descriptor_3='Measured Characteristic', then Frequency_Class_Bounds_Unit_3, Frequency_Class_Lower_Bound_3, and Frequency_Class_Upper_Bound_3 are required.
        ERR35(e)    'Frequency_Class_Descriptor_3 is required if Frequency_Class_Bounds_Unit_3, Frequency_Class_Lower_Bound_3, or Frequency_Class_Upper_Bound_3 is populated.
      Case Results_.Group_Summary_Count_or_Weight_Unit
        ERR05(e, "Group_Summary_Count_or_Weight", "Group_Summary_Count_or_Weight_Unit") 'If Group_Summary_Count_or_Weight or Group_Summary_Count_or_Weight_Unit is populated, then the other one is required.
      Case Results_.Group_Summary_Count_or_Weight
        ERR05(e, "Group_Summary_Count_or_Weight", "Group_Summary_Count_or_Weight_Unit") 'If Group_Summary_Count_or_Weight or Group_Summary_Count_or_Weight_Unit is populated, then the other one is required.
        ERR29(e)    'If Biological_Intent='Group Summary', then Group_Summary_Count_or_Weight is required.
      'Case "Lab_Sample_Preparation_ID", "Lab_Sample_Preparation_ID_Context" ' "Lab_Sample_Preparation_Method_Name"
        'ERR40(e)    'If Lab_Sample_Preparation_ID, Lab_Sample_Preparation_ID_Context or Lab_Sample_Preparation_Method_Name is populated, then the others are reqiured. 
      'Case "Lab_Sample_Preparation_End_Time", "Lab_Sample_Preparation_End_Time_Zone"
        'ERR42(e)     'If Lab_Sample_Preparation_End_Time or Lab_Sample_Preparation_End_Time_Zone is populated, then the other one is required.
      Case Results_.Lab_Sample_Preparation_Start_Date
        ERR79(e, e.Column.ColumnName, "Lab_Sample_Preparation_Start_Time", Me.Smp_Trs) 'Date and Time can't be before Activity_Start_Date and Activity_Start_Time
      Case Results_.Lab_Sample_Preparation_Start_Time
        ERR41(e)   'If Lab_Sample_Preparation_Start_Time or Lab_Sample_Preparation_Start_Time_Zone is populated, then the other one is required.
        ERR79(e, "Lab_Sample_Preparation_Start_Date", e.Column.ColumnName, Me.Smp_Trs) 'Date and Time can't be before Activity_Start_Date and Activity_Start_Time
      Case Results_.Lab_Sample_Preparation_Start_Time_Zone
        ERR41(e)  'If Lab_Sample_Preparation_Start_Time or Lab_Sample_Preparation_Start_Time_Zone is populated, then the other one is required.
      Case Results_.Limit_Comment
        ERR68(e)  'Limit_Comment must be empty unless Method_Detection_Limit, Lower_Quantification_Limit, or Upper_Quantification_Limit is populated.
      Case Results_.Method_Detection_Limit
        ERR68(e) 'Limit_Comment must be empty unless Method_Detection_Limit, Lower_Quantification_Limit, or Upper_Quantification_Limit is populated.
        ERR69(e) 'If Result_Text starts with '<' symbol then the Result_Detection_Condition must be 'Not Detected' and the Method_Detection_Limit must equal the Result_Text value after the '<' symbol.
        ERR73(e) 'If Result_Detection_Condition is 'Not Detected', Method_Detection_Limit is required.
        ERR81(e) 'If entered, Method_Detection_Limit < Lower_Quantification_Limit < Upper_Quantification_Limit.
        ERR82(e) 'Result_Text values must be >= Lower_Quantification_Limit and <= Upper_Quantification_Limit.  Result_Text values shouldn't be < Method_Detection or Lower_Quantification_Limit, or > Upper_Quantification_Limit.
        ERR89(e) 'Result_Unit required if Method_Detection_Limit, Lower_Quantification_Limit, or Upper_Quantification_Limit entered.
      Case Results_.Lower_Quantification_Limit
        ERR68(e) 'Limit_Comment must be empty unless Method_Detection_Limit, Lower_Quantification_Limit, or Upper_Quantification_Limit is populated.
        ERR71(e) 'If Result_Text starts with '^' symbol then the Result_Detection_Condition must be 'Present Below Quantification Limit' and the Lower_Quantification_Limit must equal the Result_Text value after the '^' symbol.
        ERR75(e) 'If Result_Detection_Condition is 'Present Below Quantification Limit', Lower_Quantification_Limit is required.
        ERR81(e) 'If entered, Method_Detection_Limit < Lower_Quantification_Limit < Upper_Quantification_Limit.
        ERR82(e) 'Result_Text values must be >= Lower_Quantification_Limit and <= Upper_Quantification_Limit.  Result_Text values shouldn't be < Method_Detection or Lower_Quantification_Limit, or > Upper_Quantification_Limit.
        ERR89(e) 'Result_Unit required if Method_Detection_Limit, Lower_Quantification_Limit, or Upper_Quantification_Limit entered.
      Case Results_.Upper_Quantification_Limit
        ERR68(e) 'Limit_Comment must be empty unless Method_Detection_Limit, Lower_Quantification_Limit, or Upper_Quantification_Limit is populated.
        ERR70(e) 'If Result_Text starts with '>' symbol then the Result_Detection_Condition must be 'Present Above Quantification Limit' and the Upper_Quantification_Limit must equal the Result_Text value after the '>' symbol.
        ERR74(e) 'If Result_Detection_Condition is 'Present Above Quantification Limit', Upper_Quantification_Limit is required.
        ERR81(e) 'If entered, Method_Detection_Limit < Lower_Quantification_Limit < Upper_Quantification_Limit.
        ERR82(e) 'Result_Text values must be >= Lower_Quantification_Limit and <= Upper_Quantification_Limit.  Result_Text values shouldn't be < Method_Detection or Lower_Quantification_Limit, or > Upper_Quantification_Limit.
        ERR89(e) 'Result_Unit required if Method_Detection_Limit, Lower_Quantification_Limit, or Upper_Quantification_Limit entered.
      Case Results_.Resource_Title_Name, Results_.File_Name_or_Resource_ID, Results_.Resource_Date
        ERR58(e)    'If Resource_Title_Name, File_Name_or_Resource_ID, or Resource_Date is populated, then the others are required.
      Case Results_.Analytical_Method_ID
        'ERR36(e)   'Analytical_Method_ID_Context is required if Analytical_Method_ID is populated.
        ERR55(e)    'Check in rt_sample_type to determine if Analytical_Method_ID is required.
        ERR90(e)    'If rt_analyte_detail.method_required_yn='Y' then Analytical_Method_ID must be entered.
      'Case Results_.Analytical_Method_ID_Context
        'ERR36(e)    'Analytical_Method_ID_Context is required if Analytical_Method_ID is populated.  
      Case Results_.Result_Detection_Condition
        ERR22(e)    'If Result_Detection_Condition='Y', then Result_Text is required.  If Result_Detection_Condition='N', then Result_Text must be empty.
        ERR69(e)    'If Result_Text starts with less than symbol then Result_Detection_Condition must be Not Detected and Method_Detection_Limit will be populated with the Result_Text value after the less than symbol.
        ERR70(e)    'If Result_Text starts with '>' symbol then the Result_Detection_Condition must be 'Present Above Quantification Limit' and the Upper_Quantification_Limit must equal the Result_Text value after the '>' symbol.
        ERR71(e)    'If Result_Text starts with '^' symbol then the Result_Detection_Condition must be 'Present Below Quantification Limit' and the Lower_Quantification_Limit must equal the Result_Text value after the '^' symbol.
        ERR73(e)    'If Result_Detection_Condition is 'Not Detected', Method_Detection_Limit is required.
        ERR74(e)    'If Result_Detection_Condition is 'Present Above Quantification Limit', Upper_Quantification_Limit is required.
        ERR75(e)    'If Result_Detection_Condition is 'Present Below Quantification Limit', Lower_Quantification_Limit is required.
        ERR89(e)    'Result_Unit required if Method_Detection_Limit, Lower_Quantification_Limit, or Upper_Quantification_Limit entered.
      Case Results_.Result_Depth_Height_Measure, Results_.Result_Depth_Height_Measure_Unit
        ERR05(e, "Result_Depth_Height_Measure", "Result_Depth_Height_Measure_Unit") 'If Result_Depth_Height_Measure or Result_Depth_Height_Measure_Unit is populated, then the other one is required.
      Case Results_.Result_Qualifier
        resultChecker.VerifyQualifiers(e)
        ERR82(e)    'Result_Text values must be >= Lower_Quantification_Limit and <= Upper_Quantification_Limit.  Result_Text values shouldn't be < Method_Detection or Lower_Quantification_Limit, or > Upper_Quantification_Limit.
      Case Results_.Result_Unit, Results_.Result_Type
        ERR24(e)    'Result_Unit and Result_Type are required if Result_Text is numeric.
        ERR89(e)    'Result_Unit required if Method_Detection_Limit, Lower_Quantification_Limit, or Upper_Quantification_Limit entered.
      Case Results_.Result_Text
        ERR22(e)    'If Result_Detection_Condition='Y', then Result_Text is required.  If Result_Detection_Condition='N', then Result_Text must be empty.
        ERR24(e)    'Result_Unit and Result_Type are required if Result_Text is numeric.
        'ERR26(e)   'If Result_Text is populated, then Result_Status is required.
        ERR54(e)    'If Characteristic_Name ends with the phrase 'Choice List', then Result_Text must match the domain list value.
        ERR69(e)    'If Result_Text starts with '<' symbol then the Result_Detection_Condition must be 'Not Detected' and the Method_Detection_Limit must equal the Result_Text value after the '<' symbol.
        ERR70(e)    'If Result_Text starts with '>' symbol then the Result_Detection_Condition must be 'Present Above Quantification Limit' and the Upper_Quantification_Limit must equal the Result_Text value after the '>' symbol.
        ERR71(e)    'If Result_Text starts with '^' symbol then the Result_Detection_Condition must be 'Present Below Quantification Limit' and the Lower_Quantification_Limit must equal the Result_Text value after the '^' symbol.
        ERR82(e)    'Result_Text values must be >= Lower_Quantification_Limit and <= Upper_Quantification_Limit.  Result_Text values shouldn't be < Method_Detection or Lower_Quantification_Limit, or > Upper_Quantification_Limit.
      Case Results_.Filtered_Fraction
        ERR64(e)    'Field must be populated unless there is a remap for a null value in rt_remap_detail.
        ERR59(e)    'If rt_analyte_detail.fraction_required_yn='Y' then Filtered_Fraction cannot equal 'NA'.
      'Case "Result_Status"
        'ERR26(e)    'If Result_Text is populated, then Result_Status is required.
      Case Results_.Tissue_Anatomy
        ERR48(e)    'If Biological_Intent='Tissue', then Tissue_Anatomy must be populated and Medium must be 'Tissue'.
      Case Results_.Method_Speciation
        ERR91(e)    'If rt_analyte_detail.speciation_required_yn='Y' then Method_Speciation must be entered.
      Case Results_.Subject_Taxon
        ERR92(e)    'If Activities.Medium='Biological' or 'Tissue', then Subject_Taxon is required.
      Case Results_.Biological_Individual_ID
        ERR93(e)    'If Biological_Intent='Individual', then Biological_Individual_ID is required.
  End Select
  End Sub
  Private Sub Activities_RowChanged(ByVal sender As Object, ByVal e As System.Data.DataRowChangeEventArgs)
    ERR80(e.Row) 'Check the Activities section to verify child rows in Results section.
  End Sub

  Private Sub UpdateDuplicateRowTime(table As EddTable, row As System.Data.DataRow)

    Me._Err.Parse(row.RowError)
    If Me._Err.Check(EddErrors.DuplicateRow) Then

      Dim timeColumn As String = String.Empty
      Dim time As Date
      Dim timeFormat As String = String.Empty
      Dim i As Integer = 0
      Dim sql As New System.Text.StringBuilder(String.Format("line <> '{0}'", row.Item("line").ToString))
      For Each key As System.Data.DataColumn In table.PrimaryKey
        If key.ColumnName.ToLower.EndsWith("_time") Then
          timeColumn = key.ColumnName
          If Date.TryParse(row.Item(key).ToString, time) Then
            '
            'Must get the time format as displayed in EDP since we are searching based on a string and not a time/date object
            timeFormat = CType(key, EddColumn).Format
            'If timeFormat.Length = 0 OrElse timeFormat.LastIndexOf(":") < 0 Then timeFormat = EarthSoft.EDP.IO.EddFile.INTERNATIONAL_TIME_FORMAT
            'sql.Append(String.Format(" and {0} like '{1}:%'", key.ColumnName, time.ToString(timeFormat.Substring(0, timeFormat.LastIndexOf(":")))))
            If timeFormat.Length=0 OrElse timeFormat.LastIndexOf(":")<0 Then timeFormat=EarthSoft.Common.Resources.CurrentCulture.DateTimeFormat.ShortTimePattern
            If timeFormat.Contains(":ss") Then
                timeFormat=timeFormat.Remove(timeFormat.LastIndexOf(":"),3)
            End If
            If timeFormat.Contains(" tt") Then
                'must remove AM/PM since wild card characters can only appear at the beginning or end of a value
                timeFormat=timeFormat.Remove(timeFormat.Length-3,3)
            End If
            Dim timeValue As String = String.Format("and {0} like '{1}%' ", key.ColumnName, time.ToString(timeFormat))
            sql.Append(timeValue)
          Else
            'not a valid date so we cannot change seconds
            Exit Sub
          End If

        Else
          If row.IsNull(key) Then
            sql.Append(String.Format("and {0} is null ", key.ColumnName))
          Else
            sql.Append(String.Format("and {0} = '{1}' ", key.ColumnName, row.Item(key).ToString().Replace("'", "''")))
          End If
        End If
      Next

      Dim matchingRows() As System.Data.DataRow = table.Select(sql.ToString)
      
      If Not String.IsNullOrEmpty(timeColumn) AndAlso Not String.IsNullOrEmpty(timeFormat) Then
        If matchingRows.Length > 1 Then
          Dim maxTime As Date = time
          Dim currentTime As Date
          For Each matchRow As System.Data.DataRow In matchingRows
            'Check the time of day since the AM/PM needed to be removed from the time value in the query
            If Date.TryParse(matchRow.Item(timeColumn),currentTime) AndAlso currentTime.TimeOfDay>=time.TimeOfDay AndAlso currentTime.Second > maxTime.Second Then
                maxTime=currentTime
            End If 
          Next
          row.Item(timeColumn) = maxTime.AddSeconds(1).ToString("HH:mm:ss")
          'Added by DFT 1/26/2018 to avoid missing time zone error on these records
          If IsDBNull(row.Item(timeColumn & "_Zone")) Then row.Item(timeColumn & "_Zone") = "GMT"
        Else
          row.Item(timeColumn) = time.AddSeconds(1).ToString("HH:mm:ss")
          'Added by DFT 1/26/2018 to avoid missing time zone error on these records
          If IsDBNull(row.Item(timeColumn & "_Zone")) Then row.Item(timeColumn & "_Zone") = "GMT"
        End If
      End If

    End If

  End Sub

    'Private Sub CheckResDetectionQuantLimit(ByVal sender As Object, ByVal e As System.Data.DataColumnChangeEventArgs)
    '    Select Case e.Column.ColumnName
    '        Case "DetectionQuantitationLimitTypeName", "DetectionQuantitationLimitMeasureValue"
    '            ERR43(e)      'If DetectionQuantitationLimitTypeName, DetectionQuantitationLimitMeasureValue, or DetectionQuantitationLimitMeasureUnitCode is populated, then the others are required.
    '            ERR49(e)      'If Results.Result_Detection_Condition='Not Detected', 'Present Above Quantification Limit' or 'Present and Below Quantification Limit', then DetectionQuantitationLimitTypeName, DetectionQuantitationLimitMeasureValue and DetectionQuantitationLimitMeasureUnitCode are required.
    '            ERR66(e)      'If DetectionQuantitationLimitTypeName='Lower Quantitation Limit', 'Upper Quantitation Limit', 'Method Detection Level (MDL)', 'Lower Reporting Limit', 'Upper Reporting Limit', 'LRL', 'MDL', or 'LQL' then DetectionQuantitationLimitMeasureValue must be numeric.
    '        Case "DetectionQuantitationLimitMeasureUnitCode", "Activity_ID"
    '            ERR43(e)      'If DetectionQuantitationLimitTypeName, DetectionQuantitationLimitMeasureValue, or DetectionQuantitationLimitMeasureUnitCode is populated, then the others are required.
    '            ERR49(e)      'If Results.Result_Detection_Condition='Not Detected', 'Present Above Quantification Limit' or 'Present and Below Quantification Limit', then DetectionQuantitationLimitTypeName, DetectionQuantitationLimitMeasureValue and DetectionQuantitationLimitMeasureUnitCode are required.
    '            'Case "CAS_rn"
    '            '  PopulateChemicalName(e)     'Auto-populated Characteristic_Name
    '        Case "Characteristic_Name"
    '            ' PopulateCasRn(e)     'Auto-populated CAS_rn
    '        Case "Filtered_Fraction"
    '            ERR64(e)        'Field must be populated unless there is a remap for a null value in rt_remap_detail.
    '    End Select
    'End Sub

    Private Sub CheckFiles(ByVal sender As Object, ByVal e As System.Data.DataColumnChangeEventArgs)
    Select Case e.Column.Ordinal
      Case Files_.Place_Type, Files_.Place_Code, Files_.Org_Code
        ERR63(e)          'Check for parent record
    End Select
  End Sub

#Region "Checks"
    '''' <summary>If the name or the text field is populated, then the other one is required.
    '''' Applies to:
    '''' <list type="bullet">
    ''''   <item>Organization.ElectronicAddressTypeName</item>
    ''''   <item>Organization.ElectronicAddressText</item>
    ''''   <item>Organization.TelephoneNumberTypeName</item>
    ''''   <item>Organization.TelephoneNumberText</item>
    ''''   <item>Organization.AddressTypeName</item>
    ''''   <item>Organization.AddressText</item>
    '''' </list>
    '''' </summary>
    'Private Sub ERR01(ByVal e As System.Data.DataColumnChangeEventArgs, ByVal nameColumn As String, ByVal textColumn As String)
    '    '  With e.Row
    '    '    If .IsNull(nameColumn) AndAlso Not .IsNull(textColumn) Then
    '    '      Me.AddError(e.Row, e.Row.Table.Columns.Item(nameColumn), EddErrors.Required)
    '    '    Else
    '    '      Me.RemoveError(e.Row, e.Row.Table.Columns.Item(nameColumn), EddErrors.Required)
    '    '    End If

    '    '    If .IsNull(textColumn) AndAlso Not .IsNull(nameColumn) Then
    '    '      Me.AddError(e.Row, e.Row.Table.Columns.Item(textColumn), EddErrors.Required)
    '    '    Else
    '    '      Me.RemoveError(e.Row, e.Row.Table.Columns.Item(textColumn), EddErrors.Required)
    '    '    End If
    '    '  End With
    'End Sub

    ''' <summary>If Activity_Depth is populated, then Activity_Upper_Depth and Activity_Lower_Depth cannot be populated.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Activities.Activity_Depth</item>
    '''   <item>Activities.Activity_Upper_Depth</item>
    '''   <item>Activities.Activity_Lower_Depth</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR02(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .Item("Activity_Depth").ToString <> String.Empty AndAlso (.Item("Activity_Upper_Depth").ToString <> String.Empty OrElse .Item("Activity_Lower_Depth").ToString <> String.Empty) Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Activity_Depth"), EddErrors.CustomError4)

        If .Item("Activity_Upper_Depth").ToString <> String.Empty Then
          Me.AddError(e.Row, e.Row.Table.Columns.Item("Activity_Upper_Depth"), EddErrors.CustomError4)
        Else
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_Upper_Depth"), EddErrors.CustomError4)
        End If

        If .Item("Activity_Lower_Depth").ToString <> String.Empty Then
          Me.AddError(e.Row, e.Row.Table.Columns.Item("Activity_Lower_Depth"), EddErrors.CustomError4)
        Else
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_Lower_Depth"), EddErrors.CustomError4)
        End If

      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_Depth"), EddErrors.CustomError4)
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_Upper_Depth"), EddErrors.CustomError4)
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_Lower_Depth"), EddErrors.CustomError4)
      End If

    End With
  End Sub

  ''' <summary>If Net_Type is populated, then Collection_Equipment_Name must have the same value.
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Activities.Net_Type</item>
  '''   <item>Activities.Collection_Equipment_Name</item>
  ''' </list>
  ''' </summary>
  Private Sub ERR03(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If Not .IsNull("Net_Type") AndAlso Not .IsNull("Collection_Equipment_Name") AndAlso
          Efd.package.Tables("rt_equipment_type").Select(String.Format("equipment_type='{0}' and equipment_type_desc='{1}'", .Item("Collection_Equipment_Name").ToString.Replace("'", "''"), .Item("Net_Type").ToString.Replace("'", "''"))).Length = 0 Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Collection_Equipment_Name"), EddErrors.CustomError21)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Collection_Equipment_Name"), EddErrors.CustomError21)
      End If
    End With
  End Sub

  ''' <summary>If County_Code is populated, then State_Code is required.
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Organization.State_Code</item>
  '''   <item>Organization.County_Code</item>
  '''   <item>Locations.State_Code</item>
  '''   <item>Locations.County_Code</item>
  ''' </list>
  ''' </summary>
  Private Sub ERR04(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .IsNull("State_Code") AndAlso Not .IsNull("County_Code") Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("State_Code"), EddErrors.Required)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("State_Code"), EddErrors.Required)
      End If
    End With
  End Sub
    ' Next two items removed from the following summary Applies to section
    ''''   <item>PrjMonitorLocationWeight.LocationWeightingFactorMeasureValue</item>
    ''''   <item>PrjMonitorLocationWeight.LocationWeightingFactorMeasureUnitCode</item>
    ''' <summary>If the measurement value field or the measurement unit field is populated, then the other one is required.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Locations.Well_Hole_Depth</item>
    '''   <item>Locations.Well_Hole_Depth_Unit</item>
    '''   <item>Locations.Contributing_Area</item>
    '''   <item>Locations.Contributing_Area_Unit</item>
    '''   <item>Locations.Drainage_Area</item>
    '''   <item>Locations.Drainage_Area_Unit</item>
    '''   <item>Activities.Activity_Depth</item>
    '''   <item>Activities.Activity_Depth_Unit</item>
    '''   <item>Activities.Activity_Upper_Depth</item>
    '''   <item>Activities.Activity_Lower_Depth</item>
    '''   <item>Activities.Collection_Duration</item>
    '''   <item>Activities.Collection_Duration_Unit</item>
    '''   <item>Activities.Reach_Length</item>
    '''   <item>Activities.Reach_Length_Unit</item>
    '''   <item>Activities.Reach_Width</item>
    '''   <item>Activities.Reach_Width_Unit</item>
    '''   <item>Activities.Boat_Speed</item>
    '''   <item>Activities.Boat_Speed_Unit</item>
    '''   <item>Activities.Current_Speed</item>
    '''   <item>Activities.Current_Speed_Unit</item>
    '''   <item>Activities.Container_Size</item>
    '''   <item>Activities.Container_Size_Unit</item>
    '''   <item>Activities.Collection_Effort</item>
    '''   <item>Activities.Collection_Effort_Gear_Type</item>
    '''   <item>Metrics.Metric_Value</item>
    '''   <item>Metrics.Metric_Value_Unit</item>
    '''   <item>Results.Result_Depth_Height_Measure</item>
    '''   <item>Results.Result_Depth_Height_Measure_Unit</item>
    '''   <item>Results.Group_Summary_Count_or_Weight</item>
    '''   <item>Results.Group_Summary_Count_or_Weight_Unit</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR05(ByVal e As System.Data.DataColumnChangeEventArgs, ByVal valueColumn As String, ByVal unitColumn As String)
    With e.Row
      If .IsNull(valueColumn) AndAlso Not .IsNull(unitColumn) Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item(valueColumn), EddErrors.Required)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item(valueColumn), EddErrors.Required)
      End If

      If .IsNull(unitColumn) AndAlso Not .IsNull(valueColumn) Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item(unitColumn), EddErrors.Required)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item(unitColumn), EddErrors.Required)
      End If
    End With
  End Sub
  ''' <summary>If Activity_Depth_Unit is populated, then the Activity_Depth or Activity_Upper_Depth and Activity_Lower_Depth is required.
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Activity_Depth_Unit</item>
  '''   <item>Activity_Depth</item>
  '''   <item>Activity_Upper_Depth</item>
  '''   <item>Activity_Lower_Depth</item>
  ''' </list>
  ''' </summary>
  Private Sub ERR85(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If Not .IsNull("Activity_Depth_Unit") Then
        If .IsNull("Activity_Depth") AndAlso Not .IsNull("Activity_Lower_Depth") AndAlso Not .IsNull("Activity_Upper_Depth") Then
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_Depth"), EddErrors.CustomError85)
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_Upper_Depth"), EddErrors.CustomError85)
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_Lower_Depth"), EddErrors.CustomError85)
        ElseIf Not .IsNull("Activity_Depth") AndAlso .IsNull("Activity_Upper_Depth") AndAlso .IsNull("Activity_Lower_Depth") Then
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_Depth"), EddErrors.CustomError85)
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_Upper_Depth"), EddErrors.CustomError85)
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_Lower_Depth"), EddErrors.CustomError85)
        Else
          Me.AddError(e.Row, e.Row.Table.Columns.Item("Activity_Depth"), EddErrors.CustomError85)
          Me.AddError(e.Row, e.Row.Table.Columns.Item("Activity_Upper_Depth"), EddErrors.CustomError85)
          Me.AddError(e.Row, e.Row.Table.Columns.Item("Activity_Lower_Depth"), EddErrors.CustomError85)
        End If
      Else

      End If
    End With
  End Sub

    ''' <summary>Check if value has a remap or is a valid value.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Metric.Metric_ID</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR06(ByVal e As System.Data.DataColumnChangeEventArgs)
        With e.Row
            If Not .IsNull(e.Column) AndAlso Efd.package.Tables.Item("rt_remap_detail").Select(String.Format("external_field='{0}' and external_value='{1}' and remap_code='WQX' and status_flag='A'", e.Column.ColumnName, e.Row.Item(e.Column))).Length = 0 Then
                'Me.AddError(e.Row, e.Column, EddErrors.Required)
            Else
                Me.RemoveError(e.Row, e.Column, EddErrors.ValidValue)
            End If
        End With
    End Sub
    ''' <summary>If Alternate_Location_ID or Alternate_Location_ID_Context is populated, then the other is required.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Locations.Alternate_Location_ID</item>
    '''   <item>Locations.Alternate_Location_ID_Context</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR07(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .IsNull(Locations_.Alternate_Location_ID) AndAlso Not .IsNull(Locations_.Alternate_Location_ID_Context) Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item(Locations_.Alternate_Location_ID), EddErrors.Required)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item(Locations_.Alternate_Location_ID), EddErrors.Required)
      End If

      If .IsNull(Locations_.Alternate_Location_ID_Context) AndAlso Not .IsNull(Locations_.Alternate_Location_ID) Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item(Locations_.Alternate_Location_ID_Context), EddErrors.Required)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item(Locations_.Alternate_Location_ID_Context), EddErrors.Required)
      End If
    End With
  End Sub

  ''' <summary>If Lat_Lon_Method='INTERPOLATION MAP', then Source_Map_Scale_Numeric is required.
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Locations.Source_Map_Scale_Numeric</item>
  '''   <item>Locations.Lat_Lon_Method</item>
  '''   <item>ActivitySites.Source_Map_Scale_Numeric</item>
  '''   <item>ActivitySites.Lat_Lon_Method</item>
  ''' </list>
  ''' </summary>
  Private Sub ERR08(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .IsNull("Source_Map_Scale_Numeric") AndAlso .Item("Lat_Lon_Method").ToString.ToUpper = "INTERPOLATION MAP" Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Source_Map_Scale_Numeric"), EddErrors.CustomError6)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Source_Map_Scale_Numeric"), EddErrors.CustomError6)
      End If
    End With
  End Sub

    ''' <summary>If Elevation is populated, then Elevation_Unit, Elevation_Method, and Elevation_Datum are required.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Locations.Elevation</item>
    '''   <item>Locations.Elevation_Unit</item>
    '''   <item>Locations.Elevation_Method</item>
    '''   <item>Locations.Elevation_Datum</item>
    '''   <item>ActivitySites.Elevation</item>
    '''   <item>ActivitySites.Elevation_Unit</item>
    '''   <item>ActivitySites.Elevation_Method</item>
    '''   <item>ActivitySites.Elevation_Datum</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR09(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If Not .IsNull("Elevation") Then
        If .IsNull("Elevation_Unit") Then
          Me.AddError(e.Row, e.Row.Table.Columns.Item("Elevation_Unit"), EddErrors.Required)
        Else
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Elevation_Unit"), EddErrors.Required)
        End If

        If .IsNull("Elevation_Method") Then
          Me.AddError(e.Row, e.Row.Table.Columns.Item("Elevation_Method"), EddErrors.Required)
        Else
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Elevation_Method"), EddErrors.Required)
        End If

        If .IsNull("Elevation_Datum") Then
          Me.AddError(e.Row, e.Row.Table.Columns.Item("Elevation_Datum"), EddErrors.Required)
        Else
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Elevation_Datum"), EddErrors.Required)
        End If

      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Elevation_Unit"), EddErrors.Required)
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Elevation_Method"), EddErrors.Required)
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Elevation_Datum"), EddErrors.Required)
      End If
    End With
  End Sub

  ''' <summary>If Aquifer_Name or Formation_Type is populated, then Well_Type is required.
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Locations.Aquifer_Name</item>
  '''   <item>Locations.Formation_Type</item>
  '''   <item>Locations.Well_Type</item>
  ''' </list>
  ''' </summary>
  Private Sub ERR10(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .IsNull("Well_Type") AndAlso (Not .IsNull("Aquifer_Name") OrElse Not .IsNull("Formation_Type")) Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Well_Type"), EddErrors.Required)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Well_Type"), EddErrors.Required)
      End If
    End With
  End Sub

  ''' <summary>If Preparation_Method_ID, Preparation_Method_ID_Context or Preparation_Method_Name is populated, then the others are required.
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Activities.Preparation_Method_ID</item>
  '''   <item>Activities.Preparation_Method_ID_Context</item>
  '''   <item>Activities.Preparation_Method_Name</item>
  ''' </list>
  ''' </summary>
  Private Sub ERR11(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .IsNull("Preparation_Method_ID") AndAlso (Not .IsNull("Preparation_Method_ID_Context") OrElse Not .IsNull("Preparation_Method_Name")) Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Preparation_Method_ID"), EddErrors.Required)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Preparation_Method_ID"), EddErrors.Required)
      End If

      If .IsNull("Preparation_Method_ID_Context") AndAlso (Not .IsNull("Preparation_Method_ID") OrElse Not .IsNull("Preparation_Method_Name")) Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Preparation_Method_ID_Context"), EddErrors.Required)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Preparation_Method_ID_Context"), EddErrors.Required)
      End If

      If .IsNull("Preparation_Method_Name") AndAlso (Not .IsNull("Preparation_Method_ID_Context") OrElse Not .IsNull("Preparation_Method_ID")) Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Preparation_Method_Name"), EddErrors.Required)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Preparation_Method_Name"), EddErrors.Required)
      End If
    End With
  End Sub

    ' <summary>If Activity_Start_Time_Zone or Activity_End_Date is populated, then Activity_Start_Time is required.
    ' Applies to:
    ' <list type="bullet">
    '   <item>Activities.Activity_Start_Time</item>
    '   <item>Activities.Activity_Start_Time_Zone</item>
    '   <item>Activities.Activity_End_Date</item>
    ' </list>
    ' </summary>
    '  Private Sub ERR12(ByVal e As System.Data.DataColumnChangeEventArgs)
    '      With e.Row
    '          If .IsNull("Activity_Start_Time") AndAlso (Not .IsNull("Activity_Start_Time_Zone") OrElse Not .IsNull("Activity_End_Date")) Then
    '              Me.AddError(e.Row, e.Row.Table.Columns.Item("Activity_Start_Time"), EddErrors.Required)
    '         Else
    '            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_Start_Time"), EddErrors.Required)
    '        End If
    '    End With
    'End Sub

    ' <summary>If Activity_Start_Time or Activity_End_Date is populated, then Activity_Start_Time_Zone is required.
    ' Applies to:
    ' <list type="bullet">
    '   <item>Activities.Activity_Start_Time</item>
    '   <item>Activities.Activity_Start_Time_Zone</item>
    '   <item>Activities.Activity_End_Date</item>
    ' </list>
    ' </summary>
    'Private Sub ERR13(ByVal e As System.Data.DataColumnChangeEventArgs)
    '    With e.Row
    '        If .IsNull("Activity_Start_Time_Zone") AndAlso (Not .IsNull("Activity_Start_Time") OrElse Not .IsNull("Activity_End_Date")) Then
    '            Me.AddError(e.Row, e.Row.Table.Columns.Item("Activity_Start_Time_Zone"), EddErrors.Required)
    '        Else
    '            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_Start_Time_Zone"), EddErrors.Required)
    '        End If
    '    End With
    'End Sub

    'Case32816_20090831 : Removed ERR14 & ERR15 because Activity_Relative_Depth does not seem to be associated with the end date/time
    ' <summary>If Activity_End_Time_Zone or Activity_Relative_Depth is populated, then Activity_End_Time is required.
    ' Applies to:
    ' <list type="bullet">
    '   <item>Activities.Activity_End_Time</item>
    '   <item>Activities.Activity_End_Time_Zone</item>
    '   <item>Activities.Activity_Relative_Depth</item>
    ' </list>
    ' </summary>
    'Private Sub ERR14(ByVal e As System.Data.DataColumnChangeEventArgs)
    '  With e.Row
    '    If .IsNull("Activity_End_Time") AndAlso (Not .IsNull("Activity_End_Time_Zone") OrElse Not .IsNull("Activity_Relative_Depth")) Then
    '      Me.AddError(e.Row, e.Row.Table.Columns.Item("Activity_End_Time"), EddErrors.Required)
    '    Else
    '      Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_End_Time"), EddErrors.Required)
    '    End If
    '  End With
    'End Sub

    'Case32816_20090831 : Removed ERR14 & ERR15 because Activity_Relative_Depth does not seem to be associated with the end date/time
    ' <summary>If Activity_End_Time or Activity_Relative_Depth is populated, then Activity_End_Time_Zone is required.
    ' Applies to:
    ' <list type="bullet">
    '   <item>Activities.Activity_End_Time</item>
    '   <item>Activities.Activity_End_Time_Zone</item>
    '   <item>Activities.Activity_Relative_Depth</item>
    ' </list>
    ' </summary>
    'Private Sub ERR15(ByVal e As System.Data.DataColumnChangeEventArgs)
    '  With e.Row
    '    If .IsNull("Activity_End_Time_Zone") AndAlso (Not .IsNull("Activity_End_Time") OrElse Not .IsNull("Activity_Relative_Depth")) Then
    '      Me.AddError(e.Row, e.Row.Table.Columns.Item("Activity_End_Time_Zone"), EddErrors.Required)
    '    Else
    '      Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_End_Time_Zone"), EddErrors.Required)
    '    End If
    '  End With
    'End Sub

    ''' <summary>If Preparation_Method_ID is populated then Container_Type, Container_Color and Transport_Storage_Description are required.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Activities.Preparation_Method_ID</item>
    '''   <item>Activities.Container_Type</item>
    '''   <item>Activities.Container_Color</item>
    '''   <item>Activities.Transport_Storage_Description</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR16(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If Not .IsNull("Preparation_Method_ID") Then

        If .IsNull("Container_Type") Then
          Me.AddError(e.Row, e.Row.Table.Columns.Item("Container_Type"), EddErrors.Required)
        Else
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Container_Type"), EddErrors.Required)
        End If

        If .IsNull("Container_Color") Then
          Me.AddError(e.Row, e.Row.Table.Columns.Item("Container_Color"), EddErrors.Required)
        Else
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Container_Color"), EddErrors.Required)
        End If

        If .IsNull("Transport_Storage_Description") Then
          Me.AddError(e.Row, e.Row.Table.Columns.Item("Transport_Storage_Description"), EddErrors.Required)
        Else
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Transport_Storage_Description"), EddErrors.Required)
        End If

      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Container_Type"), EddErrors.Required)
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Container_Color"), EddErrors.Required)
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Transport_Storage_Description"), EddErrors.Required)
      End If

    End With
  End Sub

    ''' <summary>'If Preparation_Method_ID, Preparation_Method_ID_Context, or Preparation_Method_Name is populated then either Chemical_Preservative or Thermal_Preservative must be populated. 
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Activities.Preparation_Method_ID</item>
    '''   <item>Activities.Preparation_Method_ID_Context</item>
    '''   <item>Activities.Preparation_Method_Name</item>
    '''   <item>Activities.Chemical_Preservative</item>
    '''   <item>Activities.Thermal_Preservative</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR17(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      'If Not .IsNull("Preparation_Method_ID") OrElse Not .IsNull("Preparation_Method_ID_Context") OrElse Not .IsNull("Preparation_Method_Name") Then
      If Not .IsNull("Preparation_Method_ID") Then
        If .IsNull("Chemical_Preservative") AndAlso .IsNull("Thermal_Preservative") Then
          Me.AddError(e.Row, e.Row.Table.Columns.Item("Chemical_Preservative"), EddErrors.CustomError5)
          Me.AddError(e.Row, e.Row.Table.Columns.Item("Thermal_Preservative"), EddErrors.CustomError5)
        Else
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Chemical_Preservative"), EddErrors.CustomError5)
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Thermal_Preservative"), EddErrors.CustomError5)
        End If

      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Chemical_Preservative"), EddErrors.CustomError5)
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Thermal_Preservative"), EddErrors.CustomError5)
      End If

    End With
  End Sub

  ''' <summary>If Latitude or Longitude is populated then the other one is required.
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>ActivitySites.Latitude</item>
  '''   <item>ActivitySites.Longitude</item>
  ''' </list>
  ''' </summary>
  Private Sub ERR18(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .IsNull("Latitude") AndAlso Not .IsNull("Longitude") Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Latitude"), EddErrors.Required)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Latitude"), EddErrors.Required)
      End If

      If .IsNull("Longitude") AndAlso Not .IsNull("Latitude") Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Longitude"), EddErrors.Required)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Longitude"), EddErrors.Required)
      End If
    End With
  End Sub

  ''' <summary>Assemblage_Sampled_Name is required if Medium="Biological".
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Activities.Assemblage_Sampled_Name</item>
  '''   <item>Activities.Medium</item>
  ''' </list>
  ''' </summary>
  Private Sub ERR19(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .IsNull("Assemblage_Sampled_Name") AndAlso .Item("Medium").ToString.ToLower = "biological" Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Assemblage_Sampled_Name"), EddErrors.CustomError1)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Assemblage_Sampled_Name"), EddErrors.CustomError1)
      End If
    End With
  End Sub

  ''' <summary>If Activity_Type contains 'Sample', then Collection_Method_ID is required.
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Activities.Collection_Method_ID</item>
  '''   <item>Activities.Activity_Type</item>
  ''' </list>
  ''' </summary>
  Private Sub ERR20(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .IsNull("Collection_Method_ID") AndAlso .Item("Activity_Type").ToString.ToUpper.Contains("SAMPLE") Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Collection_Method_ID"), EddErrors.CustomError22)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Collection_Method_ID"), EddErrors.CustomError22)
      End If
    End With
  End Sub

  ''' <summary>Lat_Lon_Method and Lat_Lon_Datum are required if Latitude or Longitude is populated.
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>ActivitySites.Lat_Lon_Method</item>
  '''   <item>ActivitySites.Lat_Lon_Datum</item>
  '''   <item>ActivitySites.Latitude</item>
  '''   <item>ActivitySites.Longitude</item>
  ''' </list>
  ''' </summary>
  Private Sub ERR21(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If Not .IsNull("Latitude") AndAlso Not .IsNull("Longitude") Then
        If .IsNull("Lat_Lon_Method") Then
          Me.AddError(e.Row, e.Row.Table.Columns.Item("Lat_Lon_Method"), EddErrors.Required)
        Else
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Lat_Lon_Method"), EddErrors.Required)
        End If

        If .IsNull("Lat_Lon_Datum") Then
          Me.AddError(e.Row, e.Row.Table.Columns.Item("Lat_Lon_Datum"), EddErrors.Required)
        Else
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Lat_Lon_Datum"), EddErrors.Required)
        End If

      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Lat_Lon_Method"), EddErrors.Required)
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Source_Map_Scale_Numeric"), EddErrors.Required)
      End If
    End With
  End Sub

    ''' <summary>If Result_Detection_Condition is 'Detected and Quantified', then Result_Text is required otherwise Result_Text must be empty.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Results.Result_Text</item>
    '''   <item>Results.Result_Detection_Condition</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR22(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .IsNull("Result_Detection_Condition") Then
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Result_Text"), EddErrors.CustomError7)
        Exit Sub
      End If

      Dim IsRequired As Boolean = False
      Dim resultDetect As String = .Item("Result_Detection_Condition").ToString.ToLower
      Select Case resultDetect
        Case "detected and quantified"
          IsRequired = True
      End Select

      If .IsNull("Result_Text") AndAlso IsRequired Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Result_Text"), EddErrors.CustomError7)
      ElseIf Not .IsNull("Result_Text") AndAlso Not IsRequired Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Result_Text"), EddErrors.CustomError7)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Result_Text"), EddErrors.CustomError7)
      End If

      'No longer using 'Y'/'N' values, use original values and do a remap on the Create
      'If .Item("Result_Detection_Condition").ToString.ToUpper = "Y" AndAlso .IsNull("Result_Text") Then
      '  Me.AddError(e.Row, e.Row.Table.Columns.Item("Result_Text"), EddErrors.CustomError7)
      'ElseIf .Item("Result_Detection_Condition").ToString.ToUpper = "N" AndAlso Not .IsNull("Result_Text") Then
      '  Me.AddError(e.Row, e.Row.Table.Columns.Item("Result_Text"), EddErrors.CustomError7)
      'Else
      '  Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Result_Text"), EddErrors.CustomError7)
      'End If
    End With
  End Sub

  ''' <summary>If Net_Type, Net_Surface_Area, Net_Surface_Area_Unit, Net_Mesh_Size or Net_Mesh_Size_Unit is populated, then the others are required.
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Activities.Net_Type</item>
  '''   <item>Activities.Net_Surface_Area</item>
  '''   <item>Activities.Net_Surface_Area_Unit</item>
  '''   <item>Activities.Net_Mesh_Size</item>
  '''   <item>Activities.Net_Mesh_Size_Unit</item>
  ''' </list>
  ''' </summary>
  Private Sub ERR23(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .IsNull("Net_Type") AndAlso (Not .IsNull("Net_Surface_Area") OrElse Not .IsNull("Net_Surface_Area_Unit") _
        OrElse Not .IsNull("Net_Mesh_Size") OrElse Not .IsNull("Net_Mesh_Size_Unit")) Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Net_Type"), EddErrors.CustomError2)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Net_Type"), EddErrors.CustomError2)
      End If

      If .IsNull("Net_Surface_Area") AndAlso (Not .IsNull("Net_Type") OrElse Not .IsNull("Net_Surface_Area_Unit") _
        OrElse Not .IsNull("Net_Mesh_Size") OrElse Not .IsNull("Net_Mesh_Size_Unit")) Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Net_Surface_Area"), EddErrors.CustomError2)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Net_Surface_Area"), EddErrors.CustomError2)
      End If
      If .IsNull("Net_Surface_Area_Unit") AndAlso (Not .IsNull("Net_Surface_Area") OrElse Not .IsNull("Net_Type") _
       OrElse Not .IsNull("Net_Mesh_Size") OrElse Not .IsNull("Net_Mesh_Size_Unit")) Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Net_Surface_Area_Unit"), EddErrors.CustomError2)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Net_Surface_Area_Unit"), EddErrors.CustomError2)
      End If

      If .IsNull("Net_Mesh_Size") AndAlso (Not .IsNull("Net_Surface_Area") OrElse Not .IsNull("Net_Surface_Area_Unit") _
            OrElse Not .IsNull("Net_Type") OrElse Not .IsNull("Net_Mesh_Size_Unit")) Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Net_Mesh_Size"), EddErrors.CustomError2)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Net_Mesh_Size"), EddErrors.CustomError2)
      End If

      If .IsNull("Net_Mesh_Size_Unit") AndAlso (Not .IsNull("Net_Surface_Area") OrElse Not .IsNull("Net_Surface_Area_Unit") _
            OrElse Not .IsNull("Net_Mesh_Size") OrElse Not .IsNull("Net_Type")) Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Net_Mesh_Size_Unit"), EddErrors.CustomError2)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Net_Mesh_Size_Unit"), EddErrors.CustomError2)
      End If
    End With
  End Sub

    ''' <summary>Result_Unit and Result_Type are required if Result_Text is numeric.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Results.Result_Unit</item>
    '''   <item>Results.Result_Type</item>
    '''   <item>Results.Result_Text</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR24(ByVal e As System.Data.DataColumnChangeEventArgs)
    Dim result As Double
    With e.Row
      If Double.TryParse(.Item("Result_Text").ToString, result) Then
        If .IsNull("Result_Unit") Then
          Me.AddError(e.Row, e.Row.Table.Columns.Item("Result_Unit"), EddErrors.Required)
        Else
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Result_Unit"), EddErrors.Required)
        End If

        If .IsNull("Result_Type") Then
          Me.AddError(e.Row, e.Row.Table.Columns.Item("Result_Type"), EddErrors.Required)
        Else
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Result_Type"), EddErrors.Required)
        End If

      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Result_Unit"), EddErrors.Required)
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Result_Type"), EddErrors.Required)
      End If
      'Check to see if choice list characteristic in which case Result_Unit and Result_Type not required
      Dim charName As String = .Item("Characteristic_Name").ToString.Trim
      'Use regular expression instead of charName.EndsWith in case the value does or does not contain parenthesis (ie 'Choice List' vs '(Choice List)')
      If System.Text.RegularExpressions.Regex.IsMatch(charName, ".+(?i)(\(?choice list\)?)") Then
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Result_Unit"), EddErrors.Required)
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Result_Type"), EddErrors.Required)
      End If
    End With
  End Sub

  ''' <summary>Boat_Speed is required if Net_Type='Net/Horizontal Tow'. 
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Activities.Boat_Speed</item>
  '''   <item>Activities.Net_Type</item>
  ''' </list>
  ''' </summary>
  Private Sub ERR25(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .IsNull("Boat_Speed") AndAlso .Item("Net_Type").ToString.ToLower = "net/horizontal tow" Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Boat_Speed"), EddErrors.CustomError3)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Boat_Speed"), EddErrors.CustomError3)
      End If
    End With
  End Sub

    ''' <summary>If Result_Text is populated, then Result_Status is required. 
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Results.Result_Status</item>
    '''   <item>Results.Result_Text</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR26(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .IsNull("Result_Status") AndAlso Not .IsNull("Result_Text") Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Result_Status"), EddErrors.Required)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Result_Status"), EddErrors.Required)
      End If
    End With
  End Sub

  ''' <summary>If Collection_Method_ID, Collection_Method_ID_Context or Collection_Method_Name is populated, then the others are required.
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Activities.Collection_Method_ID</item>
  '''   <item>Activities.Collection_Method_ID_Context</item>
  '''   <item>Activities.Collection_Method_Name</item>
  ''' </list>
  ''' </summary>
  Private Sub ERR27(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .IsNull("Collection_Method_ID") AndAlso (Not .IsNull("Collection_Method_ID_Context") OrElse Not .IsNull("Collection_Method_Name")) Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Collection_Method_ID"), EddErrors.Required)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Collection_Method_ID"), EddErrors.Required)
      End If

      If .IsNull("Collection_Method_ID_Context") AndAlso (Not .IsNull("Collection_Method_ID") OrElse Not .IsNull("Collection_Method_Name")) Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Collection_Method_ID_Context"), EddErrors.Required)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Collection_Method_ID_Context"), EddErrors.Required)
      End If

      If .IsNull("Collection_Method_Name") AndAlso (Not .IsNull("Collection_Method_ID") OrElse Not .IsNull("Collection_Method_ID_Context")) Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Collection_Method_Name"), EddErrors.Required)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Collection_Method_Name"), EddErrors.Required)
      End If
    End With
  End Sub

  ''' <summary>If Collection_Method_ID is populated, then Collection_Equipment_Name is required.
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Activities.Collection_Method_ID</item>
  '''   <item>Activities.Collection_Equipment_Name</item>
  ''' </list>
  ''' </summary>
  Private Sub ERR28(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .IsNull("Collection_Equipment_Name") AndAlso Not .IsNull("Collection_Method_ID") Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Collection_Equipment_Name"), EddErrors.Required)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Collection_Equipment_Name"), EddErrors.Required)
      End If
    End With
  End Sub

    ''' <summary>If Biological_Intent='Group Summary', then Group_Summary_Count_or_Weight is required.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Results.Biological_Intent</item>
    '''   <item>Results.Group_Summary_Count_or_Weight</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR29(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .Item(Results_.Biological_Intent).ToString.ToUpper = "GROUP SUMMARY" AndAlso .IsNull(Results_.Group_Summary_Count_or_Weight) Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item(Results_.Group_Summary_Count_or_Weight), EddErrors.CustomError8)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item(Results_.Group_Summary_Count_or_Weight), EddErrors.CustomError8)
      End If
    End With
  End Sub

    ''' <summary>If Frequency_Class_Descriptor_1='Measured Characteristic', then Frequency_Class_Bounds_Unit_1, Frequency_Class_Lower_Bound_1, and Frequency_Class_Upper_Bound are required.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Results.Frequency_Class_Descriptor_1</item>
    '''   <item>Results.Frequency_Class_Bounds_Unit_1</item>
    '''   <item>Results.Frequency_Class_Lower_Bound_1</item>
    '''   <item>Results.Frequency_Class_Upper_Bound_1</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR30(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If Not .IsNull(Results_.Frequency_Class_Descriptor_1) Then
        If GetFrequencyType(e.Row, "Frequency_Class_Descriptor_1").ToString.ToUpper = "MEASURED CHARACTERISTIC" Then

          If .IsNull(Results_.Frequency_Class_Bounds_Unit_1) Then
            Me.AddError(e.Row, e.Row.Table.Columns.Item(Results_.Frequency_Class_Bounds_Unit_1), EddErrors.Required)
          Else
            Me.RemoveError(e.Row, e.Row.Table.Columns.Item(Results_.Frequency_Class_Bounds_Unit_1), EddErrors.Required)
          End If

          If .IsNull(Results_.Frequency_Class_Lower_Bound_1) Then
            Me.AddError(e.Row, e.Row.Table.Columns.Item(Results_.Frequency_Class_Lower_Bound_1), EddErrors.Required)
          Else
            Me.RemoveError(e.Row, e.Row.Table.Columns.Item(Results_.Frequency_Class_Lower_Bound_1), EddErrors.Required)
          End If

          If .IsNull(Results_.Frequency_Class_Upper_Bound_1) Then
            Me.AddError(e.Row, e.Row.Table.Columns.Item(Results_.Frequency_Class_Upper_Bound_1), EddErrors.Required)
          Else
            Me.RemoveError(e.Row, e.Row.Table.Columns.Item(Results_.Frequency_Class_Upper_Bound_1), EddErrors.Required)
          End If

        Else
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item(Results_.Frequency_Class_Bounds_Unit_1), EddErrors.Required)
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item(Results_.Frequency_Class_Lower_Bound_1), EddErrors.Required)
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item(Results_.Frequency_Class_Upper_Bound_1), EddErrors.Required)
        End If
      End If
    End With
  End Sub

    ''' <summary>If Frequency_Class_Descriptor_2='Measured Characteristic', then Frequency_Class_Bounds_Unit_2, Frequency_Class_Lower_Bound_2, and Frequency_Class_Upper_Bound_2 are required.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Results.Frequency_Class_Descriptor_2</item>
    '''   <item>Results.Frequency_Class_Bounds_Unit_2</item>
    '''   <item>Results.Frequency_Class_Lower_Bound_2</item>
    '''   <item>Results.Frequency_Class_Upper_Bound_2</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR31(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If Not .IsNull(Results_.Frequency_Class_Descriptor_2) Then
        If GetFrequencyType(e.Row, "Frequency_Class_Descriptor_2").ToString.ToUpper = "MEASURED CHARACTERISTIC" Then

          If .IsNull(Results_.Frequency_Class_Bounds_Unit_2) Then
            Me.AddError(e.Row, e.Row.Table.Columns.Item(Results_.Frequency_Class_Bounds_Unit_2), EddErrors.Required)
          Else
            Me.RemoveError(e.Row, e.Row.Table.Columns.Item(Results_.Frequency_Class_Bounds_Unit_2), EddErrors.Required)
          End If

          If .IsNull(Results_.Frequency_Class_Lower_Bound_2) Then
            Me.AddError(e.Row, e.Row.Table.Columns.Item(Results_.Frequency_Class_Lower_Bound_2), EddErrors.Required)
          Else
            Me.RemoveError(e.Row, e.Row.Table.Columns.Item(Results_.Frequency_Class_Lower_Bound_2), EddErrors.Required)
          End If

          If .IsNull(Results_.Frequency_Class_Upper_Bound_2) Then
            Me.AddError(e.Row, e.Row.Table.Columns.Item(Results_.Frequency_Class_Upper_Bound_2), EddErrors.Required)
          Else
            Me.RemoveError(e.Row, e.Row.Table.Columns.Item(Results_.Frequency_Class_Upper_Bound_2), EddErrors.Required)
          End If

        Else
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item(Results_.Frequency_Class_Bounds_Unit_2), EddErrors.Required)
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item(Results_.Frequency_Class_Lower_Bound_2), EddErrors.Required)
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item(Results_.Frequency_Class_Upper_Bound_2), EddErrors.Required)
        End If
      End If
    End With
  End Sub

    ''' <summary>If Frequency_Class_Descriptor_3='Measured Characteristic', then Frequency_Class_Bounds_Unit_3, Frequency_Class_Lower_Bound_3, and Frequency_Class_Upper_Bound_3 are required.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Results.Frequency_Class_Descriptor_3</item>
    '''   <item>Results.Frequency_Class_Bounds_Unit_3</item>
    '''   <item>Results.Frequency_Class_Lower_Bound_3</item>
    '''   <item>Results.Frequency_Class_Upper_Bound_3</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR32(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If Not .IsNull(Results_.Frequency_Class_Descriptor_3) Then
        If GetFrequencyType(e.Row, "Frequency_Class_Descriptor_3").ToString.ToUpper = "MEASURED CHARACTERISTIC" Then

          If .IsNull(Results_.Frequency_Class_Bounds_Unit_3) Then
            Me.AddError(e.Row, e.Row.Table.Columns.Item(Results_.Frequency_Class_Bounds_Unit_3), EddErrors.Required)
          Else
            Me.RemoveError(e.Row, e.Row.Table.Columns.Item(Results_.Frequency_Class_Bounds_Unit_3), EddErrors.Required)
          End If

          If .IsNull(Results_.Frequency_Class_Lower_Bound_3) Then
            Me.AddError(e.Row, e.Row.Table.Columns.Item(Results_.Frequency_Class_Lower_Bound_3), EddErrors.Required)
          Else
            Me.RemoveError(e.Row, e.Row.Table.Columns.Item(Results_.Frequency_Class_Lower_Bound_3), EddErrors.Required)
          End If

          If .IsNull(Results_.Frequency_Class_Upper_Bound_3) Then
            Me.AddError(e.Row, e.Row.Table.Columns.Item(Results_.Frequency_Class_Upper_Bound_3), EddErrors.Required)
          Else
            Me.RemoveError(e.Row, e.Row.Table.Columns.Item(Results_.Frequency_Class_Upper_Bound_3), EddErrors.Required)
          End If

        Else
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item(Results_.Frequency_Class_Bounds_Unit_3), EddErrors.Required)
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item(Results_.Frequency_Class_Lower_Bound_3), EddErrors.Required)
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item(Results_.Frequency_Class_Upper_Bound_3), EddErrors.Required)
        End If
      End If
    End With
  End Sub

    ''' <summary>Frequency_Class_Descriptor_1 is required if Frequency_Class_Bounds_Unit_1, Frequency_Class_Lower_Bound_1, or Frequency_Class_Upper_Bound_1 is populated.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Results.Frequency_Class_Descriptor_1</item>
    '''   <item>Results.Frequency_Class_Bounds_Unit_1</item>
    '''   <item>Results.Frequency_Class_Lower_Bound_1</item>
    '''   <item>Results.Frequency_Class_Upper_Bound_1</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR33(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .IsNull("Frequency_Class_Descriptor_1") AndAlso (Not .IsNull("Frequency_Class_Bounds_Unit_1") _
      OrElse Not .IsNull("Frequency_Class_Lower_Bound_1") OrElse Not .IsNull("Frequency_Class_Upper_Bound_1")) Then

        Me.AddError(e.Row, e.Row.Table.Columns.Item("Frequency_Class_Descriptor_1"), EddErrors.Required)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Frequency_Class_Descriptor_1"), EddErrors.Required)
      End If

    End With
  End Sub

    ''' <summary>Frequency_Class_Descriptor_2 is required if Frequency_Class_Bounds_Unit_2, Frequency_Class_Lower_Bound_2, or Frequency_Class_Upper_Bound_2 is populated.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Results.Frequency_Class_Descriptor_2</item>
    '''   <item>Results.Frequency_Class_Bounds_Unit_2</item>
    '''   <item>Results.Frequency_Class_Lower_Bound_2</item>
    '''   <item>Results.Frequency_Class_Upper_Bound_2</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR34(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .IsNull("Frequency_Class_Descriptor_2") AndAlso (Not .IsNull("Frequency_Class_Bounds_Unit_2") _
      OrElse Not .IsNull("Frequency_Class_Lower_Bound_2") OrElse Not .IsNull("Frequency_Class_Upper_Bound_2")) Then

        Me.AddError(e.Row, e.Row.Table.Columns.Item("Frequency_Class_Descriptor_2"), EddErrors.Required)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Frequency_Class_Descriptor_2"), EddErrors.Required)
      End If

    End With
  End Sub

    ''' <summary>Frequency_Class_Descriptor_3 is required if Frequency_Class_Bounds_Unit_3, Frequency_Class_Lower_Bound_3, or Frequency_Class_Upper_Bound_3 is populated.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Results.Frequency_Class_Descriptor_3</item>
    '''   <item>Results.Frequency_Class_Bounds_Unit_3</item>
    '''   <item>Results.Frequency_Class_Lower_Bound_3</item>
    '''   <item>Results.Frequency_Class_Upper_Bound_3</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR35(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .IsNull("Frequency_Class_Descriptor_3") AndAlso (Not .IsNull("Frequency_Class_Bounds_Unit_3") _
      OrElse Not .IsNull("Frequency_Class_Lower_Bound_3") OrElse Not .IsNull("Frequency_Class_Upper_Bound_3")) Then

        Me.AddError(e.Row, e.Row.Table.Columns.Item("Frequency_Class_Descriptor_3"), EddErrors.Required)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Frequency_Class_Descriptor_3"), EddErrors.Required)
      End If

    End With
  End Sub

    ' <summary>Analytical_Method_ID_Context is required if Analytical_Method_ID is populated.
    ' Applies to:
    ' <list type="bullet">
    '   <item>Results.Analytical_Method_ID_Context</item>
    '   <item>Results.Analytical_Method_ID</item>
    ' </list>
    ' </summary>
    'Private Sub ERR36(ByVal e As System.Data.DataColumnChangeEventArgs)
    '    With e.Row
    '        If .IsNull("Analytical_Method_ID_Context") AndAlso Not .IsNull("Analytical_Method_ID") Then
    '            Me.AddError(e.Row, e.Row.Table.Columns.Item("Analytical_Method_ID_Context"), EddErrors.Required)
    '        Else
    '            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Analytical_Method_ID_Context"), EddErrors.Required)
    '        End If
    '    End With
    'End Sub

    ' <summary>Analysis_Start_Time is required if Analysis_Start_Time_Zone or Analysis_End_Time is populated.
    ' Applies to:
    ' <list type="bullet">
    '   <item>Results.Analysis_Start_Time</item>
    '   <item>Results.Analysis_Start_Time_Zone</item>
    '   <item>Results.Analysis_End_Time</item>
    ' </list>
    ' </summary>
    ' Private Sub ERR37(ByVal e As System.Data.DataColumnChangeEventArgs)
    '     With e.Row
    '         If .IsNull("Analysis_Start_Time") AndAlso (Not .IsNull("Analysis_Start_Time_Zone") OrElse Not .IsNull("Analysis_End_Time")) Then
    '             Me.AddError(e.Row, e.Row.Table.Columns.Item("Analysis_Start_Time"), EddErrors.Required)
    '         Else
    '             Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Analysis_Start_Time"), EddErrors.Required)
    '         End If
    '     End With
    ' End Sub

    ' <summary>Analysis_Start_Time_Zone is required if Analysis_Start_Time or Analysis_End_Date is populated.
    ' Applies to:
    ' <list type="bullet">
    '   <item>Results.Analysis_Start_Time</item>
    '   <item>Results.Analysis_Start_Time_Zone</item>
    '   <item>Results.Analysis_End_Date</item>
    ' </list>
    ' </summary>
    'Private Sub ERR38(ByVal e As System.Data.DataColumnChangeEventArgs)
    '    With e.Row
    '        If .IsNull("Analysis_Start_Time_Zone") AndAlso (Not .IsNull("Analysis_Start_Time") OrElse Not .IsNull("Analysis_End_Date")) Then
    '            Me.AddError(e.Row, e.Row.Table.Columns.Item("Analysis_Start_Time_Zone"), EddErrors.Required)
    '        Else
    '            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Analysis_Start_Time_Zone"), EddErrors.Required)
    '        End If
    '    End With
    'End Sub

    ' <summary>If Analysis_End_Time or Analysis_End_Time_Zone is populated, then the other is required.
    ' Applies to:
    ' <list type="bullet">
    '   <item>Results.Analysis_End_Time</item>
    '   <item>Results.Analysis_End_Time_Zone</item>
    ' </list>
    ' </summary>
    'Private Sub ERR39(ByVal e As System.Data.DataColumnChangeEventArgs)
    '  With e.Row
    '    If .IsNull("Analysis_End_Time") AndAlso Not .IsNull("Analysis_End_Time_Zone") Then
    '      Me.AddError(e.Row, e.Row.Table.Columns.Item("Analysis_End_Time"), EddErrors.Required)
    '    Else
    '      Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Analysis_End_Time"), EddErrors.Required)
    '    End If

    '    If .IsNull("Analysis_End_Time_Zone") AndAlso Not .IsNull("Analysis_End_Time") Then
    '      Me.AddError(e.Row, e.Row.Table.Columns.Item("Analysis_End_Time_Zone"), EddErrors.Required)
    '    Else
    '      Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Analysis_End_Time_Zone"), EddErrors.Required)
    '    End If

    '  End With
    'End Sub
    ''' <summary>If Analysis_Start_Time or Analysis_Start_Time_Zone is populated, then the other is required.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Results.Analysis_Start_Time</item>
    '''   <item>Results.Analysis_Start_Time_Zone</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR77(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .IsNull("Analysis_Start_Time") AndAlso Not .IsNull("Analysis_Start_Time_Zone") Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Analysis_Start_Time"), EddErrors.Required)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Analysis_Start_Time"), EddErrors.Required)
      End If

      If .IsNull("Analysis_Start_Time_Zone") AndAlso Not .IsNull("Analysis_Start_Time") AndAlso Not .Item("Analysis_Start_Time").ToString.Equals("00:00:00") AndAlso Not .Item("Analysis_Start_Time").ToString.Equals("12:00:00 AM") Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Analysis_Start_Time_Zone"), EddErrors.Required)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Analysis_Start_Time_Zone"), EddErrors.Required)
      End If

    End With
  End Sub

    ''' <summary>Dates cannot precede Activity_Start_Date and Activity_Start_Time
    ''' Applies to:
    ''' <list type="bullet"> 
    '''   <item>Activity.Activity_Start_Date</item>
    '''   <item>Activity.Activity_Start_Time</item>
    '''   <item>Activity.Activity_End_Date</item>
    '''   <item>Activity.Activity_End_Time</item>
    '''   <item>Results.Analysis_Start_Date</item>
    '''   <item>Results.Analysis_Start_Time</item>
    ''' <item>Results.Lab_Sample_Preparation_Start_Date</item>
    ''' <item>Results.Lab_Sample_Preparation_Start_Time</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR79(ByVal e As System.Data.DataColumnChangeEventArgs, ByVal date_field As String, ByVal time_field As String, ByVal relation As EarthSoft.EDP.EddRelation)
    ' if for some reason we don't have sample/activity rows, just exit
    If Activities.Rows.Count <= 0 Then Return
    Dim activityDate As Date
    Dim resultDate As Date
    Dim resultDateStr As String

    With e.Row
      Try
        If (Me.SampleActivityRow Is Nothing) OrElse (Me.SampleActivityRow.RowState = DataRowState.Deleted) OrElse (Me.SampleActivityRow.RowState = DataRowState.Detached) OrElse (Not Me.SampleActivityRow.Item("Activity_ID").ToString.Equals(.Item("Activity_ID"))) Then
          ' use the relation to get the parent row for this sample
          Me.SampleActivityRow = relation.GetParentRow(e.Row)
          ' make sure it found the row
          If Me.SampleActivityRow Is Nothing Then
            Me.RemoveError(e.Row, .Table.Columns.Item(date_field), EarthSoft.EDP.EddErrors.CustomError79)
            Return
          End If
        End If

        If date_field.ToLower.EndsWith("_date") AndAlso time_field.ToLower.EndsWith("_time") AndAlso Not e.Row.IsNull(time_field) Then
          resultDateStr = String.Format("{0} {1}", .Item(date_field).ToString, .Item(time_field).ToString)
        Else
          resultDateStr = .Item(date_field).ToString
        End If

        'If date_field.ToLower.EndsWith("_date") AndAlso e.Row.Table.Columns.Contains(date_field.Substring(0, date_field.Length - 4) + "Time") _
        '  AndAlso Not e.Row.IsNull(date_field.Substring(0, date_field.Length - 4) + "Time") Then
        '    resultDateStr = String.Format("{0} {1}", .Item(date_field).ToString, .Item(date_field.Substring(0, date_field.Length - 4) + "Time"))
        'Else
        '    resultDateStr = .Item(date_field).ToString
        'End If

        If SampleActivityRow IsNot Nothing AndAlso Not .IsNull(date_field) AndAlso Date.TryParse(resultDateStr, resultDate) _
           AndAlso Not SampleActivityRow.IsNull("Activity_Start_Date") AndAlso Date.TryParse(String.Format("{0} {1}", SampleActivityRow.Item("Activity_Start_Date").ToString, SampleActivityRow.Item("Activity_Start_Time").ToString), activityDate) _
           AndAlso resultDate.CompareTo(activityDate) < 0 Then

          Me.AddError(e.Row, .Table.Columns.Item(date_field), EarthSoft.EDP.EddErrors.CustomError79)
          Me.AddError(e.Row, .Table.Columns.Item(time_field), EarthSoft.EDP.EddErrors.CustomError79)

        Else
          Me.RemoveError(e.Row, .Table.Columns.Item(date_field), EarthSoft.EDP.EddErrors.CustomError79)
          Me.RemoveError(e.Row, .Table.Columns.Item(time_field), EarthSoft.EDP.EddErrors.CustomError79)
        End If

      Catch ex As Exception
        'if date conversion doesn't work, we don't want error because comparison is moot.  Just move on...
      End Try
    End With
  End Sub

    ''' <summary>Check the Activities section to verify child rows in the Results or Metrics sections.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Activities</item>
    '''   <item>Metrics</item> 
    ''' </list>
    ''' </summary>
    Private Sub ERR80(row As System.Data.DataRow)
    'BHM_Case31495_20090309 : If RowState = Detached then an exception occurs
    If IsLoading OrElse row.RowState = System.Data.DataRowState.Detached Then Return

        ' make sure the sample/activity has a child row in either Results or Metrics
        ' NOTE: the relation names must exactly match the xs:keyref names in the *.xsd

        If IsCommentRow(row) OrElse (Me.Result.Rows.Count + Me.Metrics.Rows.Count) = 0 Then
            ' if there are no records in child table, then assume no results were loaded, so there is no error
            Me.RemoveError(row, EddErrors.CustomError80)
        ElseIf Me.Smp_Trs.GetChildRows(row).Length > 0 OrElse Me.Smp_Met.GetChildRows(row).Length > 0 Then
            ' if there is at least one child row in table, then there is no error
            Me.RemoveError(row, EddErrors.CustomError80)
        Else
            ' there are rows in a child table, but not a matching row
            Me.AddError(row, EddErrors.CustomError80)
    End If
  End Sub

    ' <summary>Analysis_Start_Date and Analysis_Start_Time must precede Analysis_End_Date and Analysis_End_Time.
    ' Applies to:
    ' <list type="bullet">
    '   <item>Results.Analysis_Start_Date</item>
    '   <item>Results.Analysis_Start_Time</item>
    '   <item>Results.Analysis_End_Date</item>
    '   <item>Results.Analysis_End_Time</item>
    ' </list>
    ' </summary>
    ' Private Sub ERR78(ByVal e As System.Data.DataColumnChangeEventArgs)
    '    With e.Row
    '       If Not .IsNull("Analysis_Start_Date") AndAlso Not .IsNull("Analysis_End_Date") Then
    'Dim dt1 As DateTime = .Item("Analysis_Start_Date")
    'Dim dtt1 As DateTime = .Item("Analysis_Start_Time")
    'Dim Tsp1 As New TimeSpan(dtt1.Hour, dtt1.Minute, dtt1.Second)
    '            dt1 = dt1.Add(Tsp1)
    'Dim dt2 As DateTime = .Item("Analysis_End_Date")
    'Dim dtt2 As DateTime = .Item("Analysis_End_Time")
    'Dim Tsp2 As New TimeSpan(dtt2.Hour, dtt2.Minute, dtt2.Second)
    '            dt2 = dt2.Add(Tsp2)
    '            If dt1 <= dt2 Then
    '                Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Analysis_End_Date"), EddErrors.CustomError78)
    '            Else
    '                Me.AddError(e.Row, e.Row.Table.Columns.Item("Analysis_End_Date"), EddErrors.CustomError78)
    '            End If
    '        End If
    '    End With
    'End Sub


    ' <summary>If entered, Method_Detection_Limit < Lower_Quantification_Limit < Upper_Quantification_Limit.
    ' Applies to:
    ' <list type="bullet">
    '   <item>Results.Method_Detection_Limit</item>
    '   <item>Results.Lower_Quantification_Limit</item>
    '   <item>Results.Upper_Quantification_Limit</item>
    ' </list>
    ' </summary>
    Private Sub ERR81(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      Me.RemoveError(e.Row, .Table.Columns.Item("Method_Detection_Limit"), EarthSoft.EDP.EddErrors.CustomError81)
      Me.RemoveError(e.Row, .Table.Columns.Item("Lower_Quantification_Limit"), EarthSoft.EDP.EddErrors.CustomError81)
      Me.RemoveError(e.Row, .Table.Columns.Item("Upper_Quantification_Limit"), EarthSoft.EDP.EddErrors.CustomError81)

      Dim val As Double
      If Not .IsNull("Lower_Quantification_Limit") AndAlso Not .IsNull("Upper_Quantification_Limit") AndAlso Double.TryParse(.Item("Lower_Quantification_Limit").ToString, val) AndAlso Double.TryParse(.Item("Upper_Quantification_Limit").ToString, val) Then
        If Convert.ToDouble(.Item("Lower_Quantification_Limit")).CompareTo(Convert.ToDouble(.Item("Upper_Quantification_Limit"))) > 0 Then
          Me.AddError(e.Row, .Table.Columns.Item("Lower_Quantification_Limit"), EarthSoft.EDP.EddErrors.CustomError81)
          Me.AddError(e.Row, .Table.Columns.Item("Upper_Quantification_Limit"), EarthSoft.EDP.EddErrors.CustomError81)
        End If
      End If

      If Not .IsNull("Method_Detection_Limit") AndAlso Not .IsNull("Upper_Quantification_Limit") AndAlso Double.TryParse(.Item("Method_Detection_Limit").ToString, val) AndAlso Double.TryParse(.Item("Upper_Quantification_Limit").ToString, val) Then
        If Convert.ToDouble(.Item("Method_Detection_Limit")).CompareTo(Convert.ToDouble(.Item("Upper_Quantification_Limit"))) > 0 Then
          Me.AddError(e.Row, .Table.Columns.Item("Method_Detection_Limit"), EarthSoft.EDP.EddErrors.CustomError81)
          Me.AddError(e.Row, .Table.Columns.Item("Upper_Quantification_Limit"), EarthSoft.EDP.EddErrors.CustomError81)
        End If
      End If

      If Not .IsNull("Method_Detection_Limit") AndAlso Not .IsNull("Lower_Quantification_Limit") AndAlso Double.TryParse(.Item("Method_Detection_Limit").ToString, val) AndAlso Double.TryParse(.Item("Lower_Quantification_Limit").ToString, val) Then
        If Convert.ToDouble(.Item("Method_Detection_Limit")).CompareTo(Convert.ToDouble(.Item("Lower_Quantification_Limit"))) > 0 Then
          Me.AddError(e.Row, .Table.Columns.Item("Method_Detection_Limit"), EarthSoft.EDP.EddErrors.CustomError81)
          Me.AddError(e.Row, .Table.Columns.Item("Lower_Quantification_Limit"), EarthSoft.EDP.EddErrors.CustomError81)
        End If
      End If
    End With
  End Sub
    ''' <summary>If entered, Result_Text numeric values should be between the Lower_Quantification_Limit and Upper_Quantification_Limit.
    ''' Result_Text values shouldn't be below Method_Detection_Limit or Lower_Quantification_Limit; nor should they
    ''' exceed the Upper_Quantification_Limit.
    ''' 1/2/2018 by DFT: If a K, KJ, or U Result_Qualifier is used with the result, it overrides this rule, allowing for entry of results below
    ''' the Method_Detection_Limit and Lower_Quantification_Limit.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Results.Method_Detection_Limit</item>
    '''   <item>Results.Lower_Quantification_Limit</item>
    '''   <item>Results.Upper_Quantification_Limit</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR82(ByVal e As System.Data.DataColumnChangeEventArgs)

    Dim valResult As Double
    Dim RQTestAgainst As String() = {"K", "KJ", "U"}
    With e.Row
      Me.RemoveError(e.Row, .Table.Columns.Item("Result_Text"), EarthSoft.EDP.EddErrors.CustomError82)
      Me.RemoveError(e.Row, .Table.Columns.Item("Method_Detection_Limit"), EarthSoft.EDP.EddErrors.CustomError82)
      Me.RemoveError(e.Row, .Table.Columns.Item("Lower_Quantification_Limit"), EarthSoft.EDP.EddErrors.CustomError82)
      Me.RemoveError(e.Row, .Table.Columns.Item("Upper_Quantification_Limit"), EarthSoft.EDP.EddErrors.CustomError82)
      If Double.TryParse(.Item("Result_Text").ToString, valResult) Then
        If Not .IsNull("Method_Detection_Limit") AndAlso Double.TryParse(.Item("Method_Detection_Limit").ToString, valResult) Then
          'If Convert.ToDouble(.Item("Result_Text")).CompareTo(Convert.ToDouble(.Item("Method_Detection_Limit"))) < 0 AndAlso Not .Item("Result_Qualifier").ToString.ToUpper.Contains("KJ") Then
          If Convert.ToDouble(.Item("Result_Text")).CompareTo(Convert.ToDouble(.Item("Method_Detection_Limit"))) < 0 AndAlso Not RQTestAgainst.Contains(.Item("Result_Qualifier").ToString.ToUpper) Then
            Me.AddError(e.Row, .Table.Columns.Item("Result_Text"), EarthSoft.EDP.EddErrors.CustomError82)
            Me.AddError(e.Row, .Table.Columns.Item("Method_Detection_Limit"), EarthSoft.EDP.EddErrors.CustomError82)
          Else
            Me.RemoveError(e.Row, .Table.Columns.Item("Result_Text"), EarthSoft.EDP.EddErrors.CustomError82)
            Me.RemoveError(e.Row, .Table.Columns.Item("Method_Detection_Limit"), EarthSoft.EDP.EddErrors.CustomError82)
          End If
        End If
        If Not .IsNull("Lower_Quantification_Limit") AndAlso Double.TryParse(.Item("Lower_Quantification_Limit").ToString, valResult) Then
          'If Convert.ToDouble(.Item("Result_Text")).CompareTo(Convert.ToDouble(.Item("Lower_Quantification_Limit"))) < 0 AndAlso Not .Item("Result_Qualifier").ToString.ToUpper.Contains("KJ") Then
          If Convert.ToDouble(.Item("Result_Text")).CompareTo(Convert.ToDouble(.Item("Lower_Quantification_Limit"))) < 0 AndAlso Not RQTestAgainst.Contains(.Item("Result_Qualifier").ToString.ToUpper) Then
            Me.AddError(e.Row, .Table.Columns.Item("Result_Text"), EarthSoft.EDP.EddErrors.CustomError82)
            Me.AddError(e.Row, .Table.Columns.Item("Lower_Quantification_Limit"), EarthSoft.EDP.EddErrors.CustomError82)
          Else
            Me.RemoveError(e.Row, .Table.Columns.Item("Result_Text"), EarthSoft.EDP.EddErrors.CustomError82)
            Me.RemoveError(e.Row, .Table.Columns.Item("Lower_Quantification_Limit"), EarthSoft.EDP.EddErrors.CustomError82)
          End If
        End If
        If Not .IsNull("Upper_Quantification_Limit") AndAlso Double.TryParse(.Item("Upper_Quantification_Limit").ToString, valResult) Then
          If Convert.ToDouble(.Item("Result_Text")).CompareTo(Convert.ToDouble(.Item("Upper_Quantification_Limit"))) > 0 Then
            Me.AddError(e.Row, .Table.Columns.Item("Result_Text"), EarthSoft.EDP.EddErrors.CustomError82)
            Me.AddError(e.Row, .Table.Columns.Item("Upper_Quantification_Limit"), EarthSoft.EDP.EddErrors.CustomError82)
          Else
            Me.RemoveError(e.Row, .Table.Columns.Item("Result_Text"), EarthSoft.EDP.EddErrors.CustomError82)
            Me.RemoveError(e.Row, .Table.Columns.Item("Upper_Quantification_Limit"), EarthSoft.EDP.EddErrors.CustomError82)
          End If
        End If
      End If
    End With

  End Sub
  ' <summary>Activity_End_Date/Time cannot precede Activity_Start_Date/Time.
  ' Applies to:
  ' <list type="bullet">
  '   <item>Activity.Activity_Start_Date</item>
  '   <item>Activity.Activity_Start_Time</item>
  '   <item>Activity.Activity_End_Date</item>
  '   <item>Activity.Activity_End_Time</item>
  ' </list>
  ' </summary>
  Private Sub ERR83(ByVal e As System.Data.DataColumnChangeEventArgs)
    If IsCommentRow(e.Row) Then Return
    'Dim Activity_End_Date, Activity_Start_Date As Date
    Dim AED, ASD As Date
    With e.Row
      'If Not .IsNull("Activity_End_Time") Then
      '    AEDstr = String.Format("{0} {1}", .Item("Activity_End_Date").ToString, .Item("Activity_End_Time").ToString)
      'Else
      '    AEDstr = .Item("Activity_End_Date").ToString
      'End If
      'If Not .IsNull("Activity_Start_Time") Then
      '    ASDstr = String.Format("{0} {1}", .Item("Activity_Start_Date").ToString, .Item("Activity_Start_Time").ToString)
      'Else
      '    ASDstr = .Item("Activity_Start_Date").ToString
      'End If

      If Not .IsNull("Activity_End_Date") AndAlso Not .IsNull("Activity_Start_Date") AndAlso Date.TryParse(String.Format("{0} {1}", .Item("Activity_Start_Date").ToString, .Item("Activity_Start_Time").ToString), ASD) AndAlso Date.TryParse(String.Format("{0} {1}", .Item("Activity_End_Date").ToString, .Item("Activity_End_Time").ToString), AED) AndAlso AED.CompareTo(ASD) < 0 Then
        Me.AddError(e.Row, CType(.Table.Columns.Item("Activity_Start_Date"), System.Data.DataColumn), EddErrors.CustomError83)
        Me.AddError(e.Row, CType(.Table.Columns.Item("Activity_End_Date"), System.Data.DataColumn), EddErrors.CustomError83)
      Else
        Me.RemoveError(e.Row, CType(.Table.Columns.Item("Activity_Start_Date"), System.Data.DataColumn), EddErrors.CustomError83)
        Me.RemoveError(e.Row, CType(.Table.Columns.Item("Activity_End_Date"), System.Data.DataColumn), EddErrors.CustomError83)
      End If


      'If Not .IsNull("Activity_End_Date") AndAlso Not .IsNull("Activity_Start_Date") AndAlso Date.TryParse(.Item("Activity_End_Date").ToString, Activity_End_Date) AndAlso Date.TryParse(.Item("Activity_Start_Date").ToString, Activity_Start_Date) Then
      '    If (System.DateTime.Compare(Activity_End_Date, Activity_Start_Date) < 0) Then
      '        Me.AddError(e.Row, CType(.Table.Columns.Item("Activity_Start_Date"), System.Data.DataColumn), EddErrors.CustomError83)
      '        Me.AddError(e.Row, CType(.Table.Columns.Item("Activity_End_Date"), System.Data.DataColumn), EddErrors.CustomError83)
      '    Else
      '        Me.RemoveError(e.Row, CType(.Table.Columns.Item("Activity_Start_Date"), System.Data.DataColumn), EddErrors.CustomError83)
      '        Me.RemoveError(e.Row, CType(.Table.Columns.Item("Activity_End_Date"), System.Data.DataColumn), EddErrors.CustomError83)
      '    End If
      'Else
      '    Me.RemoveError(e.Row, CType(.Table.Columns.Item("Activity_Start_Date"), System.Data.DataColumn), EddErrors.CustomError83)
      '    Me.RemoveError(e.Row, CType(.Table.Columns.Item("Activity_End_Date"), System.Data.DataColumn), EddErrors.CustomError83)
      'End If
    End With
  End Sub

  ' <summary>Activity_Start_Time_Zone and Activity_End_Time_Zone must be in the same geography (e.g. Eastern) but can be different (i.e. daylight vs. standard).
  ' Applies to:
  ' <list type="bullet">
  '   <item>Activity.Activity_Start_Time_Zone</item>
  '   <item>Activity.Activity_End_Time_Zone</item>
  ' </list>
  ' </summary>
  Private Sub ERR84(ByVal e As System.Data.DataColumnChangeEventArgs)
    If IsCommentRow(e.Row) Then Return
    If Not Efd.package.Tables.Contains("rt_timezone") Then Return
    With e.Row
      If Not .IsNull("Activity_Start_Time_Zone") AndAlso Not .IsNull("Activity_End_Time_Zone") Then
        'Parse error and check for ValidValue error. If it has a valid value error and we add another error then exception occurs when adding by value.
        Me._Err.Parse(e.Row.GetColumnError(e.Row.Table.Columns("Activity_End_Time_Zone")))
        If .Item("Activity_Start_Time_Zone").ToString = String.Empty OrElse .Item("Activity_End_Time_Zone").ToString = String.Empty OrElse Me._Err.Check(EddErrors.ValidValue) Then
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_End_Time_Zone"), EddErrors.CustomError84)
        Else
          Dim tn1, tn2 As String
          Dim rows1() As System.Data.DataRow = Me.rt_timezone.Select(String.Format("timezone_code = '{0}'", .Item("Activity_Start_Time_Zone").ToString))
          tn1 = rows1(0)("timezone_name")
          Dim rows2() As System.Data.DataRow = Me.rt_timezone.Select(String.Format("timezone_code = '{0}'", .Item("Activity_End_Time_Zone").ToString))
          tn2 = rows2(0)("timezone_name")
          If Left(tn1, InStr(tn1, " ") - 1) <> Left(tn2, InStr(tn2, " ") - 1) Then
            Me.AddError(e.Row, e.Row.Table.Columns.Item("Activity_End_Time_Zone"), EddErrors.CustomError84)
          Else
            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_End_Time_Zone"), EddErrors.CustomError84)
          End If
        End If
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_End_Time_Zone"), EddErrors.CustomError84)
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_Start_Time_Zone"), EddErrors.CustomError84)
      End If
    End With
  End Sub
    ' <summary>If Lab_Sample_Preparation_ID, Lab_Sample_Preparation_ID_Context, or Lab_Sample_Preparation_Method_Name is populated, then the others are required. 
    ' Applies to:
    ' <list type="bullet">
    '   <item>Results.Lab_Sample_Preparation_ID</item>
    '   <item>Results.Lab_Sample_Preparation_ID_Context</item>
    '   <item>Results.Lab_Sample_Preparation_Method_Name</item>
    ' </list>
    ' </summary>
    'Private Sub ERR40(ByVal e As System.Data.DataColumnChangeEventArgs)
    '    With e.Row
    '        If .IsNull("Lab_Sample_Preparation_ID") AndAlso (Not .IsNull("Lab_Sample_Preparation_ID_Context")) Then
    '            'OrElse Not .IsNull("Lab_Sample_Preparation_Method_Name")) Then
    '            Me.AddError(e.Row, e.Row.Table.Columns.Item("Lab_Sample_Preparation_ID"), EddErrors.Required)
    '        Else
    '            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Lab_Sample_Preparation_ID"), EddErrors.Required)
    '        End If

    '        If .IsNull("Lab_Sample_Preparation_ID_Context") AndAlso (Not .IsNull("Lab_Sample_Preparation_ID")) Then
    '            'OrElse Not .IsNull("Lab_Sample_Preparation_Method_Name")) Then
    '            Me.AddError(e.Row, e.Row.Table.Columns.Item("Lab_Sample_Preparation_ID_Context"), EddErrors.Required)
    '        Else
    '            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Lab_Sample_Preparation_ID_Context"), EddErrors.Required)
    '        End If

    '        'If .IsNull("Lab_Sample_Preparation_Method_Name") AndAlso (Not .IsNull("Lab_Sample_Preparation_ID_Context") _
    '        '                                                          OrElse Not .IsNull("Lab_Sample_Preparation_ID")) Then
    '        'Me.AddError(e.Row, e.Row.Table.Columns.Item("Lab_Sample_Preparation_Method_Name"), EddErrors.Required)
    '        'Else
    '        'Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Lab_Sample_Preparation_Method_Name"), EddErrors.Required)
    '        'End If
    '    End With
    'End Sub

    ''' <summary>If Lab_Sample_Preparation_Start_Time or Lab_Sample_Preparation_Start_Time_Zone is populated, then the other one is required.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Results.Lab_Sample_Preparation_Start_Time</item>
    '''   <item>Results.Lab_Sample_Preparation_Start_Time_Zone</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR41(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .IsNull("Lab_Sample_Preparation_Start_Time") AndAlso Not .IsNull("Lab_Sample_Preparation_Start_Time_Zone") Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Lab_Sample_Preparation_Start_Time"), EddErrors.Required)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Lab_Sample_Preparation_Start_Time"), EddErrors.Required)
      End If

      If .IsNull("Lab_Sample_Preparation_Start_Time_Zone") AndAlso Not .IsNull("Lab_Sample_Preparation_Start_Time") Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Lab_Sample_Preparation_Start_Time_Zone"), EddErrors.Required)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Lab_Sample_Preparation_Start_Time_Zone"), EddErrors.Required)
      End If
    End With
  End Sub

    ' <summary>If Lab_Sample_Preparation_End_Time or Lab_Sample_Preparation_End_Time_Zone is populated, then the other one is required.
    ' Applies to:
    ' <list type="bullet">
    '   <item>Results.Lab_Sample_Preparation_End_Time</item>
    '   <item>Results.Lab_Sample_Preparation_End_Time_Zone</item>
    ' </list>
    ' </summary>
    'Private Sub ERR42(ByVal e As System.Data.DataColumnChangeEventArgs)
    '    With e.Row
    '        If .IsNull("Lab_Sample_Preparation_End_Time") AndAlso Not .IsNull("Lab_Sample_Preparation_End_Time_Zone") Then
    '            Me.AddError(e.Row, e.Row.Table.Columns.Item("Lab_Sample_Preparation_End_Time"), EddErrors.Required)
    '        Else
    '            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Lab_Sample_Preparation_End_Time"), EddErrors.Required)
    '        End If

    '        If .IsNull("Lab_Sample_Preparation_End_Time_Zone") AndAlso Not .IsNull("Lab_Sample_Preparation_End_Time") Then
    '            Me.AddError(e.Row, e.Row.Table.Columns.Item("Lab_Sample_Preparation_End_Time_Zone"), EddErrors.Required)
    '        Else
    '            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Lab_Sample_Preparation_End_Time_Zone"), EddErrors.Required)
    '        End If
    '    End With
    'End Sub

    ' ''' <summary>If DetectionQuantitationLimitTypeName, DetectionQuantitationLimitMeasureValue, or DetectionQuantitationLimitMeasureUnitCode is populated, then the others are required.
    ' ''' Applies to:
    ' ''' <list type="bullet">
    ' '''   <item>ResDetectionQuantLimit.DetectionQuantitationLimitTypeName</item>
    ' '''   <item>ResDetectionQuantLimit.DetectionQuantitationLimitMeasureValue</item>
    ' '''   <item>ResDetectionQuantLimit.DetectionQuantitationLimitMeasureUnitCode</item>
    ' ''' </list>
    ' ''' </summary>
    'Private Sub ERR43(ByVal e As System.Data.DataColumnChangeEventArgs)
    '    With e.Row
    '        'Use .ToString for the type field since it is an enumeration and empty values are not getting replaced with a null value so errors are occuring when they shouldn't
    '        If .Item("DetectionQuantitationLimitTypeName").ToString = String.Empty AndAlso (Not .IsNull("DetectionQuantitationLimitMeasureValue") OrElse Not .IsNull("DetectionQuantitationLimitMeasureUnitCode")) Then
    '            Me.AddError(e.Row, e.Row.Table.Columns.Item("DetectionQuantitationLimitTypeName"), EddErrors.Required)
    '        Else
    '            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("DetectionQuantitationLimitTypeName"), EddErrors.Required)
    '        End If

    '        If .IsNull("DetectionQuantitationLimitMeasureValue") AndAlso (Not .Item("DetectionQuantitationLimitTypeName").ToString = String.Empty OrElse Not .IsNull("DetectionQuantitationLimitMeasureUnitCode")) Then
    '            Me.AddError(e.Row, e.Row.Table.Columns.Item("DetectionQuantitationLimitMeasureValue"), EddErrors.Required)
    '        Else
    '            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("DetectionQuantitationLimitMeasureValue"), EddErrors.Required)
    '        End If

    '        If .IsNull("DetectionQuantitationLimitMeasureUnitCode") AndAlso (Not .IsNull("DetectionQuantitationLimitMeasureValue") OrElse .Item("DetectionQuantitationLimitTypeName").ToString = String.Empty) Then
    '            Me.AddError(e.Row, e.Row.Table.Columns.Item("DetectionQuantitationLimitMeasureUnitCode"), EddErrors.Required)
    '        Else
    '            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("DetectionQuantitationLimitMeasureUnitCode"), EddErrors.Required)
    '        End If
    '    End With
    'End Sub

    ' '' <summary>Activity_End_Time_Zone must be the same as Activity_Start_Time_Zone.
    ' '' Applies to:
    ' '' <list type="bullet">
    ' ''   <item>Activities.Activity_End_Time_Zone</item>
    ' ''   <item>Activities.Activity_Start_Time_Zone</item>
    ' '' </list>
    ' '' </summary>
    'Private Sub ERR44(ByVal e As System.Data.DataColumnChangeEventArgs)
    '    With e.Row
    '        If Not .IsNull("Activity_End_Time_Zone") AndAlso Not .IsNull("Activity_Start_Time_Zone") AndAlso _
    '  .Item("Activity_End_Time_Zone").ToString.ToUpper <> .Item("Activity_Start_Time_Zone").ToString.ToUpper Then
    '            Me.AddError(e.Row, e.Row.Table.Columns.Item("Activity_End_Time_Zone"), EddErrors.CustomError9)
    '        Else
    '            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_End_Time_Zone"), EddErrors.CustomError9)
    '        End If
    '    End With
    'End Sub

    ''' <summary>Biological_Intent is required if any of the biological result fields are populated.
    ''' Biological result fields include Biological_Individual_ID to Frequency_Class_Upper_Bound_3.               
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Results.Biological_Intent</item>
    '''   <item>Results.Biological_Individual_ID</item>
    '''   <item>Results.Subject_Taxon</item>
    '''   <item>Results.Unidentified_Species_ID</item>
    '''   <item>Results.Tissue_Anatomy</item>
    '''   <item>Results.Group_Summary_Count_or_Weight</item>
    '''   <item>Results.Group_Summary_Count_or_Weight_Unit</item>
    '''   <item>Results.Cell_Form</item>
    '''   <item>Results.Cell_Shape</item>
    '''   <item>Results.Habit_Name_1</item>
    '''   <item>Results.Habit_Name_2</item>
    '''   <item>Results.Habit_Name_3</item>
    '''   <item>Results.Voltinism</item>
    '''   <item>Results.Pollution_Tolerance</item>
    '''   <item>Results.Pollution_Tolerance_Scale</item>
    '''   <item>Results.Trophic_Level</item>
    '''   <item>Results.Functional_Feeding_Group_1</item>
    '''   <item>Results.Functional_Feeding_Group_2</item>
    '''   <item>Results.Functional_Feeding_Group_3</item>
    '''   <item>Results.Frequency_Class_Descriptor_1</item>
    '''   <item>Results.Frequency_Class_Bounds_Unit_1</item>
    '''   <item>Results.Frequency_Class_Lower_Bound_1</item>
    '''   <item>Results.Frequency_Class_Upper_Bound_1</item>
    '''   <item>Results.Frequency_Class_Descriptor_2</item>
    '''   <item>Results.Frequency_Class_Bounds_Unit_2</item>
    '''   <item>Results.Frequency_Class_Lower_Bound_2</item>
    '''   <item>Results.Frequency_Class_Upper_Bound_2</item>
    '''   <item>Results.Frequency_Class_Descriptor_3</item>
    '''   <item>Results.Frequency_Class_Bounds_Unit_3</item>
    '''   <item>Results.Frequency_Class_Lower_Bound_3</item>
    '''   <item>Results.Frequency_Class_Upper_Bound_3</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR45(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If String.IsNullOrEmpty(.item("Biological_Intent").ToString) AndAlso
  (Not String.IsNullOrEmpty(.item("Biological_Individual_ID").ToString) OrElse Not String.IsNullOrEmpty(.item("Subject_Taxon").ToString) OrElse
  Not String.IsNullOrEmpty(.item("Unidentified_Species_ID").ToString) OrElse Not String.IsNullOrEmpty(.item("Tissue_Anatomy").ToString) OrElse
  Not String.IsNullOrEmpty(.item("Group_Summary_Count_or_Weight").ToString) OrElse Not String.IsNullOrEmpty(.item("Group_Summary_Count_or_Weight_Unit").ToString) OrElse
  Not String.IsNullOrEmpty(.item("Cell_Form").ToString) OrElse Not String.IsNullOrEmpty(.item("Cell_Shape").ToString) OrElse Not String.IsNullOrEmpty(.item("Habit_Name_1").ToString) OrElse
  Not String.IsNullOrEmpty(.item("Habit_Name_2").ToString) OrElse Not String.IsNullOrEmpty(.item("Habit_Name_3").ToString) OrElse Not String.IsNullOrEmpty(.item("Voltinism").ToString) OrElse
  Not String.IsNullOrEmpty(.item("Pollution_Tolerance").ToString) OrElse Not String.IsNullOrEmpty(.item("Pollution_Tolerance_Scale").ToString) OrElse
  Not String.IsNullOrEmpty(.item("Trophic_Level").ToString) OrElse Not String.IsNullOrEmpty(.item("Functional_Feeding_Group_1").ToString) OrElse 
  Not String.IsNullOrEmpty(.item("Functional_Feeding_Group_2").ToString) OrElse
  Not String.IsNullOrEmpty(.item("Functional_Feeding_Group_3").ToString) OrElse Not String.IsNullOrEmpty(.item("Frequency_Class_Descriptor_1").ToString) OrElse
  Not String.IsNullOrEmpty(.item("Frequency_Class_Bounds_Unit_1").ToString) OrElse Not String.IsNullOrEmpty(.item("Frequency_Class_Lower_Bound_1").ToString) OrElse
  Not String.IsNullOrEmpty(.item("Frequency_Class_Upper_Bound_1").ToString) OrElse Not String.IsNullOrEmpty(.item("Frequency_Class_Descriptor_2").ToString) OrElse
  Not String.IsNullOrEmpty(.item("Frequency_Class_Bounds_Unit_2").ToString) OrElse Not String.IsNullOrEmpty(.item("Frequency_Class_Lower_Bound_2").ToString) OrElse
  Not String.IsNullOrEmpty(.item("Frequency_Class_Upper_Bound_2").ToString) OrElse Not String.IsNullOrEmpty(.item("Frequency_Class_Descriptor_3").ToString) OrElse
  Not String.IsNullOrEmpty(.item("Frequency_Class_Bounds_Unit_3").ToString) OrElse Not String.IsNullOrEmpty(.item("Frequency_Class_Lower_Bound_3").ToString) OrElse
  Not String.IsNullOrEmpty(.item("Frequency_Class_Upper_Bound_3").ToString)) Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Biological_Intent"), EddErrors.CustomError10)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Biological_Intent"), EddErrors.CustomError10)
      End If
    End With
  End Sub

    ''' <summary>If Biological_Intent='Frequency Class', then Characteristic_Name must be 'Count'.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Results.Biological_Intent</item>
    '''   <item>Results.Characteristic_Name</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR46(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .Item(Results_.Biological_Intent).ToString.ToUpper = "FREQUENCY CLASS" AndAlso .Item(Results_.Characteristic_Name).ToString.ToUpper <> "COUNT" Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item(Results_.Characteristic_Name), EddErrors.CustomError11)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item(Results_.Characteristic_Name), EddErrors.CustomError11)
      End If
    End With
  End Sub

    ''' <summary>If Biological_Intent='Population Census', then Characteristic_Name must be 'Count' or 'Total Sample Weight'.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Results.Biological_Intent</item>
    '''   <item>Results.Characteristic_Name</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR47(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .Item("Biological_Intent").ToString.ToUpper = "POPULATION CENSUS" AndAlso
(.Item("Characteristic_Name").ToString.ToUpper <> "COUNT" And .Item("Characteristic_Name").ToString.ToUpper <> "TOTAL SAMPLE WEIGHT") Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Characteristic_Name"), EddErrors.CustomError12)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Characteristic_Name"), EddErrors.CustomError12)
      End If
    End With
  End Sub

    ''' <summary>If Results.Biological_Intent or Activities.Medium='Tissue', then the other must also be 'Tissue' and Results.Tissue_Anatomy must be populated.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Results.Activity_ID</item>
    '''   <item>Results.Biological_Intent</item>
    '''   <item>Results.Tissue_Anatomy</item>
    '''   <item>Activities.Activity_ID</item>
    '''   <item>Activities.Medium</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR48(ByVal e As System.Data.DataColumnChangeEventArgs)

    With e.Row
      Select Case .Table.TableName.ToLower
        Case "activities"
          If Not .IsNull("Activity_ID") AndAlso .Item("Activity_ID").ToString.Length > 0 AndAlso (.IsNull("Medium") OrElse .Item("Medium").ToString.ToUpper <> "TISSUE") Then
            Dim resultRows() As System.Data.DataRow = Me.Result.Select(String.Format("Activity_ID='{0}' and Biological_Intent='Tissue'", .Item("Activity_ID").ToString.Replace("'", "''")))
            If resultRows.Length > 0 Then
              Me.AddError(e.Row, e.Row.Table.Columns.Item("Medium"), EddErrors.CustomError13)
            Else
              Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Medium"), EddErrors.CustomError13)
            End If

          Else
            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Medium"), EddErrors.CustomError13)
          End If


        Case "results"
          If Not .IsNull("Activity_ID") AndAlso .Item("Activity_ID").ToString.Length > 0 Then
            If .IsNull("Biological_Intent") OrElse .Item("Biological_Intent").ToString.ToUpper <> "TISSUE" Then
              Dim actRows() As System.Data.DataRow = Me.Activities.Select(String.Format("Activity_ID='{0}' and Medium='Tissue'", .Item("Activity_ID").ToString.Replace("'", "''")))
              If actRows.Length > 0 Then
                Me.AddError(e.Row, e.Row.Table.Columns.Item("Tissue_Anatomy"), EddErrors.CustomError13)
                Me.AddError(e.Row, e.Row.Table.Columns.Item("Biological_Intent"), EddErrors.CustomError13)
              Else
                Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Biological_Intent"), EddErrors.CustomError13)
                Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Tissue_Anatomy"), EddErrors.CustomError13)
              End If

            ElseIf .Item("Biological_Intent").ToString.ToUpper = "TISSUE" AndAlso .IsNull("Tissue_Anatomy") Then
              Me.AddError(e.Row, e.Row.Table.Columns.Item("Tissue_Anatomy"), EddErrors.CustomError13)
              Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Biological_Intent"), EddErrors.CustomError13)
            Else
              Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Tissue_Anatomy"), EddErrors.CustomError13)
              Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Biological_Intent"), EddErrors.CustomError13)
            End If

          Else
            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Biological_Intent"), EddErrors.CustomError13)

            If .Item("Biological_Intent").ToString.ToUpper = "TISSUE" AndAlso .IsNull("Tissue_Anatomy") Then
              Me.AddError(e.Row, e.Row.Table.Columns.Item("Tissue_Anatomy"), EddErrors.CustomError13)
            Else
              Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Tissue_Anatomy"), EddErrors.CustomError13)
            End If
          End If
      End Select
    End With
  End Sub

    ' ''' <summary>If Results.Result_Detection_Condition='Not Detected', 'Present Above Quantification Limit' or 'Present Below Quantification Limit', 
    ' ''' then the associated Method_Detection_Limit, Lower_Quantifcation_Limit, or Upper_Quantification_Limit is required.
    ' ''' Applies to:
    ' ''' <list type="bullet">
    ' '''   <item>Results.Result_Detection_Condition</item>
    ' '''   <item>Results.Activity_ID</item>
    ' '''   <item>ResDetectionQuantLimit.Activity_ID</item>
    ' '''   <item>Results.Method_Detection_Limit</item>
    ' '''   <item>Results.Lower_Quantification_Limit</item>
    ' '''   <item>Results.Upper_Quantitication_Limit</item>
    ' ''' </list>
    ' ''' </summary>
    'Private Sub ERR49(ByVal e As System.Data.DataColumnChangeEventArgs)
    '    With e.Row
    '        If .IsNull("Activity_ID") Then
    '            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("DetectionQuantitationLimitTypeName"), EddErrors.CustomError14)
    '            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("DetectionQuantitationLimitMeasureValue"), EddErrors.CustomError14)
    '            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("DetectionQuantitationLimitMeasureUnitCode"), EddErrors.CustomError14)
    '            Return
    '        End If

    '        Dim sysSampleCode As String = .Item("Activity_ID").ToString
    '        Dim resultRows() As System.Data.DataRow = Me.Result.Select(String.Format("Activity_ID='{0}'", sysSampleCode.Replace("'", "''")))
    '        If resultRows.Length > 0 Then
    '            Dim resultDetection As String = resultRows(0).Item("Result_Detection_Condition").ToString.ToLower

    '            If resultDetection = "not detected" OrElse resultDetection = "present above quantification limit" OrElse resultDetection = "present and below quantification limit" Then
    '                If .IsNull("DetectionQuantitationLimitTypeName") Then
    '                    Me.AddError(e.Row, e.Row.Table.Columns.Item("DetectionQuantitationLimitTypeName"), EddErrors.CustomError14)
    '                Else
    '                    Me.RemoveError(e.Row, e.Row.Table.Columns.Item("DetectionQuantitationLimitTypeName"), EddErrors.CustomError14)
    '                End If

    '                If .IsNull("DetectionQuantitationLimitMeasureValue") Then
    '                    Me.AddError(e.Row, e.Row.Table.Columns.Item("DetectionQuantitationLimitMeasureValue"), EddErrors.CustomError14)
    '                Else
    '                    Me.RemoveError(e.Row, e.Row.Table.Columns.Item("DetectionQuantitationLimitMeasureValue"), EddErrors.CustomError14)
    '                End If

    '                If .IsNull("DetectionQuantitationLimitMeasureUnitCode") Then
    '                    Me.AddError(e.Row, e.Row.Table.Columns.Item("DetectionQuantitationLimitMeasureUnitCode"), EddErrors.CustomError14)
    '                Else
    '                    Me.RemoveError(e.Row, e.Row.Table.Columns.Item("DetectionQuantitationLimitMeasureUnitCode"), EddErrors.CustomError14)
    '                End If

    '            Else
    '                'Result_Detection_Condition value is not detected
    '                Me.RemoveError(e.Row, e.Row.Table.Columns.Item("DetectionQuantitationLimitTypeName"), EddErrors.CustomError14)
    '                Me.RemoveError(e.Row, e.Row.Table.Columns.Item("DetectionQuantitationLimitMeasureValue"), EddErrors.CustomError14)
    '                Me.RemoveError(e.Row, e.Row.Table.Columns.Item("DetectionQuantitationLimitMeasureUnitCode"), EddErrors.CustomError14)
    '            End If
    '        Else
    '            'No matching rows in the Result section
    '            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("DetectionQuantitationLimitTypeName"), EddErrors.CustomError14)
    '            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("DetectionQuantitationLimitMeasureValue"), EddErrors.CustomError14)
    '            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("DetectionQuantitationLimitMeasureUnitCode"), EddErrors.CustomError14)
    '        End If

    '    End With
    'End Sub

    ''' <summary>If Activity_Upper_Depth or Activity_Lower_Depth is populated, then the other is required.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Activities.Activity_Upper_Depth</item>
    '''   <item>Activities.Activity_Lower_Depth</item> 
    ''' </list>
    ''' </summary>
    Private Sub ERR50(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .Item("Activity_Upper_Depth").ToString = String.Empty AndAlso .Item("Activity_Lower_Depth").ToString <> String.Empty Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Activity_Upper_Depth"), EddErrors.CustomError15)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_Upper_Depth"), EddErrors.CustomError15)
      End If

      If .Item("Activity_Lower_Depth").ToString = String.Empty AndAlso .Item("Activity_Upper_Depth").ToString <> String.Empty Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Activity_Lower_Depth"), EddErrors.CustomError15)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_Lower_Depth"), EddErrors.CustomError15)
      End If

    End With
  End Sub

  ''' <summary>If Activity_Type='Sample-Integrated Vertical Profile', then Activity_Upper_Depth and Activity_Lower_Depth are required.
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Activities.Activity_Type</item>
  '''   <item>Activities.Activity_Upper_Depth</item>
  '''   <item>Activities.Activity_Lower_Depth</item> 
  ''' </list>
  ''' </summary>
  Private Sub ERR51(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .Item("Activity_Type").ToString.ToUpper = "SAMPLE-INTEGRATED VERTICAL PROFILE" Then

        If .IsNull("Activity_Upper_Depth") Then
          Me.AddError(e.Row, e.Row.Table.Columns.Item("Activity_Upper_Depth"), EddErrors.CustomError16)
        Else
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_Upper_Depth"), EddErrors.CustomError16)
        End If

        If .IsNull("Activity_Lower_Depth") Then
          Me.AddError(e.Row, e.Row.Table.Columns.Item("Activity_Lower_Depth"), EddErrors.CustomError16)
        Else
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_Lower_Depth"), EddErrors.CustomError16)
        End If

      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_Upper_Depth"), EddErrors.CustomError16)
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_Lower_Depth"), EddErrors.CustomError16)
      End If

    End With
  End Sub

  ''' <summary>Metrics.Index_ID is a foreign key to Indices.Bio_Habitat_Index_ID.
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Metrics.Index_ID</item>
  '''   <item>Indices.Bio_Habitat_Index_ID</item>
  ''' </list>
  ''' </summary>
  Private Sub ERR52(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If Not .IsNull("Index_ID") AndAlso Me.Indices.Rows.Count > 0 Then
        Dim IsOrphan As Boolean = True
        For Each row As System.Data.DataRow In Me.Indices.Rows
          If row.Item("Bio_Habitat_Index_ID").ToString.ToUpper = .Item("Index_ID").ToString.ToUpper AndAlso Not IsCommentRow(row) Then
            IsOrphan = False
            Exit For
          End If
        Next

        If IsOrphan Then
          Me.AddError(e.Row, e.Row.Table.Columns.Item("Index_ID"), EddErrors.OrphanRow)
        Else
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Index_ID"), EddErrors.OrphanRow)
        End If

      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Index_ID"), EddErrors.OrphanRow)
      End If

    End With
  End Sub

  ''' <summary>Checks if the county coded belongs to the selected state code
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Organization.State_Code</item>
  '''   <item>Organization.County_Code</item>
  '''   <item>Locations.State_Code</item>
  '''   <item>Locations.County_Code</item>
  ''' </list>
  ''' </summary>
  Private Sub ERR53(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If Not Efd.package.Tables.Contains("rt_county") Then Return

      'Parse error and check for ValidValue error.  If it has a valid value error and we add another error then exception occurs when adding by value.
      Me._Err.Parse(e.Row.GetColumnError(e.Row.Table.Columns("County_Code")))
      If .Item("State_Code").ToString = String.Empty OrElse .Item("County_Code").ToString = String.Empty OrElse Me._Err.Check(EddErrors.ValidValue) Then
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("County_Code"), EddErrors.CustomError17)

      Else
        Dim rows = Me.rt_county.Select(String.Format("county_name = '{0}' and state_code = '{1}'", e.Row.Item("County_Code").ToString, e.Row.Item("State_Code").ToString))
        If Not rows.Count > 0 Then
          Me.AddError(e.Row, e.Row.Table.Columns.Item("County_Code"), EddErrors.CustomError17)
        Else
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("County_Code"), EddErrors.CustomError17)
        End If
      End If
    End With
  End Sub

    ''' <summary>If Characteristic_Name ends with the phrase 'Choice List', then Result_Text must match the domain list value.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Results.ResultValueMeasure</item>
    '''   <item>Results.Characteristic_Name</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR54(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .IsNull("Result_Text") OrElse .IsNull("Characteristic_Name") Then
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Result_Text"), EddErrors.CustomError18)

      Else
        Dim charName As String = .Item("Characteristic_Name").ToString.Trim
        'Use regular expression instead of charName.EndsWith in case the value does or does not contain parenthesis (ie 'Choice List' vs '(Choice List)')
        If System.Text.RegularExpressions.Regex.IsMatch(charName, ".+(?i)(\(?choice list\)?)") Then
          'Characteristic_Name ends with 'Choice List'

          ' MS.199172: creating/resetting a filter in this method is slow - set the SortOrder on the DefaultView and use Select
          If Not dtResultValue.Select(String.Format("characteristic_name = '{0}' and result_code='{1}'", charName.Replace("'", "''"), .Item("Result_Text").ToString.Trim.Replace("'", "''"))).Length > 0 Then
            Me.AddError(e.Row, e.Row.Table.Columns.Item("Result_Text"), EddErrors.CustomError18)
          Else
            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Result_Text"), EddErrors.CustomError18)
          End If

        Else
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Result_Text"), EddErrors.CustomError18)
        End If
      End If
    End With
  End Sub

    ''' <summary>Check in enumeration activity_type_code to determine if Analytical_Method_ID is required.  Gets Activity_Type from the Activities section based on Activity_ID.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Results.Analytical_Method_ID</item>
    '''   <item>Results.Activity_ID</item>
    '''   <item>Activities.Activity_ID</item>
    '''   <item>Activities.Activity_Type</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR55(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .IsNull("Analytical_Method_ID") AndAlso Not .IsNull("Activity_ID") AndAlso Me.Activities.Rows.Count > 0 Then
        Dim ActivityResults() As System.Data.DataRow = Me.Activities.Select(String.Format("Activity_ID='{0}'", .Item("Activity_ID").ToString.Replace("'", "''")))

        'Get the first matching row in the Activities section that is not a comment row
        Dim activityRow As System.Data.DataRow = Nothing
        For Each row As System.Data.DataRow In ActivityResults
          If Not IsCommentRow(row) Then
            activityRow = row
            Exit For
          End If
        Next

        If Not activityRow Is Nothing Then
          Dim drActivity() As System.Data.DataRow = Me.dtActivityType.Select(String.Format("activity_code='{0}'", ActivityResults(0).Item("Activity_Type").ToString.Replace("'", "''")))

          If drActivity.Length > 0 Then
            If drActivity(0).Item("analytical_method_required").ToString.ToUpper = "Y" Then
              Me.AddError(e.Row, e.Row.Table.Columns.Item("Analytical_Method_ID"), EddErrors.Required)
            Else
              Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Analytical_Method_ID"), EddErrors.Required)
            End If

          Else
            'There is no matching records in the activity_type_code enumeration
            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Analytical_Method_ID"), EddErrors.Required)
          End If
        Else
          'There is no matching data rows in the Activities section based on Activity_ID
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Analytical_Method_ID"), EddErrors.Required)
        End If

      Else
        'Either Analytical_Method_ID is not null, Activity_ID is null, or there is no rows in the Activities section
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Analytical_Method_ID"), EddErrors.Required)
      End If

    End With
  End Sub

  ''' <summary>Check in enumeration activity_type_code to determine if Location_ID is required.
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Activities.Location_ID</item>
  '''   <item>Activities.Activity_Type</item>
  ''' </list>
  ''' </summary>
  Private Sub ERR56(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .IsNull("Location_ID") AndAlso Not .IsNull("Activity_Type") Then
        Dim drActivity() As System.Data.DataRow = Me.dtActivityType.Select(String.Format("activity_code='{0}'", .Item("Activity_Type").ToString.Replace("'", "''")))

        If drActivity.Length > 0 Then
          If drActivity(0).Item("location_required").ToString.ToUpper = "Y" Then
            Me.AddError(e.Row, e.Row.Table.Columns.Item("Location_ID"), EddErrors.Required)
          Else
            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Location_ID"), EddErrors.Required)
          End If

        Else
          'There is no matching records in the activity_type_code enumeration
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Location_ID"), EddErrors.Required)
        End If

      Else
        'Either Location_ID is not null or Activity_Type is null
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Location_ID"), EddErrors.Required)
      End If

    End With
  End Sub

  Private RowError As EddError = New EddError(String.Empty, Me)
  ''' <summary>Maximum number of rows is 1.
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Organization</item>
  ''' </list>
  ''' </summary>
  Public Sub ERR57(ByVal e As System.Data.DataRowChangeEventArgs)
    Dim dtFacility As EddTable = e.Row.Table
    Dim index As Integer = e.Row.Table.Rows.IndexOf(e.Row)

    If index > 0 And Not IsCommentRow(e.Row) Then
      For i As Integer = index - 1 To 0 Step -1
        If Not IsCommentRow(dtFacility.Rows(i)) Then
          RowError.Parse(e.Row.RowError)
          RowError.Add(EddErrors.CustomError19)
          e.Row.RowError = RowError.ToString
          Exit Sub
        End If
      Next
    End If

    RowError.Parse(e.Row.RowError)
    RowError.Remove(EddErrors.CustomError19)
    e.Row.RowError = RowError.ToString
  End Sub

    ''' <summary>If Resource_Title_Name, File_Name_or_Resource_ID, or Resource_Date is populated, then the others are required.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>PrjMonitorLocationWeight.Resource_Title_Name</item>
    '''   <item>PrjMonitorLocationWeight.File_Name_or_Resource_ID</item>
    '''   <item>PrjMonitorLocationWeight.Resource_Date</item>
    '''   <item>Indices.Resource_Title_Name</item>
    '''   <item>Indices.File_Name_or_Resource_ID</item>
    '''   <item>Indices.Resource_Date</item>
    '''   <item>Metrics.Resource_Title_Name</item>
    '''   <item>Metrics.File_Name_or_Resource_IDr</item>
    '''   <item>Metrics.Resource_Date</item>
    '''   <item>Results.Resource_Title_Name</item>
    '''   <item>Results.File_Name_or_Resource_ID</item>
    '''   <item>Results.Resource_Date</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR58(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .IsNull("Resource_Title_Name") AndAlso (Not .IsNull("File_Name_or_Resource_ID") OrElse Not .IsNull("Resource_Date")) Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Resource_Title_Name"), EddErrors.CustomError20)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Resource_Title_Name"), EddErrors.CustomError20)
      End If

      If .IsNull("File_Name_or_Resource_ID") AndAlso (Not .IsNull("Resource_Title_Name") OrElse Not .IsNull("Resource_Date")) Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("File_Name_or_Resource_ID"), EddErrors.CustomError20)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("File_Name_or_Resource_ID"), EddErrors.CustomError20)
      End If

      If .IsNull("Resource_Date") AndAlso (Not .IsNull("File_Name_or_Resource_ID") OrElse Not .IsNull("Resource_Title_Name")) Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Resource_Date"), EddErrors.CustomError20)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Resource_Date"), EddErrors.CustomError20)
      End If
    End With
  End Sub

    ''' <summary>If rt_analyte_detail.fraction_required_yn='Y' then Filtered_Fraction cannot equal 'NA'.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Results.Filtered_Fraction</item>
    '''   <item>Results.CAS_rn</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR59(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If Not rt_analyte_detail Is Nothing AndAlso Not .IsNull("Characteristic_Name") Then
        Dim cas_rn As String = GetCasRn(e.Row)
        If Not String.IsNullOrEmpty(cas_rn) Then
          Dim analyteResults() As System.Data.DataRow = rt_analyte_detail.Select(String.Format("cas_rn = '{0}'", cas_rn.Replace("'", "''")))
          If analyteResults.Length > 0 Then
            If analyteResults(0).Item("fraction_required_yn").ToString = "Y" AndAlso Remap(.Item("Filtered_Fraction"), "Filtered_Fraction", e.Row, "fraction", analyteResults(0)).ToString.ToUpper = "NA" Then
              Me.AddError(e.Row, e.Row.Table.Columns.Item("Filtered_Fraction"), EddErrors.CustomError23)

            Else
              'rt_analyte_detail.fraction_required_yn is null or 'N', OR fraction is null or 'Y'
              Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Filtered_Fraction"), EddErrors.CustomError23)
            End If

          Else
            'Cas_rn is not in rt_analyte_detail
            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Filtered_Fraction"), EddErrors.CustomError23)
          End If
        Else
          ' CAS_rn is null
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Filtered_Fraction"), EddErrors.CustomError23)
        End If

      Else
        'rt_analyte_detail is not in efd or CAS_rn is null
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Filtered_Fraction"), EddErrors.CustomError23)
      End If
    End With
  End Sub
    ''' <summary>If rt_analyte_detail.method_required_yn='Y' then Analytical_Method_ID must be entered.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Results.Analytical_Method_ID</item>
    '''   <item>Results.CAS_rn</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR90(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If Not rt_analyte_detail Is Nothing AndAlso Not .IsNull("Characteristic_Name") Then
        Dim cas_rn As String = GetCasRn(e.Row)
        If Not String.IsNullOrEmpty(cas_rn) Then
          Dim analyteResults() As System.Data.DataRow = rt_analyte_detail.Select(String.Format("cas_rn = '{0}'", cas_rn.Replace("'", "''")))
          If analyteResults.Length > 0 Then
            If analyteResults(0).Item("method_required_yn").ToString = "Y" AndAlso String.IsNullOrEmpty(.Item("Analytical_Method_ID").ToString) Then
              Me.AddError(e.Row, e.Row.Table.Columns.Item("Analytical_Method_ID"), EddErrors.CustomError90)
            Else
              'rt_analyte_detail.method_required_yn is null or 'N', OR method is null or 'Y'
              Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Analytical_Method_ID"), EddErrors.CustomError90)
            End If

          Else
            'Cas_rn is not in rt_analyte_detail
            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Analytical_Method_ID"), EddErrors.CustomError90)
          End If
        Else
          ' CAS_rn is null
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Analytical_Method_ID"), EddErrors.CustomError90)
        End If

      Else
        'rt_analyte_detail is not in efd or CAS_rn is null
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Analytical_Method_ID"), EddErrors.CustomError90)
      End If
    End With
  End Sub

    ''' <summary>If rt_analyte_detail.speciation_required_yn='Y' then Method_Speciation must be entered and can't be 'None'.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Results.Method_Speciation</item>
    '''   <item>Results.CAS_rn</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR91(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If Not rt_analyte_detail Is Nothing AndAlso Not .IsNull("Characteristic_Name") Then
        Dim cas_rn As String = GetCasRn(e.Row)
        If Not String.IsNullOrEmpty(cas_rn) Then
          Dim analyteResults() As System.Data.DataRow = rt_analyte_detail.Select(String.Format("cas_rn = '{0}'", cas_rn.Replace("'", "''")))
          If analyteResults.Length > 0 Then
            If analyteResults(0).Item("speciation_required_yn").ToString = "Y" AndAlso (.IsNull("Method_Speciation") or .Item("Method_Speciation").ToString.ToUpper = "NONE") Then
              Me.AddError(e.Row, e.Row.Table.Columns.Item("Method_Speciation"), EddErrors.CustomError91)
            Else
              'rt_analyte_detail.speciation_required_yn is null or 'N', OR speciation is null or 'Y'
              Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Method_Speciation"), EddErrors.CustomError91)
            End If

          Else
            'Cas_rn is not in rt_analyte_detail
            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Method_Speciation"), EddErrors.CustomError91)
          End If
        Else
          ' CAS_rn is null
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Method_Speciation"), EddErrors.CustomError91)
        End If

      Else
        'rt_analyte_detail is not in efd or CAS_rn is null
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Method_Speciation"), EddErrors.CustomError91)
      End If
    End With
  End Sub
    ''' <summary>If Activities.Medium='Biological' or 'Tissue', then Subject_Taxon is required.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Activities.Activity_ID</item>
    '''   <item>Activities.Medium</item>
    '''   <item>Results.Activity_ID</item>
    '''   <item>Results.Subject_Taxon</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR92(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If Not .IsNull("Activity_ID") AndAlso .Item("Activity_ID").ToString.Length > 0 AndAlso String.IsNullOrEmpty(.Item("Subject_Taxon").ToString) Then

        Dim activityId As String = .Item("Activity_ID").ToString.Replace("'", "''")

        ' MS.199172: the complexity of using the "X and (Y or Z)" criteria seems to avoid using the sorted DataView, so we will do it in two separate steps
        'Dim actRows() As System.Data.DataRow = Me.Activities.Select(String.Format("Activity_ID='{0}' and (Medium='Biological' or Medium='Tissue')", .Item("Activity_ID").ToString.Replace("'", "''")))

        ' first check for Medium='Biological'
        Dim actRows() As System.Data.DataRow = Me.Activities.Select(String.Format("Activity_ID='{0}' and Medium='Biological'", activityId))
        If actRows.Length > 0 Then
          Me.AddError(e.Row, e.Row.Table.Columns.Item("Subject_Taxon"), EddErrors.CustomError92)
        Else
          ' next check for Medium='Tissue'
          actRows = Me.Activities.Select(String.Format("Activity_ID='{0}' and Medium='Tissue'", activityId))
          If actRows.Length > 0 Then
            Me.AddError(e.Row, e.Row.Table.Columns.Item("Subject_Taxon"), EddErrors.CustomError92)
          Else
            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Subject_Taxon"), EddErrors.CustomError92)
          End If

        End If

      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Subject_Taxon"), EddErrors.CustomError92)
      End If
    End With
  End Sub

    ''' <summary>If Biological_Intent='Individual', then Biological_Individual_ID must be entered.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Results.Biological_Intent</item>
    '''   <item>Results.Biological_Individual_ID</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR93(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .Item("Biological_Intent").ToString.ToUpper = "INDIVIDUAL" AndAlso String.IsNullOrEmpty(.Item("Biological_Individual_ID").ToString) Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Biological_Individual_ID"), EddErrors.CustomError93)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Biological_Individual_ID"), EddErrors.CustomError93)
      End If
    End With
  End Sub


  ''' <summary>If Project_ID is populated then a parent record must exist in the Project section or in the database.
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Activities.Project_ID</item>
  ''' </list>
  ''' </summary>
  Private Sub ERR67(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If Not .IsNull("Project_ID") AndAlso Not Me.Efd.package.Connection Is Nothing Then
        Dim projectID As String = .Item("Project_ID").ToString
        'Look in the Project section for parent record
        Dim rows() As System.Data.DataRow = Me.Projects.Select(String.Format("Project_ID='{0}'", projectID.Replace("'", "''")))
        If rows.Length > 0 Then
          For Each row As System.Data.DataRow In rows
            If Not Me.IsCommentRow(row) Then
              'Valid parent record exist in the Project section
              Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Project_ID"), EddErrors.OrphanRow)
              Exit Sub
            End If
          Next

          'No parent record in the Project section so look in the database
          If HasDatabaseRecord(e.Row, "dt_task", "task_code", projectID) Then
            'Parent record exist in the database
            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Project_ID"), EddErrors.OrphanRow)
          Else
            'No parent record in the database
            Me.AddError(e.Row, e.Row.Table.Columns.Item("Project_ID"), EddErrors.OrphanRow)
          End If
        Else
          'No parent record in the Project section so look in the database
          If HasDatabaseRecord(e.Row, "dt_task", "task_code", projectID) Then
            'Parent record exist in the database
            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Project_ID"), EddErrors.OrphanRow)
          Else
            'No parent record in the database
            Me.AddError(e.Row, e.Row.Table.Columns.Item("Project_ID"), EddErrors.OrphanRow)
          End If
        End If
      Else
        'Project_ID is null or we are in Standalone
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Project_ID"), EddErrors.OrphanRow)
      End If
    End With
  End Sub

  ''' <summary>If Location_ID is populated then a parent record must exist in the Locations section or in the database.
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Activities.Location_ID</item>
  ''' </list>
  ''' </summary>
  Private Sub ERR60(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If Not .IsNull("Location_ID") AndAlso Not Me.Efd.package.Connection Is Nothing Then
        Dim stationID As String = .Item("Location_ID").ToString
        'Look in the Stations section for parent record
        Dim rows() As System.Data.DataRow = Me.Locations.Select(String.Format("Location_ID='{0}'", stationID.Replace("'", "''")))
        If rows.Length > 0 Then
          For Each row As System.Data.DataRow In rows
            If Not Me.IsCommentRow(row) Then
              'Valid parent record exist in the Station section
              Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Location_ID"), EddErrors.OrphanRow)
              Exit Sub
            End If
          Next

          'No parent record in the Station section so look in the database
          If HasDatabaseRecord(e.Row, "dt_location", "sys_loc_code", stationID) Then
            'Parent record exist in the database
            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Location_ID"), EddErrors.OrphanRow)
          Else
            'No parent record in the database
            Me.AddError(e.Row, e.Row.Table.Columns.Item("Location_ID"), EddErrors.OrphanRow)
          End If
        Else
          'No parent record in the Station section so look in the database
          If HasDatabaseRecord(e.Row, "dt_location", "sys_loc_code", stationID) Then
            'Parent record exist in the database
            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Location_ID"), EddErrors.OrphanRow)
          Else
            'No parent record in the database
            Me.AddError(e.Row, e.Row.Table.Columns.Item("Location_ID"), EddErrors.OrphanRow)
          End If
        End If
      Else
        'Station_ID is null or we are in Standalone
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Location_ID"), EddErrors.OrphanRow)
      End If
    End With
  End Sub

  Private Function HasDatabaseRecord(eddRow As System.Data.DataRow, ByVal tableName As String, ByVal columnName As String, ByVal value As String) As Boolean
    'Dim facilityId As String = Efd.package.Connection.SelectedFacility.Id
    If Efd.package.Connection Is Nothing Then Return False

    Dim facilityId As String = GetFacilityID(eddRow)
    If facilityId < 0 Then Return False

    Dim queryString As String = String.Format("select * from {0} where facility_id = {1} and {2} = '{3}'", tableName, facilityId, columnName, value.Replace("'", "''"))
    Dim dsResults As New System.Data.DataSet()

    Efd.package.Connection.Fill(dsResults, tableName, New EarthSoft.Common.Data.SafeSqlString(queryString))

    If dsResults.Tables(tableName).Rows.Count > 0 Then
      'record exists in the database
      Return True
    End If

    Return False
  End Function
  ''' <summary>If Activity_Start_Time or Activity_Start_Time_Zone is populated then the other is required.
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Activities.Activity_Start_Time</item>
  '''   <item>Activities.Activity_Start_Time_Zone</item>
  ''' </list>
  ''' </summary>
  Public Sub ERR76(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .IsNull("Activity_Start_Time") AndAlso Not .IsNull("Activity_Start_Time_Zone") Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Activity_Start_Time"), EddErrors.Required)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_Start_Time"), EddErrors.Required)
      End If

      If .IsNull("Activity_Start_Time_Zone") AndAlso Not .IsNull("Activity_Start_Time") Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Activity_Start_Time_Zone"), EddErrors.Required)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_Start_Time_Zone"), EddErrors.Required)
      End If

    End With
  End Sub

  ''' <summary>If Activity_End_Time or Activity_End_Time_Zone is populated then the other is required.
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Activities.Activity_End_Time</item>
  '''   <item>Activities.Activity_End_Time_Zone</item>
  ''' </list>
  ''' </summary>
  Public Sub ERR61(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .IsNull("Activity_End_Time") AndAlso Not .IsNull("Activity_End_Time_Zone") Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Activity_End_Time"), EddErrors.Required)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_End_Time"), EddErrors.Required)
      End If

      If .IsNull("Activity_End_Time_Zone") AndAlso Not .IsNull("Activity_End_Time") Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Activity_End_Time_Zone"), EddErrors.Required)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_End_Time_Zone"), EddErrors.Required)
      End If

    End With
  End Sub

  ''' <summary>If Activity_ID is populated then Activities.Location_ID must be populated.
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Activities.Activity_ID</item>
  ''' </list>
  ''' </summary>
  Public Sub ERR62(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .Item("Activity_ID").ToString <> String.Empty Then
        Dim activityRows() As System.Data.DataRow = Me.Activities.Select(String.Format("Activity_ID='{0}'", .Item("Activity_ID").ToString.Replace("'", "''")))
        If activityRows.Length > 0 Then
          For Each row As System.Data.DataRow In activityRows
            If row.Item("Location_ID").ToString <> String.Empty AndAlso Not IsCommentRow(row) Then
              Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_ID"), EddErrors.CustomError24)
              Exit Sub
            End If
          Next

          Me.AddError(e.Row, e.Row.Table.Columns.Item("Activity_ID"), EddErrors.CustomError24)
        Else
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_ID"), EddErrors.CustomError24)
          Me.AddError(e.Row, e.Row.Table.Columns.Item("Activity_ID"), EddErrors.OrphanRow)
        End If

      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Activity_ID"), EddErrors.CustomError24)
      End If
    End With
  End Sub

    ''' <summary>Check for parent record.
    '''If Place_Type='Project_ID' then parent needs to be in the Project section or dt_task.
    ''' If Place_Type='Location_ID' then parent needs to be in the Locations section or dt_location.
    ''' If Place_Type='Activity_ID' then parent needs to be in the Activities section or dt_sample.
    '''If Place_Type='Organization_ID' then parent needs to be in the Organization section or dt_facility.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Files.Place_Type</item>
    '''   <item>Files.Place_Code</item>
    ''' </list>
    ''' </summary>

    Private Sub ERR63(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If Not .IsNull("Place_Type") AndAlso Not .IsNull("Place_Code") AndAlso Not .IsNull("Org_Code") Then
        Dim placeCode As String = .Item("Place_Code").ToString.Replace("'", "''")
        Dim orgCode As String = .Item("Org_Code").ToString.Replace("'", "''")

        Dim resultRows() As System.Data.DataRow = Nothing
                Select Case .Item("Place_Type").ToString
                    Case "Organization_ID"
                        resultRows = Me.Organization.Select(String.Format("Organization_ID='{0}'", placeCode))
                    Case "Project_ID"
                        resultRows = Me.Projects.Select(String.Format("Project_ID='{0}' and Org_Code='{1}'", placeCode, orgCode))
                    Case "Location_ID"
                        resultRows = Me.Locations.Select(String.Format("Location_ID='{0}' and Org_Code='{1}'", placeCode, orgCode))
                    Case "Activity_ID"
                        resultRows = Me.Activities.Select(String.Format("Activity_ID='{0}' and Org_Code='{1}'", placeCode, orgCode))
                End Select

                If Not resultRows Is Nothing AndAlso resultRows.Length > 0 Then
          Dim hasParent As Boolean = False
          For Each row As System.Data.DataRow In resultRows
            If Not IsCommentRow(row) Then
              hasParent = True
              Exit For
            End If
          Next

          If hasParent Then
            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Place_Code"), EddErrors.OrphanRow)
          Else
            'There is no parent records that are not comment rows
            Me.AddError(e.Row, e.Row.Table.Columns.Item("Place_Code"), EddErrors.OrphanRow)
          End If
        Else
          'There is not matching rows in the parent table
          Dim hasParent As Boolean = False

          If Efd.package.Connection IsNot Nothing Then
            Dim cmd As System.Data.IDbCommand
            Dim dbCachedRow As System.Data.DataRow
            Dim facilityID As Integer = GetFacilityID(e.Row)
                        Select Case .Item("Place_Type").ToString
                            Case "Project_ID"
                                dbCachedRow = dbCachedData.Tables("dt_task").Rows.Find(New Object() {facilityID, placeCode})
                                If dbCachedRow IsNot Nothing Then
                                    If dbCachedRow.Item("found") Then
                                        hasParent = True
                                    End If
                                Else
                                    cmd = Efd.package.Connection.CreateCommand("select count(*) from dt_task where facility_id = @facility_id and task_code = @task_code")
                                    cmd.Parameters.Add(Efd.package.Connection.CreateDataParameter("@facility_id", facilityID, System.Data.DbType.Int32))
                                    cmd.Parameters.Add(Efd.package.Connection.CreateDataParameter("@task_code", placeCode, System.Data.DbType.String))
                                    Efd.package.Connection.PrepareTextCommand(cmd)
                                    If CType(cmd.ExecuteScalar(), Integer) > 0 Then
                                        hasParent = True
                                        dbCachedData.Tables("dt_task").Rows.Add(New Object() {facilityID, placeCode, True})
                                    Else
                                        dbCachedData.Tables("dt_task").Rows.Add(New Object() {facilityID, placeCode, False})
                                    End If
                                End If

                            Case "Location_ID"
                                dbCachedRow = dbCachedData.Tables("dt_location").Rows.Find(New Object() {facilityID, placeCode})
                                If dbCachedRow IsNot Nothing Then
                                    If dbCachedRow.Item("found") Then
                                        hasParent = True
                                    End If
                                Else
                                    cmd = Efd.package.Connection.CreateCommand("select count(*) from dt_location where facility_id = @facility_id and sys_loc_code = @sys_loc_code")
                                    cmd.Parameters.Add(Efd.package.Connection.CreateDataParameter("@facility_id", facilityID, System.Data.DbType.Int32))
                                    cmd.Parameters.Add(Efd.package.Connection.CreateDataParameter("@sys_loc_code", placeCode, System.Data.DbType.String))
                                    Efd.package.Connection.PrepareTextCommand(cmd)
                                    If CType(cmd.ExecuteScalar(), Integer) > 0 Then
                                        hasParent = True
                                        dbCachedData.Tables("dt_location").Rows.Add(New Object() {facilityID, placeCode, True})
                                    Else
                                        dbCachedData.Tables("dt_location").Rows.Add(New Object() {facilityID, placeCode, False})
                                    End If
                                End If

                            Case "Activity_ID"
                                dbCachedRow = dbCachedData.Tables("dt_sample").Rows.Find(New Object() {facilityID, placeCode})
                                If dbCachedRow IsNot Nothing Then
                                    If dbCachedRow.Item("found") Then
                                        hasParent = True
                                    End If
                                Else
                                    cmd = Efd.package.Connection.CreateCommand("select count(*) from dt_sample where facility_id = @facility_id and sys_sample_code = @sys_sample_code")
                                    cmd.Parameters.Add(Efd.package.Connection.CreateDataParameter("@facility_id", facilityID, System.Data.DbType.Int32))
                                    cmd.Parameters.Add(Efd.package.Connection.CreateDataParameter("@sys_sample_code", placeCode, System.Data.DbType.String))
                                    Efd.package.Connection.PrepareTextCommand(cmd)
                                    If CType(cmd.ExecuteScalar(), Integer) > 0 Then
                                        hasParent = True
                                        dbCachedData.Tables("dt_sample").Rows.Add(New Object() {facilityID, placeCode, True})
                                    Else
                                        dbCachedData.Tables("dt_sample").Rows.Add(New Object() {facilityID, placeCode, False})
                                    End If
                                End If

                            Case "Organization_ID"
                                dbCachedRow = dbCachedData.Tables("dt_facility").Rows.Find(New Object() {facilityID, placeCode})
                                If dbCachedRow IsNot Nothing Then
                                    If dbCachedRow.Item("found") Then
                                        hasParent = True
                                    End If
                                Else
                                    cmd = Efd.package.Connection.CreateCommand("select count(*) from dt_facility where facility_id = @facility_id")
                                    cmd.Parameters.Add(Efd.package.Connection.CreateDataParameter("@facility_id", facilityID, System.Data.DbType.Int32))
                                    cmd.Parameters.Add(Efd.package.Connection.CreateDataParameter("@facility_code", placeCode, System.Data.DbType.String))
                                    Efd.package.Connection.PrepareTextCommand(cmd)
                                    If CType(cmd.ExecuteScalar(), Integer) > 0 Then
                                        hasParent = True
                                        dbCachedData.Tables("dt_facility").Rows.Add(New Object() {facilityID, placeCode, True})
                                    Else
                                        dbCachedData.Tables("dt_facility").Rows.Add(New Object() {facilityID, placeCode, False})
                                    End If
                                End If

                        End Select
                    End If

          If Not hasParent Then
            Me.AddError(e.Row, e.Row.Table.Columns.Item("Place_Code"), EddErrors.OrphanRow)
          Else
            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Place_Code"), EddErrors.OrphanRow)
          End If
        End If
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Place_Code"), EddErrors.OrphanRow)
      End If

    End With
  End Sub

    ''' <summary>Field must be populated unless there is a remap for a null value in rt_remap_detail.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Activities.Medium_Subdivision</item>
    '''   <item>Results.Filtered_Fraction</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR64(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .IsNull(e.Column) Then
        If Efd.package.Tables.Item("rt_remap_detail").Select(String.Format("external_field='{0}' and external_value='null' and remap_code='WQX' and status_flag='A'", e.Column.ColumnName)).Length > 0 Then
          Me.RemoveError(e.Row, e.Column, EddErrors.CustomError25)
        Else
          Me.AddError(e.Row, e.Column, EddErrors.CustomError25)
        End If
      Else
        Me.RemoveError(e.Row, e.Column, EddErrors.CustomError25)
      End If
    End With
  End Sub

    ''' <summary>If Activities.Activity_Type='Field Msr/Obs-Portable Data Logger' or 'Quality Control Field Replicate Portable Data Logger', then Data_Logger_Line_Name is required.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Activities.Activity_ID</item>
    '''   <item>Activities.Activity_Type</item>
    '''   <item>Results.Activity_ID</item>
    '''   <item>Results.Data_Logger_Line_Name</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR65(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If Not .IsNull("Activity_ID") AndAlso .Item("Activity_ID").ToString.Length > 0 AndAlso .IsNull("Data_Logger_Line_Name") Then

        Dim activityId As String = .Item("Activity_ID").ToString.Replace("'", "''")

        ' MS.199172: the complexity of using the "X and (Y or Z)" criteria seems to avoid using the sorted DataView, so we will do it in two separate steps
        'Dim actRows() As System.Data.DataRow = Me.Activities.Select(String.Format("Activity_ID='{0}' and (Activity_Type='Field Msr/Obs-Portable Data Logger' or Activity_Type='Quality Control Field Replicate Portable Data Logger')", .Item("Activity_ID").ToString.Replace("'", "''")))

        ' first check for Activity_Type='Field Msr/Obs-Portable Data Logger'
        Dim actRows() As System.Data.DataRow = Me.Activities.Select(String.Format("Activity_ID='{0}' and Activity_Type='Field Msr/Obs-Portable Data Logger'", activityId))
        If actRows.Length > 0 Then
          Me.AddError(e.Row, e.Row.Table.Columns.Item("Data_Logger_Line_Name"), EddErrors.CustomError26)
        Else

          ' next check for Activity_Type='Quality Control Field Replicate Portable Data Logger'
          actRows = Me.Activities.Select(String.Format("Activity_ID='{0}' and Activity_Type='Quality Control Field Replicate Portable Data Logger'", activityId))
          If actRows.Length > 0 Then
            Me.AddError(e.Row, e.Row.Table.Columns.Item("Data_Logger_Line_Name"), EddErrors.CustomError26)
          Else
            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Data_Logger_Line_Name"), EddErrors.CustomError26)
          End If

        End If

      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Data_Logger_Line_Name"), EddErrors.CustomError26)
      End If
    End With
  End Sub

  ' ''' <summary>If DetectionQuantitationLimitTypeName='Lower Quantitation Limit', 'Upper Quantitation Limit', 'Method Detection Level (MDL)', 'Lower Reporting Limit', 'Upper Reporting Limit', 'LRL', 'MDL', or 'LQL' then DetectionQuantitationLimitMeasureValue must be numeric.
  ' ''' Applies to:
  ' ''' <list type="bullet">
  ' '''   <item>ResDetectionQuantLimit.DetectionQuantitationLimitTypeName</item>
  ' '''   <item>ResDetectionQuantLimit.DetectionQuantitationLimitMeasureValue</item>
  ' ''' </list>
  ' ''' </summary>
  'Private Sub ERR66(ByVal e As System.Data.DataColumnChangeEventArgs)
  '    Dim val As Double
  '    With e.Row
  '        If Not .IsNull("DetectionQuantitationLimitMeasureValue") AndAlso Me.limitTypes.Contains(.Item("DetectionQuantitationLimitTypeName").ToString.ToLower) AndAlso Not Double.TryParse(.Item("DetectionQuantitationLimitMeasureValue").ToString, val) Then
  '            Me.AddError(e.Row, e.Row.Table.Columns.Item("DetectionQuantitationLimitMeasureValue"), EddErrors.CustomError27)
  '        Else
  '            Me.RemoveError(e.Row, e.Row.Table.Columns.Item("DetectionQuantitationLimitMeasureValue"), EddErrors.CustomError27)
  '        End If
  '    End With
  'End Sub

  ''' <summary>Limit_Comment must be empty unless Method_Detection_Limit, Lower_Quantification_Limit, or Upper_Quantification_Limit is populated.
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Results.Limit_Comment</item>
  '''   <item>Results.Lower_Quantification_Limit</item>
  '''   <item>Results.Upper_Quantification_Limit</item>
  '''   <item>Results.Method_Detection_Limit</item>
  ''' </list>
  ''' </summary>
  Private Sub ERR68(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If Not .IsNull("Limit_Comment") AndAlso .IsNull("Lower_Quantification_Limit") AndAlso .IsNull("Upper_Quantification_Limit") AndAlso .IsNull("Method_Detection_Limit") Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Limit_Comment"), EddErrors.CustomError28)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Limit_Comment"), EddErrors.CustomError28)
      End If
    End With
  End Sub

  Private skipErr69 As Boolean = False
  ''' <summary>If Result_Text starts with a less than symbol then Result_Detection_Condition must be 'Not Detected' and Method_Detection_Limit will be populated with the Result_Text value after the less than symbol.
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Results.Result_Text</item>
  '''   <item>Results.Result_Detection_Condition</item>
  '''   <item>Results.Method_Detection_Limit</item>
  ''' </list>
  ''' </summary>
  Private Sub ERR69(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If skipErr69 Then Return

      Dim result_text As String = .Item("Result_Text").ToString
      Dim result_numeric As Double
            If result_text.StartsWith("<") AndAlso Double.TryParse(result_text.Substring(1).Trim, result_numeric) AndAlso InStr(.Item(Results_.Characteristic_Name).ToString.ToUpper, "CHOICE LIST") = 0 Then
                Dim hasError As Boolean = False
                If Not .IsNull("Result_Detection_Condition") AndAlso .Item("Result_Detection_Condition").ToString.ToLower <> "not detected" Then
                    hasError = True
                    Me.AddError(e.Row, e.Row.Table.Columns.Item("Result_Detection_Condition"), EddErrors.CustomError29)
                Else
                    Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Result_Detection_Condition"), EddErrors.CustomError29)
                End If


                If Not .IsNull("Method_Detection_Limit") AndAlso .Item("Method_Detection_Limit").ToString.ToLower <> result_text.Substring(1).Trim Then
                    hasError = True
                    Me.AddError(e.Row, e.Row.Table.Columns.Item("Method_Detection_Limit"), EddErrors.CustomError30)
                Else
                    Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Method_Detection_Limit"), EddErrors.CustomError30)
                End If

                If Not hasError Then
                    skipErr69 = True
                    .Item("Result_Detection_Condition") = "Not Detected"
                    .Item("Method_Detection_Limit") = result_text.Substring(1).Trim
                    .Item("Result_Text") = DBNull.Value
                    skipErr69 = False
                End If

            Else
                Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Result_Detection_Condition"), EddErrors.CustomError29)
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Method_Detection_Limit"), EddErrors.CustomError30)
      End If
    End With
  End Sub
  Private skipErr70 As Boolean = False
  ''' <summary>If Result_Text starts with a greater than symbol then Result_Detection_Condition must be 'Present Above Quantification Limit' and Upper_Quantification_Limit will be populated with the Result_Text value after the greater than symbol.
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Results.Result_Text</item>
  '''   <item>Results.Result_Detection_Condition</item>
  '''   <item>Results.Upper_Quantification_Limit</item>
  ''' </list>
  ''' </summary>
  Private Sub ERR70(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If skipErr70 Then Return

      Dim result_text As String = .Item("Result_Text").ToString
      Dim result_numeric As Double
            If result_text.StartsWith(">") AndAlso Double.TryParse(result_text.Substring(1).Trim, result_numeric) AndAlso InStr(.Item(Results_.Characteristic_Name).ToString.ToUpper, "CHOICE LIST") = 0 Then
                Dim hasError As Boolean = False
                If Not .IsNull("Result_Detection_Condition") AndAlso .Item("Result_Detection_Condition").ToString.ToLower <> "present above quantification limit" Then
                    hasError = True
                    Me.AddError(e.Row, e.Row.Table.Columns.Item("Result_Detection_Condition"), EddErrors.CustomError31)
                Else
                    Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Result_Detection_Condition"), EddErrors.CustomError31)
                End If


                If Not .IsNull("Upper_Quantification_Limit") AndAlso .Item("Upper_Quantification_Limit").ToString.ToLower <> result_text.Substring(1).Trim Then
                    hasError = True
                    Me.AddError(e.Row, e.Row.Table.Columns.Item("Upper_Quantification_Limit"), EddErrors.CustomError32)
                Else
                    Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Upper_Quantification_Limit"), EddErrors.CustomError32)
                End If

                If Not hasError Then
                    skipErr70 = True
                    .Item("Result_Detection_Condition") = "Present Above Quantification Limit"
                    .Item("Upper_Quantification_Limit") = result_text.Substring(1).Trim
                    .Item("Result_Text") = DBNull.Value
                    skipErr70 = False
                End If

            Else
                Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Result_Detection_Condition"), EddErrors.CustomError31)
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Upper_Quantification_Limit"), EddErrors.CustomError32)
      End If
    End With
  End Sub
  Private skipErr71 As Boolean = False
  ''' <summary>If Result_Text starts with a caret symbol then Result_Detection_Condition must be 'Present Below Quantification Limit' and Lower_Quantification_Limit will be populated with the Result_Text value after the caret symbol.
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Results.Result_Text</item>
  '''   <item>Results.Result_Detection_Condition</item>
  '''   <item>Results.Lower_Quantification_Limit</item>
  ''' </list>
  ''' </summary>
  Private Sub ERR71(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If skipErr71 Then Return

      Dim result_text As String = .Item("Result_Text").ToString
      Dim result_numeric As Double
            If result_text.StartsWith("^") AndAlso Double.TryParse(result_text.Substring(1).Trim, result_numeric) AndAlso InStr(.Item(Results_.Characteristic_Name).ToString.ToUpper, "CHOICE LIST") = 0 Then
                Dim hasError As Boolean = False
                If Not .IsNull("Result_Detection_Condition") AndAlso .Item("Result_Detection_Condition").ToString.ToLower <> "present below quantification limit" Then
                    hasError = True
                    Me.AddError(e.Row, e.Row.Table.Columns.Item("Result_Detection_Condition"), EddErrors.CustomError33)
                Else
                    Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Result_Detection_Condition"), EddErrors.CustomError33)
                End If


                If Not .IsNull("Lower_Quantification_Limit") AndAlso .Item("Lower_Quantification_Limit").ToString.ToLower <> result_text.Substring(1).Trim Then
                    hasError = True
                    Me.AddError(e.Row, e.Row.Table.Columns.Item("Lower_Quantification_Limit"), EddErrors.CustomError34)
                Else
                    Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Lower_Quantification_Limit"), EddErrors.CustomError34)
                End If

                If Not hasError Then
                    skipErr71 = True
                    .Item("Result_Detection_Condition") = "Present Below Quantification Limit"
                    .Item("Lower_Quantification_Limit") = result_text.Substring(1).Trim
                    .Item("Result_Text") = DBNull.Value
                    skipErr71 = False
                End If

            Else
                Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Result_Detection_Condition"), EddErrors.CustomError33)
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Lower_Quantification_Limit"), EddErrors.CustomError34)
      End If
    End With
  End Sub
  ''' <summary>Location_ID must begin with the Park_Code followed by Underscore
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Locations.Location_ID</item>
  '''   <item>Locations.Park_Code</item>
  ''' </list>
  ''' </summary>
  Private Sub ERR72(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
            'If Not .IsNull("Location_ID") AndAlso Not .IsNull("Park_Code") AndAlso Not .Item("Location_ID").StartsWith(.Item("Park_Code") + "_") Then
            '8/18/2017 allow Location_IDs to begin with Park_Code or Org_Code and Park_Code
            '5/2/2023 allow Location_IDs to begin with just the Org_Code
            If Not .IsNull("Location_ID") AndAlso Not .IsNull("Park_Code") AndAlso Not (.Item("Location_ID").StartsWith(.Item("Park_Code") + "_") Or .Item("Location_ID").StartsWith(.Item("Org_Code") + "_" + .Item("Park_Code") + "_") Or .Item("Location_ID").StartsWith(.Item("Org_Code") + "_")) Then
                Me.AddError(e.Row, e.Row.Table.Columns.Item("Location_ID"), EddErrors.CustomError35)
            Else
                Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Location_ID"), EddErrors.CustomError35)
            End If
        End With
  End Sub
  ''' <summary>If Result_Detection_Condition is 'Not Detected', Method_Detection_Limit is required.
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Results.Result_Detection_Condition</item>
  '''   <item>Results.Method_Detection_Limit</item>
  ''' </list>
  ''' </summary>
  Private Sub ERR73(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .Item("Result_Detection_Condition").ToString.ToLower = "not detected" AndAlso .IsNull("Method_Detection_Limit") Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Method_Detection_Limit"), EddErrors.CustomError36)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Method_Detection_Limit"), EddErrors.CustomError36)
      End If
    End With
  End Sub
  ''' <summary>If Result_Detection_Condition is 'Present Above Quantification Limit', Upper_Quantification_Limit is required.
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Results.Result_Detection_Condition</item>
  '''   <item>Results.Upper_Quantification_Limit</item>
  ''' </list>
  ''' </summary>
  Private Sub ERR74(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .Item("Result_Detection_Condition").ToString.ToLower = "present above quantification limit" AndAlso .IsNull("Upper_Quantification_Limit") Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Upper_Quantification_Limit"), EddErrors.CustomError37)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Upper_Quantification_Limit"), EddErrors.CustomError37)
      End If
    End With
  End Sub
  ''' <summary>If Result_Detection_Condition is 'Present Below Quantification Limit', Lower_Quantification_Limit is required.
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Results.Result_Detection_Condition</item>
  '''   <item>Results.Lower_Quantification_Limit</item>
  ''' </list>
  ''' </summary>
  Private Sub ERR75(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .Item("Result_Detection_Condition").ToString.ToLower = "present below quantification limit" AndAlso .IsNull("Lower_Quantification_Limit") Then
        Me.AddError(e.Row, e.Row.Table.Columns.Item("Lower_Quantification_Limit"), EddErrors.CustomError75)
      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Lower_Quantification_Limit"), EddErrors.CustomError75)
      End If
    End With
  End Sub
    ''' <summary>If Elevation is not populated, then Elevation_Unit, Elevation_Method, Elevation_Datum, Elevation_Accuracy, and Elevation_Accuracy_Unit should be empty required.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Locations.Elevation</item>
    '''   <item>Locations.Elevation_Unit</item>
    '''   <item>Locations.Elevation_Method</item>
    '''   <item>Locations.Elevation_Datum</item>
    '''   <item>Locations.Elevation_Accuracy</item>
    '''   <item>Locations.Elevation_Accuracy_Unit</item>
    '''   <item>ActivitySites.Elevation</item>
    '''   <item>ActivitySites.Elevation_Unit</item>
    '''   <item>ActivitySites.Elevation_Method</item>
    '''   <item>ActivitySites.Elevation_Datum</item>
    '''   <item>ActivitySites.Elevation_Accuracy</item>
    '''   <item>ActivitySites.Elevation_Accuracy_Unit</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR86(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .IsNull("Elevation") Then
        If Not .IsNull("Elevation_Unit") Then
          Me.AddError(e.Row, e.Row.Table.Columns.Item("Elevation_Unit"), EddErrors.CustomError86)
        Else
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Elevation_Unit"), EddErrors.CustomError86)
        End If

        If Not .IsNull("Elevation_Method") Then
          Me.AddError(e.Row, e.Row.Table.Columns.Item("Elevation_Method"), EddErrors.CustomError86)
        Else
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Elevation_Method"), EddErrors.CustomError86)
        End If

        If Not .IsNull("Elevation_Datum") Then
          Me.AddError(e.Row, e.Row.Table.Columns.Item("Elevation_Datum"), EddErrors.CustomError86)
        Else
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Elevation_Datum"), EddErrors.CustomError86)
        End If

        If Not .IsNull("Elevation_Accuracy") Then
          Me.AddError(e.Row, e.Row.Table.Columns.Item("Elevation_Accuracy"), EddErrors.CustomError86)
        Else
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Elevation_Accuracy"), EddErrors.CustomError86)
        End If

        If Not .IsNull("Elevation_Accuracy_Unit") Then
          Me.AddError(e.Row, e.Row.Table.Columns.Item("Elevation_Accuracy_Unit"), EddErrors.CustomError86)
        Else
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Elevation_Accuracy_Unit"), EddErrors.CustomError86)
        End If

      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Elevation_Unit"), EddErrors.CustomError86)
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Elevation_Method"), EddErrors.CustomError86)
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Elevation_Datum"), EddErrors.CustomError86)
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Elevation_Accuracy"), EddErrors.CustomError86)
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Elevation_Accuracy_Unit"), EddErrors.CustomError86)

      End If
    End With
  End Sub
  ''' <summary>If Latitude or Longitude not populated, then Lat_Lon_Accuracy and Lat_Lon_Accuracy_Unit should be empty.
  ''' Applies to:
  ''' <list type="bullet">
  '''   <item>Locations.Latitude</item>
  '''   <item>Locations.Longitude</item>
  '''   <item>Locations.Lat_Lon_Accuracy</item>
  '''   <item>Locations.Lat_Lon_Accuracy_Unit</item>
  ''' </list>
  ''' </summary>
  Private Sub ERR87(ByVal e As System.Data.DataColumnChangeEventArgs)
    With e.Row
      If .IsNull("Latitude") Or .IsNull("Longitude") Then

        If Not .IsNull("Lat_Lon_Accuracy") Then
          Me.AddError(e.Row, e.Row.Table.Columns.Item("Lat_Lon_Accuracy"), EddErrors.CustomError87)
        Else
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Lat_Lon_Accuracy"), EddErrors.CustomError87)
        End If

        If Not .IsNull("Lat_Lon_Accuracy_Unit") Then
          Me.AddError(e.Row, e.Row.Table.Columns.Item("Lat_Lon_Accuracy_Unit"), EddErrors.CustomError87)
        Else
          Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Lat_Lon_Accuracy_Unit"), EddErrors.CustomError87)
        End If

      Else
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Lat_Lon_Accuracy"), EddErrors.CustomError87)
        Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Lat_Lon_Accuracy_Unit"), EddErrors.CustomError87)

      End If
    End With
  End Sub
    ''' <summary>If Latitude or Longitude not populated, then Lat_Lon_Method, Lat_Lon_Datum, Lat_Lon_Accuracy and Lat_Lon_Accuracy_Unit should be empty.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>ActivitySites.Latitude</item>
    '''   <item>ActivitySites.Longitude</item>
    '''   <item>ActivitySites.Lat_Lon_Method</item>
    '''   <item>ActivitySites.Lat_Lon_Datum</item>
    '''   <item>ActivitySites.Lat_Lon_Accuracy</item>
    '''   <item>ActivitySites.Lat_Lon_Accuracy_Unit</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR88(ByVal e As System.Data.DataColumnChangeEventArgs)
        With e.Row
            If .IsNull("Latitude") Or .IsNull("Longitude") Then

                If Not .IsNull("Lat_Lon_Method") Then
                    Me.AddError(e.Row, e.Row.Table.Columns.Item("Lat_Lon_Method"), EddErrors.CustomError88)
                Else
                    Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Lat_Lon_Method"), EddErrors.CustomError88)
                End If

                If Not .IsNull("Lat_Lon_Datum") Then
                    Me.AddError(e.Row, e.Row.Table.Columns.Item("Lat_Lon_Datum"), EddErrors.CustomError88)
                Else
                    Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Lat_Lon_Datum"), EddErrors.CustomError88)
                End If

                If Not .IsNull("Lat_Lon_Accuracy") Then
                    Me.AddError(e.Row, e.Row.Table.Columns.Item("Lat_Lon_Accuracy"), EddErrors.CustomError88)
                Else
                    Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Lat_Lon_Accuracy"), EddErrors.CustomError88)
                End If

                If Not .IsNull("Lat_Lon_Accuracy_Unit") Then
                    Me.AddError(e.Row, e.Row.Table.Columns.Item("Lat_Lon_Accuracy_Unit"), EddErrors.CustomError88)
                Else
                    Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Lat_Lon_Accuracy_Unit"), EddErrors.CustomError88)
                End If

            Else
                Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Lat_Lon_Method"), EddErrors.CustomError88)
                Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Lat_Lon_Datum"), EddErrors.CustomError88)
                Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Lat_Lon_Accuracy"), EddErrors.CustomError88)
                Me.RemoveError(e.Row, e.Row.Table.Columns.Item("Lat_Lon_Accuracy_Unit"), EddErrors.CustomError88)

            End If
        End With
    End Sub
    ''' <summary>Result_Unit required if Method_Detection_Limit, Lower_Quantification_Limit, or Upper_Quantification_Limit is populated.
    ''' Applies to:
    ''' <list type="bullet">
    '''   <item>Results.Result_Unit</item>
    '''   <item>Results.Lower_Quantification_Limit</item>
    '''   <item>Results.Upper_Quantification_Limit</item>
    '''   <item>Results.Method_Detection_Limit</item>
    ''' </list>
    ''' </summary>
    Private Sub ERR89(ByVal e As System.Data.DataColumnChangeEventArgs)
        With e.Row
            If .IsNull("Result_Unit") Then
                If Not .IsNull("Method_Detection_Limit") OrElse Not .IsNull("Lower_Quantification_Limit") OrElse Not .IsNull("Upper_Quantification_Limit") Then
                    Me.AddError(e.Row, e.Row.Table.Columns.Item("Result_Unit"), EddErrors.CustomError89)
                Else
                    Me.RemoveError(e.Row, e.Row.Table.Columns.item("Result_Unit"), EddErrors.CustomError89)
                End If
            Else
                Me.RemoveError(e.Row, e.Row.Table.Columns.item("Result_Unit"), EddErrors.CustomError89)
            End If
        End With
    End Sub


#End Region

    Private skipAnalytePopulate As Boolean = False
  Private Sub PopulateChemicalName(ByVal e As System.Data.DataColumnChangeEventArgs)
    If skipAnalytePopulate Then Return
    With e.Row
      If Not .IsNull("CAS_rn") Then
        Dim dtAnalyte As System.Data.DataTable = Me.Efd.package.Tables("rt_analyte")
        Dim result() As System.Data.DataRow = dtAnalyte.Select(String.Format("cas_rn='{0}'", .Item("CAS_rn").ToString.Replace("'", "''")))
        If result.Length > 0 Then
          skipAnalytePopulate = True
          .Item("Characteristic_Name") = result(0).Item("chemical_name")
          skipAnalytePopulate = False
        End If
      End If
    End With
  End Sub
  Private Sub PopulateCasRn(ByVal e As System.Data.DataColumnChangeEventArgs)
    If skipAnalytePopulate Then Return
    With e.Row
      If Not .IsNull("Characteristic_Name") Then
        Dim dtAnalyte As System.Data.DataTable = Me.Efd.package.Tables("rt_analyte")
        Dim result() As System.Data.DataRow = dtAnalyte.Select(String.Format("chemical_name='{0}'", .Item("Characteristic_Name").ToString.Replace("'", "''")))
        If result.Length > 0 Then
          skipAnalytePopulate = True
          .Item("CAS_rn") = result(0).Item("cas_rn")
          skipAnalytePopulate = False
        End If
      End If
    End With
  End Sub

  Public Shadows Function GetCasRn(eddRow As System.Data.DataRow) As String
    Dim analyteRows() As System.Data.DataRow = Efd.package.Tables("rt_analyte").Select(String.Format("chemical_name='{0}'", eddRow.Item("Characteristic_Name").ToString.Replace("'", "''")))
    If analyteRows.Length > 0 Then
      Return analyteRows(0).Item("cas_rn").ToString
    End If

    Return String.Empty
  End Function

  Private Function IsCommentRow(ByVal row As System.Data.DataRow) As Boolean
    For Each symbol As String In Me.Efd.CommentIndicator
      If row.Item(0).ToString.StartsWith(symbol) Then Return True
    Next

    Return False
  End Function

  ''' <summary>
  ''' Determines whether the column is one of the biological result columns.
  ''' </summary>
  ''' <param name="columnOrdinal">The index/ordinal of the column within the Results section.</param>
  ''' <returns>
  ''' <c>true</c> if the column is part of the biological results columns; otherwise, <c>false</c>.
  ''' </returns>
  Private Function IsBiologicalResult(columnOrdinal As Integer) As Boolean
    Select Case columnOrdinal
      Case Results_.Biological_Individual_ID, Results_.Subject_Taxon, Results_.Unidentified_Species_ID, Results_.Tissue_Anatomy,
  Results_.Group_Summary_Count_or_Weight, Results_.Group_Summary_Count_or_Weight_Unit, Results_.Cell_Form, Results_.Cell_Shape,
  Results_.Habit_Name_1, Results_.Habit_Name_2, Results_.Habit_Name_3, Results_.Voltinism, Results_.Pollution_Tolerance, Results_.Pollution_Tolerance_Scale,
  Results_.Trophic_Level, Results_.Functional_Feeding_Group_1, Results_.Functional_Feeding_Group_2, Results_.Functional_Feeding_Group_3,
  Results_.Frequency_Class_Descriptor_1, Results_.Frequency_Class_Bounds_Unit_1, Results_.Frequency_Class_Lower_Bound_1, Results_.Frequency_Class_Upper_Bound_1,
  Results_.Frequency_Class_Descriptor_2, Results_.Frequency_Class_Bounds_Unit_2, Results_.Frequency_Class_Lower_Bound_2, Results_.Frequency_Class_Upper_Bound_2,
  Results_.Frequency_Class_Descriptor_3, Results_.Frequency_Class_Bounds_Unit_3, Results_.Frequency_Class_Lower_Bound_3, Results_.Frequency_Class_Upper_Bound_3

        Return True
    End Select

    Return False
  End Function

#Region "Grid Events"
  Public Overrides Sub Grid_BeforeCellListDropDown(ByVal sender As Object, ByVal e As Object, ByVal edp As Object)
    If e.cell.column.key = "County_Code" Then
      'Filter County_Code drop down based on State_Code
      If e.cell.row.cells.item("State_Code").value Is DBNull.Value Then
        e.cell.Column.ValueList.Datasource.Rowfilter = String.Empty
      Else
        e.cell.Column.ValueList.Datasource.Rowfilter = String.Format("state_code='{0}'", e.cell.row.cells.item("State_Code").value)
      End If

    End If
  End Sub

  'for most checks, if one cell is updated, the other needs to be explicitly updated
  'because the error will need to be added/removed to both columns
  Public Overrides Sub Grid_AfterCellUpdate(ByVal sender As Object, ByVal e As Object, ByVal edp As Object)
    Try
      Select Case CType(e.cell.row.listObject, System.Data.DataRowView).DataView.Table.TableName
        'Case "Organization"
        '  Organization_Refresh(sender, e, edp)
        'Case "PrjMonitorLocationWeight"
        '  PrjMonitorLocationWeight_Refresh(sender, e, edp)
        Case "Indices"
          Indices_Refresh(sender, e, edp)
        Case "Locations"
          MonitoringLocation_Refresh(sender, e, edp)
        Case "Activities"
          Activity_Refresh(sender, e, edp)
        Case "ActivitySites"
          ActivitySites_Refresh(sender, e, edp)
        Case "Metrics"
          Metrics_Refresh(sender, e, edp)
        Case Result.TableName
          'Case "Results"
          Result_Refresh(sender, e, edp)
       'Case "ResDetectionQuantLimit"
         'ResDetectionQuantLimit_Refresh(sender, e, edp)
        Case "Files"
          Files_Refresh(sender, e, edp)
      End Select

    Catch ex As System.Exception
      'ignore exceptions for now...
      'EarthSoft.Common.Message.Show(ex)
    End Try
  End Sub

    'Private Sub Organization_Refresh(ByVal sender As Object, ByVal e As Object, ByVal edp As Object)
    '  Select Case e.Cell.Column.Key
    '    Case "AddressText"
    '      edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("AddressTypeName"))       'ERR01
    '    Case "AddressTypeName"
    '      edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("AddressText"))     'ERR01
    '    Case "County_Code"
    '      edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("State_Code"))       'ERR04
    '    Case "ElectronicAddressText"
    '      edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("ElectronicAddressTypeName"))       'ERR01
    '    Case "ElectronicAddressTypeName"
    '      edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("ElectronicAddressText"))     'ERR01
    '    Case "State_Code"
    '      edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("County_Code"))       'ERR53
    '    Case "TelephoneNumberText"
    '      edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("TelephoneNumberTypeName"))       'ERR01
    '    Case "TelephoneNumberTypeName"
    '      edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("TelephoneNumberText"))     'ERR01
    '  End Select
    'End Sub

    Private Sub PrjMonitorLocationWeight_Refresh(ByVal sender As Object, ByVal e As Object, ByVal edp As Object)
    Select Case e.Cell.Column.Key
      Case "LocationWeightingFactorMeasureUnitCode"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("LocationWeightingFactorMeasureValue"))     'ERR05
      Case "LocationWeightingFactorMeasureValue"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("LocationWeightingFactorMeasureUnitCode"))     'ERR05
      Case "Resource_Title_Name", "File_Name_or_Resource_ID", "Resource_Date"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Resource_Title_Name"))     'ERR58
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("File_Name_or_Resource_ID"))     'ERR58
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Resource_Date"))     'ERR58
    End Select
  End Sub

  Private Sub MonitoringLocation_Refresh(ByVal sender As Object, ByVal e As Object, ByVal edp As Object)
    Select Case e.Cell.Column.Key
      Case "Park_Code"
                'Comment out for the SFAN network because of GOGA/PORE where PORE actually administers lands for GOGA
                edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Location_ID"))     'ERR72
            Case "Alternate_Location_ID_Context"
                edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Alternate_Location_ID"))     'ERR07
      Case "Alternate_Location_ID"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Alternate_Location_ID_Context"))       'ERR07
      Case "Aquifer_Name", "Formation_Type"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Well_Type"))       'ERR10
      Case "Latitude"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lat_Lon_Accuracy"))       'ERR87
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lat_Lon_Accuracy_Unit"))       'ERR87
      Case "Longitude"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lat_Lon_Accuracy"))       'ERR87
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lat_Lon_Accuracy_Unit"))       'ERR87
      Case "Lat_Lon_Accuracy_Unit"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lat_Lon_Accuracy"))       'ERR05
      Case "Lat_Lon_Accuracy"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lat_Lon_Accuracy_Unit"))       'ERR05   
      Case "Elevation_Accuracy_Unit"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Elevation_Accuracy"))       'ERR05
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Elevation_Accuracy_Unit"))       'ERR86
      Case "Elevation_Accuracy"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Elevation_Accuracy_Unit"))       'ERR05   
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Elevation_Accuracy"))       'ERR86
      Case "Lat_Lon_Method"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Source_Map_Scale_Numeric"))       'ERR08
      Case "Elevation"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Elevation_Unit"))       'ERR09
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Elevation_Method"))       'ERR09
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Elevation_Datum"))       'ERR09
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Elevation_Accuracy"))       'ERR86
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Elevation_Accuracy_Unit"))       'ERR86
      Case "Well_Hole_Depth_Unit"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Well_Hole_Depth"))       'ERR05
      Case "Well_Hole_Depth"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Well_Hole_Depth_Unit"))       'ERR05
      Case "Contributing_Area_Unit"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Contributing_Area"))       'ERR05
      Case "Contributing_Area"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Contributing_Area_Unit"))       'ERR05
      Case "Drainage_Area_Unit"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Drainage_Area"))       'ERR05
      Case "Drainage_Area"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Drainage_Area_Unit"))       'ERR05
      Case "State_Code"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("County_Code"))       'ERR53
    End Select
  End Sub

  Private Sub Indices_Refresh(ByVal sender As Object, ByVal e As Object, ByVal edp As Object)
    Select Case e.Cell.Column.Key
      Case "Resource_Title_Name", "File_Name_or_Resource_ID", "Resource_Date"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Resource_Title_Name"))     'ERR58
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("File_Name_or_Resource_ID"))     'ERR58
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Resource_Date"))     'ERR58
    End Select
  End Sub

  Private Sub Activity_Refresh(ByVal sender As Object, ByVal e As Object, ByVal edp As Object)
    Select Case e.Cell.Column.Key
      Case "Activity_Start_Date"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_End_Date"))                         'ERR83
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_End_Time"))                         'ERR83
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_Start_Time"))                       'ERR83
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Analysis_Start_Date"))                       'ERR79
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Analysis_Start_Time"))                       'ERR79
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lab_Sample_Preparation_Start_Date"))         'ERR79
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lab_Sample_Preparation_Start_Time"))         'ERR79
      Case "Activity_Start_Time"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_End_Date"))          'ERR83
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_End_Time"))          'ERR83
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_Start_Date"))        'ERR83
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_Start_Time_Zone"))   'ERR76
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_Start_Time"))       'ERR12
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_Start_Time_Zone"))  'ERR13
      Case "Activity_Start_Time_Zone"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_Start_Time"))        'ERR76
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_End_Time_Zone"))     'ERR84
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_End_Time_Zone"))    'ERR44  
      Case "Activity_End_Date"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_Start_Date"))        'ERR83
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_Start_Time"))        'ERR83
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_End_Time"))          'ERR83
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_Start_Time"))       'ERR12
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_Start_Time_Zone"))  'ERR13
      Case "Activity_End_Time"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_Start_Date"))        'ERR83
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_Start_Time"))        'ERR83
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_End_Date"))          'ERR83
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_End_Time_Zone"))     'ERR61
      Case "Activity_End_Time_Zone"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_End_Time"))          'ERR61
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_Start_Time_Zone"))   'ERR84
      Case "Activity_Depth"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_Depth_Unit"))        'ERR05
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_Upper_Depth"))       'ERR02
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_Lower_Depth"))       'ERR02
      Case "Activity_Depth_Unit"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_Depth_Unit"))        'ERR85   
      Case "Container_Size"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Container_Size_Unit"))        'ERR05
      Case "Container_Size_Unit"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Container_Size"))             'ERR05   
      Case "Activity_Type"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Collection_Method_ID"))       'ERR20
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_Upper_Depth"))       'ERR51
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_Lower_Depth"))       'ERR51
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Location_ID"))                'ERR56
     'Case "Activity_Lower_Depth_Unit"
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_Lower_Depth"))      'ERR05
      Case "Activity_Lower_Depth"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_Depth_Unit"))        'ERR05
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_Upper_Depth"))       'ERR02
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_Depth"))             'ERR02
      Case "Activity_ID"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Medium"))                     'ERR48
      Case "Medium"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Medium"))                     'ERR48
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Assemblage_Sampled_Name"))    'ERR19
      'Case "Activity_Relative_Depth"
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_End_Time"))         'ERR14
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_End_Time_Zone"))    'ERR15
      'Case "Activity_Upper_Depth_Unit"
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_Upper_Depth"))      'ERR05
      Case "Activity_Upper_Depth"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_Lower_Depth"))       'ERR02
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_Depth"))             'ERR02
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Activity_Depth_Unit"))        'ERR05
      Case "Boat_Speed_Unit"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Boat_Speed"))                 'ERR05
      Case "Boat_Speed"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Boat_Speed_Unit"))            'ERR05
      Case "Collection_Duration"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Collection_Duration_Unit"))   'ERR05
      Case "Collection_Duration_Unit"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Collection_Duration"))        'ERR05
      Case "Current_Speed"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Current_Speed_Unit"))         'ERR05
      Case "Current_Speed_Unit"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Current_Speed"))              'ERR05
      Case "Collection_Effort"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Collection_Effort_Gear_Type"))'ERR05
      Case "Collection_Effort_Gear_Type"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Collection_Effort"))          'ERR05
      Case "Net_Surface_Area", "Net_Surface_Area_Unit", "Net_Mesh_Size", "Net_Mesh_Size_Unit"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Net_Type"))                   'ERR23
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Net_Surface_Area"))           'ERR23
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Net_Surface_Area_Unit"))      'ERR23
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Net_Mesh_Size"))              'ERR23
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Net_Mesh_Size_Unit"))         'ERR23
      Case "Net_Type"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Net_Surface_Area"))           'ERR23
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Net_Surface_Area_Unit"))      'ERR23
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Net_Mesh_Size"))              'ERR23
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Net_Mesh_Size_Unit"))         'ERR23
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Boat_Speed"))                 'ERR25
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Collection_Equipment_Name"))  'ERR03
      Case "Reach_Length"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Reach_Length_Unit"))          'ERR05
      Case "Reach_Length_Unit"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Reach_Length"))               'ERR05
      Case "Reach_Width"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Reach_Width_Unit"))           'ERR05
      Case "Reach_Width_Unit"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Reach_Width"))                'ERR05
      'Case "Collection_Method_ID_Context", "Collection_Method_Name"
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Collection_Method_ID"))          'ERR27
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Collection_Method_ID_Context"))  'ERR27
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Collection_Method_Name"))        'ERR27
      Case "Collection_Method_ID"
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Collection_Method_ID_Context"))  'ERR27
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Collection_Method_Name"))        'ERR27
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Collection_Equipment_Name"))      'ERR28
      Case "Preparation_Method_ID"
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Preparation_Method_Name"))       'ERR11
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Preparation_Method_ID_Context")) 'ERR11
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Container_Type"))                 'ERR16
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Container_Color"))                'ERR16
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Transport_Storage_Description"))  'ERR16
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Chemical_Preservative"))          'ERR17
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Thermal_Preservative"))           'ERR17
      'Case "Preparation_Method_ID_Context", "Preparation_Method_Name"
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Preparation_Method_Name"))       'ERR11
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Preparation_Method_ID_Context")) 'ERR11
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Preparation_Method_ID"))         'ERR11
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Chemical_Preservative"))         'ERR17
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Thermal_Preservative"))          'ERR17
    End Select
  End Sub

  Private Sub ActivitySites_Refresh(ByVal sender As Object, ByVal e As Object, ByVal edp As Object)
    Select Case e.Cell.Column.Key
      Case "Latitude"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Longitude"))                 'ERR18
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lat_Lon_Method"))            'ERR21, ERR88
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lat_Lon_Datum"))             'ERR21, ERR88
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lat_Lon_Accuracy"))          'ERR88
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lat_Lon_Accuracy_Unit"))     'ERR88
      Case "Longitude"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Latitude"))                  'ERR18
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lat_Lon_Method"))            'ERR21, ERR88
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lat_Lon_Datum"))             'ERR21, ERR88
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lat_Lon_Accuracy"))          'ERR88
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lat_Lon_Accuracy_Unit"))     'ERR88
      Case "Lat_Lon_Method"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Source_Map_Scale_Numeric"))  'ERR08
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lat_Lon_Method"))            'ERR88
      Case "Lat_Lon_Datum"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lat_Lon_Datum"))             'ERR88
      Case "Lat_Lon_Accuracy_Unit"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lat_Lon_Accuracy"))          'ERR05
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lat_Lon_Accuracy_Unit"))     'ERR88
      Case "Lat_Lon_Accuracy"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lat_Lon_Accuracy_Unit"))     'ERR05   
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lat_Lon_Accuracy"))          'ERR88
      Case "Elevation_Accuracy_Unit"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Elevation_Accuracy"))        'ERR05
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Elevation_Accuracy_Unit"))   'ERR86
      Case "Elevation_Accuracy"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Elevation_Accuracy_Unit"))   'ERR05
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Elevation_Accuracy"))        'ERR86
      Case "Lat_Lon_Method"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Source_Map_Scale_Numeric"))  'ERR08
      Case "Elevation"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Elevation_Unit"))            'ERR09
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Elevation_Method"))          'ERR09
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Elevation_Datum"))           'ERR09
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Elevation_Accuracy"))        'ERR86
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Elevation_Accuracy_Unit"))   'ERR86 
      Case "Elevation_Method"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Elevation_Unit"))            'ERR09
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Elevation"))                 'ERR09
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Elevation_Datum"))           'ERR09
      Case "Elevation_Datum"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Elevation_Unit"))            'ERR09
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Elevation_Method"))          'ERR09
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Elevation"))                 'ERR09
    End Select
  End Sub

  Private Sub Metrics_Refresh(ByVal sender As Object, ByVal e As Object, ByVal edp As Object)
    Select Case e.Cell.Column.Key
      Case "Index_ID"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Index_ID"))                  'ERR52
      Case "Metric_Value"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Metric_Value_Unit"))         'ERR05
      Case "Metric_Value_Unit"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Metric_Value"))              'ERR05
      Case "Resource_Title_Name", "File_Name_or_Resource_ID", "Resource_Date"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Resource_Title_Name"))       'ERR58
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("File_Name_or_Resource_ID"))  'ERR58
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Resource_Date"))             'ERR58
    End Select
  End Sub

  Private Sub Result_Refresh(ByVal sender As Object, ByVal e As Object, ByVal edp As Object)

    ' The grid column as a "Tag" property that is the EddColumn
    Dim columnOrdinal As Integer = e.Cell.Column.Tag.Ordinal

    If IsBiologicalResult(columnOrdinal) Then edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Biological_Intent")) 'ERR45

    Select Case columnOrdinal
      Case Results_.Activity_ID
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Analytical_Method_ID"))                     'ERR55
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Data_Logger_Line_Name"))                    'ERR65
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Subject_Taxon"))                            'ERR92
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Biological_Intent"))                        'ERR48
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Tissue_Anatomy"))                           'ERR48
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Analysis_Start_Date"))                      'ERR79
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Analysis_Start_Time"))                      'ERR79
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lab_Sample_Preparation_Start_Date"))        'ERR79
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lab_Sample_Preparation_Start_Time"))        'ERR79
      'Case "Analysis_End_Date"
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Analysis_Start_Time_Zone"))                 ERR38
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Analysis_End_Date"))                       'ERR78
      'Case "Analysis_End_Time"
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Analysis_End_Time_Zone"))                  'ERR39
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Analysis_End_Date"))                       'ERR78
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Analysis_Start_Time"))                     'ERR37
      'Case "Analysis_End_Time_Zone"
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Analysis_End_Time"))                       'ERR39
      Case Results_.Analysis_Start_Date
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Analysis_End_Date"))                       'ERR78
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Analysis_Start_Date"))                      'ERR79
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Analysis_Start_Time"))                      'ERR79
      Case Results_.Analysis_Start_Time
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Analysis_Start_Time_Zone"))                 'ERR77
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Analysis_End_Date"))                       'ERR78
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Analysis_Start_Time_Zone"))                'ERR38
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Analysis_Start_Date"))                      'ERR79
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Analysis_Start_Time"))                      'ERR79
      Case Results_.Analysis_Start_Time_Zone
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Analysis_Start_Time"))                      'ERR77
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Analysis_Start_Time"))                      'ERR37
      Case Results_.Biological_Intent
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Group_Summary_Count_or_Weight"))            'ERR29
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Characteristic_Name"))                      'ERR46, ERR47
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Tissue_Anatomy"))                           'ERR48
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Biological_Intent"))                        'ERR48
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Biological_Individual_ID"))                 'ERR93 
     'Case "CAS_rn"
       'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Characteristic_Name"))       'PopulateChemicalName
       'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Filtered_Fraction"))       'ERR59
      Case Results_.Characteristic_Name
        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("CAS_rn"))    'PopulateCasRn
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Result_Text"))       'ERR54
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Filtered_Fraction")) 'ERR59
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Analytical_Method_ID")) 'ERR90
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Method_Speciation")) 'ERR91
      Case Results_.Frequency_Class_Descriptor_1
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Frequency_Class_Bounds_Unit_1"))       'ERR30
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Frequency_Class_Lower_Bound_1"))       'ERR30
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Frequency_Class_Upper_Bound_1"))       'ERR30
      Case Results_.Frequency_Class_Bounds_Unit_1, Results_.Frequency_Class_Lower_Bound_1, Results_.Frequency_Class_Upper_Bound_1
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Frequency_Class_Descriptor_1"))       'ERR33
      Case Results_.Frequency_Class_Descriptor_2
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Frequency_Class_Bounds_Unit_2"))       'ERR31
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Frequency_Class_Lower_Bound_2"))       'ERR31
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Frequency_Class_Upper_Bound_2"))       'ERR31
      Case Results_.Frequency_Class_Bounds_Unit_2, Results_.Frequency_Class_Lower_Bound_2, Results_.Frequency_Class_Upper_Bound_2
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Frequency_Class_Descriptor_2"))       'ERR34
      Case Results_.Frequency_Class_Descriptor_3
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Frequency_Class_Bounds_Unit_3"))       'ERR32
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Frequency_Class_Lower_Bound_3"))       'ERR32
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Frequency_Class_Upper_Bound_3"))       'ERR32
      Case Results_.Frequency_Class_Bounds_Unit_3, Results_.Frequency_Class_Lower_Bound_3, Results_.Frequency_Class_Upper_Bound_3
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Frequency_Class_Descriptor_3"))       'ERR35
      Case Results_.Group_Summary_Count_or_Weight_Unit
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Group_Summary_Count_or_Weight"))       'ERR05
      Case Results_.Group_Summary_Count_or_Weight
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Group_Summary_Count_or_Weight_Unit"))       'ERR05
      Case Results_.Lab_Sample_Preparation_ID ', Results_.Lab_Sample_Preparation_ID_Context ', "Lab_Sample_Preparation_Method_Name"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lab_Sample_Preparation_ID"))       'ERR40
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lab_Sample_Preparation_ID_Context"))       'ERR40
       'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lab_Sample_Preparation_Method_Name"))       'ERR40
      Case Results_.Lower_Quantification_Limit
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Limit_Comment"))       'ERR68
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Result_Detection_Condition"))       'ERR69, ERR75
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Result_Text"))       'ERR22, ERR82
        edp.AfterCellUpdate(sender, e.cell.row.cells.item("Method_Detection_Limit")) 'ERR81
        edp.AfterCellUpdate(sender, e.cell.row.cells.item("Upper_Quantification_Limit")) 'ERR81
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Result_Unit"))       'ERR89 
      Case Results_.Upper_Quantification_Limit
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Limit_Comment"))       'ERR68
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Result_Detection_Condition"))       'ERR69, ERR74
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Result_Text"))       'ERR22, ERR82
        edp.AfterCellUpdate(sender, e.cell.row.cells.item("Method_Detection_Limit")) 'ERR81
        edp.AfterCellUpdate(sender, e.cell.row.cells.item("Lower_Quantification_Limit")) 'ERR81
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Result_Unit"))       'ERR89
      Case Results_.Method_Detection_Limit
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Limit_Comment"))       'ERR68
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Result_Detection_Condition"))       'ERR69, ERR73
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Result_Text"))       'ERR22, ERR82
        edp.AfterCellUpdate(sender, e.cell.row.cells.item("Lower_Quantification_Limit")) 'ERR81
        edp.AfterCellUpdate(sender, e.cell.row.cells.item("Upper_Quantification_Limit")) 'ERR81
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Result_Unit"))       'ERR89
      Case Results_.Result_Text
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Result_Unit"))       'ERR24
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Result_Type"))       'ERR24
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Result_Status"))       'ERR26
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Result_Detection_Condition"))       'ERR69
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Method_Detection_Limit"))       'ERR69, ERR82
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Upper_Quantification_Limit"))       'ERR70, ERR82
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lower_Quantification_Limit"))       'ERR71, ERR82
      Case Results_.Result_Qualifier
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Result_Text"))       'ERR22, ERR82
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Result_Detection_Condition"))       'ERR69
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Method_Detection_Limit"))       'ERR69, ERR82
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Upper_Quantification_Limit"))       'ERR70, ERR82
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lower_Quantification_Limit"))       'ERR71, ERR82
      Case Results_.Lab_Sample_Preparation_Start_Date
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lab_Sample_Preparation_Start_Date"))         'ERR79
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lab_Sample_Preparation_Start_Time"))         'ERR79
      Case Results_.Lab_Sample_Preparation_Start_Time
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lab_Sample_Preparation_Start_Date"))         'ERR79
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lab_Sample_Preparation_Start_Time"))         'ERR79
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lab_Sample_Preparation_Start_Time"))       'ERR41
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lab_Sample_Preparation_Start_Time_Zone"))       'ERR41
      Case Results_.Lab_Sample_Preparation_Start_Time_Zone
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lab_Sample_Preparation_Start_Time"))       'ERR41
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lab_Sample_Preparation_Start_Time_Zone"))       'ERR41
      Case Results_.Resource_Title_Name, Results_.File_Name_or_Resource_ID, Results_.Resource_Date
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Resource_Title_Name"))     'ERR58
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("File_Name_or_Resource_ID"))     'ERR58
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Resource_Date"))     'ERR58
      Case Results_.Analytical_Method_ID
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Analytical_Method_ID_Context"))       'ERR36
      Case Results_.Result_Depth_Height_Measure_Unit
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Result_Depth_Height_Measure"))       'ERR05
      Case Results_.Result_Depth_Height_Measure
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Result_Depth_Height_Measure_Unit"))       'ERR05
      Case Results_.Result_Detection_Condition
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Result_Text"))       'ERR22
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Method_Detection_Limit"))       'ERR69, ERR73
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Upper_Quantification_Limit"))       'ERR70, ERR74
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Lower_Quantification_Limit"))       'ERR71, ERR75
      Case Results_.Tissue_Anatomy
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Biological_Intent"))       'ERR48
      Case Results_.Biological_Individual_ID
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Biological_Intent"))                 'ERR93 
    End Select
  End Sub

  'Private Sub ResDetectionQuantLimit_Refresh(ByVal sender As Object, ByVal e As Object, ByVal edp As Object)
  '    Select Case e.Cell.Column.Key
  '        'Case "DetectionQuantitationLimitTypeName", "DetectionQuantitationLimitMeasureValue", "DetectionQuantitationLimitMeasureUnitCode"
  '        '    edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("DetectionQuantitationLimitTypeName"))       'ERR43, ERR49
  '        '    edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("DetectionQuantitationLimitMeasureValue"))       'ERR43, ERR49
  '        '    edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("DetectionQuantitationLimitMeasureUnitCode"))       'ERR43, ERR49
  '        'Case "Activity_ID"
  '        '    edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("DetectionQuantitationLimitTypeName"))       'ERR49
  '        '    edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("DetectionQuantitationLimitMeasureValue"))       'ERR49
  '        '    edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("DetectionQuantitationLimitMeasureUnitCode"))       'ERR49
  '        'Case "CAS_rn"
  '        'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Characteristic_Name"))       'PopulateChemicalName
  '        Case "Characteristic_Name"
  '            'edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("CAS_rn"))       'PopulateCasRn
  '        Case "DetectionQuantitationLimitTypeName"
  '            edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("DetectionQuantitationLimitMeasureValue"))       'ERR66
  '    End Select
  'End Sub

  Private Sub Files_Refresh(ByVal sender As Object, ByVal e As Object, ByVal edp As Object)
    Select Case e.Cell.Column.Key
      Case "Place_Type", "Org_Code"
        edp.AfterCellUpdate(sender, e.Cell.Row.Cells.Item("Place_Code"))       'ERR63
    End Select
  End Sub


  Public Overrides Sub Grid_ClickCellButton(ByVal sender As Object, ByVal e As Object, ByVal edp As Object)
    'edit button clicked for field file_name in File_v1 section
    Dim dlg As New System.Windows.Forms.OpenFileDialog
    With dlg
      .Title = "Select File"
      '.Filter = "PDF Files (*.pdf)|*.pdf"

      If .ShowDialog = Windows.Forms.DialogResult.Cancel Then Return

    End With

    e.Cell.Value = System.IO.Path.GetFileName(dlg.FileName)
    PopulatedFileFields(e, dlg.FileName)
  End Sub

  'BHM_Case26818_20081112
  'Populate other file fields after filename is updated
  Private Sub PopulatedFileFields(ByVal e As Object, ByVal filename As String)
    With e.cell.row.cells
      'Cannot access File Summary information (author, title, comment) without using DSOFile dll
      'dll download site: http://www.microsoft.com/downloads/details.aspx?familyid=9ba6fac6-520b-4a0a-878a-53ec8300c4c2&displaylang=en
      'example site: http://forums.asp.net/p/1256106/2337231.aspx#2337231

      If e.cell.band.key = "Files" Then
        If System.IO.File.Exists(filename) Then
          Dim colType As EddColumn = CType(Me.Files.Columns("File_Type"), EddColumn)
          If colType.Lookup Is Nothing Then
            .Item("File_Type").value = System.IO.Path.GetExtension(filename)
          Else
            Dim row() As System.Data.DataRowView = colType.Lookup.FindRows(System.IO.Path.GetExtension(filename))
            If row.Length > 0 Then
              .Item("File_Type").value = row(0).Item("file_type")
            Else
              .Item("File_Type").value = System.IO.Path.GetExtension(filename)
            End If
          End If

          'Only automatically fill the file date if the file type isn't an image
          'Need to compare to image types in rt_file_type (file_type)
          'Image files are identified by the first 5 characters of app_code='image'
          Dim Frows() As System.Data.DataRow = Efd.package.Tables.Item("rt_file_type").Select(String.Format("file_type='{0}' and app_code like 'image%'", .item("File_Type").Value.ToString.Replace("'", "''")))
          If Frows.Length = 0 Then
            .Item("File_Date").value = System.IO.File.GetCreationTime(filename).Date

          End If
          Dim fs As System.IO.FileStream
          fs = New System.IO.FileStream(filename, System.IO.FileMode.Open, System.IO.FileAccess.Read)
          Try
            Dim data(fs.Length) As Byte
            fs.Read(data, 0, fs.Length)
            .Item("File_Content").value = System.Convert.ToBase64String(data)

          Catch ex As Exception

          Finally
            fs.Close()
          End Try
        Else
          .Item("File_Type").value = DBNull.Value
          .Item("File_Date").value = DBNull.Value
          .Item("File_Content").value = DBNull.Value
        End If

      ElseIf e.cell.band.key = "Results" Then
        If System.IO.File.Exists(filename) Then
          .Item("Result_File_Date").value = System.IO.File.GetCreationTime(filename).Date

          Dim fs As System.IO.FileStream
          fs = New System.IO.FileStream(filename, System.IO.FileMode.Open, System.IO.FileAccess.Read)
          Try
            Dim data(fs.Length) As Byte
            fs.Read(data, 0, fs.Length)
            .Item("Result_File_Content").value = System.Convert.ToBase64String(data)

          Catch ex As Exception

          Finally
            fs.Close()
          End Try
        Else
          .Item("Result_File_Date").value = DBNull.Value
          .Item("Result_File_Content").value = DBNull.Value
        End If
      End If
    End With

  End Sub
#End Region

#Region "Create"
  Private FacilityID As Integer = -1
  Public Function NewFacilityID(ByVal eddRow As System.Data.DataRow) As Integer
    Try
      Dim query As String = String.Format("select facility_id from dt_facility where facility_code='{0}'", eddRow.Item("OrganizationIdentifier").ToString.Replace("'", "''"))
      Dim dsResults As New System.Data.DataSet
      Me.Efd.package.Connection.Fill(dsResults, "facility", New EarthSoft.Common.Data.SafeSqlString(query))
      If dsResults.Tables.Item("facility").Rows.Count > 0 Then
        FacilityID = dsResults.Tables.Item("facility").Rows(0).Item("facility_id")
      Else
        'The facility_code does not exist in the database
        FacilityID = Efd.package.Connection.NewId(EarthSoft.Common.Data.Connection.Ids.facility_id)
      End If

    Catch ex As Exception
      FacilityID = Integer.MinValue
    End Try

    Return FacilityID
  End Function
  '9/28/2015
  Public Function GetFacilityID(ByVal eddrow As System.Data.DataRow) As Integer
    If eddrow.IsNull("Org_Code") Then Return Efd.package.Connection.SelectedFacility.Id

    Static lastFacilityCode As String
    Static facilityId As Integer
    Try
      Dim thisFacilityCode As String = eddrow.Item("Org_Code").ToString
      If lastFacilityCode Is Nothing OrElse Not lastFacilityCode.Equals(thisFacilityCode) Then

        lastFacilityCode = thisFacilityCode
        Dim rows = dtFacilities.Select(String.Format("facility_code='{0}'", thisFacilityCode.Replace("'", "''")))
        If rows.Count > 0 Then
          facilityId = rows(0).Item("facility_id")
        Else
          facilityId = Integer.MinValue
        End If

      End If
    Catch ex As Exception
      facilityId = Integer.MinValue
    End Try

    Return facilityId
  End Function

  'Public Function GetFacilityID() As Integer
  '  If FacilityID = -1 Then
  '    'Facility ID has not been set so there is no rows in the Organization section or all the rows have errors.
  '    If Not IsNothing(Me.Organization) Then
  '      If Me.Organization.Rows.Count > 0 Then
  '        For Each row As System.Data.DataRow In Me.Organization.Rows
  '          If Not IsCommentRow(row) Then
  '            'There is a row in the Organzation section with errors so set the Facility ID to fail 
  '            FacilityID = Integer.MinValue
  '            Exit For
  '          End If
  '        Next

  '        'All the rows in the Organization section are comment rows so we will set the Facility ID to the current facility
  '        If FacilityID = -1 Then FacilityID = Efd.package.Connection.SelectedFacility.Id
  '      Else
  '        'There is no rows in the Organization section so we will set the Facility ID to the current facility
  '        FacilityID = Efd.package.Connection.SelectedFacility.Id
  '      End If
  '    Else
  '      'There is no rows in the Organization section so we will set the Facility ID to the current facility
  '      FacilityID = Efd.package.Connection.SelectedFacility.Id
  '    End If
  '  End If

  '  'Facility ID >=0 : Facility ID was found or there is no Organization rows and we are using the current facility
  '  'Facility ID < -1 : Either an exception occured in NewFacilityID method or there is a row with errors in the Organization section so we set the facility ID to fail
  '  Return FacilityID
  'End Function

  Private Samples As New System.Collections.Generic.Dictionary(Of String, SampleRecord)
  Private ClearDictionary As Boolean = False
  ''' <summary>
  ''' If Container_Type, Container_Color, Chemical_Preservative, Thermal_Preservative, or Transport_Storage_Description is 
  ''' populated then create reference to the row so we can map those fields to dt_test in the Result section.
  ''' </summary>
  ''' <param name="eddRow">The edd row.</param>
  ''' <param name="targetRow">The target row.</param>
  ''' <returns>Activity_ID</returns>
  Public Function AddReference(ByVal eddRow As System.Data.DataRow, ByVal targetRow As System.Data.DataRow) As Object
    Try
      'We need to clear the list each time the Create button is clicked
      If ClearDictionary Then
        Samples.Clear()
        ClearDictionary = False
      End If

      With eddRow
        If Not .IsNull("Container_Type") OrElse Not .IsNull("Container_Color") OrElse Not .IsNull("Chemical_Preservative") _
  OrElse Not .IsNull("Thermal_Preservative") OrElse Not .IsNull("Transport_Storage_Description") Then

          If Not Samples.ContainsKey(.Item("Activity_ID").ToString) Then
            Samples.Add(.Item("Activity_ID").ToString, New SampleRecord(eddRow))
          End If
        End If
      End With

    Catch ex As Exception
      'Ignore exceptions
      'Only 2 types of exceptions could occur:
      '  ArgumentNullException - key is null reference (Nothing in Visual Basic).
      '  ArgumentException - An element with the same key already exists in the Dictionary<(Of <(TKey, TValue>)>).
    End Try

    Return eddRow.Item("Activity_ID")
  End Function

  ''' <summary>
  ''' Maps the sample fields from the Activities section.
  ''' </summary>
  ''' <param name="eddRow">The edd row.</param>
  ''' <param name="targetRow">The target row.</param>
  ''' <returns>Time_Basis</returns>
  Public Function MapSampleFields(ByVal eddRow As System.Data.DataRow, ByVal targetRow As System.Data.DataRow) As Object
    'When this function is called all valid rows in Activities will be mapped and cleared, so if we set the flag here to clear the dictionary, then it will get cleared the next time the Create button is clicked.
    ClearDictionary = True

    With targetRow
      If Samples.ContainsKey(eddRow.Item("Activity_ID").ToString) Then
        Dim sampleRow As SampleRecord = Samples.Item(eddRow("Activity_ID").ToString)

        .Item("container_type") = sampleRow.ContainerType
        .Item("container_color") = sampleRow.ContainerColor
        .Item("container_size") = sampleRow.ContainerSize
        .Item("container_unit") = sampleRow.ContainerSizeUnit
        .Item("preservative") = sampleRow.Preservative
        .Item("temp_preserve_type") = sampleRow.TempPreserveType
        .Item("remark") = sampleRow.Remark
      End If

    End With

    Return eddRow.Item("Time_Basis")
  End Function
  Public Shadows Function GetCasRn(ByVal eddRow As System.Data.DataRow, ByVal targetRow As System.Data.DataRow) As String
    Static chemicalName As String = String.Empty
        'Dim dv As System.Data.DataView
        Static casRn As String = String.Empty

    ' get the chemical name in the current row
    Dim str As String = eddRow.Item("Characteristic_Name").ToString

    If Not chemicalName.Equals(str) Then
      chemicalName = str
      Dim rows = Me.rt_analyte.Select("chemical_name = '" & chemicalName.Replace("'", "''") & "'")
      ' get the sample_id from dt_sample
      If rows.Count > 0 Then
        casRn = rows(0).Item("cas_rn").ToString
      Else
        casRn = String.Empty
      End If
    End If
    Return casRn
  End Function

  Private Function GetFrequencyType(ByVal eddRow As System.Data.DataRow, ByVal strField As String) As String
    Static FrequencyType As String = String.Empty
    With eddRow
      If Not IsCommentRow(eddRow) Then
        If Not .IsNull(strField) Then
          Dim sampleTypeRows() As System.Data.DataRow = Efd.package.Tables.Item("rt_frequency_class").Select(String.Format("frequency_class='{0}'", .Item(strField).ToString.Replace("'", "''")))
          If sampleTypeRows.Length = 1 Then
            FrequencyType = sampleTypeRows(0).Item("frequency_type").ToString.ToUpper
          Else
            FrequencyType = String.Empty
          End If
        End If
      End If
    End With
    Return FrequencyType
  End Function
  Public Shadows Function GetSampleID(ByVal eddRow As System.Data.DataRow, ByVal targetRow As System.Data.DataRow) As Integer
    Static sysSampleCode As String = String.Empty
    Static sampleId As Integer

    ' get the sys_sample_code in the current row
    Dim str As String = eddRow.Item("Activity_ID").ToString

    ' If Not sysSampleCode.Equals(str) Then
    sysSampleCode = str
    Dim rows = Me.dt_sample.Select("sys_sample_code = '" & sysSampleCode.Replace("'", "''") & "'")
    ' get the sample_id from dt_sample 
    If rows.Count > 0 Then
      sampleId = CType(rows(0).Item("sample_id"), Integer)
    Else
      sampleId = -1
    End If

    'End If
    Return sampleId
  End Function

  ' we need  to include biological_intent, taxon, and unidentified_species
  Protected Structure WqxTestAlternateKey
    Public sample_id As Integer
    Public analytic_method As String
    Public analysis_date As Date
    Public fraction As String
    Public column_number As String
    Public test_type As String
    Public biological_intent As String
    Public taxon As String
    Public Unidentified_Species As String
    Public Overrides Function ToString() As String
      'Return String.Format("sample_id={0}; analytic_method={1}; analysis_date={2}; fraction={3}; column_number={4}; test_type={5}; biological_intent={6}; taxon={7}", sample_id, analytic_method, analysis_date, fraction, column_number, test_type, biological_intent, taxon)
      Return String.Format("sample_id={0}; analytic_method={1}; analysis_date={2}; fraction={3}; column_number={4}; test_type={5}; biological_intent={6}; taxon={7}; Unidentified_Species={8}", sample_id, analytic_method, analysis_date, fraction, column_number, test_type, biological_intent, taxon, Unidentified_Species)
    End Function
  End Structure

  Public Shadows Function GetTestID(ByVal eddRow As System.Data.DataRow, ByVal targetRow As System.Data.DataRow) As Integer
    Static testId As Integer

    ' cache the last test that was accessed
    Static lastKey As WqxTestAlternateKey
    Dim thisKey As WqxTestAlternateKey = GetCurrentKey(eddRow, targetRow, True)

    ' does the last key we found match this key?
    ' If Not lastKey.Equals(thisKey) Then

    ' cache this key
    lastKey = thisKey

    ' build the filter (NOTE: If you change the order of these fields or add/remove fields, make sure to change the dt_test.DefaultView.Sort in AddDataHandlers)
    Dim filter As New System.Text.StringBuilder(255)
    filter.Append("sample_id = '" & thisKey.sample_id & "' AND analytic_method = '" & thisKey.analytic_method.Replace("'", "''") & "' ")
    filter.Append(String.Format(" and isnull(analysis_date, #1900/1/1 00:00:00#) = #{0}#", thisKey.analysis_date.ToString("yyyy-MM-dd HH:mm:ss")))
    filter.Append(String.Format(" and isnull(fraction, '') = '{0}'", thisKey.fraction.Replace("'", "''")))
    filter.Append(String.Format(" and isnull(column_number, '') = '{0}'", thisKey.column_number.Replace("'", "''")))
    filter.Append(String.Format(" and isnull(test_type, '') = '{0}'", thisKey.test_type.Replace("'", "''")))
    filter.Append(String.Format(" and isnull(biological_intent, '') = '{0}'", thisKey.biological_intent.Replace("'", "''")))
    filter.Append(String.Format(" and isnull(taxon, '') = '{0}'", thisKey.taxon.Replace("'", "''")))
    filter.Append(String.Format(" and isnull(unknown_species_identifier, '') = '{0}'", thisKey.Unidentified_Species.Replace("'", "''")))

    ' get the test_id from dt_test
    Dim rows = Me.dt_test.Select(filter.ToString)
    If rows.Count > 0 Then
      testId = CType(rows(0).Item("test_id"), Integer)
    Else
      testId = -1
    End If

    ' End If

    Return testId
  End Function

  Private Function GetCurrentKey(eddRow As System.Data.DataRow, targetRow As System.Data.DataRow, FindColumnNumber As Boolean) As WqxTestAlternateKey
    Dim thisKey As New WqxTestAlternateKey

    ' get all of the values for this key
    With thisKey
      .sample_id = GetSampleID(eddRow, targetRow)
      .analytic_method = GetAnalyticMethod(eddRow)
      .analysis_date = GetAnalysis_Start_Date(eddRow)
      .fraction = Remap(eddRow.Item("Filtered_Fraction").ToString, "Filtered_Fraction", eddRow, "fraction", targetRow)
      If FindColumnNumber Then .column_number = GetColumnNumber(eddRow, targetRow)
      .test_type = GetTest_Type(eddRow)
      .biological_intent = Microsoft.VisualBasic.IIf(eddRow.IsNull("Biological_Intent"), String.Empty, eddRow.Item("Biological_Intent"))
      .taxon = Microsoft.VisualBasic.IIf(eddRow.IsNull("Subject_Taxon"), String.Empty, eddRow.Item("Subject_Taxon"))
      .Unidentified_Species = Microsoft.VisualBasic.IIf(eddRow.IsNull("Unidentified_Species_ID"), String.Empty, eddRow.Item("Unidentified_Species_ID"))
    End With

    Return thisKey
  End Function

  Public Function GetColumnNumber(eddRow As System.Data.DataRow, targetRow As System.Data.DataRow) As String
    With eddRow
      If Not .IsNull("weight_basis") OrElse Not .IsNull("temperature_basis") OrElse Not .IsNull("dilution_factor") OrElse Not .IsNull("time_basis") Then

        Dim thisKey As WqxTestAlternateKey = GetCurrentKey(eddRow, targetRow, False)
        Dim filter As New System.Text.StringBuilder(255)
        filter.Append("sample_id = '" & thisKey.sample_id & "' AND analytic_method = '" & thisKey.analytic_method.Replace("'", "''") & "' ")
        filter.Append(String.Format(" and isnull(analysis_date, #1900/1/1 00:00:00#) = #{0}#", thisKey.analysis_date.ToString("yyyy-MM-dd HH:mm:ss")))
        filter.Append(String.Format(" and isnull(fraction, '') = '{0}'", thisKey.fraction.Replace("'", "''")))
        filter.Append(String.Format(" and isnull(test_type, '') = '{0}'", thisKey.test_type.Replace("'", "''")))
        filter.Append(String.Format(" and isnull(biological_intent, '') = '{0}'", thisKey.biological_intent.Replace("'", "''")))
        filter.Append(String.Format(" and isnull(taxon, '') = '{0}'", thisKey.taxon.Replace("'", "''")))
        filter.Append(String.Format(" and isnull(unknown_species_identifier, '') = '{0}'", thisKey.Unidentified_Species.Replace("'", "''")))

        Dim strBuilder As New System.Text.StringBuilder
        strBuilder.Append(String.Format(" and isnull(basis, '') = '{0}'", .Item("weight_basis").ToString.Replace("'", "''")))
        strBuilder.Append(String.Format(" and isnull(temp_basis, '') = '{0}'", .Item("temperature_basis").ToString.Replace("'", "''")))
        strBuilder.Append(String.Format(" and isnull(duration_basis, '') = '{0}'", .Item("time_basis").ToString.Replace("'", "''")))
        strBuilder.Append(String.Format(" and isnull(convert(dilution_factor, 'System.String'), '') = '{0}'", .Item("dilution_factor").ToString.Replace("'", "''")))
        'Adding Tissue_Anatomy to custom_field_1, This enables us to generate a new column number for different Tissue_Anatomy values. We mapped it to dt_test.custom_field_1 because Tissue_Anatomy 
        'is mapped to dt_biological_result and when generating a column number we cannot get this value by linking to this table as you can't calculate the test_id untill you have a column number
        strBuilder.Append(String.Format(" and isnull(custom_field_1, '') = '{0}'", .Item("Tissue_Anatomy").ToString.Replace("'", "''")))

        Dim testRecords() As System.Data.DataRow = Me.dt_test.Select(filter.ToString + strBuilder.ToString)
        If testRecords.Length > 0 Then Return testRecords(0).Item("column_number")

        ' In order to use the vw_test index, we will just use "filter" and then apply the other logic with Linq
        'testRecords = Me.dt_test.Select(filter.ToString + " and (basis is not null or temp_basis is not null or duration_basis is not null or dilution_factor is not null)")
        testRecords = Me.dt_test.Select(filter.ToString)
        testRecords = (From dr As DataRow In testRecords Where Not dr.IsNull("basis") Or Not dr.IsNull("temp_basis") Or Not dr.IsNull("duration_basis") Or Not dr.IsNull("dilution_factor") Select dr).ToArray()

        If testRecords.Length > 0 Then
          Dim max As Integer = 0
          Dim count As Integer
          For Each record As System.Data.DataRow In testRecords
            If Integer.TryParse(record.Item("column_number").ToString, count) AndAlso count > max Then max = count
          Next
          Return (max + 1).ToString
        Else
          Return "1"
        End If
      End If
    End With

    Return "NA"
  End Function

  Public Function GetCountyCode(ByVal eddrow As System.Data.DataRow) As Object
    With eddrow
      If .IsNull("County_Code") Then Return DBNull.Value

      Dim county As String = .Item("County_Code").ToString.Replace("'", "''")
      Dim state As String = .Item("State_Code").ToString.Replace("'", "''")
      Dim rows() As System.Data.DataRow = Efd.package.Tables.Item("rt_county").Select(String.Format("state_code='{0}' and county_name='{1}'", state, county))
      If rows.Length > 0 Then
        Return rows(0).Item("county_name")
      Else
        Return .Item("County_Code")
      End If
    End With
  End Function

  ''' <summary>
  ''' Gets the result analytic method.
  ''' </summary>
  ''' <param name="eddRow">The edd row.</param>
  ''' <returns>'NPS_Unspecified' if analytical method is null; otherwise returns the value in the analytic method.</returns>
  Public Function GetAnalyticMethod(ByVal eddRow As System.Data.DataRow) As String
    If Not eddRow.IsNull("Analytical_Method_ID") Then Return eddRow.Item("Analytical_Method_ID")

    Return "NPS_Unspecified"
  End Function
  ''' <summary>
  ''' Populate test_type.
  ''' </summary>
  ''' <param name="eddRow">The edd row.</param>
  ''' <returns>'INITIAL' if Statistical_Basis is null; otherwise returns the left 10 characters of Statistical_Basis.</returns>
  Public Function GetTest_Type(ByVal eddRow As System.Data.DataRow) As String
    If Not eddRow.IsNull("Statistical_Basis") Then Return Left(eddRow.Item("Statistical_Basis"), 10).Trim
    Return "INITIAL"
  End Function
  ''' <summary>
  ''' Check Location_Description
  ''' </summary>
  ''' <param name="eddRow">The edd row.</param>
  ''' <returns>Null if Location_Description is null; otherwise returns 'See Remark_2'.</returns>
  Public Function Check_for_Location_Description(ByVal eddRow As System.Data.DataRow) As String
    If Not eddRow.IsNull("Location_Description") Then Return "See Remark_2"
    Return Nothing
  End Function
  Public Function GetPublicLatitude(ByVal eddRow As System.Data.DataRow) As String
    If eddRow.IsNull("Public_Latitude") Then Return eddRow.Item("Latitude")
    Return eddRow.Item("Public_Latitude")
  End Function
  Public Function GetPublicLongitude(ByVal eddRow As System.Data.DataRow) As String
    If eddRow.IsNull("Public_Longitude") Then Return eddRow.Item("Longitude")
    Return eddRow.Item("Public_Longitude")
  End Function

  Public Function GetActivityStartDate(ByVal eddRow As System.Data.DataRow) As Date
    If eddRow.IsNull("Activity_Start_Date") Then Return Nothing
    If Not eddRow.Table.Columns.Contains("Activity_Start_Time") Then Return CType(eddRow.Item("Activity_Start_Date"), Date)
    Return Date.Parse(String.Format("{0} {1}", CType(eddRow.Item("Activity_Start_Date"), Date).ToShortDateString, eddRow.Item("Activity_Start_Time")))
  End Function

  Public Function GetActivityEndDate(ByVal eddRow As System.Data.DataRow) As Date
    If eddRow.IsNull("Activity_End_Date") Then Return Nothing
    If Not eddRow.Table.Columns.Contains("Activity_End_Time") Then Return CType(eddRow.Item("Activity_End_Date"), Date)
    Return Date.Parse(String.Format("{0} {1}", CType(eddRow.Item("Activity_End_Date"), Date).ToShortDateString, eddRow.Item("Activity_End_Time")))
  End Function

  Public Function GetAnalysis_Start_Date(ByVal eddRow As System.Data.DataRow) As Date
    If eddRow.IsNull("Analysis_Start_Date") Then Return Nothing
    If Not eddRow.Table.Columns.Contains("Analysis_Start_Time") Then Return CType(eddRow.Item("Analysis_Start_Date"), Date)
    If eddRow.IsNull("Analysis_Start_Time") OrElse String.IsNullOrEmpty(eddRow.Item("Analysis_Start_Time").ToString) Then Return CType(eddRow.Item("Analysis_Start_Date"), Date)
    Return Date.Parse(String.Format("{0} {1}", CType(eddRow.Item("Analysis_Start_Date"), Date).ToShortDateString, eddRow.Item("Analysis_Start_Time")))
  End Function
  'Public Function GetAnalysis_End_Date(ByVal eddRow As System.Data.DataRow) As Date
  '    If eddRow.IsNull("Analysis_End_Date") Then Return Nothing
  '    If Not eddRow.Table.Columns.Contains("Analysis_End_Time") Then Return CType(eddRow.Item("Analysis_End_Date"), Date)
  '    Return Date.Parse(String.Format("{0} {1}", CType(eddRow.Item("Analysis_End_Date"), Date).ToShortDateString, eddRow.Item("Analysis_End_Time")))
  'End Function

  Public Function GetPreparationStartDate(ByVal eddRow As System.Data.DataRow) As Date
    If eddRow.IsNull("Lab_Sample_Preparation_Start_Date") Then Return Nothing
    If Not eddRow.Table.Columns.Contains("Lab_Sample_Preparation_Start_Time") Then Return CType(eddRow.Item("Lab_Sample_Preparation_Start_Date"), Date)
    Return Date.Parse(String.Format("{0} {1}", CType(eddRow.Item("Lab_Sample_Preparation_Start_Date"), Date).ToShortDateString, eddRow.Item("Lab_Sample_Preparation_Start_Time")))
  End Function

  'Public Function GetPreparationEndDate(ByVal eddRow As System.Data.DataRow) As Date
  '    If eddRow.IsNull("Lab_Sample_Preparation_End_Date") Then Return Nothing
  '    If Not eddRow.Table.Columns.Contains("Lab_Sample_Preparation_End_Time") Then Return CType(eddRow.Item("Lab_Sample_Preparation_End_Date"), Date)
  '    Return Date.Parse(String.Format("{0} {1}", CType(eddRow.Item("Lab_Sample_Preparation_End_Date"), Date).ToShortDateString, eddRow.Item("Lab_Sample_Preparation_End_Time")))
  'End Function

  ''' <summary>
  ''' Populates the depth columns.  If Activity_Depth is populated then start_depth=Activity_Depth,
  ''' otherwise start_depth=Activity_Upper_Depth and end_depth=Activity_Lower_Depth.
  ''' </summary>
  ''' <param name="eddRow">The edd row.</param>
  ''' <param name="targetRow">The target row.</param>
  ''' <returns></returns>
  Public Function PopulateDepthValues(ByVal eddRow As System.Data.DataRow, ByVal targetRow As System.Data.DataRow) As Object
    With eddRow
      If Not .IsNull("Activity_Depth") Then
        Return .Item("Activity_Depth")
      Else
        targetRow.Item("end_depth") = .Item("Activity_Lower_Depth")
        Return .Item("Activity_Upper_Depth")
      End If
    End With
  End Function

  'Public Function UpdateDtResult(ByVal eddRow As System.Data.DataRow) As Boolean
  '    Return Not eddRow.IsNull("DetectionQuantitationLimitTypeName")
  'End Function

  Public Function MapLimits(ByVal eddRow As System.Data.DataRow, ByVal targetRow As System.Data.DataRow) As Object
    With eddRow
      Select Case .Item("DetectionQuantitationLimitTypeName").ToString
        Case "Lower Quantitation Limit", "Upper Quantitation Limit"
          targetRow.Item("quantitation_limit") = .Item("DetectionQuantitationLimitMeasureValue")
          targetRow.Item("detection_limit_unit") = .Item("DetectionQuantitationLimitMeasureUnitCode")
        Case "Method Detection Level (MDL)"
          targetRow.Item("method_detection_limit") = .Item("DetectionQuantitationLimitMeasureValue")
          targetRow.Item("detection_limit_unit") = .Item("DetectionQuantitationLimitMeasureUnitCode")
        Case "Lower Reporting Limit", "Upper Reporting Limit"
          targetRow.Item("reporting_detection_limit") = .Item("DetectionQuantitationLimitMeasureValue")
          targetRow.Item("detection_limit_unit") = .Item("DetectionQuantitationLimitMeasureUnitCode")
        Case "LRL"
          targetRow.Item("reporting_detection_limit") = .Item("DetectionQuantitationLimitMeasureValue")
          targetRow.Item("detection_limit_unit") = .Item("DetectionQuantitationLimitMeasureUnitCode")
        Case "MDL"
          targetRow.Item("method_detection_limit") = .Item("DetectionQuantitationLimitMeasureValue")
          targetRow.Item("detection_limit_unit") = .Item("DetectionQuantitationLimitMeasureUnitCode")
        Case "LQL"
          targetRow.Item("quantitation_limit") = .Item("DetectionQuantitationLimitMeasureValue")
          targetRow.Item("detection_limit_unit") = .Item("DetectionQuantitationLimitMeasureUnitCode")
      End Select
    End With

    Return eddRow.Item("CAS_rn")
  End Function

  Public Function HasWell_Type(ByVal eddRow As System.Data.DataRow) As Boolean
    Return Not eddRow.IsNull("Well_Type")
  End Function
  Public Function HasContributing_Area(ByVal eddRow As System.Data.DataRow) As Boolean
    Return Not eddRow.IsNull("Contributing_Area")
  End Function
  Public Function HasDrainage_Area(ByVal eddRow As System.Data.DataRow) As Boolean
    Return Not eddRow.IsNull("Drainage_Area")
  End Function
  Public Function Has_Something_For_dt_field_sample(ByVal eddRow As System.Data.DataRow) As Boolean
    Return (Not eddRow.IsNull("Preparation_Method_ID") Or Not eddRow.IsNull("Activity_Sampler") Or Not eddRow.IsNull("Activity_Recorder") Or Not eddRow.IsNull("Custody_ID"))
  End Function
  Public Function Has_Station_Visit_Comment(ByVal eddRow As System.Data.DataRow) As Boolean
    Return Not eddRow.IsNull("Station_Visit_Comment")
  End Function
  Public Function Has_Additional_Location_Info(ByVal eddRow As System.Data.DataRow) As Boolean
    Return Not eddRow.IsNull("Additional_Location_Info")
  End Function
  Public Function Has_Gear_Deployment(ByVal eddRow As System.Data.DataRow) As Boolean
    Return Not eddRow.IsNull("Gear_Deployment")
  End Function
  Public Function Has_Transport_Storage(ByVal eddRow As System.Data.DataRow) As Boolean
    Return Not eddRow.IsNull("Transport_Storage_Description")
  End Function
  Public Function Has_Gear_Description(ByVal eddRow As System.Data.DataRow) As Boolean
    Return Not eddRow.IsNull("Collection_Equipment_Description")
  End Function
    'Public Function Has_Deprecated_Activity_File(ByVal eddRow As System.Data.DataRow) As Boolean
    '  Return Not eddRow.IsNull("Deprecated_Activity_File")
    'End Function
    Public Function Has_COC(ByVal eddRow As System.Data.DataRow) As Boolean
    Return Not eddRow.IsNull("Custody_ID")
  End Function

  Public Function HasData_Logger_Line_Name(ByVal eddRow As System.Data.DataRow) As Boolean
    Return Not eddRow.IsNull("Data_Logger_Line_Name")
  End Function
  Public Function HasReplicate_Number(ByVal eddRow As System.Data.DataRow) As Boolean
    Return Not eddRow.IsNull("Replicate_Number")
  End Function
  'Public Function HasParticle_Size_Basis(ByVal eddRow As System.Data.DataRow) As Boolean
  '    Return Not eddRow.IsNull("Particle_Size_Basis")
  'End Function
  Public Function HasStudy_Area_Description(ByVal eddRow As System.Data.DataRow) As Boolean
    Return Not eddRow.IsNull("Study_Area_Description")
  End Function
  Public Function HasDesign_Sampling_Summary(ByVal eddRow As System.Data.DataRow) As Boolean
    Return Not eddRow.IsNull("Design_Sampling_Summary")
  End Function
  Public Function HasQAPP_Summary(ByVal eddRow As System.Data.DataRow) As Boolean
    Return Not eddRow.IsNull("QAPP_Summary")
  End Function
  Public Function HasMeasurement_Quality_Objectives(ByVal eddRow As System.Data.DataRow) As Boolean
    Return Not eddRow.IsNull("Measurement_Quality_Objectives")
  End Function
  Public Function HasContact(ByVal eddRow As System.Data.DataRow) As Boolean
    Return Not eddRow.IsNull("Contact")
  End Function

  Public Function HasPrecision(ByVal eddRow As System.Data.DataRow) As Boolean
    Return Not eddRow.IsNull("Precision")
  End Function

  Public Function HasBias(ByVal eddRow As System.Data.DataRow) As Boolean
    Return Not eddRow.IsNull("Bias")
  End Function
  Public Function HasLab_Batch_ID(ByVal eddRow As System.Data.DataRow) As Boolean
    Return Not eddRow.IsNull("Lab_Batch_ID")
  End Function

  Public Function HasConfidence_Interval(ByVal eddRow As System.Data.DataRow) As Boolean
    Return Not eddRow.IsNull("Confidence_Interval")
  End Function

  Public Function HasUpper_Confidence_Limit(ByVal eddRow As System.Data.DataRow) As Boolean
    Return Not eddRow.IsNull("Upper_Confidence_Limit")
  End Function
  Public Function HasLogger_Standard_Difference(ByVal eddRow As System.Data.DataRow) As Boolean
    Return Not eddRow.IsNull("Logger_Standard_Difference")
  End Function
  Public Function HasLogger_Percent_Error(ByVal eddRow As System.Data.DataRow) As Boolean
    Return Not eddRow.IsNull("Logger_Percent_Error")
  End Function

  Public Function HasLower_Confidence_Limit(ByVal eddRow As System.Data.DataRow) As Boolean
    Return Not eddRow.IsNull("Lower_Confidence_Limit")
  End Function

  Public Function HasResult_Depth_Height_Measure(ByVal eddRow As System.Data.DataRow) As Boolean
    Return Not eddRow.IsNull("Result_Depth_Height_Measure")
  End Function

  Public Function HasResult_Sampling_Point_Name(ByVal eddRow As System.Data.DataRow) As Boolean
    Return Not eddRow.IsNull("Result_Sampling_Point_Name")
  End Function

  'Public Function HasLab_Accreditation_Indicator(ByVal eddRow As System.Data.DataRow) As Boolean
  '    Return Not eddRow.IsNull("Lab_Accreditation_Indicator")
  'End Function

  'Public Function HasTaxonomist_Accreditation_Indicator(ByVal eddRow As System.Data.DataRow) As Boolean
  '    Return Not eddRow.IsNull("Taxonomist_Accreditation_Indicator")
  'End Function

  Public Function HasAlternateLocation_ID(ByVal eddRow As System.Data.DataRow) As Boolean
    Return Not eddRow.IsNull("Alternate_Location_ID")
  End Function

  Public Function HasResultFileName(ByVal eddRow As System.Data.DataRow) As Boolean
    Return Not eddRow.IsNull("Result_File_Name")
  End Function
  Public Function HasGroup(ByVal eddRow As System.Data.DataRow) As Boolean
    Return Not eddRow.IsNull("Activity_Group_ID")
  End Function

  ''' <summary>
  ''' Determines whether dt_biological_sample should be populated based on if Medium='Biological'.
  ''' </summary>
  ''' <param name="eddRow">The edd row.</param>
  ''' <returns>
  ''' <c>true</c> if this instance populates dt_biological_sample; otherwise, <c>false</c>.
  ''' </returns>
  ''' <history>
  ''' <mod user="bhm" case="57763" date="9/27/2010" remark="created" />
  ''' <mod user="bhm" case="94997" date="11/12/2013" remarks="added 'tissue' to acceptable values" />
  ''' <mod user="dft" case="" date="12/9/2014" remarks="added 'habitat' to acceptable values" />
  ''' </history>
  Public Function Populate_dt_biological_sample(ByVal eddRow As System.Data.DataRow) As Boolean
    Dim mediaName As String = eddRow.Item("Medium").ToString.ToLower
    If mediaName = "biological" OrElse mediaName = "tissue" OrElse mediaName = "habitat" Then
      Return True
    Else
      Return False
    End If
  End Function

  ''' <summary>
  ''' Determines whether dt_biological_result should be populated based on if a matching sample_id is found in dt_biological_sample.
  ''' </summary>
  ''' <param name="eddRow">The edd row.</param>
  ''' <param name="targetRow">The target row.</param>
  ''' <returns>
  ''' <c>true</c> if this instance populates dt_biological_result; otherwise, <c>false</c>.
  ''' </returns>
  ''' <history>
  ''' <mod user="bhm" case="57763" date="9/27/2010" remark="created" />
  ''' </history>
  Public Function Populate_dt_biological_result(ByVal eddRow As System.Data.DataRow, ByVal targetRow As System.Data.DataRow) As Boolean
    Dim sample_id As Integer = GetSampleID(eddRow, targetRow)
    If sample_id < 0 Then Return False

    Dim rows() As System.Data.DataRow = Efd.package.Tables.Item("dt_biological_sample").Select(String.Format("sample_id = {0}", sample_id))
    If rows.Length > 0 Then Return True

    Return False
  End Function

  Public Function Populate_dt_file(ByVal eddRow As System.Data.DataRow) As Boolean
    With eddRow
      If Not .IsNull("Resource_Title_Name") OrElse Not .IsNull("Resource_Creator_Name") OrElse Not .IsNull("Resource_Subject_Text") _
      OrElse Not .IsNull("Resource_Publisher_Name") OrElse Not .IsNull("Resource_Date") OrElse Not .IsNull("File_Name_or_Resource_ID") Then Return True
    End With

    Return False
  End Function

  Private FileID As Integer
  Private dbFiles As New System.Data.DataSet
  Public Function CreateFileID(ByVal eddRow As System.Data.DataRow) As Integer
    Try
      With eddRow
        If dbFiles.Tables.Count = 0 Then Efd.package.Connection.Fill(dbFiles, "dt_file", EarthSoft.Common.Data.Connection.FillModes.Schema)
        Dim fileName As String = .Item("File_Name_or_Resource_ID").ToString

        Dim strBuilder As New System.Text.StringBuilder()
        strBuilder.Append(String.Format("facility_id={0}", GetFacilityID(eddRow)))
        If Not String.IsNullOrEmpty(fileName) Then strBuilder.Append(String.Format(" and file_name='{0}'", fileName.Replace("'", "''")))
        If eddRow.Table.TableName = Files.TableName Then
          strBuilder.Append(String.Format(" and isnull(place_type, '') = '{0}'", .Item("Place_Type").ToString.Replace("'", "''")))
          strBuilder.Append(String.Format(" and isnull(place_code, '') = '{0}'", .Item("Place_Code").ToString.Replace("'", "''")))
          strBuilder.Append(String.Format(" and isnull(place_subcode, '') = '{0}'", .Item("Place_Subcode").ToString.Replace("'", "''")))
        Else
          Dim title As String = .Item("Resource_Title_Name").ToString
          Dim author As String = .Item("Resource_Creator_Name").ToString
          Dim remark As String = .Item("Resource_Subject_Text").ToString
          Dim publisher As String = .Item("Resource_Publisher_Name").ToString
          Dim fileDate As String = .Item("Resource_Date").ToString
          If Not String.IsNullOrEmpty(title) Then strBuilder.Append(String.Format(" and title='{0}'", title.Replace("'", "''")))
          If Not String.IsNullOrEmpty(author) Then strBuilder.Append(String.Format(" and author='{0}'", author.Replace("'", "''")))
          If Not String.IsNullOrEmpty(remark) Then strBuilder.Append(String.Format(" and remark='{0}'", remark.Replace("'", "''")))
          If Not String.IsNullOrEmpty(publisher) Then strBuilder.Append(String.Format(" and publisher='{0}'", publisher.Replace("'", "''")))
          If Not String.IsNullOrEmpty(fileDate) Then strBuilder.Append(String.Format(" and file_date='{0}'", fileDate.Replace("'", "''")))
        End If

        'Look in the package
        Dim sql As String = strBuilder.ToString
        Dim rows() As System.Data.DataRow
        If Efd.package.Tables("dt_file").Rows.Count > 0 Then
          rows = Efd.package.Tables("dt_file").Select(sql)
          If rows.Count > 0 Then
            FileID = rows(0).Item("file_id")
            Return FileID
          End If
        End If

        'Look in the cached database rows
        If dbFiles.Tables("dt_file").Rows.Count > 0 Then
          rows = dbFiles.Tables("dt_file").Select(sql)
          If rows.Count > 0 Then
            FileID = rows(0).Item("file_id")
            Return FileID
          End If

        End If

        'look in the database
        Dim columnSelect As New System.Text.StringBuilder()
        For Each column As System.Data.DataColumn In dbFiles.Tables("dt_file").Columns
          If column.ColumnName.ToLowerInvariant <> "content" Then
            columnSelect.Append(", " + column.ColumnName)
          End If
        Next
        columnSelect.Remove(0, 1)

        Dim dsTemp As New System.Data.DataSet
        Efd.package.Connection.Fill(dsTemp, "dt_file", New EarthSoft.Common.Data.SafeSqlString("select " + columnSelect.ToString + " from dt_file where " + sql))
        If dsTemp.Tables("dt_file").Rows.Count > 0 Then
          Dim newRow As System.Data.DataRow = dbFiles.Tables("dt_file").NewRow

          For Each col As System.Data.DataColumn In dsTemp.Tables("dt_file").Columns
            newRow.Item(col.ColumnName) = dsTemp.Tables("dt_file").Rows(0).Item(col)
          Next
          dbFiles.Tables("dt_file").Rows.Add(newRow)

          FileID = dsTemp.Tables("dt_file").Rows(0).Item("file_id")
          Return FileID
        End If

        'create a new file_id
        FileID = Efd.package.Connection.NewId(EarthSoft.Common.Data.Connection.Ids.file_id)
      End With
    Catch ex As Exception
      'If an error occurred we want the dt_file and at_subfacility_location mappings to fail so they won't be associated with the wrong ID
      FileID = -1
    End Try

    Return FileID
  End Function

  Public Function GetFileID(ByVal eddRow As System.Data.DataRow) As Object
    If Populate_dt_file(eddRow) Then Return FileID

    Return DBNull.Value
  End Function

  Public Function MapResultValue(ByVal eddrow As System.Data.DataRow, ByVal targetRow As System.Data.DataRow) As Object
    Dim resultValue As Object = DBNull.Value
    With eddrow
      If Not .IsNull("Result_Text") Then
        resultValue = Remap(eddrow.Item("Result_Text"), "Result_Text", eddrow, "result_text", targetRow)
        Dim resultNumeric As Double
        If Double.TryParse(resultValue.ToString, resultNumeric) Then targetRow.Item("result_numeric") = resultValue
      End If
    End With

    Return resultValue
  End Function
  Public Function GetResultNumeric(ByVal eddrow As System.Data.DataRow, ByVal targetRow As System.Data.DataRow) As Object
    Dim resultValue As Object = DBNull.Value
    With eddrow
      If Not .IsNull("Result_Text") Then
        resultValue = Remap(eddrow.Item("Result_Text"), "Result_Text", eddrow, "result_text", targetRow)
        Dim resultNumeric As Double
        If Double.TryParse(resultValue.ToString, resultNumeric) Then
          Return resultNumeric
        End If
      End If
    End With
    Return DBNull.Value
  End Function

  Public Function GetDetectionLimitUnit(ByVal eddRow As System.Data.DataRow) As Object
    With eddRow
      If Not .IsNull("Method_Detection_Limit") OrElse Not .IsNull("Upper_Quantification_Limit") OrElse Not .IsNull("Lower_Quantification_Limit") Then
        Return .Item("Result_Unit")
      Else
        Return DBNull.Value
      End If
    End With
  End Function
  Public Function SetReportableResult(ByVal eddRow As System.Data.DataRow) As Object
    With eddRow
      If Not .IsNull("Reportable_Result") Then
        Return .Item("Reportable_Result")
      Else
        Return "Y"
      End If
    End With
  End Function
  Public Function MapDetectFlag(ByVal eddRow As System.Data.DataRow) As Object
    Select Case eddRow.Item("Result_Detection_Condition").ToLower
      Case "detected and quantified"
        Return "Y"
      Case "not detected"
        Return "N"
      Case "present below quantification limit"
        Return "N"
      Case "present above quantification limit"
        Return "N"
      Case "not reported"
        Return "N"
      Case "detected not quantified"
        Return "Y"
      Case Else
        Return "N"
    End Select

    'If (eddRow.IsNull("Result_Detection_Condition") OrElse String.IsNullOrEmpty(eddRow.Item("Result_Detection_Condition").ToString)) AndAlso Not eddRow.IsNull("Result_Text") Then
    '    Return "Y"
    'Else
    '    Return "N"
    'End If
  End Function

  Public Function GetSysLocCode(ByVal eddRow As System.Data.DataRow) As Object
    Try
      Dim sampleRow As System.Data.DataRow = Me.Efd.package.Tables.Item("dt_sample").Select(String.Format("sys_sample_code='{0}'", eddRow.Item("Activity_ID").ToString.Replace("'", "''")))(0)
      If Not sampleRow Is Nothing Then
        Return sampleRow.Item("sys_loc_code")
      Else
        Return DBNull.Value
      End If
    Catch ex As Exception
      Return DBNull.Value
    End Try
  End Function

  Public Function GetFilePlaceCode(ByVal eddRow As System.Data.DataRow, ByVal targetRow As System.Data.DataRow) As String
    Return String.Format("{0}.{1}", GetTestID(eddRow, targetRow), GetCasRn(eddRow, targetRow))
  End Function
  Public Function GetIndexPlaceCode(ByVal eddRow As System.Data.DataRow) As String
    Return String.Format("{0}.{1}", eddRow.Item("Location_ID"), eddRow.Item("Index_ID"))
  End Function

  Public Function GetFileType(ByVal eddRow As System.Data.DataRow) As Object
    If Not eddRow.IsNull("Result_File_Type") Then Return eddRow.Item("Result_File_Type")

    Dim fileName As String = eddRow.Item("Result_File_Name").ToString
    Dim index As Integer = fileName.LastIndexOf(".")
    If index >= 0 Then
      Return fileName.Substring(index)
    Else
      Return DBNull.Value
    End If
  End Function
  Public Function GetFileType2(ByVal eddRow As System.Data.DataRow) As Object
    If Not eddRow.IsNull("Result_File_Type") Then Return eddRow.Item("Result_File_Type")

    Dim fileName As String = eddRow.Item("File_Name_or_Resource_ID").ToString
    Dim index As Integer = fileName.LastIndexOf(".")
    If index >= 0 Then
      Return fileName.Substring(index)
    Else
      Return DBNull.Value
    End If
  End Function

  ''' <summary>
  ''' The generic EddCustomHandler.Remap method works, but is not optimal for this specific format.
  ''' This method optimizes the logic for this format based on known REMAP_CODE, EXTERNAL_FIELD that is just the column name, and single EXTERNAL_VALUE (not multiple, pipe-delimited values).
  ''' </summary>
  ''' <param name="originalValue">The original value contained in the EDD.</param>
  ''' <param name="sourceColumn">The name of the source column in the EDD.</param>
  ''' <param name="eddRow">The current row in the EDD that is being processed.</param>
  ''' <param name="targetColumn">The name of the target column in the package table.</param>
  ''' <param name="targetRow">The current row that will be added to the package table.</param>
  ''' <returns>The INTERNAL_VALUE of the remapping if it exists; the originalValue otherwise.</returns>
  Public Overrides Function Remap(ByVal originalValue As Object, ByVal sourceColumn As String, ByVal eddRow As System.Data.DataRow, ByVal targetColumn As String, ByVal targetRow As System.Data.DataRow) As Object

    ' make sure we have a value to remap
    If originalValue Is Nothing OrElse originalValue Is DBNull.Value OrElse String.IsNullOrEmpty(originalValue.ToString) Then Return originalValue

    'BHM_Case62455_20110502: Escape special characters in external value.
    Dim externalValue As String = originalValue.ToString
    If externalValue.Contains("[") AndAlso externalValue.Contains("]") Then
      Dim sb As New System.Text.StringBuilder(externalValue.Length)
      For i As Integer = 0 To externalValue.Length - 1
        Dim c As String = externalValue(i)
        Select Case c
          Case "[", "]", "%", "*"
            sb.Append(String.Format("[{0}]", c))
          Case Else
            sb.Append(c)
        End Select
      Next

      externalValue = sb.ToString
    Else
      externalValue = externalValue.Replace("]", "[]]").Replace("[", "[[]").Replace("%", "[%]").Replace("*", "[*]")
    End If

    ' these columns should exactly match Me.vw_remap_detail
    Dim criteria As String = String.Format("EXTERNAL_FIELD = '{0}' and EXTERNAL_VALUE = '{1}'", sourceColumn, externalValue.Replace("'", "''"))
    Dim rows() As System.Data.DataRow = rt_remap_detail.Select(criteria)

    ' this assumes that no EXTERNAL_VALUE values contain multiple values in a pipe-delimited string
    If rows.Length = 1 Then
      Return rows(0)("INTERNAL_VALUE")
    Else
      Return originalValue
    End If

  End Function

#End Region

#Region "Open"

  Public Overrides Function Open(ByVal filename As String, ByRef Efd As EarthSoft.EDP.EddFormatDefinition, Optional ByVal tablename As String = "") As Boolean

    Dim success As Boolean = False

    'get extension
    Select Case System.IO.Path.GetExtension(filename).ToLower

      Case ".xls", ".xlsx"
        Dim xlsfilename As String = filename.ToLower
        success = EarthSoft.EDP.IO.ExcelFile.LoadWorkbook(filename, Efd)

      Case ".xml"
        'NOTE: for now, this XML must match the DataSet schema
        success = EarthSoft.EDP.IO.XmlFile.LoadFile(filename, Efd)

      Case ".csv"
        ' assume comma separated, quote delimited
        success = EarthSoft.EDP.IO.TextFile.LoadFile(filename, Efd.GetTable(tablename), ","c, """"c)

      Case ".zip", ".edd"
        success = LoadZipFile(filename, Efd)

        'VJN_Case5071_20041206 'Loading the EDD from an .mdb file
      Case ".mdb"
        success = EarthSoft.EDP.IO.MdbFile.LoadDatabase(filename, Efd)

      Case Else          '*.txt, *.smp, *.tst, *.res, etc.
        'let Textfile determine the separator/delimiter
        success = EarthSoft.EDP.IO.TextFile.LoadFile(filename, Efd.GetTable(tablename))

    End Select

    Return success
  End Function

  Public Overrides Sub LoadingPreprocess(ByVal filename As String, ByRef fileContent As String)
    'Remove namespaces from the XML EDD before loading the data
    fileContent = System.Text.RegularExpressions.Regex.Replace(fileContent, "xmlns[^=]*=""[^""]*""", "")
    'Remove schema locations with a prefix from the XML EDD before loading the data
    fileContent = System.Text.RegularExpressions.Regex.Replace(fileContent, "\S+schemaLocation[^=]*=""[^""]*""", "")
  End Sub

  Public Overrides Sub CustomColumnLoading(ByVal filename As String, ByVal column As EarthSoft.EDP.EddColumn, ByRef parentNode As System.Xml.XmlNode, ByVal eddRow As System.Data.DataRow, ByVal xNsp As System.Xml.XmlNamespaceManager)
    If column.ColumnName = "Place_Type" AndAlso column.Table.TableName = "Files" Then
      eddRow.Item(column.ColumnName) = parentNode.ParentNode.LocalName & "Identifier"

    ElseIf column.ColumnName = "Frequency_Class_Descriptor_1" AndAlso column.Table.TableName = "Results" Then
      LoadFrequencyDescriptor(parentNode, eddRow, xNsp)
    ElseIf column.ColumnName = "Functional_Feeding_Group_1" AndAlso column.Table.TableName = "Results" Then
      LoadFunctionalFeedingGroup(parentNode, eddRow, xNsp)
    ElseIf column.ColumnName = "Habit_Name_1" AndAlso column.Table.TableName = "Results" Then
      LoadHabitatName(parentNode, eddRow, xNsp)
    End If

  End Sub

  ''' <summary>
  ''' Loads the frequency descriptor fields.
  ''' </summary>
  ''' <param name="parentNode">The parent node.</param>
  ''' <param name="eddRow">The edd row.</param>
  ''' <param name="xNsp">The XmlNamespaceManager used for XPath queries.</param>
  Private Sub LoadFrequencyDescriptor(ByRef parentNode As System.Xml.XmlNode, ByVal eddRow As System.Data.DataRow, ByVal xNsp As System.Xml.XmlNamespaceManager)
    'Load all the FrequencyClassDescriptor fields
    'Xpath = ./BiologicalResultDescription/FrequencyClassInformation
    Dim freqNodes As System.Xml.XmlNodeList = parentNode.SelectNodes("./BiologicalResultDescription/FrequencyClassInformation", xNsp)

    For i As Integer = 0 To freqNodes.Count - 1
      If i > 2 Then Exit For

      Dim code As System.Xml.XmlNode = freqNodes(i).SelectSingleNode("./FrequencyClassDescriptorCode/text()", xNsp)
      Dim unit As System.Xml.XmlNode = freqNodes(i).SelectSingleNode("./FrequencyClassDescriptorUnitCode/text()", xNsp)
      Dim lowerBound As System.Xml.XmlNode = freqNodes(i).SelectSingleNode("./LowerClassBoundValue/text()", xNsp)
      Dim upperBound As System.Xml.XmlNode = freqNodes(i).SelectSingleNode("./UpperClassBoundValue/text()", xNsp)

      If Not code Is Nothing Then
        eddRow.Item("Frequency_Class_Descriptor_" & i + 1) = code.Value
      End If

      If Not unit Is Nothing Then
        eddRow.Item("Frequency_Class_Bounds_Unit_" & i + 1) = unit.Value
      End If

      If Not lowerBound Is Nothing Then
        eddRow.Item("Frequency_Class_Lower_Bound_" & i + 1) = lowerBound.Value
      End If

      If Not upperBound Is Nothing Then
        eddRow.Item("Frequency_Class_Upper_Bound_" & i + 1) = upperBound.Value
      End If
    Next

  End Sub

  ''' <summary>
  ''' Loads the functional feeding group fields.
  ''' </summary>
  ''' <param name="parentNode">The parent node.</param>
  ''' <param name="eddRow">The edd row.</param>
  ''' <param name="xNsp">The XmlNamespaceManager used for XPath queries.</param>
  Private Sub LoadFunctionalFeedingGroup(ByRef parentNode As System.Xml.XmlNode, ByVal eddRow As System.Data.DataRow, ByVal xNsp As System.Xml.XmlNamespaceManager)
    'XPath = ./BiologicalResultDescription/TaxonomicDetails/FunctionalFeedingGroupName
    Dim feedingNodes As System.Xml.XmlNodeList = parentNode.SelectNodes("./BiologicalResultDescription/TaxonomicDetails/FunctionalFeedingGroupName/text()", xNsp)

    For i As Integer = 0 To feedingNodes.Count - 1
      If i > 2 Then Exit For

      eddRow.Item("Functional_Feeding_Group_" & i + 1) = feedingNodes(i).Value
    Next
  End Sub

  ''' <summary>
  ''' Loads the habitat name fields.
  ''' </summary>
  ''' <param name="parentNode">The parent node.</param>
  ''' <param name="eddRow">The edd row.</param>
  ''' <param name="xNsp">The XmlNamespaceManager used for XPath queries.</param>
  Private Sub LoadHabitatName(ByRef parentNode As System.Xml.XmlNode, ByVal eddRow As System.Data.DataRow, ByVal xNsp As System.Xml.XmlNamespaceManager)
    'XPath = ./BiologicalResultDescription/TaxonomicDetails/HabitName
    Dim habitatNodes As System.Xml.XmlNodeList = parentNode.SelectNodes("./BiologicalResultDescription/TaxonomicDetails/HabitName/text()", xNsp)

    For i As Integer = 0 To habitatNodes.Count - 1
      If i > 2 Then Exit For

      eddRow.Item("Habit_Name_" & i + 1) = habitatNodes(i).Value
    Next
  End Sub

#Region "Zip EDD"
  '''<summary>Load the ZIP File</summary>
  '''<param name='filename'><see cref='System.String' /> The filename to read from </param>
  '''<param name='efd'><see cref='EddFormatDefinition' /> The data set to populate </param>
  '''<returns> indicating success or failure of operation</returns>
  Private Function LoadZipFile(ByVal filename As String, ByVal efd As EddFormatDefinition) As Boolean
    Dim zipStream As System.IO.Stream = Nothing
    Try
      zipStream = New System.IO.FileStream(filename, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read)
      Return LoadZipFile(zipStream, efd)
    Catch ex As Exception
      _Log.Debug(ex.Message, ex)
      Throw ex
      Return False
    Finally
      If Not zipStream Is Nothing Then zipStream.Close()
    End Try
  End Function

  Private Function LoadZipFile(ByVal fileStream As System.IO.Stream, ByVal efd As EddFormatDefinition) As Boolean
    Dim zipFile As Zip.ZipFile = Nothing
    Dim zip As Zip.ZipEntry
    Dim edt As EddTable
    Dim reader As System.IO.StreamReader
    Dim separator As Char
    Dim delimiter As Char
    'BHM_Case38317_20090625 : Allow multiple file sections
    Dim fileTables As New System.Collections.Generic.List(Of EddTable)
    For Each table As EddTable In efd.Tables
      If table.IsFileSection OrElse efd.FileSectionName.ToLower = table.TableName.ToLower Then fileTables.Add(table)
    Next

    ' save the current load mode, we'll use "Append" for loading zip files
    Dim loadMode As EddFormatDefinition.EddLoadModes = efd.LoadMode
    efd.LoadMode = EddFormatDefinition.EddLoadModes.Append

    Dim success As Boolean = True

    'FB.22218: extra files that need to be loaded
    Dim extraFiles As New System.Collections.Generic.List(Of Zip.ZipEntry)
    'BHM_Case43146_20091208: load text files first based on order of tables in format then all other files
    Dim textFiles As New System.Collections.Generic.List(Of Zip.ZipEntry)
    Dim NonTextFiles As New System.Collections.Generic.List(Of Zip.ZipEntry)

    Try
      ' open the zip file
      zipFile = New Zip.ZipFile(fileStream)

      For Each zip In zipFile
        If zip.Size > 0 Then
          Select Case System.IO.Path.GetExtension(zip.Name).ToLower
            Case ".xls", ".xlsx", ".mdb", ".accdb", ".xml"
              NonTextFiles.Add(zip)
            Case Else
              textFiles.Add(zip)
          End Select
        End If
      Next

      'Load all text files based on the order of the tables in the format
      For Each edt In efd.Tables
        For i As Integer = textFiles.Count - 1 To 0 Step -1
          If textFiles.Item(i).Name.ToLower.IndexOf(edt.TableName.ToLower & ".") >= 0 Then
            If Not edt.Visible Then
              textFiles.RemoveAt(i)
              Continue For
            End If

            ' get the input stream
            reader = New System.IO.StreamReader(zipFile.GetInputStream(textFiles.Item(i)), System.Text.Encoding.Default)

            ' guess the separator and delimiter
            EarthSoft.EDP.IO.TextFile.GetFileType(reader, separator, delimiter)

            'VJN_Case_4985_20041119 'For the zipped data files the first line was getting skipped on loading the data
            ' So the reader is reinitializing so that it wont skip the first line. 
            reader = New System.IO.StreamReader(zipFile.GetInputStream(textFiles.Item(i)), System.Text.Encoding.Default)

            ' load data from this file
            success = success And EarthSoft.EDP.IO.TextFile.LoadFile(reader, edt, separator, delimiter)

            ' save the filename/extension
            edt.Filename = textFiles.Item(i).Name
            edt.FileExtension = System.IO.Path.GetExtension(textFiles.Item(i).Name)
            edt.FileSeparator = separator
            edt.FileDelimiter = delimiter

            'Remove the file from the list since we already used it and so it saves time
            textFiles.RemoveAt(i)
          End If
        Next
      Next

      'Load all non text data files
      For Each zip In NonTextFiles
        Select Case System.IO.Path.GetExtension(zip.Name.ToLower)
          Case ".xls", ".xlsx"
            Dim xlsFileRows() As DataRow = Nothing
            If efd.FileSectionName.Length > 0 Then
              For Each section As EddTable In fileTables
                Dim fileNameCol As String = String.Empty
                If section.FileNameColumn.Length > 0 Then
                  fileNameCol = section.FileNameColumn
                ElseIf section.Columns.Contains("file_name") Then
                  fileNameCol = "file_name"
                End If
                xlsFileRows = section.Select(String.Format("{0} = '{1}'", fileNameCol, zip.Name))
                If xlsFileRows.Length > 0 Then Exit For
              Next
            End If

            If xlsFileRows Is Nothing OrElse xlsFileRows.Length = 0 Then
              success = success And EarthSoft.EDP.IO.ExcelFile.LoadWorkbook(EarthSoft.EDP.IO.ZipFile.Unzip(zipFile, zip), efd)
            Else
              'Adding it to the list of extraFiles the attached file belongs to Files_v1 table.
              extraFiles.Add(zip)
            End If
          Case ".mdb", ".accdb"
            success = success And EarthSoft.EDP.IO.MdbFile.LoadDatabase(EarthSoft.EDP.IO.ZipFile.Unzip(zipFile, zip), efd)
          Case ".xml"
            success = success And EarthSoft.EDP.IO.XmlFile.LoadFile(EarthSoft.EDP.IO.ZipFile.Unzip(zipFile, zip), efd)
        End Select
      Next

      'Only non data files should be left
      For Each zip In textFiles
        'FB.22218: is this an extra "non-data" file?
        If Not zip.Name.ToLower.EndsWith(".usr") AndAlso zip.IsFile Then
          extraFiles.Add(zip)
        End If
      Next

      'FB.22218: process "non-data" files
      If fileTables.Count > 0 Then
        For Each dt As EddTable In fileTables
          dt.InitializeLoad()
        Next
        For Each z As Zip.ZipEntry In extraFiles
          ProcessNonDataFile(fileTables, z, EarthSoft.EDP.IO.ZipFile.Unzip(zipFile, z))
        Next

        For Each dt As EddTable In fileTables
          'FB.61918_20110902: If a non-data file has the same extension as a data file then it will not be uploaded so we need to go through
          ' the file sections and load any files that did not get loaded.
          If dt.FileContentColumn.Length > 0 AndAlso dt.FileNameColumn.Length > 0 Then
            For Each row As DataRow In dt.Rows
              If row.IsNull(dt.FileContentColumn) AndAlso Not row.IsNull(dt.FileNameColumn) Then
                For Each zip In zipFile
                  If 0 = String.Compare(row.Item(dt.FileNameColumn).ToString, zip.Name, True) Then
                    EarthSoft.EDP.IO.ZipFile.UploadFile(row, dt.FileContentColumn, zip, zipFile)
                  End If
                Next
              End If
            Next
          Else
                        Dim nameColumn As String = FindColumnName(ColumnType.Name, dt)
                        Dim contentColumn As String = FindColumnName(ColumnType.Content, dt)
                        If nameColumn.Length > 0 AndAlso contentColumn.Length > 0 AndAlso TypeOf dt.Columns.Item(contentColumn) Is EddColumn _
                AndAlso CType(dt.Columns.Item(contentColumn), EddColumn).DefinedType.ToString = "System.Byte[]" Then
                            For Each row As DataRow In dt.Rows
                                If row.IsNull(contentColumn) AndAlso Not row.IsNull(nameColumn) Then
                                    For Each zip In zipFile
                                        If 0 = String.Compare(row.Item(nameColumn).ToString, zip.Name, True) Then
                                            EarthSoft.EDP.IO.ZipFile.UploadFile(row, contentColumn, zip, zipFile)
                                        End If
                                    Next
                                End If
                            Next
                        End If
                    End If

                    dt.FinalizeLoad()
                Next
            End If

            efd.LoadMode = loadMode

            Return success

        Catch ex As CancelLoadException
            _Log.Debug(ex.Message, ex)
            Diagnostics.Debug.WriteLine(ex.ToString)
            Return False
        Catch ex As Exception
            _Log.Debug(ex.Message, ex)
            Throw ex
            Return False
        Finally
            If Not zipFile Is Nothing Then zipFile.Close()
        End Try
    End Function

    ''' <summary>
    ''' Processes the non data files.
    ''' </summary>
    ''' <param name="fileTables">The file sections.</param>
    ''' <param name="zip">The zip entry.</param>
    ''' <param name="tempFile">The temporary file.</param>
    ''' <history>
    '''   <mod case="22218" remarks="created" />
    '''   <mod user="bhm" case="38317" date="6/25/2009" remarks="modified" notes="Allow multiple file sections" />
    '''   <mod user="bhm" case="111010" date="3/4/2015" remarks="overloaded method to use temp file instead of buffer" />
    ''' </history>
    Private Sub ProcessNonDataFile(ByVal fileTables As System.Collections.Generic.List(Of EddTable), ByVal zip As Zip.ZipEntry, tempFile As String)
        ' use just the filename (exclude folder name)
        Dim filename As String = System.IO.Path.GetFileName(zip.Name)
        Dim edt As EddTable = Nothing
        Dim fileRows() As DataRow = Nothing
        Dim contentColumn As String
        Dim fileNameColumn As String
        Dim fileDateColumn As String

        Dim encoding As New System.Text.UnicodeEncoding

        ' check to see if this file already exists in any of the file sections, file name may not always be the PK and multiple rows could contain the same file
        For Each table As EddTable In fileTables
            If table.FileNameColumn <> String.Empty Then
                fileNameColumn = table.FileNameColumn
            Else
                fileNameColumn = FindColumnName(ColumnType.Name, table)
            End If

            If fileNameColumn = String.Empty Then Continue For

            'bhm_case42052_20091015 : Spaces and parenthesis cause an exception when they are in the column name.  Putting the column name in brackets
            If fileNameColumn.Contains(" ") OrElse fileNameColumn.Contains("(") OrElse fileNameColumn.Contains(")") Then fileNameColumn = String.Format("[{0}]", fileNameColumn)

            fileRows = table.Select(String.Format("{0}='{1}'", fileNameColumn, filename))
            If Not fileRows Is Nothing AndAlso fileRows.Length > 0 Then
                ' row already exists, so just update the content
                If table.FileContentColumn <> String.Empty Then
                    contentColumn = table.FileContentColumn
                Else
                    contentColumn = FindColumnName(ColumnType.Content, table)
                End If

                'If we find the content column then add the file to it
                If contentColumn <> String.Empty Then
                    edt = table

                    For Each row As DataRow In fileRows
                        row.Item(contentColumn) = System.Convert.ToBase64String(encoding.GetBytes("edp.file::" & tempFile))
                    Next
                End If
            End If

        Next

        If edt Is Nothing Then

            If fileTables.Contains(Files) Then
                ' row does not exist, so create it in the Files section
                edt = fileTables.Item(fileTables.IndexOf(Files))
            Else
                ' row does not exist, so create it in the first file section
                edt = fileTables.Item(0)
            End If

            If edt.FileNameColumn <> String.Empty Then
                fileNameColumn = edt.FileNameColumn
            Else
                fileNameColumn = FindColumnName(ColumnType.Name, edt)
            End If

            If edt.FileDateColumn <> String.Empty Then
                fileDateColumn = edt.FileDateColumn
            Else
                fileDateColumn = FindColumnName(ColumnType.Date, edt)
            End If

            If edt.FileContentColumn <> String.Empty Then
                contentColumn = edt.FileContentColumn
            Else
                contentColumn = FindColumnName(ColumnType.Content, edt)
            End If

            If fileNameColumn = String.Empty OrElse contentColumn = String.Empty Then Exit Sub

            Dim fileRow As System.Data.DataRow
            fileRow = edt.NewRow
            fileRow.Item(fileNameColumn) = filename
            Dim fileTypeColumn As String
            If edt.FileTypeColumn <> String.Empty Then
                fileTypeColumn = edt.FileTypeColumn
            Else
                fileTypeColumn = FindColumnName(ColumnType.Type, edt)
            End If

            If fileTypeColumn <> String.Empty Then fileRow.Item(fileTypeColumn) = System.IO.Path.GetExtension(filename)

            If fileDateColumn <> String.Empty Then
                Try
                    If CType(edt.Columns.Item(fileDateColumn), EarthSoft.EDP.EddColumn).DateTimeType = EddColumn.DateTimeTypes.Date Then
                        'File date field only allows a date, no time
                        fileRow.Item(fileDateColumn) = zip.DateTime.Date
                    Else
                        'File date field allows date and time
                        If CType(edt.DataSet, EddFormatDefinition).package.Tables.Item("dt_file").Columns.Item("file_date").ExtendedProperties.Contains("SMALLDATETIME") Then
                            ' remove the second
                            fileRow.Item(fileDateColumn) = New Date(zip.DateTime.Year, zip.DateTime.Month, zip.DateTime.Day, zip.DateTime.Hour, zip.DateTime.Minute, 0)
                        Else
                            fileRow.Item(fileDateColumn) = zip.DateTime
                        End If
                    End If

                Catch ex As Exception
                    _Log.Debug(ex.Message, ex)
                    fileRow.Item(fileDateColumn) = zip.DateTime
                End Try
            End If

            'fileRow.Item(contentColumn) = System.Convert.ToBase64String(buffer)
            fileRow.Item(contentColumn) = System.Convert.ToBase64String(encoding.GetBytes("edp.file::" & tempFile))
            edt.Rows.Add(fileRow)
        End If

    End Sub

    ''' <summary>
    ''' Finds the first column that matches the column type.
    ''' </summary>
    ''' <param name="type">Type of the column.</param>
    ''' <param name="table">The table that contains the column type.</param>
    ''' <returns><see cref="System.Boolean"/><para/>The column name of the desired column.</returns>
    ''' <remarks>
    ''' Columns with the name 'content', 'file_name', 'file_date', and 'file_type' take precedence over any other similar columns. If those columns don't exist then it will return the
    ''' first column name it finds with a similar name.  Searches for the content column from the end of the table to the beginning; others are searched from the beginning to end.
    ''' </remarks>
    ''' <history>
    ''' <mod user="bhm" case="38317" date="6/24/2009" remarks="created" notes="Search the table for the file column types so the column names don't have to be 'content', 'file_name', file_type, and 'file_date'"/>
    ''' </history>
    Private Function FindColumnName(ByVal type As ColumnType, ByVal table As DataTable) As String
        Select Case type
            Case ColumnType.Content
                If table.Columns.Contains("content") Then Return "content"

                'search from the end of the table because the content column is most likely to be at the end
                For i As Integer = table.Columns.Count - 1 To 0 Step -1
                    'Use regular expression to check if column is a match.  (?i) makes everything after it case insensitive.
                    If TypeOf table.Columns(i) Is EddColumn AndAlso System.Text.RegularExpressions.Regex.IsMatch(table.Columns(i).ColumnName, ".*(?i)content.*") Then Return table.Columns(i).ColumnName
                Next

            Case ColumnType.Name
                If table.Columns.Contains("file_name") Then Return "file_name"

                'search from the start of the table because the file name column is most likely to be at the start
                For i As Integer = 0 To table.Columns.Count - 1
                    'Use regular expression to check if column is a match.  (?i) makes everything after it case insensitive. (matches incude 'file_name', 'FileName', 'File Name', 'BinaryObjectFileName', etc..)
                    If TypeOf table.Columns(i) Is EddColumn AndAlso System.Text.RegularExpressions.Regex.IsMatch(table.Columns(i).ColumnName, ".*(?i)(file(_|\s)?name).*") Then Return table.Columns(i).ColumnName
                Next

            Case ColumnType.Date
                If table.Columns.Contains("file_date") Then Return "file_date"
                'search from the start of the table because the file date column is most likely to be at the start
                For i As Integer = 0 To table.Columns.Count - 1
                    'Use regular expression to check if column is a match.  (?i) makes everything after it case insensitive. (matches incude 'file_date', 'FileDate', 'File Date', 'BinaryObjectFileDate', etc..)
                    If TypeOf table.Columns(i) Is EddColumn AndAlso System.Text.RegularExpressions.Regex.IsMatch(table.Columns(i).ColumnName, ".*(?i)(file(_|\s)?date).*") Then Return table.Columns(i).ColumnName
                Next

            Case ColumnType.Type
                If table.Columns.Contains("file_type") Then Return "file_type"
                'search from the start of the table because the file type column is most likely to be at the start
                For i As Integer = 0 To table.Columns.Count - 1
                    'Use regular expression to check if column is a match.  (?i) makes everything after it case insensitive. (matches incude 'file_type', 'FileType', 'File Type', 'BinaryObjectFileTypeCode', etc..)
                    If TypeOf table.Columns(i) Is EddColumn AndAlso System.Text.RegularExpressions.Regex.IsMatch(table.Columns(i).ColumnName, ".*(?i)(file(_|\s)?type).*") Then Return table.Columns(i).ColumnName
                Next

        End Select

        Return String.Empty
    End Function

    ''' <summary>
    ''' The type of column to search for.
    ''' </summary>
    Private Enum ColumnType
    ''' <summary>
    ''' Column name 'content' takes precedence.  If column 'content' does exist then first column containing the word 'content' will be used.
    ''' </summary>
    Content
    ''' <summary>
    ''' Column name 'file_name' takes precedence.  If column 'file_name' does exist then first column containing the word 'file_name'(underscore optional) will be used.
    ''' </summary>
    Name
    ''' <summary>
    ''' Column name 'file_date' takes precedence.  If column 'file_date' does exist then first column containing the word 'file_date'(underscore optional) will be used.
    ''' </summary>
    [Date]
    ''' <summary>
    ''' Column name 'file_type' takes precedence.  If column 'file_type' does exist then first column containing the word 'file_type'(underscore optional) will be used.
    ''' </summary>
    Type
  End Enum
#End Region
#End Region

#Region "Save"
  Public Overrides Function CustomRowSaving(ByVal eddRow As System.Data.DataRow, ByRef xDoc As System.Xml.XmlDocument, ByVal xNsp As System.Xml.XmlNamespaceManager) As Boolean
    If eddRow.Table.TableName = "Files" Then
      Dim sectionNode As System.Xml.XmlNode

      If eddRow.IsNull("Place_Type") OrElse eddRow.Item("Place_Type").ToString = String.Empty Then
        Dim wqxNode As System.Xml.XmlNode = xDoc.SelectSingleNode("//WQX/", xNsp)
        If wqxNode Is Nothing Then
          wqxNode = CreateNodePath(xDoc, xNsp, "Document/Payload/WQX")
        End If

        sectionNode = xDoc.CreateElement("AttachedBinaryObject", Nothing)
        wqxNode.AppendChild(sectionNode)
        SaveBinaryObjectRow(eddRow, sectionNode, xDoc, xNsp)

        Return True
      End If

      Dim identifier As String = String.Empty
      If Not eddRow.IsNull("Place_Code") Then identifier = eddRow.Item("Place_Code").ToString
      Dim placeType As String = eddRow.Item("Place_Type").ToString()

      Dim query As String = String.Empty
      Select Case placeType
        Case "OrganizationIdentifier"
          If identifier = String.Empty Then
            query = "Document/Payload/WQX/Organization[not(OrganizationDescription/OrganizationIdentifier[text()])]"
          Else
            query = String.Format("Document/Payload/WQX/Organization[OrganizationDescription/OrganizationIdentifier[text()='{0}']]", identifier)
          End If
        Case "Project_ID"
          If identifier = String.Empty Then
            query = "Document/Payload/WQX/Organization/Projects[not(Project_ID[text()])]"
          Else
            query = String.Format("Document/Payload/WQX/Organization/Projects[Project_ID[text()='{0}']]", identifier)
          End If
        Case "Location_ID"
          If identifier = String.Empty Then
            query = "Document/Payload/WQX/Organization/Locations[not(MonitoringLocationIdentity/Location_ID[text()])]"
          Else
            query = String.Format("Document/Payload/WQX/Organization/Locations[MonitoringLocationIdentity/Location_ID[text()='{0}']]", identifier)
          End If
        Case "Activity_ID"
          If identifier = String.Empty Then
            query = "Document/Payload/WQX/Organization/Activities[not(ActivityDescription/Activity_ID[text()])]"
          Else
            query = String.Format("Document/Payload/WQX/Organization/Activities[ActivityDescription/Activity_ID[text()='{0}']]", identifier)
          End If
      End Select

      Dim parentNode As System.Xml.XmlNode = Nothing
      If query.Length > 0 Then
        parentNode = xDoc.SelectSingleNode(query, xNsp)
      Else
        query = "Document/Payload/WQX/Organization"
      End If

      If parentNode Is Nothing Then
        'Node does not exist so we have to create it
        parentNode = xDoc.SelectSingleNode("//WQX/Organization", xNsp)
        If parentNode Is Nothing Then
          parentNode = CreateNodePath(xDoc, xNsp, "Document/Payload/WQX/Organization")
        End If

        If query.IndexOf("[", "Document/Payload/WQX/Organization".Length) >= 0 Then
          Dim nodes() As String = query.Substring("Document/Payload/WQX/Organization".Length, query.IndexOf("[") - "Document/Payload/WQX/Organization".Length).Split("/"c)
          For Each node As String In nodes
            If node.Trim = String.Empty Then Continue For

            Dim newNode As System.Xml.XmlNode = xDoc.CreateElement(node, Nothing)
            parentNode.AppendChild(newNode)
            parentNode = newNode
          Next
        End If
      End If

      sectionNode = xDoc.CreateElement("AttachedBinaryObject", Nothing)
      parentNode.AppendChild(sectionNode)
      SaveBinaryObjectRow(eddRow, sectionNode, xDoc, xNsp)

      Return True

    Else
      Return False
    End If
  End Function

  Public Overrides Sub CustomColumnSaving(ByVal column As EarthSoft.EDP.EddColumn, ByRef sectionNode As System.Xml.XmlNode, ByVal eddRow As System.Data.DataRow, ByRef xDoc As System.Xml.XmlDocument, ByVal xNsp As System.Xml.XmlNamespaceManager)
    If column.ColumnName = "Frequency_Class_Descriptor_1" AndAlso column.Table.TableName = "Results" Then
      'We need to save this column in the custom handler because the XPath needs to be null since we are loading it in the custom handler
      ' and because all frequency fields in the same row would be save under the same FrequencyClassInformation node.
      Dim SaveRow As Boolean = False
      For i As Integer = 1 To 3
        If HasFrequencyValue(eddRow, i) Then
          SaveRow = True
          Exit For
        End If
      Next

      If Not SaveRow Then Return

      SaveFrequencyClassDescriptor(sectionNode, eddRow, xDoc, xNsp)

    ElseIf column.ColumnName = "Functional_Feeding_Group_1" AndAlso column.Table.TableName = "Results" Then
      SaveFunctionalFeedingGroup(sectionNode, eddRow, xDoc, xNsp)
    ElseIf column.ColumnName = "Habit_Name_1" AndAlso column.Table.TableName = "Results" Then
      SaveHabitatName(sectionNode, eddRow, xDoc, xNsp)
    End If
  End Sub

  ''' <summary>
  ''' Saves the frequency class fields.
  ''' </summary>
  ''' <param name="sectionNode">The section node.</param>
  ''' <param name="eddRow">The edd row.</param>
  ''' <param name="xDoc">The XmlDocument.</param>
  ''' <param name="xNsp">The XmlNamespaceManager used to perform XPath queries.</param>
  Private Sub SaveFrequencyClassDescriptor(ByRef sectionNode As System.Xml.XmlNode, ByVal eddRow As System.Data.DataRow, ByRef xDoc As System.Xml.XmlDocument, ByVal xNsp As System.Xml.XmlNamespaceManager)
    './BiologicalResultDescription/FrequencyClassInformation
    Dim bioNode As System.Xml.XmlNode = sectionNode.SelectSingleNode("./BiologicalResultDescription", xNsp)
    If bioNode Is Nothing Then
      bioNode = xDoc.CreateElement("BiologicalResultDescription", Nothing)
      sectionNode.AppendChild(bioNode)
    End If

    For i As Integer = 1 To 3
      If HasFrequencyValue(eddRow, i) Then
        Dim freqNod As System.Xml.XmlNode = xDoc.CreateElement("FrequencyClassInformation", Nothing)
        bioNode.AppendChild(freqNod)
        Dim colNode As System.Xml.XmlNode
        Dim textNode As System.Xml.XmlNode

        If Not eddRow.IsNull("Frequency_Class_Descriptor_" & i) Then
          colNode = xDoc.CreateElement("FrequencyClassDescriptorCode", Nothing)
          textNode = xDoc.CreateNode(Xml.XmlNodeType.Text, Nothing, Nothing)
          textNode.Value = eddRow.Item("Frequency_Class_Descriptor_" & i).ToString
          colNode.AppendChild(textNode)
          freqNod.AppendChild(colNode)
        End If

        If Not eddRow.IsNull("Frequency_Class_Bounds_Unit_" & i) Then
          colNode = xDoc.CreateElement("FrequencyClassDescriptorUnitCode", Nothing)
          textNode = xDoc.CreateNode(Xml.XmlNodeType.Text, Nothing, Nothing)
          textNode.Value = eddRow.Item("Frequency_Class_Bounds_Unit_" & i).ToString
          colNode.AppendChild(textNode)
          freqNod.AppendChild(colNode)
        End If

        If Not eddRow.IsNull("Frequency_Class_Lower_Bound_" & i) Then
          colNode = xDoc.CreateElement("LowerClassBoundValue", Nothing)
          textNode = xDoc.CreateNode(Xml.XmlNodeType.Text, Nothing, Nothing)
          textNode.Value = eddRow.Item("Frequency_Class_Lower_Bound_" & i).ToString
          colNode.AppendChild(textNode)
          freqNod.AppendChild(colNode)
        End If

        If Not eddRow.IsNull("Frequency_Class_Upper_Bound_" & i) Then
          colNode = xDoc.CreateElement("UpperClassBoundValue", Nothing)
          textNode = xDoc.CreateNode(Xml.XmlNodeType.Text, Nothing, Nothing)
          textNode.Value = eddRow.Item("Frequency_Class_Upper_Bound_" & i).ToString
          colNode.AppendChild(textNode)
          freqNod.AppendChild(colNode)
        End If

      End If
    Next
  End Sub

  ''' <summary>
  ''' Saves the functional feeding group fields.
  ''' </summary>
  ''' <param name="sectionNode">The section node.</param>
  ''' <param name="eddRow">The edd row.</param>
  ''' <param name="xDoc">The XmlDocument.</param>
  ''' <param name="xNsp">The XmlNamespaceManager used for performing XPath queries.</param>
  Private Sub SaveFunctionalFeedingGroup(ByRef sectionNode As System.Xml.XmlNode, ByVal eddRow As System.Data.DataRow, ByRef xDoc As System.Xml.XmlDocument, ByVal xNsp As System.Xml.XmlNamespaceManager)
    './BiologicalResultDescription/TaxonomicDetails/FunctionalFeedingGroupName
    If eddRow.IsNull("Functional_Feeding_Group_1") AndAlso eddRow.IsNull("Functional_Feeding_Group_2") AndAlso eddRow.IsNull("Functional_Feeding_Group_3") Then Exit Sub

    Dim parentNode As System.Xml.XmlNode = sectionNode.SelectSingleNode("./BiologicalResultDescription", xNsp)
    If parentNode Is Nothing Then
      parentNode = xDoc.CreateElement("BiologicalResultDescription", Nothing)
      sectionNode.AppendChild(parentNode)
      Dim taxNode As System.Xml.XmlNode = xDoc.CreateElement("TaxonomicDetails", Nothing)
      parentNode.AppendChild(taxNode)
      parentNode = taxNode
    Else
      Dim taxNode As System.Xml.XmlNode = parentNode.SelectSingleNode("./TaxonomicDetails", xNsp)
      If taxNode Is Nothing Then
        taxNode = xDoc.CreateElement("TaxonomicDetails", Nothing)
        parentNode.AppendChild(taxNode)
        parentNode = taxNode
      Else
        parentNode = taxNode
      End If
    End If


    For i As Integer = 1 To 3
      If Not eddRow.IsNull("Functional_Feeding_Group_" & i) Then
        Dim colNode As System.Xml.XmlNode = xDoc.CreateElement("FunctionalFeedingGroupName", Nothing)
        parentNode.AppendChild(colNode)
        Dim textNode As System.Xml.XmlNode = xDoc.CreateNode(Xml.XmlNodeType.Text, Nothing, Nothing)
        textNode.Value = eddRow.Item("Functional_Feeding_Group_" & i).ToString
        colNode.AppendChild(textNode)
      End If
    Next
  End Sub

  ''' <summary>
  ''' Saves the habitat name fields.
  ''' </summary>
  ''' <param name="sectionNode">The section node.</param>
  ''' <param name="eddRow">The edd row.</param>
  ''' <param name="xDoc">The XmlDocument.</param>
  ''' <param name="xNsp">The XmlNamespaceManager used for XPath queries.</param>
  Private Sub SaveHabitatName(ByRef sectionNode As System.Xml.XmlNode, ByVal eddRow As System.Data.DataRow, ByRef xDoc As System.Xml.XmlDocument, ByVal xNsp As System.Xml.XmlNamespaceManager)
    './BiologicalResultDescription/TaxonomicDetails/HabitName
    If eddRow.IsNull("Habit_Name_1") AndAlso eddRow.IsNull("Habit_Name_2") AndAlso eddRow.IsNull("Habit_Name_3") Then Exit Sub

    Dim parentNode As System.Xml.XmlNode = sectionNode.SelectSingleNode("./BiologicalResultDescription", xNsp)
    If parentNode Is Nothing Then
      parentNode = xDoc.CreateElement("BiologicalResultDescription", Nothing)
      sectionNode.AppendChild(parentNode)
      Dim taxNode As System.Xml.XmlNode = xDoc.CreateElement("TaxonomicDetails", Nothing)
      parentNode.AppendChild(taxNode)
      parentNode = taxNode
    Else
      Dim taxNode As System.Xml.XmlNode = parentNode.SelectSingleNode("./TaxonomicDetails", xNsp)
      If taxNode Is Nothing Then
        taxNode = xDoc.CreateElement("TaxonomicDetails", Nothing)
        parentNode.AppendChild(taxNode)
        parentNode = taxNode
      Else
        parentNode = taxNode
      End If
    End If


    For i As Integer = 1 To 3
      If Not eddRow.IsNull("Habit_Name_" & i) Then
        Dim colNode As System.Xml.XmlNode = xDoc.CreateElement("HabitName", Nothing)
        parentNode.AppendChild(colNode)
        Dim textNode As System.Xml.XmlNode = xDoc.CreateNode(Xml.XmlNodeType.Text, Nothing, Nothing)
        textNode.Value = eddRow.Item("Habit_Name_" & i).ToString
        colNode.AppendChild(textNode)
      End If
    Next
  End Sub

  Private Function HasFrequencyValue(ByVal eddrow As System.Data.DataRow, ByVal index As Integer) As Boolean
    If Not eddrow.IsNull("Frequency_Class_Descriptor_" & index) OrElse Not eddrow.IsNull("Frequency_Class_Bounds_Unit_" & index) OrElse Not eddrow.IsNull("Frequency_Class_Lower_Bound_" & index) OrElse Not eddrow.IsNull("Frequency_Class_Upper_Bound_" & index) Then Return True
    Return False
  End Function

  '''<summary>Creates the nodes in the path if they don't exist </summary>
  '''<param name='xdoc'>The <see cref='System.Xml.XmlDocument' /> to create the nodes in</param>
  '''<param name='path'>The absolute path of the node which needs to be created </param>
  '''<returns> the newly created node </returns>
  ''' <history>
  '''   <mod user="BHM" case="36579" date="05/6/2009" remark="Created" />
  ''' </history>
  Private Shared Function CreateNodePath(ByRef xdoc As System.Xml.XmlDocument, ByVal xNsp As System.Xml.XmlNamespaceManager, ByVal path As String) As System.Xml.XmlNode
    Dim node As System.Xml.XmlNode = Nothing
    Dim pathNodes() As String = path.Split("/"c)
    For Each nodeName As String In pathNodes
      Dim name As String = nodeName.Trim
      Dim nameSplit() As String = name.Split(":"c)
      If nameSplit.Length > 1 Then
        name = nameSplit(1)
      End If


      If name.Length > 0 Then
        If node Is Nothing Then
          'This should be the root node
          If xdoc.DocumentElement Is Nothing Then
            'Create the root node
            Dim rootNode As System.Xml.XmlNode = xdoc.CreateElement(name, Nothing)
            xdoc.AppendChild(rootNode)
            node = rootNode
          Else
            If xdoc.DocumentElement.LocalName = name Then
              node = xdoc.DocumentElement
            Else
              Return Nothing
            End If
          End If

        Else
          Dim childNode As System.Xml.XmlNode = node.SelectSingleNode("./" & name, xNsp)
          If childNode Is Nothing Then
            Dim newNode As System.Xml.XmlNode = xdoc.CreateNode(Xml.XmlNodeType.Element, name, Nothing)
            node.AppendChild(newNode)
            node = newNode
          Else
            node = childNode
          End If

        End If

      End If
    Next

    Return node
  End Function

  ''' <summary>
  ''' Saves the row in the heirarchial XML EDD.
  ''' </summary>
  ''' <param name="eddRow">The edd row.</param>
  ''' <param name="sectionNode">The node all the row data will be part of.</param>
  ''' <param name="xDoc">The XmlDocument object containing the EDD.</param>
  ''' <param name="xNsp">The XmlNamespaceManager for performing XPath queries.</param>
  Private Shared Sub SaveBinaryObjectRow(ByVal eddRow As System.Data.DataRow, ByRef sectionNode As System.Xml.XmlNode, ByRef xDoc As System.Xml.XmlDocument, ByVal xNsp As System.Xml.XmlNamespaceManager)
    For Each column As System.Data.DataColumn In eddRow.Table.Columns
      Dim currNode As System.Xml.XmlNode = sectionNode
      If TypeOf column Is EddColumn Then
        Dim edd_column As EddColumn = CType(column, EddColumn)
        If Not eddRow.IsNull(edd_column.ColumnName) AndAlso eddRow.Item(edd_column.ColumnName).ToString.Length > 0 Then

          If column.ColumnName = "Place_Code" Then
            Dim identifier As String = eddRow.Item(column.ColumnName).ToString
            Dim identifierNode As System.Xml.XmlNode = Nothing
            Dim textNode As System.Xml.XmlNode = Nothing

            Select Case sectionNode.ParentNode.LocalName.ToLower

              Case "organization"
                'OrganizationDescription/OrganizationIdentifier
                Dim parentNode As System.Xml.XmlNode = sectionNode.ParentNode
                Dim childNode As System.Xml.XmlNode = parentNode.SelectSingleNode(String.Format("./OrganizationDescription/OrganizationIdentifier[text()='{0}'] | ./OrganizationDescription", identifier), xNsp)
                If childNode Is Nothing Then
                  childNode = parentNode.SelectSingleNode(String.Format("./OrganizationDescription", identifier), xNsp)
                  If childNode Is Nothing Then
                    Dim orgDesc As System.Xml.XmlNode = xDoc.CreateElement("OrganizationDescription", Nothing)
                    parentNode.AppendChild(orgDesc)
                    childNode = orgDesc
                  End If
                  identifierNode = xDoc.CreateElement("OrganizationIdentifier", Nothing)
                  textNode = xDoc.CreateNode(Xml.XmlNodeType.Text, Nothing, Nothing)
                  textNode.Value = identifier
                  identifierNode.AppendChild(textNode)
                  childNode.AppendChild(identifierNode)
                End If

              Case "projects"
                'Project_ID
                Dim parentNode As System.Xml.XmlNode = sectionNode.ParentNode
                Dim childNode As System.Xml.XmlNode = parentNode.SelectSingleNode(String.Format("./Project_ID[text()='{0}']", identifier), xNsp)
                If childNode Is Nothing Then
                  'Project_ID with the specified value does not exist so we need to create it
                  identifierNode = xDoc.CreateElement("Project_ID", Nothing)
                  textNode = xDoc.CreateNode(Xml.XmlNodeType.Text, Nothing, Nothing)
                  textNode.Value = identifier
                  identifierNode.AppendChild(textNode)
                  parentNode.AppendChild(identifierNode)
                End If

              Case "Locations"
                'MonitoringLocationIdentity/Location_ID
                Dim parentNode As System.Xml.XmlNode = sectionNode.ParentNode
                Dim childNode As System.Xml.XmlNode = parentNode.SelectSingleNode(String.Format("./MonitoringLocationIdentity/Location_ID[text()='{0}']", identifier), xNsp)
                If childNode Is Nothing Then
                  childNode = parentNode.SelectSingleNode(String.Format("./MonitoringLocationIdentity", identifier), xNsp)
                  If childNode Is Nothing Then
                    Dim monitIdent As System.Xml.XmlNode = xDoc.CreateElement("MonitoringLocationIdentity", Nothing)
                    parentNode.AppendChild(monitIdent)
                    childNode = monitIdent
                  End If
                  identifierNode = xDoc.CreateElement("Location_ID", Nothing)
                  textNode = xDoc.CreateNode(Xml.XmlNodeType.Text, Nothing, Nothing)
                  textNode.Value = identifier
                  identifierNode.AppendChild(textNode)
                  childNode.AppendChild(identifierNode)
                End If

              Case "activities"
                'ActivityDescription/Activity_ID
                Dim parentNode As System.Xml.XmlNode = sectionNode.ParentNode
                Dim childNode As System.Xml.XmlNode = parentNode.SelectSingleNode(String.Format("./ActivityDescription/Activity_ID[text()='{0}']", identifier), xNsp)
                If childNode Is Nothing Then
                  childNode = parentNode.SelectSingleNode(String.Format("./ActivityDescription", identifier), xNsp)
                  If childNode Is Nothing Then
                    Dim actDesc As System.Xml.XmlNode = xDoc.CreateElement("ActivityDescription", Nothing)
                    parentNode.AppendChild(actDesc)
                    childNode = actDesc
                  End If

                  identifierNode = xDoc.CreateElement("Activity_ID", Nothing)
                  textNode = xDoc.CreateNode(Xml.XmlNodeType.Text, Nothing, Nothing)
                  textNode.Value = identifier
                  identifierNode.AppendChild(textNode)
                  childNode.AppendChild(identifierNode)
                End If

              Case "wqx"
                'Place_Type is null
                identifierNode = xDoc.CreateElement("Identifier", Nothing)
                textNode = xDoc.CreateNode(Xml.XmlNodeType.Text, Nothing, Nothing)
                textNode.Value = identifier
                identifierNode.AppendChild(textNode)
                sectionNode.AppendChild(identifierNode)
            End Select

            Continue For
          End If


          'Use the first XPath query
          Dim paths() As String = edd_column.XmlXPath.Split("|"c)
          If paths.Length = 0 OrElse paths(0).Length = 0 Then Continue For
          'Get the list of nodes in the field XPath query
          Dim nodesList() As String = paths(0).Trim.Split("/"c)
          For i As Integer = 0 To nodesList.Length - 1
            Dim node As String = nodesList(i)
            If node = "." Then
              'Do nothing because this means the node is a child of the current node
            ElseIf node = ".." Then
              'Place_Code is the only field with this type of XPath and Place_Type will determine the XPath
              'The node is in the parent node of the current node
              'currNode = currNode.ParentNode
            ElseIf i = nodesList.Length - 1 Then
              'This is the node that contains the field value
              Dim fieldNode As System.Xml.XmlNode = xDoc.CreateNode(Xml.XmlNodeType.Element, node, Nothing)
              Dim colValue As String = eddRow.Item(edd_column.ColumnName).ToString.Trim

              Dim childNode As Xml.XmlNode = currNode.SelectSingleNode(String.Format("./{0}[text()='{1}']", node, colValue), xNsp)
              If Not childNode Is Nothing Then Continue For

              'The node does not exist yet, so create it
              Dim textNode As System.Xml.XmlNode = xDoc.CreateNode(Xml.XmlNodeType.Text, Nothing, Nothing)
              textNode.Value = colValue
              fieldNode.AppendChild(textNode)
              currNode.AppendChild(fieldNode)
            Else
              'This is a parent node to the field node
              Try
                Dim childNode As Xml.XmlNode = currNode.SelectSingleNode(String.Format("./{0}", node), xNsp)
                If Not childNode Is Nothing Then
                  currNode = childNode
                  Continue For
                End If

                'The node does not exist so create it
                Dim fieldNode As System.Xml.XmlNode = xDoc.CreateNode(Xml.XmlNodeType.Element, node, Nothing)
                currNode.AppendChild(fieldNode)
                currNode = fieldNode
              Catch ex As Exception

              End Try
            End If
          Next

        End If
      End If
    Next

  End Sub

  Public Overrides Sub SavingPostProcess(ByVal filename As String, ByRef xDoc As System.Xml.XmlDocument, ByVal xNsp As System.Xml.XmlNamespaceManager)
    'Here we can add namespaces into the EDD or header information
    If xDoc.DocumentElement Is Nothing Then Return

    If xDoc.DocumentElement.LocalName = "Document" Then
      'Add header information
      Dim headerNode As System.Xml.XmlNode = xDoc.DocumentElement.SelectSingleNode("./Header", xNsp)
      If Not headerNode Is Nothing Then Return

      headerNode = xDoc.CreateElement("Header", Nothing)
      xDoc.DocumentElement.PrependChild(headerNode)
      'Create Author node
      Dim node As System.Xml.XmlNode = xDoc.CreateElement("Author", Nothing)
      headerNode.AppendChild(node)
      Dim textNode As System.Xml.XmlNode = xDoc.CreateNode(Xml.XmlNodeType.Text, Nothing, Nothing)
      textNode.Value = "EDP"
      node.AppendChild(textNode)

      'Create Organization node
      node = xDoc.CreateElement("Organization", Nothing)
      headerNode.AppendChild(node)
      textNode = xDoc.CreateNode(Xml.XmlNodeType.Text, Nothing, Nothing)
      textNode.Value = "Org"
      node.AppendChild(textNode)

      'Create Title node
      node = xDoc.CreateElement("Title", Nothing)
      headerNode.AppendChild(node)
      textNode = xDoc.CreateNode(Xml.XmlNodeType.Text, Nothing, Nothing)
      textNode.Value = "WQX"
      node.AppendChild(textNode)

      'Create CreationTime node
      node = xDoc.CreateElement("CreationTime", Nothing)
      headerNode.AppendChild(node)
      textNode = xDoc.CreateNode(Xml.XmlNodeType.Text, Nothing, Nothing)
      textNode.Value = Date.Now.ToString()
      node.AppendChild(textNode)

      'Create DataService node
      node = xDoc.CreateElement("DataService", Nothing)
      headerNode.AppendChild(node)
      textNode = xDoc.CreateNode(Xml.XmlNodeType.Text, Nothing, Nothing)
      textNode.Value = "WQX"
      node.AppendChild(textNode)

      'Create ContactInfo node
      node = xDoc.CreateElement("ContactInfo", Nothing)
      headerNode.AppendChild(node)
      textNode = xDoc.CreateNode(Xml.XmlNodeType.Text, Nothing, Nothing)
      textNode.Value = "Contact Info"
      node.AppendChild(textNode)

      'Create Notification node
      node = xDoc.CreateElement("Notification", Nothing)
      headerNode.AppendChild(node)
      'textNode = xDoc.CreateNode(Xml.XmlNodeType.Text, Nothing, Nothing)
      'textNode.Value = ""
      'node.AppendChild(textNode)
    End If

    'Add namespaces
    If xDoc.DocumentElement.LocalName = "WQX" Then
      Dim att As System.Xml.XmlAttribute = xDoc.CreateAttribute("xmlns")
      att.Value = "http://www.exchangenetwork.net/schema/wqx/2"
      xDoc.DocumentElement.Attributes.Append(att)
    Else
      Dim att As System.Xml.XmlAttribute = xDoc.CreateAttribute("xmlns")
      att.Value = "http://www.exchangenetwork.net/schema/v1.0/ExchangeNetworkDocument.xsd"
      xDoc.DocumentElement.Attributes.Append(att)
      Dim wqxNode As System.Xml.XmlNode = xDoc.SelectSingleNode("//WQX", xNsp)
      If Not wqxNode Is Nothing Then
        att = xDoc.CreateAttribute("xmlns")
        att.Value = "http://www.exchangenetwork.net/schema/wqx/2"
        wqxNode.Attributes.Append(att)
      End If
    End If

  End Sub
#End Region

#Region "Column Ordinals"
  Private Structure Projects_
    Public Const Org_Code As Integer = 0
    Public Const Project_ID As Integer = 1
    Public Const Project_Name As Integer = 2
    Public Const Project_Description As Integer = 3
    Public Const Project_Start_Date As Integer = 4
    Public Const Project_Duration As Integer = 5
    Public Const Project_Type As Integer = 6
    Public Const QAPP_Summary As Integer = 7
    Public Const QAPP_Approved_Indicator As Integer = 8
    Public Const QAPP_Approval_Agency_Name As Integer = 9
    Public Const Study_Area_Description As Integer = 10
    Public Const Design_Sampling_Summary As Integer = 11
    Public Const Measurement_Quality_Objectives As Integer = 12
    Public Const Contact As Integer = 13
  End Structure
  Private Structure Locations_
    Public Const Org_Code As Integer = 0
    Public Const Park_Code As Integer = 1
    Public Const Location_ID As Integer = 2
    Public Const Location_Name As Integer = 3
    Public Const Location_Type As Integer = 4
    Public Const Latitude As Integer = 5
    Public Const Longitude As Integer = 6
    Public Const Lat_Lon_Method As Integer = 7
    Public Const Lat_Lon_Datum As Integer = 8
    Public Const Source_Map_Scale_Numeric As Integer = 9
    Public Const Lat_Lon_Accuracy As Integer = 10
    Public Const Lat_Lon_Accuracy_Unit As Integer = 11
    Public Const Location_Description As Integer = 12
    Public Const Travel_Directions As Integer = 13
    Public Const Location_Purpose As Integer = 14
    Public Const Establishment_Date As Integer = 15
    Public Const HUC8_Code As Integer = 16
    Public Const HUC12_Code As Integer = 17
    Public Const Alternate_Location_ID As Integer = 18
    Public Const Alternate_Location_ID_Context As Integer = 19
    Public Const Elevation As Integer = 20
    Public Const Elevation_Unit As Integer = 21
    Public Const Elevation_Method As Integer = 22
    Public Const Elevation_Datum As Integer = 23
    Public Const Elevation_Accuracy As Integer = 24
    Public Const Elevation_Accuracy_Unit As Integer = 25
    Public Const Country_Code As Integer = 26
    Public Const State_Code As Integer = 27
    Public Const County_Code As Integer = 28
    Public Const Drainage_Area As Integer = 29
    Public Const Drainage_Area_Unit As Integer = 30
    Public Const Contributing_Area As Integer = 31
    Public Const Contributing_Area_Unit As Integer = 32
    Public Const Tribal_Land_Indicator As Integer = 33
    Public Const Tribal_Land_Name As Integer = 34
    Public Const Well_ID As Integer = 35
    Public Const Well_Type As Integer = 36
    Public Const Aquifer_Name As Integer = 37
    Public Const Formation_Type As Integer = 38
    Public Const Well_Hole_Depth As Integer = 39
    Public Const Well_Hole_Depth_Unit As Integer = 40
    Public Const Well_Status As Integer = 41
    Public Const Public_Latitude As Integer = 42
    Public Const Public_Longitude As Integer = 43
  End Structure
    Private Structure Activities_
        Public Const Org_Code As Integer = 0
        Public Const Project_ID As Integer = 1
        Public Const Location_ID As Integer = 2
        Public Const Activity_ID As Integer = 3
        Public Const Activity_Type As Integer = 4
        Public Const Medium As Integer = 5
        Public Const Medium_Subdivision As Integer = 6
        Public Const Assemblage_Sampled_Name As Integer = 7
        Public Const Activity_Start_Date As Integer = 8
        Public Const Activity_Start_Time As Integer = 9
        Public Const Activity_Start_Time_Zone As Integer = 10
        Public Const Activity_End_Date As Integer = 11
        Public Const Activity_End_Time As Integer = 12
        Public Const Activity_End_Time_Zone As Integer = 13
        Public Const Activity_Relative_Depth As Integer = 14
        Public Const Activity_Depth As Integer = 15
        Public Const Activity_Depth_Unit As Integer = 16
        Public Const Activity_Upper_Depth As Integer = 17
        Public Const Activity_Lower_Depth As Integer = 18
        Public Const Activity_Depth_Reference As Integer = 19
        Public Const Additional_Location_Info As Integer = 20
        Public Const Activity_Sampler As Integer = 21
        Public Const Activity_Recorder As Integer = 22
        Public Const Custody_ID As Integer = 23
        Public Const Activity_Conducting_Organization As Integer = 24
        Public Const Station_Visit_Comment As Integer = 25
        Public Const Activity_Comment As Integer = 26
        Public Const Collection_Method_ID As Integer = 27
        Public Const Collection_Equipment_Name As Integer = 28
        Public Const Collection_Equipment_Description As Integer = 29
        Public Const Gear_Deployment As Integer = 30
        Public Const Container_Type As Integer = 31
        Public Const Container_Color As Integer = 32
        Public Const Container_Size As Integer = 33
        Public Const Container_Size_Unit As Integer = 34
        Public Const Preparation_Method_ID As Integer = 35
        Public Const Chemical_Preservative As Integer = 36
        Public Const Thermal_Preservative As Integer = 37
        Public Const Transport_Storage_Description As Integer = 38
        Public Const Activity_Group_ID As Integer = 39
        Public Const Activity_Group_Name As Integer = 40
        Public Const Activity_Group_Type As Integer = 41
        Public Const Collection_Duration As Integer = 42
        Public Const Collection_Duration_Unit As Integer = 43
        Public Const Sampling_Component_Name As Integer = 44
        Public Const Sampling_Component_Place_In_Series As Integer = 45
        Public Const Reach_Length As Integer = 46
        Public Const Reach_Length_Unit As Integer = 47
        Public Const Reach_Width As Integer = 48
        Public Const Reach_Width_Unit As Integer = 49
        Public Const Pass_Count As Integer = 50
        Public Const Net_Type As Integer = 51
        Public Const Net_Surface_Area As Integer = 52
        Public Const Net_Surface_Area_Unit As Integer = 53
        Public Const Net_Mesh_Size As Integer = 54
        Public Const Net_Mesh_Size_Unit As Integer = 55
        Public Const Boat_Speed As Integer = 56
        Public Const Boat_Speed_Unit As Integer = 57
        Public Const Current_Speed As Integer = 58
        Public Const Current_Speed_Unit As Integer = 59
        Public Const Toxicity_Test_Type As Integer = 60
        Public Const Collection_Effort As Integer = 61
        Public Const Collection_Effort_Gear_Type As Integer = 62
        'Public Const Deprecated_Activity_File As Integer = 63
        'Public Const Deprecated_TSRFDACT_IS_NUMBER As Integer = 64
        'Public Const Deprecated_ID_Code As Integer = 65
        'Public Const Deprecated_Replicate_Number As Integer = 66
        'Public Const Deprecated_QC_Indicator As Integer = 67
        'Public Const Deprecated_Project_Year As Integer = 68
        'Public Const Deprecated_TSRSTVST_IS_NUMBER As Integer = 69
    End Structure
    Private Structure ActivitySites_
    Public Const Org_Code As Integer = 0
    Public Const Activity_ID As Integer = 1
    Public Const Latitude As Integer = 2
    Public Const Longitude As Integer = 3
    Public Const Lat_Lon_Method As Integer = 4
    Public Const Lat_Lon_Datum As Integer = 5
    Public Const Source_Map_Scale_Numeric As Integer = 6
    Public Const Lat_Lon_Accuracy As Integer = 7
    Public Const Lat_Lon_Accuracy_Unit As Integer = 8
    Public Const Elevation As Integer = 9
    Public Const Elevation_Unit As Integer = 10
    Public Const Elevation_Method As Integer = 11
    Public Const Elevation_Datum As Integer = 12
    Public Const Elevation_Accuracy As Integer = 13
    Public Const Elevation_Accuracy_Unit As Integer = 14
    Public Const Public_Latitude As Integer = 15
    Public Const Public_Longitude As Integer = 16
  End Structure
    Private Structure Results_
        Public Const Org_Code As Integer = 0
        Public Const Activity_ID As Integer = 1
        Public Const Characteristic_Name As Integer = 2
        Public Const Method_Speciation As Integer = 3
        Public Const Filtered_Fraction As Integer = 4
        Public Const Result_Detection_Condition As Integer = 5
        Public Const Result_Text As Integer = 6
        Public Const Result_Unit As Integer = 7
        Public Const Result_Qualifier As Integer = 8
        Public Const Result_Status As Integer = 9
        Public Const Result_Type As Integer = 10
        Public Const Result_Comment As Integer = 11
        Public Const Method_Detection_Limit As Integer = 12
        Public Const Lower_Quantification_Limit As Integer = 13
        Public Const Upper_Quantification_Limit As Integer = 14
        Public Const Limit_Comment As Integer = 15
        Public Const Temperature_Basis As Integer = 16
        Public Const Statistical_Basis As Integer = 17
        Public Const Time_Basis As Integer = 18
        Public Const Weight_Basis As Integer = 19
        Public Const Particle_Size_Basis As Integer = 20
        Public Const Precision As Integer = 21
        Public Const Bias As Integer = 22
        Public Const Confidence_Interval As Integer = 23
        Public Const Upper_Confidence_Limit As Integer = 24
        Public Const Lower_Confidence_Limit As Integer = 25
        Public Const Result_Sampling_Point_Name As Integer = 26
        Public Const Result_Depth_Height_Measure As Integer = 27
        Public Const Result_Depth_Height_Measure_Unit As Integer = 28
        Public Const Result_Depth_Altitude_Reference_Point As Integer = 29
        Public Const Analytical_Method_ID As Integer = 30
        Public Const Analytical_Remark As Integer = 31
        Public Const Lab_ID As Integer = 32
        Public Const Lab_Remark_Code As Integer = 33
        Public Const Analysis_Start_Date As Integer = 34
        Public Const Analysis_Start_Time As Integer = 35
        Public Const Analysis_Start_Time_Zone As Integer = 36
        Public Const Lab_Accreditation_Indicator As Integer = 37
        Public Const Lab_Accreditation_Authority_Name As Integer = 38
        Public Const Lab_Batch_ID As Integer = 39
        Public Const Lab_Sample_Preparation_ID As Integer = 40
        Public Const Lab_Sample_Preparation_Start_Date As Integer = 41
        Public Const Lab_Sample_Preparation_Start_Time As Integer = 42
        Public Const Lab_Sample_Preparation_Start_Time_Zone As Integer = 43
        Public Const Dilution_Factor As Integer = 44
        Public Const Num_of_Replicates As Integer = 45
        Public Const Data_Logger_Line_Name As Integer = 46
        Public Const Biological_Intent As Integer = 47
        Public Const Biological_Individual_ID As Integer = 48
        Public Const Subject_Taxon As Integer = 49
        Public Const Unidentified_Species_ID As Integer = 50
        Public Const Tissue_Anatomy As Integer = 51
        Public Const Group_Summary_Count_or_Weight As Integer = 52
        Public Const Group_Summary_Count_or_Weight_Unit As Integer = 53
        Public Const Cell_Form As Integer = 54
        Public Const Cell_Shape As Integer = 55
        Public Const Habit_Name_1 As Integer = 56
        Public Const Habit_Name_2 As Integer = 57
        Public Const Habit_Name_3 As Integer = 58
        Public Const Voltinism As Integer = 59
        Public Const Pollution_Tolerance As Integer = 60
        Public Const Pollution_Tolerance_Scale As Integer = 61
        Public Const Trophic_Level As Integer = 62
        Public Const Functional_Feeding_Group_1 As Integer = 63
        Public Const Functional_Feeding_Group_2 As Integer = 64
        Public Const Functional_Feeding_Group_3 As Integer = 65
        Public Const File_Name_or_Resource_ID As Integer = 66
        Public Const Resource_Date As Integer = 67
        Public Const Resource_Title_Name As Integer = 68
        Public Const Resource_Creator_Name As Integer = 69
        Public Const Resource_Publisher_Name As Integer = 70
        Public Const Resource_Publication_Year As Integer = 71
        Public Const Resource_Volume_Pages As Integer = 72
        Public Const Resource_Subject_Text As Integer = 73
        Public Const Frequency_Class_Descriptor_1 As Integer = 74
        Public Const Frequency_Class_Bounds_Unit_1 As Integer = 75
        Public Const Frequency_Class_Lower_Bound_1 As Integer = 76
        Public Const Frequency_Class_Upper_Bound_1 As Integer = 77
        Public Const Frequency_Class_Descriptor_2 As Integer = 78
        Public Const Frequency_Class_Bounds_Unit_2 As Integer = 79
        Public Const Frequency_Class_Lower_Bound_2 As Integer = 80
        Public Const Frequency_Class_Upper_Bound_2 As Integer = 81
        Public Const Frequency_Class_Descriptor_3 As Integer = 82
        Public Const Frequency_Class_Bounds_Unit_3 As Integer = 83
        Public Const Frequency_Class_Lower_Bound_3 As Integer = 84
        Public Const Frequency_Class_Upper_Bound_3 As Integer = 85
        Public Const Taxonomist_Accreditation_Indicator As Integer = 86
        Public Const Taxonomist_Accreditation_Authority_Name As Integer = 87
        Public Const Result_File_Name As Integer = 88
        Public Const Lab_Reported_Result As Integer = 89
        Public Const Reportable_Result As Integer = 90
        Public Const Source_Flags As Integer = 91
        Public Const Logger_Standard_Difference As Integer = 92
        Public Const Logger_Percent_Error As Integer = 93
        Public Const Analytical_Method_ID_Context As Integer = 94
    End Structure
    Private Structure Indices_
    Public Const Org_Code As Integer = 0
    Public Const Project_ID As Integer = 1
    Public Const Location_ID As Integer = 2
    Public Const Bio_Habitat_Index_ID As Integer = 3
    Public Const Index_ID As Integer = 4
    'Public Const Index_Name As Integer = 5
    'Public Const Index_Context As Integer = 6
    'Public Const Index_Description As Integer = 7
    'Public Const Index_Scale As Integer = 8
    Public Const Index_Score As Integer = 5
    Public Const Index_Qualifier_Code As Integer = 6
    Public Const Index_Comment As Integer = 7
    Public Const Index_Calculated_Date As Integer = 8
    Public Const File_Name_or_Resource_ID As Integer = 9
    Public Const Resource_Date As Integer = 10
    Public Const Resource_Title_Name As Integer = 11
    Public Const Resource_Creator_Name As Integer = 12
    Public Const Resource_Publisher_Name As Integer = 13
    Public Const Resource_Publication_Year As Integer = 14
    Public Const Resource_Volume_Pages As Integer = 15
    Public Const Resource_Subject_Text As Integer = 16
  End Structure
  Private Structure Metrics_
        Public Const Org_Code As Integer = 0
        Public Const Activity_ID As Integer = 1
        Public Const Metric_ID As Integer = 2
        'Public Const Metric_Name As Integer = 3
        'Public Const Metric_Context As Integer = 4
        'Public Const Metric_Scale As Integer = 5
        'Public Const Formula_Description As Integer = 6
        Public Const Metric_Value As Integer = 3
        Public Const Metric_Value_Unit As Integer = 4
        Public Const Metric_Score As Integer = 5
        Public Const Metric_Comment As Integer = 6
        Public Const Index_ID As Integer = 7
        Public Const File_Name_or_Resource_ID As Integer = 8
        Public Const Resource_Date As Integer = 9
        Public Const Resource_Title_Name As Integer = 10
        Public Const Resource_Creator_Name As Integer = 11
        Public Const Resource_Publisher_Name As Integer = 12
        Public Const Resource_Publication_Year As Integer = 13
        Public Const Resource_Volume_Pages As Integer = 14
        Public Const Resource_Subject_Text As Integer = 15
    End Structure
    Private Structure Files_
        Public Const Org_Code As Integer = 0
        Public Const File_Name_or_Resource_ID As Integer = 1
        Public Const File_Type As Integer = 2
        Public Const Place_Type As Integer = 3
        Public Const Place_Code As Integer = 4
        Public Const Place_Subcode As Integer = 5
        Public Const File_Date As Integer = 6
        Public Const File_Confidential As Integer = 7
        Public Const Title As Integer = 8
        Public Const Author As Integer = 9
        Public Const Publisher As Integer = 10
        Public Const Publication_Year As Integer = 11
        Public Const Volume_Pages As Integer = 12
        Public Const Comments As Integer = 13
        Public Const Citation_Included As Integer = 14
        Public Const File_Content As Integer = 15
    End Structure
#End Region


End Class

''' <summary>
''' Class containing the sample fields from the Sample section.  Need to keep a reference to these 5 values so they can be mapped later in the Result section to dt_test.
''' </summary>
Public Class SampleRecord
  Private m_container_type As Object = DBNull.Value
  Private m_container_color As Object = DBNull.Value
  Private m_container_size As Object = DBNull.Value
  Private m_container_size_unit As Object = DBNull.Value
  Private m_preservative As Object = DBNull.Value
  Private m_temp_preserve_type As Object = DBNull.Value
  Private m_remark As Object = DBNull.Value

  Public Sub New(ByVal dr As System.Data.DataRow)
    If Not dr.IsNull("Container_Type") Then Me.m_container_type = dr.Item("Container_Type")
    If Not dr.IsNull("Container_Color") Then Me.m_container_color = dr.Item("Container_Color")
    If Not dr.IsNull("Container_Size") Then Me.m_container_size = dr.Item("Container_Size")
    If Not dr.IsNull("Container_Size_Unit") Then Me.m_container_size_unit = dr.Item("Container_Size_Unit")
    If Not dr.IsNull("Chemical_Preservative") Then Me.m_preservative = dr.Item("Chemical_Preservative")
    If Not dr.IsNull("Thermal_Preservative") Then Me.m_temp_preserve_type = dr.Item("Thermal_Preservative")
    If Not dr.IsNull("Transport_Storage_Description") Then Me.m_remark = dr.Item("Transport_Storage_Description")
  End Sub

#Region "Properties"
  Public ReadOnly Property ContainerType() As Object
    Get
      Return Me.m_container_type
    End Get
  End Property

  Public ReadOnly Property ContainerColor() As Object
    Get
      Return Me.m_container_color
    End Get
  End Property
  Public ReadOnly Property ContainerSize() As Object
    Get
      Return Me.m_container_size
    End Get
  End Property
  Public ReadOnly Property ContainerSizeUnit As Object
    Get
      Return Me.m_container_size_unit
    End Get
  End Property
  Public ReadOnly Property Preservative() As Object
    Get
      Return Me.m_preservative
    End Get
  End Property

  Public ReadOnly Property TempPreserveType() As Object
    Get
      Return Me.m_temp_preserve_type
    End Get
  End Property

  Public ReadOnly Property Remark() As Object
    Get
      Return Me.m_remark
    End Get
  End Property
#End Region
End Class