using Ato.CD.Inbound.Shared;
using Ato.CD.Inbound.Shared201802;
using Ato.EN.IntegrationServices.CodeGenerationCGTS;
using Ato.EN.IntegrationServices.CodeGenerationCTR;
using VaTS;
using DataContracts;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace Ato.CD.Inbound.CTR202502
{
    internal class CrossFormValidatorCGTS : ICrossFormValidator
    {
        private CTR2025 ParentDocument { get; }

        private CGTS2018 ChildDocument { get; }

        private List<Context> Contexts { get; }

        internal CrossFormValidatorCGTS(CTR2025 report, BusinessDocument childDocument)
        {
            ParentDocument = report;
            ChildDocument = (CGTS2018)childDocument.ConsumedReport;
            Contexts = ChildDocument.GetContexts();
        }

        public List<ProcessMessageDocument> ValidateCrossFormRules()
        {
            var response = new List<ProcessMessageDocument>();

            VRATOCTR428027(response);
            VRATOCTR430031(response);
            VRATOGEN438022(response);
            VRATOGEN438023(response);
            VRATOGEN438024(response);
            VRATOGEN438025(response);
            VRATOGEN438026(response);
            VRATOGEN438027(response);
            VRATOGEN438028(response);
            VRATOCTR428098(response);
            VRATOCTR430023(response);
            //CGTS-CTR
            VRATOGEN402009(response);
            VRATOGEN438000(response);
            VRATOGEN438001(response);
            VRATOCGTS402230(response);
            VRATOCGTS402226(response);
            //TT2022 
            VRATOCGTS402240(response);
            VRATOCGTS402173(response);
            VRATOCGTS402174(response);
            VRATOCGTS402203(response);

            return response;
        }

        //CTR-CGTS
        #region VR.ATO.CTR.428027
        /*  VR.ATO.CTR.428027
                  Companies cannot claim CGT discount unless they are life insurance companies or friendly societies or the company type is corporate unit trusts or public trading trusts and cannot claim if the entity is head company of a consolidated group.

              Legacy Rule Format:
                  IF (([CTR49] <> SET ("63100","62400") AND 
                  [CTR52] <> SET ("054", "174")) OR ([CTR52] = SET ("054", "174") AND [CTR53] = "1")) AND [CGTS126] > 0
                     RETURN VALIDATION MESSAGE
                  ENDIF

                  [CGTS126] = CGTS:RP.Applied:gfagc.02.06:TaxConcession.CapitalGains.DiscountTotal.Amount
                  [CTR49] = CTR:RP:pyde.02.30:OrganisationDetails.OrganisationIndustry2006Extended.Code
                  [CTR52] = CTR:RP:pyde.02.26:OrganisationDetails.OrganisationType.Code
                  [CTR53] = CTR:RP:pyde.02.03:OrganisationDetails.TaxConsolidationStatus.Code

          Technical Business Rule Format:
                  ((NotInSet(^CTR49, '"63100","62400"') AND NotInSet(^CTR52, '"054", "174"')) OR (InSet(^CTR52, '"054", "174"') AND ^CTR53 = '1')) AND ^CGTS126 > 0

      Data Elements:

                  RP:^CTR52 = tns:OrganisationDetails.OrganisationType.Code

                  RP:^CGTS126 = CGTS:RP.Applied:gfagc.02.06:TaxConcession.CapitalGains.DiscountTotal.Amount

                  RP:^CTR49 = tns:OrganisationDetails.OrganisationIndustry2006Extended.Code

                  RP:^CTR53 = tns:OrganisationDetails.TaxConsolidationStatus.Code
                  */
        private void VRATOCTR428027(List<ProcessMessageDocument> response)
        {
            bool assertion =
                (!IsMatch(ParentDocument.CTR49, "^(63100|62400)$", RegexOptions.IgnoreCase) &&
                 !IsMatch(ParentDocument.CTR52, "^(054|174)$", RegexOptions.IgnoreCase) ||
                 IsMatch(ParentDocument.CTR52, "^(054|174)$") && ParentDocument.CTR53 == "1") &&
                ChildDocument.CGTS126.GetValueOrDefault() > 0;

            if (assertion)
            {
                var processMessage = new ProcessMessageDocument
                {
                    Code = "CMN.ATO.CTR.438052",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Total CGT discount applied not applicable",
                    LongDescription = @"Companies cannot claim CGT discount unless they are life insurance companies or friendly societies or the company type is corporate unit trusts or public trading trusts and cannot claim if the entity is head company of a consolidated group",
                    Location = "/xbrli:xbrl/tns:OrganisationDetails.OrganisationType.Code",
                    Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.CTR.428027" } }
                };

                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CTR49", Value = ParentDocument.CTR49 });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CTR52", Value = ParentDocument.CTR52 });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CTR53", Value = ParentDocument.CTR53 });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CGTS126", Value = ChildDocument.CGTS126.GetValueOrDefault().ToString() });

                response.Add(processMessage);
            }
        }
        #endregion // VR.ATO.CTR.428027

        #region VR.ATO.CTR.430031

        /*  VR.ATO.CTR.430031
                    If taxpayer is required to lodge a CGT schedule and CGT exemption or rollover applied code is "Intercompany rollover Subdivision 126B", then Capital gains disregarded as a result of inter-company assets roll-over amount on attached CGT schedule must be completed

                Legacy Rule Format:
                    IF ([CTR330] = "G - Inter-company roll-over") AND (COUNT(SCHEDULE = "CGTS") = 1) AND [CGTS46] = NULL
                     RETURN VALIDATION MESSAGE
                    ENDIF
                    
                    [CGTS46] = CGTS:RP:rvctc3.02.11:Capital.Gains.InterCompanyAssetRolloverDeferral.Amount
                    [CTR330] = CTR:RP:rvctc3.02.33:CapitalGainsTax.ExemptionOrRolloverApplied.Code

            Technical Business Rule Format:
                    (^CTR330 = 'G - Inter-company roll-over') AND (CountDocument('CGTS') = 1) AND ^CGTS46 = NULL

        Data Elements:
            
                    RP:^CTR330 = tns:CapitalGainsTax.ExemptionOrRolloverApplied.Code
            
                    RP:^CGTS46 = CGTS:RP:rvctc3.02.11:Capital.Gains.InterCompanyAssetRolloverDeferral.Amount
                    */
        protected void VRATOCTR430031(List<ProcessMessageDocument> response)
        {
            if (!ChildDocument.CGTS46.HasValue && ParentDocument.CTR330Collection != null)
                response.AddRange(ParentDocument.CTR330Collection.Select((s, i) => new { ctr330 = s, Index = i })
                    .Where(c => IsMatch(c.ctr330, "^(G - Inter-company roll-over)$", RegexOptions.IgnoreCase)).Select(c =>
                        new ProcessMessageDocument
                        {
                            Code = "CMN.ATO.CTR.430031",
                            Severity = ProcessMessageSeverity.Error,
                            Description = @"Capital gains disregarded as a result of inter-company assets roll-over amount missing from CGT schedule",
                            LongDescription = @"If taxpayer is required to lodge a CGT schedule and CGT exemption or rollover applied code is ""Intercompany rollover Subdivision 126B"", then Capital gains disregarded as a result of inter-company assets roll-over amount on attached CGT schedule must be completed",
                            Location = c.Index == 0 ? "/xbrli:xbrl/tns:CapitalGainsTax.ExemptionOrRolloverApplied.Code" : $"/xbrli:xbrl/tns:CapitalGainsTax.ExemptionOrRolloverApplied.Code[{c.Index + 1}]",
                            Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.CTR.430031" }, new ProcessMessageParameter { Name = "CTR330", Value = c.ctr330 } }
                        }
                    ));
        }
        #endregion // VR.ATO.CTR.430031

        #region VR.ATO.GEN.438022

        /*  VR.ATO.GEN.438022
                    If taxpayer is required to lodge a CGT schedule and CGT exemption or rollover applied code is "Small business active asset reduction (Subdivision 152-C)", then Small business active asset reduction amount on attached CGT schedule must be completed

                Legacy Rule Format:
                    IF (RP:rvctc3.xx.xx:CapitalGainsTax.ExemptionOrRolloverApplied.Code = "A - Small business active asset reduction") AND (COUNT(SCHEDULE = "CGTS") = 1) AND [CGTS127] = NULL
                     RETURN VALIDATION MESSAGE
                    ENDIF
                    
                    [CGTS127] = CGTS:RP:gfagc.02.01:TaxConcession.CapitalGains.SmallBusinessActiveAssetReduction.Amount

            Technical Business Rule Format:
                    (^CTR330 = 'A - Small business active asset reduction') AND (CountDocument('CGTS') = 1) AND ^CGTS127 = NULL

        Data Elements:
            
                    RP:^CTR330 = tns:CapitalGainsTax.ExemptionOrRolloverApplied.Code
            
                    RP:^CGTS127 = CGTS:RP:gfagc.02.01:TaxConcession.CapitalGains.SmallBusinessActiveAssetReduction.Amount
                    */
        protected void VRATOGEN438022(List<ProcessMessageDocument> response)
        {
            bool assertion = ParentDocument.CTR330Collection != null &&
                       ParentDocument.CTR330Collection.Any(s => s.Equals("A - Small business active asset reduction")) &&
                       !ChildDocument.CGTS127.HasValue;

            if (assertion)
            {
                var processMessage = new ProcessMessageDocument
                {
                    Code = "CMN.ATO.GEN.438022",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Small business active asset reduction amount missing from CGT schedule",
                    LongDescription = @"If taxpayer is required to lodge a CGT schedule and CGT exemption or rollover applied code is ""Small business active asset reduction (Subdivision 152-C)"", then Small business active asset reduction amount on attached CGT schedule must be completed",
                    Location = "/xbrli:xbrl/tns:CapitalGainsTax.ExemptionOrRolloverApplied.Code",
                    Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.GEN.438022" } }
                };

                response.Add(processMessage);
            }
        }
        #endregion // VR.ATO.GEN.438022

        #region VR.ATO.GEN.438023

        /*  VR.ATO.GEN.438023
                    If taxpayer is required to lodge a CGT schedule and CGT exemption or rollover applied code is "Small business retirement exemption (Subdivision152-D)", then Small business retirement exemption amount on attached CGT schedule must be completed

                Legacy Rule Format:
                    IF (RP:rvctc3.xx.xx:CapitalGainsTax.ExemptionOrRolloverApplied.Code = "B - Small business retirement exemption") AND (COUNT(SCHEDULE = "CGTS") = 1) AND [CGTS128] = NULL
                     RETURN VALIDATION MESSAGE
                    ENDIF
                    
                    [CGTS128] = CGTS:RP:gfagc.02.01:TaxConcession.CapitalGains.SmallBusinessRetirementExemption.Amount

            Technical Business Rule Format:
                    (^CTR330 = 'B - Small business retirement exemption') AND (CountDocument('CGTS') = 1) AND ^CGTS128 = NULL

        Data Elements:
            
                    RP:^CTR330 = tns:CapitalGainsTax.ExemptionOrRolloverApplied.Code
            
                    RP:^CGTS128 = CGTS:RP:gfagc.02.01:TaxConcession.CapitalGains.SmallBusinessRetirementExemption.Amount
                    */
        protected void VRATOGEN438023(List<ProcessMessageDocument> response)
        {
            if (!ChildDocument.CGTS128.HasValue && ParentDocument.CTR330Collection != null)
                response.AddRange(ParentDocument.CTR330Collection.Select((s, i) => new { ctr330 = s, Index = i })
                    .Where(c => IsMatch(c.ctr330, "^(B - Small business retirement exemption)$", RegexOptions.IgnoreCase)).Select(c =>
                        new ProcessMessageDocument
                        {
                            Code = "CMN.ATO.GEN.438023",
                            Severity = ProcessMessageSeverity.Error,
                            Description = @"Small business retirement exemption amount missing from CGT schedule",
                            LongDescription = @"If taxpayer is required to lodge a CGT schedule and CGT exemption or rollover applied code is ""Small business retirement exemption (Subdivision152-D)"", then Small business retirement exemption amount on attached CGT schedule must be completed",
                            Location = c.Index == 0 ? "/xbrli:xbrl/tns:CapitalGainsTax.ExemptionOrRolloverApplied.Code" : $"/xbrli:xbrl/tns:CapitalGainsTax.ExemptionOrRolloverApplied.Code[{c.Index + 1}]",
                            Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.GEN.438023" }, new ProcessMessageParameter { Name = "CTR330", Value = c.ctr330 } }
                        }
                    ));
        }
        #endregion // VR.ATO.GEN.438023

        #region VR.ATO.GEN.438024

        /*  VR.ATO.GEN.438024
                    If taxpayer is required to lodge a CGT schedule and CGT exemption or rollover applied code is "Small business roll-over (Subdivision 152-E)", then Small business roll-over amount on attached CGT schedule must be completed

                Legacy Rule Format:
                    IF (RP:rvctc3.xx.xx:CapitalGainsTax.ExemptionOrRolloverApplied.Code = "C - Small business roll-over") AND (COUNT(SCHEDULE = "CGTS") = 1) AND [CGTS129] = NULL
                     RETURN VALIDATION MESSAGE
                    ENDIF
                    
                    [CGTS129] = CGTS:RP:gfagc.02.01:TaxConcession.CapitalGains.SmallBusinessRollover.Amount

            Technical Business Rule Format:
                    (^CTR330 = 'C - Small business roll-over') AND (CountDocument('CGTS') = 1) AND ^CGTS129 = NULL

        Data Elements:
            
                    RP:^CTR330 = tns:CapitalGainsTax.ExemptionOrRolloverApplied.Code
            
                    RP:^CGTS129 = CGTS:RP:gfagc.02.01:TaxConcession.CapitalGains.SmallBusinessRollover.Amount
                    */
        protected void VRATOGEN438024(List<ProcessMessageDocument> response)
        {
            if (!ChildDocument.CGTS129.HasValue && ParentDocument.CTR330Collection != null)
                response.AddRange(ParentDocument.CTR330Collection.Select((s, i) => new { ctr330 = s, Index = i })
                    .Where(c => IsMatch(c.ctr330, "^(C - Small business roll-over)$", RegexOptions.IgnoreCase)).Select(c =>
                        new ProcessMessageDocument
                        {
                            Code = "CMN.ATO.GEN.438024",
                            Severity = ProcessMessageSeverity.Error,
                            Description = @"Small business roll-over amount missing from CGT schedule",
                            LongDescription = @"If taxpayer is required to lodge a CGT schedule and CGT exemption or rollover applied code is ""Small business roll-over (Subdivision 152-E)"", then Small business roll-over amount on attached CGT schedule must be completed",
                            Location = c.Index == 0 ? "/xbrli:xbrl/tns:CapitalGainsTax.ExemptionOrRolloverApplied.Code" : $"/xbrli:xbrl/tns:CapitalGainsTax.ExemptionOrRolloverApplied.Code[{c.Index + 1}]",
                            Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.GEN.438024" }, new ProcessMessageParameter { Name = "CTR330", Value = c.ctr330 } }
                        }
                    ));
        }
        #endregion // VR.ATO.GEN.438024

        #region VR.ATO.GEN.438025

        /*  VR.ATO.GEN.438025
                    If taxpayer is required to lodge a CGT schedule and CGT exemption or rollover applied code is "Small business 15 year exemption (Subdivision152-B)", then Small business 15 year exemption amount on attached CGT schedule must be completed

                Legacy Rule Format:
                    IF (RP:rvctc3.xx.xx:CapitalGainsTax.ExemptionOrRolloverApplied.Code = "D - Small business 15 year exemption") AND (COUNT(SCHEDULE = "CGTS") = 1) AND [CGTS138] = NULL
                     RETURN VALIDATION MESSAGE
                    ENDIF
                    
                    [CGTS138] = CGTS:RP:gfagc.02.01:TaxConcession.CapitalGains.SmallBusinessExemptionExempt.Amount

            Technical Business Rule Format:
                    (^CTR330 = 'D - Small business 15 year exemption') AND (CountDocument('CGTS') = 1) AND ^CGTS138 = NULL

        Data Elements:
            
                    RP:^CTR330 = tns:CapitalGainsTax.ExemptionOrRolloverApplied.Code
            
                    RP:^CGTS138 = CGTS:RP:gfagc.02.01:TaxConcession.CapitalGains.SmallBusinessExemptionExempt.Amount
                    */
        protected void VRATOGEN438025(List<ProcessMessageDocument> response)
        {
            if (!ChildDocument.CGTS138.HasValue && ParentDocument.CTR330Collection != null)
                response.AddRange(ParentDocument.CTR330Collection.Select((s, i) => new { ctr330 = s, Index = i })
                    .Where(c => IsMatch(c.ctr330, "^(D - Small business 15 year exemption)$", RegexOptions.IgnoreCase)).Select(c =>
                        new ProcessMessageDocument
                        {
                            Code = "CMN.ATO.GEN.438025",
                            Severity = ProcessMessageSeverity.Error,
                            Description = @"Small business 15 year exemption amount missing from CGT schedule",
                            LongDescription = @"If taxpayer is required to lodge a CGT schedule and CGT exemption or rollover applied code is ""Small business 15 year exemption (Subdivision152-B)"", then Small business 15 year exemption amount on attached CGT schedule must be completed",
                            Location = c.Index == 0 ? "/xbrli:xbrl/tns:CapitalGainsTax.ExemptionOrRolloverApplied.Code" : $"/xbrli:xbrl/tns:CapitalGainsTax.ExemptionOrRolloverApplied.Code[{c.Index + 1}]",
                            Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.GEN.438025" }, new ProcessMessageParameter { Name = "CTR330", Value = c.ctr330 } }
                        }
                    ));
        }
        #endregion // VR.ATO.GEN.438025

        #region VR.ATO.GEN.438026

        /*  VR.ATO.GEN.438026
                    If taxpayer is required to lodge a CGT schedule and CGT exemption or rollover applied code is "Foreign resident CGT exemption (Division 855)", then Capital gains disregarded by a foreign resident amount on attached CGT schedule must be completed

                Legacy Rule Format:
                    IF (RP:rvctc3.xx.xx:CapitalGainsTax.ExemptionOrRolloverApplied.Code = "E - Foreign resident CGT exemption") AND (COUNT(SCHEDULE = "CGTS") = 1) AND [CGTS140] = NULL
                     RETURN VALIDATION MESSAGE
                    ENDIF
                    
                    [CGTS140] = CGTS:RP:rvctc3.02.11:Capital.Gains.ForeignResidentExemption.Amount

            Technical Business Rule Format:
                    (^CTR330 = 'E - Foreign resident CGT exemption') AND (CountDocument('CGTS') = 1) AND ^CGTS140 = NULL

        Data Elements:
            
                    RP:^CTR330 = tns:CapitalGainsTax.ExemptionOrRolloverApplied.Code
            
                    RP:^CGTS140 = CGTS:RP:rvctc3.02.11:Capital.Gains.ForeignResidentExemption.Amount
                    */
        protected void VRATOGEN438026(List<ProcessMessageDocument> response)
        {
            if (!ChildDocument.CGTS140.HasValue && ParentDocument.CTR330Collection != null)
                response.AddRange(ParentDocument.CTR330Collection.Select((s, i) => new { ctr330 = s, Index = i })
                    .Where(c => IsMatch(c.ctr330, "^(E - Foreign resident CGT exemption)$", RegexOptions.IgnoreCase)).Select(c =>
                        new ProcessMessageDocument
                        {
                            Code = "CMN.ATO.GEN.438026",
                            Severity = ProcessMessageSeverity.Error,
                            Description = @"Capital gains disregarded by a foreign resident amount missing from CGT schedule",
                            LongDescription = @"If taxpayer is required to lodge a CGT schedule and CGT exemption or rollover applied code is ""Foreign resident CGT exemption (Division 855)"", then Capital gains disregarded by a foreign resident amount on attached CGT schedule must be completed",
                            Location = c.Index == 0 ? "/xbrli:xbrl/tns:CapitalGainsTax.ExemptionOrRolloverApplied.Code" : $"/xbrli:xbrl/tns:CapitalGainsTax.ExemptionOrRolloverApplied.Code[{c.Index + 1}]",
                            Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.GEN.438026" }, new ProcessMessageParameter { Name = "CTR330", Value = c.ctr330 } }
                        }
                    ));
        }
        #endregion // VR.ATO.GEN.438026

        #region VR.ATO.GEN.438027

        /*  VR.ATO.GEN.438027
                    If taxpayer is required to lodge a CGT schedule and CGT exemption or rollover applied code is "Scrip for scrip roll-over (Subdivision 124-M)", then Capital gains disregarded as a result of a scrip for scrip roll-over amount on attached CGT schedule must be completed

                Legacy Rule Format:
                    IF (RP:rvctc3.xx.xx:CapitalGainsTax.ExemptionOrRolloverApplied.Code = "F - Scrip for scrip roll-over") AND (COUNT(SCHEDULE = "CGTS") = 1) AND [CGTS45] = NULL
                     RETURN VALIDATION MESSAGE
                    ENDIF
                    
                    [CGTS45] = CGTS:RP:rvctc3.02.11:Capital.Gains.ScriptForScriptRolloverDeferral.Amount

            Technical Business Rule Format:
                    (^CTR330 = 'F - Scrip for scrip roll-over') AND (CountDocument('CGTS') = 1) AND ^CGTS45 = NULL

        Data Elements:
            
                    RP:^CTR330 = tns:CapitalGainsTax.ExemptionOrRolloverApplied.Code
            
                    RP:^CGTS45 = CGTS:RP:rvctc3.02.11:Capital.Gains.ScriptForScriptRolloverDeferral.Amount
                    */
        protected void VRATOGEN438027(List<ProcessMessageDocument> response)
        {
            if (!ChildDocument.CGTS45.HasValue && ParentDocument.CTR330Collection != null)
                response.AddRange(ParentDocument.CTR330Collection.Select((s, i) => new { ctr330 = s, Index = i })
                    .Where(c => IsMatch(c.ctr330, "^(F - Scrip for scrip roll-over)$", RegexOptions.IgnoreCase)).Select(c =>
                        new ProcessMessageDocument
                        {
                            Code = "CMN.ATO.GEN.438027",
                            Severity = ProcessMessageSeverity.Error,
                            Description = @"Capital gains disregarded as a result of a scrip for scrip roll-over amount missing from CGT schedule",
                            LongDescription = @"If taxpayer is required to lodge a CGT schedule and CGT exemption or rollover applied code is ""Scrip for scrip roll-over (Subdivision 124-M)"", then Capital gains disregarded as a result of a scrip for scrip roll-over amount on attached CGT schedule must be completed",
                            Location = c.Index == 0 ? "/xbrli:xbrl/tns:CapitalGainsTax.ExemptionOrRolloverApplied.Code" : $"/xbrli:xbrl/tns:CapitalGainsTax.ExemptionOrRolloverApplied.Code[{c.Index - 1}]",
                            Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.GEN.438027" }, new ProcessMessageParameter { Name = "CTR330", Value = c.ctr330 } }
                        }
                    ));
        }
        #endregion // VR.ATO.GEN.438027

        #region VR.ATO.GEN.438028

        /*  VR.ATO.GEN.438028
                    If taxpayer is required to lodge a CGT schedule and CGT exemption or rollover applied code is "Demerger exemption (Subdivision 125-C)", then Capital gains disregarded by a demerging entity amount on attached CGT schedule must be completed

                Legacy Rule Format:
                    IF (RP:rvctc3.xx.xx:CapitalGainsTax.ExemptionOrRolloverApplied.Code = "H - Demerger exemption") AND (COUNT(SCHEDULE = "CGTS") = 1) AND [CGTS47] = NULL
                     RETURN VALIDATION MESSAGE
                    ENDIF
                    
                    [CGTS47] = CGTS:RP:rvctc3.02.11:Capital.Gains.DemergingEntityExemption.Amount

            Technical Business Rule Format:
                    (^CTR330 = 'H - Demerger exemption') AND (CountDocument('CGTS') = 1) AND ^CGTS47 = NULL

        Data Elements:
            
                    RP:^CTR330 = tns:CapitalGainsTax.ExemptionOrRolloverApplied.Code
            
                    RP:^CGTS47 = CGTS:RP:rvctc3.02.11:Capital.Gains.DemergingEntityExemption.Amount
                    */
        protected void VRATOGEN438028(List<ProcessMessageDocument> response)
        {
            if (!ChildDocument.CGTS47.HasValue && ParentDocument.CTR330Collection != null)
                response.AddRange(ParentDocument.CTR330Collection.Select((s, i) => new { ctr330 = s, Index = i })
                    .Where(c => IsMatch(c.ctr330, "^(H - Demerger exemption)$", RegexOptions.IgnoreCase)).Select(c =>
                        new ProcessMessageDocument
                        {
                            Code = "CMN.ATO.GEN.438028",
                            Severity = ProcessMessageSeverity.Error,
                            Description = @"Capital gains disregarded by a demerging entity amount missing from CGT schedule",
                            LongDescription = @"If taxpayer is required to lodge a CGT schedule and CGT exemption or rollover applied code is ""Demerger exemption (Subdivision 125-C)"", then Capital gains disregarded by a demerging entity amount on attached CGT schedule must be completed",
                            Location = c.Index == 0 ? "/xbrli:xbrl/tns:CapitalGainsTax.ExemptionOrRolloverApplied.Code" : $"/xbrli:xbrl/tns:CapitalGainsTax.ExemptionOrRolloverApplied.Code[{c.Index - 1}]",
                            Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.GEN.438028" }, new ProcessMessageParameter { Name = "CTR330", Value = c.ctr330 } }
                        }
                    ));
        }
        #endregion // VR.ATO.GEN.438028

        #region VR.ATO.CTR.428098

        /*  VR.ATO.CTR.428098
                    Net capital gain in return must equal net capital gain in CGT schedule

                Legacy Rule Format:
                    IF (COUNT(SCHEDULE = "CGTS") = 1) AND ([CTR91] <> [CGTS131])
                       RETURN VALIDATION MESSAGE
                    ENDIF
                    
                    [CGTS131] = CGTS:RP:bafpr1.02.00:Income.CapitalGainsNet.Amount
                    [CTR91] = CTR:RP:bafpr1.02.00:Income.CapitalGainsNet.Amount

            Technical Business Rule Format:
                    (CountDocument('CGTS') = 1) AND (^CTR91 <> ^CGTS131)

        Data Elements:
            
                    RP:^CTR91 = tns:Income.CapitalGainsNet.Amount
            
                    RP:^CGTS131 = CGTS:RP:bafpr1.02.00:Income.CapitalGainsNet.Amount
                    */
        protected void VRATOCTR428098(List<ProcessMessageDocument> response)
        {
            bool assertion = ParentDocument.CTR91.GetValueOrDefault() != ChildDocument.CGTS131.GetValueOrDefault();

            if (assertion)
            {
                var processMessage = new ProcessMessageDocument
                {
                    Code = "CMN.ATO.CTR.430019",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Net capital gain in return must equal net capital gain in CGT schedule",
                    LongDescription = @"Net capital gain amount on the company return  must equal the net capital gain amount on the CGT schedule",
                    Location = "/xbrli:xbrl/tns:Income.CapitalGainsNet.Amount",
                    Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.CTR.428098" } }
                };

                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CTR91", Value = ParentDocument.CTR91.GetValueOrDefault().ToString() });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CGTS131", Value = ChildDocument.CGTS131.GetValueOrDefault().ToString() });

                response.Add(processMessage);
            }
        }
        #endregion // VR.ATO.CTR.428098

        #region VR.ATO.CTR.430023

        /*  VR.ATO.CTR.430023
                    The net capital losses carried forward (including collectables) must be consistent between the income tax return and the CGT schedule

                Legacy Rule Format:
                    IF [CTR176] <> NULL  AND (COUNT(SCHEDULE = "CGTS") = 1) AND ([CTR176] <> ([CGTS124] + [CGTS125]))
                       RETURN VALIDATION MESSAGE
                    ENDIF
                    
                    [CGTS124] = CGTS:RP.Collectables.Unapplied(Instant):rvctc3.02.16:Capital.Losses.CarriedForward.Net.Amount
                    [CGTS125] = CGTS:RP.CGTOther.Unapplied(Instant):rvctc3.02.16:Capital.Losses.CarriedForward.Net.Amount
                    [CTR176] = CTR:RP(Instant):rvctc3.02.16:Capital.Losses.CarriedForward.Net.Amount

            Technical Business Rule Format:
                    ^CTR176 <> NULL  AND (CountDocument('CGTS') = 1) AND (^CTR176 <> (^CGTS124 + ^CGTS125))

        Data Elements:
            
                    RP(Instant):^CTR176 = tns:Capital.Losses.CarriedForward.Net.Amount
            
                    RP(Instant):^CGTS124 = CGTS:RP.Collectables.Unapplied(Instant):rvctc3.02.16:Capital.Losses.CarriedForward.Net.Amount
            
                    RP(Instant):^CGTS125 = CGTS:RP.CGTOther.Unapplied(Instant):rvctc3.02.16:Capital.Losses.CarriedForward.Net.Amount
                    */
        protected void VRATOCTR430023(List<ProcessMessageDocument> response)
        {
            bool assertion = ParentDocument.CTR176 != null && ParentDocument.CTR176.GetValueOrDefault() !=
                             ChildDocument.CGTS124.GetValueOrDefault() + ChildDocument.CGTS125.GetValueOrDefault();
            if (assertion)
            {
                var processMessage = new ProcessMessageDocument
                {
                    Code = "CMN.ATO.CTR.430023",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Net capital losses carried forward to later income years incorrect",
                    LongDescription = @"Net capital losses carried forward to later income years on the company return  must equal the total net capital losses carried forward (including collectables) to later income years on the CGT schedule",
                    Location = "/xbrli:xbrl/tns:Capital.Losses.CarriedForward.Net.Amount",
                    Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.CTR.430023" } },
                };

                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CTR176", Value = ParentDocument.CTR176.GetValueOrDefault().ToString() });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CGTS124", Value = ChildDocument.CGTS124.GetValueOrDefault().ToString() });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CGTS125", Value = ChildDocument.CGTS125.GetValueOrDefault().ToString() });

                response.Add(processMessage);
            }
        }
        #endregion // VR.ATO.CTR.430023

        // CGTS-CTR

        #region VR.ATO.GEN.402009
        /* VR.ATO.GEN.402009
            IF (RP:entity.identifier.TFN <> PARENT RETURN:RP:entity.identifier.TFN)
                RETURN VALIDATION MESSAGE
            ENDIF 
        */
        private void VRATOGEN402009(List<ProcessMessageDocument> response)
        {
            bool assertion = !ParentDocument.RPIdentifierTFN.Equals(ChildDocument.RPIdentifierTFN);

            if (assertion)
            {
                var processMessage = new ProcessMessageDocument
                {
                    Code = "CMN.ATO.GEN.402009",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Your supplied TFN does not match the TFN supplied on the form it was submitted with",
                    LongDescription = @"Your supplied TFN does not match the TFN supplied on the parent form it was submitted with",
                    Location = "/xbrli:xbrl/xbrli:context/xbrli:entity/xbrli:identifier",
                    Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.GEN.402009" } }
                };

                response.Add(processMessage);
            }
        }
        #endregion // VR.ATO.GEN.402009

        #region VR.ATO.GEN.438000
        /*  VR.ATO.GEN.438000
            IF (period.startDate WHERE CONTEXT(ALL)) <> PARENT RETURN:RP:period.startDate
               RETURN VALIDATION MESSAGE
            ENDIF
              private void VRATOCGTS438000(List<ProcessMessageDocument> response)
        */
        private void VRATOGEN438000(List<ProcessMessageDocument> response)
        {
            response.AddRange(from context in Contexts
                              where context.StartDate.GetValueOrDefault() != ParentDocument.RPStartDate.GetValueOrDefault()
                              select new ProcessMessageDocument
                              {
                                  Code = "CMN.ATO.GEN.438000",
                                  Severity = ProcessMessageSeverity.Error,
                                  Description = @"The context period start date is incorrect.",
                                  LongDescription = @"Period start date within context on the schedule must match period start date within the parent return reporting party context",
                                  Location = $"/xbrli:xbrl/xbrli:context[{context.Index}]/xbrli:period/xbrli:startDate",
                                  Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.GEN.438000" } }
                              });
        }
        #endregion // VR.ATO.GEN.438000

        #region VR.ATO.GEN.438001
        /*  VR.ATO.CGTS.438001
            IF (period.endDate WHERE CONTEXT(ALL)) <> PARENT RETURN:RP:period.endDate
               RETURN VALIDATION MESSAGE
            ENDIF
        */
        private void VRATOGEN438001(List<ProcessMessageDocument> response)
        {
            response.AddRange(from context in Contexts
                              where context.EndDate.GetValueOrDefault() != ParentDocument.RPEndDate.GetValueOrDefault()
                              select new ProcessMessageDocument
                              {
                                  Code = "CMN.ATO.GEN.438001",
                                  Severity = ProcessMessageSeverity.Error,
                                  Description = @"The context period end date is incorrect.",
                                  LongDescription = @"Period end date within context on the schedule must match period end date within the parent return reporting party context",
                                  Location = $"/xbrli:xbrl/xbrli:context[{context.Index}]/xbrli:period/xbrli:endDate",
                                  Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.GEN.438001" } }
                              });
        }
        #endregion // VR.ATO.GEN.438001

        #region VR.ATO.CGTS.402230
        /*  VR.ATO.CGTS.402230
          
          IF PARENT RETURN  <> "TRTAMI" AND ([CGTS153] <> NULL OR [CGTS154] <> NULL OR [CGTS155] <> NULL)
            RETURN VALIDATION MESSAGE
          ENDIF
           
        */
        private void VRATOCGTS402230(List<ProcessMessageDocument> response)
        {
            bool assertion = !string.IsNullOrEmpty(ChildDocument.CGTS153) || ChildDocument.CGTS154.HasValue || ChildDocument.CGTS155.HasValue;

            if (assertion)
            {
                var processMessage = new ProcessMessageDocument
                {
                    Code = "CMN.ATO.CGTS.402230",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Multi-class treatment fields incorrectly supplied",
                    Location = "/xbrli:xbrl/tns:IncomeTax.AttributionManagedInvestmentTrustClass.Description",
                    Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.CGTS.402230" } }
                };

                response.Add(processMessage);
            }
        }
        #endregion // VR.ATO.CGTS.402230

        #region VR.ATO.CGTS.402226
        /*  VR.ATO.CGTS.402226
          
            IF (PARENT RETURN:RP:pyin.xx.xx:Report.Amendment.Indicator = TRUE) AND ([CGTS150] <> NULL AND [CGTS151] <> NULL)
               RETURN VALIDATION MESSAGE
            ENDIF

            [CGTS150] = CGTS:RP:pyin.02.37:Report.TargetFinancial.Year
            [CGTS151] = CGTS:RP:bafot.02.26:Miscellaneous.RequestedAmendment.Amount
           
        */
        private void VRATOCGTS402226(List<ProcessMessageDocument> response)
        {
            bool assertion = ParentDocument.CTR298.GetValueOrDefault() && ChildDocument.CGTS150.HasValue && ChildDocument.CGTS151.HasValue;

            if (assertion)
            {
                var processMessage = new ProcessMessageDocument
                {
                    Code = "CMN.ATO.CGTS.402226",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Income year earnout right created and Amount to be amended cannot be supplied when Parent return Amendment indicator is present.",
                    Location = "/xbrli:xbrl/tns:Report.TargetFinancial.Year",
                    Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.CGTS.402226" } }
                };

                response.Add(processMessage);
            }
        }
        #endregion // VR.ATO.CGTS.402226       

        #region VR.ATO.CGTS.402240
        /* VR.ATO.CGTS.402240

            IF([CGTS150] <> NULL) AND([CGTS150] = (PARENT RETURN:RP:pyin.xx.xx:Report.TargetFinancial.Year))
               RETURN VALIDATION MESSAGE
            ENDIF

            [CGTS150] = CGTS:RP:pyin.02.37:Report.TargetFinancial.Year         
        */
        private void VRATOCGTS402240(List<ProcessMessageDocument> response)
        {
            bool assertion = ChildDocument.CGTS150.HasValue && (ChildDocument.CGTS150.GetValueOrDefault() == ParentDocument.CTR2.GetValueOrDefault());

            if (assertion)
            {
                var processMessage = new ProcessMessageDocument
                {
                    Code = "CMN.ATO.CGTS.402240",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Income year earnout right created incorrect",
                    Location = "/xbrli:xbrl/tns:Report.TargetFinancial.Year",
                    Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.CGTS.402240" } }
                };

                response.Add(processMessage);
            }
        }
        #endregion // VR.ATO.CGTS.402240

        #region VR.ATO.CGTS.402173

        /*  VR.ATO.CGTS.402173
          
            IF PARENT RETURN = "CTR" AND ([CTR49] <> SET ("63100","62400")) AND [CGTS126] > ((([CGTS118] - [CGTS123]) *0.33) +1)
               RETURN VALIDATION MESSAGE
            ENDIF
            */
        protected void VRATOCGTS402173(List<ProcessMessageDocument> response)
        {
            ProcessMessageDocument processMessage;

            bool assertion = !IsMatch(ParentDocument.CTR49, @"^(63100|62400)$", RegexOptions.IgnoreCase) &&
                  ChildDocument.CGTS126.GetValueOrDefault() > (ChildDocument.CGTS118.GetValueOrDefault() - ChildDocument.CGTS123.GetValueOrDefault()) * 0.33M + 1;

            if (assertion)
            {
                processMessage = new ProcessMessageDocument()
                {
                    Code = "CMN.ATO.CGTS.402173",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"The total percentage applied to capital gains by a company must not be greater than 33%",
                    LongDescription = @"The available discount on capital gains is 33% for life insurance companies, friendly societies and FHSA trusts",
                    Location = "/xbrli:xbrl/tns:TaxConcession.CapitalGains.DiscountTotal.Amount",
                    Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() { Name = "RuleIdentifier", Value = "VR.ATO.CGTS.402173" } },
                };
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CTR49", Value = ParentDocument.CTR49 });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CGTS126", Value = ChildDocument.CGTS126.GetValueOrDefault().ToString() });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CGTS118", Value = ChildDocument.CGTS118.GetValueOrDefault().ToString() });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CGTS123", Value = ChildDocument.CGTS123.GetValueOrDefault().ToString() });
                response.Add(processMessage);
            }
        }

        #endregion // VR.ATO.CGTS.402173

        #region VR.ATO.CGTS.402174
        /* VR.ATO.CGTS.402174

         IF PARENT RETURN = SET("TRT", "CTR","TRTAMI") AND  [CGTS126] > ((([CGTS118] - [CGTS123]) *0.5) +1)
         RETURN VALIDATION MESSAGE
        ENDIF      
            [CGTS118] = CGTS:RP:rvctc3.02.11:Capital.Gains.Total.Amount
            [CGTS123] = CGTS:RP.Applied:rvctc3.02.11:Capital.Losses.Total.Amount
            [CGTS126] = CGTS:RP.Applied:gfagc.02.06:TaxConcession.CapitalGains.DiscountTotal.Amount
           
        */
        private void VRATOCGTS402174(List<ProcessMessageDocument> response)
        {
            bool assertion = ChildDocument.CGTS126.GetValueOrDefault() >
                             (ChildDocument.CGTS118.GetValueOrDefault() - ChildDocument.CGTS123.GetValueOrDefault()) * 0.50M + 1;
            if (assertion)
            {
                var processMessage = new ProcessMessageDocument
                {
                    Code = "CMN.ATO.CGTS.402174",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"The CGT discount rate applied to capital gains by a trust or company must not be greater than 50%",
                    Location = "/xbrli:xbrl/tns:TaxConcession.CapitalGains.DiscountTotal.Amount",
                    Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.CGTS.402174" } }
                };

                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CGTS126", Value = ChildDocument.CGTS126.GetValueOrDefault().ToString() });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CGTS118", Value = ChildDocument.CGTS118.GetValueOrDefault().ToString() });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CGTS123", Value = ChildDocument.CGTS123.GetValueOrDefault().ToString() });

                response.Add(processMessage);
            }
        }
        #endregion // VR.ATO.CGTS.402174

        #region VR.ATO.CGTS.402203
        /* VR.ATO.CGTS.402203

             IF ([CTR53] <> "1") AND ([CGTS131] >0) AND ([CGTS125] > 0) 
               RETURN VALIDATION MESSAGE 
            ENDIF

            [CGTS125] = CGTS:RP.CGTOther.Unapplied:rvctc3.02.16:Capital.Losses.CarriedForward.Net.Amount
            [CGTS131] = CGTS:RP:bafpr1.02.00:Income.CapitalGainsNet.Amount
            [CTR53] = CTR:RP:pyde.02.03:OrganisationDetails.TaxConsolidationStatus.Code
         */
        private void VRATOCGTS402203(List<ProcessMessageDocument> response)
        {
            bool assertion = ParentDocument.CTR53 != "1" && (ChildDocument.CGTS131.GetValueOrDefault() > 0) &&
                             ChildDocument.CGTS125.GetValueOrDefault() > 0;
            if (assertion)
            {
                var processMessage = new ProcessMessageDocument
                {
                    Code = "CMN.ATO.CGTS.402203",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"A capital loss must not be carried forward when a positive net capital gain amount has been provided",
                    Location = "/xbrli:xbrl/tns:Capital.Losses.CarriedForward.Net.Amount",
                    Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.CGTS.402203" } }
                };

                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CTR53", Value = ParentDocument.CTR53 });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CGTS131", Value = ChildDocument.CGTS131.GetValueOrDefault().ToString() });
                processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CGTS125", Value = ChildDocument.CGTS125.GetValueOrDefault().ToString() });

                response.Add(processMessage);
            }
        }
        #endregion // VR.ATO.CGTS.402203

        #region VR.ATO.CGTS.402241
        /* VR.ATO.CGTS.402241
         
          IF (PARENT RETURN:RP:pyin.xx.xx:Report.Amendment.Indicator  <> TRUE AND [CGTS162] <> NULL AND [CGTS161] <> TRUE)
             RETURN VALIDATION MESSAGE
          ENDIF
          [CGTS161] = CGTS:RP:rvctc3.02.36:CapitalGainsTax.DeferredRelief.Indicator
          [CGTS162] = CGTS:RP:rvctc3.02.36:CapitalGainsTax.DeferredRelief.Amount  
        */
        //private void VRATOCGTS402241(List<ProcessMessageDocument> response)
        //{
        //    bool assertion = !ParentDocument.CTR298.GetValueOrDefault() && ChildDocument.CGTS162.HasValue &&
        //                     !ChildDocument.CGTS161.GetValueOrDefault();
        //    if (assertion)
        //    {
        //        var processMessage = new ProcessMessageDocument
        //        {
        //            Code = "CMN.ATO.CGTS.402241",
        //            Severity = ProcessMessageSeverity.Error,
        //            Description = @"CGT Relief information required",
        //            LongDescription = @"If 'Capital gains amount deferred' is present, then 'Capital gains deferred due to CGT relief' must be 'True'.",
        //            Location = "/xbrli:xbrl/tns:CapitalGainsTax.DeferredRelief.Indicator",
        //            Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.CGTS.402241" } }
        //        };

        //        response.Add(processMessage);
        //    }
        //}
        #endregion // VR.ATO.CGTS.402241

        #region VR.ATO.CGTS.402243
        /* VR.ATO.CGTS.402243

        IF PARENT RETURN:RP:pyin.xx.xx:Report.Amendment.Indicator = TRUE AND [CGTS161] <> NULL 
           RETURN VALIDATION MESSAGE
        ENDIF

        [CGTS161] = CGTS:RP:rvctc3.02.36:CapitalGainsTax.DeferredRelief.Indicator

         */
        //private void VRATOCGTS402243(List<ProcessMessageDocument> response)
        //{
        //    bool assertion = ParentDocument.CTR298 == true && ChildDocument.CGTS161.HasValue;

        //    if (assertion)
        //    {
        //        var processMessage = new ProcessMessageDocument
        //        {
        //            Code = "CMN.ATO.CGTS.402243",
        //            Severity = ProcessMessageSeverity.Error,
        //            Description = @"CGT Relief indicator can not be amended.",
        //            Location = "/xbrli:xbrl/tns:CapitalGainsTax.DeferredRelief.Indicator",
        //            Parameters = new ProcessMessageParameters { new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.CGTS.402243" } }
        //        };

        //        processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CTR298", Value = ParentDocument.CTR298.ToString() });
        //        processMessage.Parameters.Add(new ProcessMessageParameter { Name = "CGTS161", Value = ChildDocument.CGTS161.GetValueOrDefault().ToString() });

        //        response.Add(processMessage);
        //    }
        //}
        #endregion // VR.ATO.CGTS.402243

        private static bool IsMatch(string field, string expression, RegexOptions options = RegexOptions.None)
            => field != null && Regex.IsMatch(field, expression, options);
    }
}