using System.Linq;
using System.Collections.Generic;
using VaTS;
using DataContracts;
using Ato.EN.IntegrationServices.CodeGenerationPSS;
using Ato.EN.IntegrationServices.CodeGenerationRS;
using Ato.EN.IntegrationServices.CodeGenerationIEE;
using Ato.EN.IntegrationServices.CodeGenerationIDS;
using Ato.EN.IntegrationServices.CodeGenerationPTR;
using Ato.EN.IntegrationServices.CodeGenerationDISTBENTRT;
using Ato.CD.Inbound.Shared;
using static Ato.CD.Inbound.Shared.ValidatorHelpers;

namespace Ato.CD.Inbound.PTR202502
{
    public class CrossFormValidator
    {
        private PTR2025 ParentDocument { get; }
        private BusinessDocumentCollection ChildDocuments { get; }
        private IEnumerable<PSS2018> PSSChildDocuments { get; }
        private IEnumerable<RS2018> RSChildDocuments { get; }
        private IEnumerable<IEE2021> IEEChildDocuments { get; }
        private IEnumerable<IDS2025> IDSChildDocuments { get; }
        private IEnumerable<DISTBENTRT2024> DISTBENTRTChildDocuments { get; }

        /// <summary>
        /// The response parameter
        /// </summary>
        public List<ProcessMessageDocument> Response { get; private set; }

        public CrossFormValidator(PTR2025 report, BusinessDocumentCollection childDocuments)
        {
            Response = new List<ProcessMessageDocument>();
            ParentDocument = report;
            ChildDocuments = childDocuments ?? new BusinessDocumentCollection();

            PSSChildDocuments = ChildDocuments
                    .Where(s => s.DocumentName.Equals(Schedule.PSS.ToString()))
                    .Select(p => (PSS2018)p.ConsumedReport);

            RSChildDocuments = ChildDocuments
                    .Where(s => s.DocumentName.Equals(Schedule.RS.ToString()))
                    .Select(p => (RS2018)p.ConsumedReport);

            IEEChildDocuments = ChildDocuments
                    .Where(s => s.DocumentName.Equals(Schedule.IEE.ToString()))
                    .Select(p => (IEE2021)p.ConsumedReport);

            IDSChildDocuments = ChildDocuments
                        .Where(s => s.DocumentName.Equals(Schedule.IDS.ToString()))
                        .Select(p => (IDS2025)p.ConsumedReport);

            DISTBENTRTChildDocuments = ChildDocuments
                      .Where(s => s.DocumentName.Equals(Schedule.DISTBENTRT.ToString()))
                      .Select(p => (DISTBENTRT2024)p.ConsumedReport);
        }

        public List<ProcessMessageDocument> ValidateCrossFormRules()
        {
            // DISTBENTRT CrossForm Validation
            VRATOPTR440038();

            // IDS CrossForm Validation
            VRATOPTR440374();
            VRATOPTR431000();
            VRATOPTR440375();
            VRATOPTR440376();
            VRATOPTR431014();
            VRATOPTR431015();

            // IEE CrossForm Validation
            VRATOPTR430180();

            // PSS CrossForm Validation
            VRATOPTR430019();
            VRATOPTR430183();

            // RS CrossForm Validation
            VRATOPTR430081();
            VRATOPTR430082();
            VRATOPTR430083();
            VRATOPTR430084();
            VRATOPTR430086();
            VRATOPTR430088();
            VRATOPTR430090();

            return Response;
        }

        #region DISTBENTRT CrossForm Validation Rules

        #region VR.ATO.PTR.440038

        /*  
            VR.ATO.PTR.440038
            Distributions to Beneficiaries of Trust schedule must be present when Trust distributions - Income amounts or credits are provided.

            Legacy Rule Format:
            CountDocument('DISTBENTRT') = 0 AND (^PTR66 > 0 OR ^PTR70 > 0 OR ^PTR322 > 0)

            Technical Business Rule Format:
            CountDocument('DISTBENTRT') = 0 AND (^PTR66 > 0 OR ^PTR70 > 0 OR ^PTR322 > 0)

            Data Elements:
    
            ^PTR66 = PTR:RP:Income:PartnershipsTrustsPrimaryProduction:Income.TrustShareNet.Amount
    
            ^PTR70 = PTR:RP:Income:PartnershipTrustNonPrimaryProduction:Income.TrustShareNetExcludeNetCapitalGainsAndForeignIncomeAndDistributionFranked.Amount
    
            ^PTR322 = PTR:RP:Income:PartnershipTrustNonPrimaryProduction:Income.TrustDistributionFranked.Amount
        */
        public void VRATOPTR440038()
        {

            bool assertion = (ParentDocument.PTR66.GetValueOrDefault() > 0 || ParentDocument.PTR70.GetValueOrDefault() > 0 || ParentDocument.PTR322.GetValueOrDefault() > 0)
                  && (DISTBENTRTChildDocuments.Count() == 0);

            if (assertion)
            {
                Response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.PTR.440038",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Distributions to Beneficiaries of Trust schedule must be present",
                    LongDescription = @"Distributions to Beneficiaries of Trust schedule must be present when Trust distributions - Income amounts or credits are provided",
                    Location = "/tns:PTR/tns:RP/tns:Income/tns:PartnershipsTrustsPrimaryProduction/tns:TrustShareNetA",

                    Parameters = new ProcessMessageParameters
                    {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.PTR.440038" },
                        new ProcessMessageParameter { Name = "PTR66", Value = GetValueOrEmpty(ParentDocument.PTR66) },
                        new ProcessMessageParameter { Name = "PTR70", Value = GetValueOrEmpty(ParentDocument.PTR70) },
                        new ProcessMessageParameter { Name = "PTR322", Value = GetValueOrEmpty(ParentDocument.PTR322) }
                    }
                });

            }
        }
        #endregion // VR.ATO.PTR.440038

        #endregion DISTBENTRT CrossForm Validation Rules

        #region IDS CrossForm Validation Rules

        #region VR.ATO.PTR.440374
        /*
            VR.ATO.PTR.440374

            If the response to the question to whether the entity had either a direct or indirect interest in a foreign trust, controlled foreign company or 
            transferor trust (Attributed foreign income) is 'Yes, an International Dealings Schedule must be attached


            Technical Business Rule Format:
            ^PTR102 = TRUE AND CountDocument('IDS') = 0

            Data Elements:
            ^PTR102 = PTR:RP:AttributedForeignIncome:InternationalDealingsTrustorControlledCompanyorTransferorTrustI
        */

        public void VRATOPTR440374()
        {
            bool assertion = ParentDocument.PTR102.GetValueOrDefault() && IDSChildDocuments.Count() == 0;

            if (assertion)
            {
                Response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.GEN.438002",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"International Dealings Schedule is not attached",
                    LongDescription = @"The answer to the question 'Did the entity have either a direct or indirect interest in a foreign trust, controlled foreign company or transferor trust?' is 'Yes', and no International Dealings Schedule is attached.",
                    Location = "/tns:PTR/tns:RP/tns:Income/tns:BusinessIncomeAndExpenses/tns:IncomePrimaryProduction/tns:RemunerationABNNotQuotedPaymentGrossA",
                    Parameters = new ProcessMessageParameters
                        {
                            new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.PTR.440374" },
                            new ProcessMessageParameter { Name = "PTR102", Value = ParentDocument.PTR102.GetValueOrDefault().ToString() },
                        }
                });
            }
        }

        #endregion VR.ATO.PTR.440374

        #region VR.ATO.PTR.431000

        /*
            VR.ATO.PTR.431000

            Attributed foreign income - Listed country or Attributed foreign income - Unlisted country has been completed and the number of controlled foreign companies 
            or trusts on the IDS, has not been shown. Show zero at Number of CFCs and CFTs - Listed countries, Number of CFCs and CFTs - Specified countries, Number of CFC 
            and CFTs - Other unlisted countries on the IDS if at the end of your income year you no longer held an interest in CFCs or CFTs.
    
            Technical Business Rule Format:
            (^PTR98 > 0 OR ^PTR100 > 0) AND (CountDocument('IDS') = 0 OR (^IDS185 = NULL AND ^IDS186 = NULL AND ^IDS187 = NULL))

            Data Elements:
            ^PTR98  = PTR:RP:AttributedForeignIncome:ListedCountryInternationalDealingsA
            ^PTR100 = PTR:RP:AttributedForeignIncome:UnlistedCountryInternationalDealingsA
            ^IDS185
            ^IDS186
            ^IDS187
        */
        public void VRATOPTR431000()
        {   
            int idsCount = IDSChildDocuments == null ? 0 : IDSChildDocuments.Count(ids => !ids.IDS185.HasValue && !ids.IDS186.HasValue && !ids.IDS187.HasValue);

            bool assertion = (ParentDocument.PTR98.GetValueOrDefault() > 0 || ParentDocument.PTR100.GetValueOrDefault() > 0) &&
                   (IDSChildDocuments == null ? true : IDSChildDocuments.Count() == 0 || idsCount > 0);

            if (assertion)
            {
                Response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.PTR.434000",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Number of controlled foreign companies or trusts required",
                    LongDescription = @"Attributed foreign income - Listed country or Attributed foreign income - Unlisted country has been completed and the number of controlled foreign companies or trusts on the IDS has not been shown. Show zero on the IDS if at the end of your income year you no longer held an interest in CFCs or CFTs.",
                    Location = "/tns:PTR/tns:RP/tns:AttributedForeignIncome/tns:ListedCountryInternationalDealingsA",
                    Parameters = new ProcessMessageParameters
                        {
                            new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.PTR.431000" },
                            new ProcessMessageParameter { Name = "PTR98", Value = ParentDocument.PTR98.HasValue ? ParentDocument. PTR98.GetValueOrDefault().ToString() : "null" },
                            new ProcessMessageParameter { Name = "PTR100", Value = ParentDocument.PTR100.HasValue ? ParentDocument.PTR100.GetValueOrDefault().ToString() : "null" },
                            new ProcessMessageParameter { Name = "IDS185", Value = "null" },
                            new ProcessMessageParameter { Name = "IDS186", Value = "null" },
                            new ProcessMessageParameter { Name = "IDS187", Value = "null" },
                        }
                });
            }
        }

        #endregion VR.ATO.PTR.431000

        #region VR.ATO.PTR.440375

        /*  
            VR.ATO.PTR.440375
            International Dealings Schedule is not attached

            Legacy Rule Format:
            ^PTR108 = TRUE AND CountDocument('IDS') = 0

            Technical Business Rule Format:
            ^PTR108 = TRUE AND CountDocument('IDS') = 0

            Data Elements:    
            
            ^PTR108 = PTR:RP:OverseasTransactions:InternationalDealings.RelatedPartiesTransactionsExcessAggregateValue.Indicator

        */
        public void VRATOPTR440375()
        {

            bool assertion = ParentDocument.PTR108.GetValueOrDefault() && IDSChildDocuments.Count() == 0;

            if (assertion)
            {
                Response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.GEN.438003",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"International Dealings Schedule is not attached",
                    LongDescription = @"The answer to the question 'Was the aggregate amount of your transactions or dealings with international related parties (including the value of any property or service transferred or the balance of any loans) greater than $2 million?'(Overseas transactions) is 'Yes' , and no International Dealings Schedule is attached.",
                    Location = "/tns:PTR/tns:RP/tns:OverseasTransactions/tns:InternationalDealingsRelatedPartiesTransactionsExcessAggregateValueI",

                    Parameters = new ProcessMessageParameters
                    {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.PTR.440375" },
                        new ProcessMessageParameter { Name = "PTR108", Value = ParentDocument.PTR108.GetValueOrDefault().ToString()}
                    }
                });

            }
        }
        #endregion VR.ATO.PTR.440375     

        #region VR.ATO.PTR.440376

        /*  
            VR.ATO.PTR.440376
            International Dealings Schedule not attached

            Legacy Rule Format:
            ^PTR277 = TRUE AND CountDocument('IDS') = 0

            Technical Business Rule Format:
            ^PTR277 = TRUE AND CountDocument('IDS') = 0

            Data Elements:    
            
            ^PTR277 = PTR:RP:OverseasTransactions:Liabilities.ThinCapitalisation.ProvisionsApplied.Indicator

        */
        public void VRATOPTR440376()
        {

            bool assertion = ParentDocument.PTR277.GetValueOrDefault() && IDSChildDocuments.Count() == 0;

            if (assertion)
            {
                Response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.PTR.440376",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"International Dealings Schedule not attached",
                    LongDescription = @"If the thin capitalisation or debt deduction creation rules apply then International Dealings Schedule must be attached",
                    Location = "/tns:PTR/tns:RP/tns:OverseasTransactions/tns:LiabilitiesThinCapitalisationProvisionsAppliedI",

                    Parameters = new ProcessMessageParameters
                    {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.PTR.440376" },
                        new ProcessMessageParameter { Name = "PTR277", Value = ParentDocument.PTR277.GetValueOrDefault().ToString()}
                    }
                });

            }
        }
        #endregion VR.ATO.PTR.440376     

        #region VR.ATO.PTR.431014

        /*  
            VR.ATO.PTR.431014
            International Dealings Schedule not attached

            Legacy Rule Format:
            ^PTR137 > 0 AND CountDocument('IDS') = 0

            Technical Business Rule Format:
            ^PTR137 > 0 AND CountDocument('IDS') = 0

            Data Elements:    
            
            ^PTR137 = PTR:RP:OverseasTransactions:Expense.Interest.Amount

        */
        public void VRATOPTR431014()
        {

            bool assertion = ParentDocument.PTR137.GetValueOrDefault() > 0 && IDSChildDocuments.Count() == 0;

            if (assertion)
            {
                Response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.PTR.431014",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"International Dealings Schedule not attached",
                    LongDescription = @"An ‘International dealings schedule’ (IDS) is not attached when a value greater than zero is present at label Interest expenses overseas",
                    Location = "/tns:PTR/tns:RP/tns:OverseasTransactions/tns:ExpenseInterestA",

                    Parameters = new ProcessMessageParameters
                    {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.PTR.431014" },
                        new ProcessMessageParameter { Name = "PTR137", Value = ParentDocument.PTR137.GetValueOrDefault().ToString()}
                    }
                });

            }
        }
        #endregion VR.ATO.PTR.431014     

        #region VR.ATO.PTR.431015

        /*  
            VR.ATO.PTR.431015
            International Dealings Schedule not attached

            Legacy Rule Format:
            ^PTR138 > 0 AND CountDocument('IDS') = 0

            Technical Business Rule Format:
            ^PTR138 > 0 AND CountDocument('IDS') = 0

            Data Elements:    
            
            ^PTR138 = PTR:RP:OverseasTransactions:Expense.Royalties.Amount

        */
        public void VRATOPTR431015()
        {

            bool assertion = ParentDocument.PTR138.GetValueOrDefault() > 0 && IDSChildDocuments.Count() == 0;

            if (assertion)
            {
                Response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.PTR.431015",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"International Dealings Schedule not attached",
                    LongDescription = @"An ‘International dealings schedule’ (IDS) is not attached when a value greater than zero is present at label Royalty expenses overseas",
                    Location = "/tns:PTR/tns:RP/tns:OverseasTransactions/tns:ExpenseRoyaltiesA",

                    Parameters = new ProcessMessageParameters
                    {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.PTR.431015" },
                        new ProcessMessageParameter { Name = "PTR138", Value = ParentDocument.PTR138.GetValueOrDefault().ToString()}
                    }
                });

            }
        }
        #endregion VR.ATO.PTR.431015     

        #endregion IDS CrossForm Validation Rules

        #region IEE CrossForm Validation Rules

        #region VR.ATO.PTR.430180

        /*  
            VR.ATO.PTR.430180
            If the Interposed Entity Election revocation code is present, an IEE schedule must be present

            Legacy Rule Format:
            ^PTR27 = 'R' AND CountDocument('IEE') = 0

            Technical Business Rule Format:
            ^PTR27 = 'R' AND CountDocument('IEE') = 0

            Data Elements:    
            
            ^PTR27 = PTR:RP:Elections.InterposedEntityElectionRevocation.Code

        */
        public void VRATOPTR430180()
        {

            bool assertion = !string.IsNullOrWhiteSpace(ParentDocument.PTR27) && ParentDocument.PTR27.ToUpper() == "R" && IEEChildDocuments.Count() == 0;

            if (assertion)
            {
                Response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.GEN.430180",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"If the Interposed Entity Election revocation code is present, an IEE schedule must be present",
                    Location = "/tns:PTR/tns:RP/tns:ElectionsInterposedEntityElectionRevocationC",

                    Parameters = new ProcessMessageParameters
                    {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.PTR.430180" },
                        new ProcessMessageParameter { Name = "PTR27", Value = ParentDocument.PTR27}
                    }
                });

            }
        }
        #endregion // VR.ATO.PTR.430180     

        #endregion IEE CrossForm Validation Rules

        #region PSS CrossForm Validation Rules

        #region VR.ATO.PTR.430019
        /*
            VR.ATO.PTR.430019

            Payment Summary schedule must be present if Gross payments where ABN not quoted is present

            Technical Business Rule Format:
            (^PTR35 + ^PTR36) > 0 AND CountDocument('PSS') = 0            

            Data Elements:

            ^PTR35 = PTR:RP:Income:BusinessIncomeAndExpenses:IncomePrimaryProduction:RemunerationABNNotQuotedPaymentGrossA

            ^PTR36 = PTR:RP:Income:BusinessIncomeAndExpenses:IncomeNonPrimaryProduction:RemunerationABNNotQuotedPaymentGrossA
        */

        public void VRATOPTR430019()
        {
            bool assertion = (ParentDocument.PTR35.GetValueOrDefault() + ParentDocument.PTR36.GetValueOrDefault()) > 0
                && PSSChildDocuments.Count() == 0;

            if (assertion)
            {
                Response.Add(new ProcessMessageDocument
                {
                    Code = "CMN.ATO.GEN.430019",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Payment Summary schedule must be present if Gross payments where ABN not quoted is present",
                    Location = "/tns:PTR/tns:RP/tns:Income/tns:BusinessIncomeAndExpenses/tns:IncomePrimaryProduction/tns:RemunerationABNNotQuotedPaymentGrossA",

                    Parameters = new ProcessMessageParameters
                        {
                            new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.PTR.430019" },
                            new ProcessMessageParameter { Name = "PTR35", Value = ParentDocument.PTR35.HasValue ? ParentDocument.PTR35.GetValueOrDefault().ToString() : "null" },
                            new ProcessMessageParameter { Name = "PTR36", Value = ParentDocument.PTR36.HasValue ? ParentDocument.PTR36.GetValueOrDefault().ToString() : "null" },
                        }
                });
            }
        }

        #endregion VR.ATO.PTR.430019

        #region VR.ATO.PTR.430183
        /*
            VR.ATO.PTR.430183

            Payment Summary schedule must include Tax withheld where ABN not quoted amount

            Technical Business Rule Format:
            ^PTR63 > 0 AND (CountDocument('PSS') = 0 OR ^PTR63 <> Sum(^PSS23))

            Data Elements:

            ^PTR38 = /tns:PTR/tns:RP/tns:Income/tns:BusinessIncomeAndExpenses/tns:PayAsYouGoWithholding/tns:TaxCreditForTaxWithheldWhereABNNotQuotedA

            ^PSS23 = /xbrli:xbrl/RP.Payer.{PSSeqNum}:tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldBusinessABNNotQuoted.Amount
        */

        public void VRATOPTR430183()
        {
            var sumPSS23 = PSSChildDocuments
                            .Where(rp => rp.RPPayerPSSeqNumContextCollection != null)
                            .SelectMany(rp => rp.RPPayerPSSeqNumContextCollection
                            .Select(p => p.PSS23.GetValueOrDefault())).Sum();

            bool assertion = ParentDocument.PTR63.HasValue &&
                ParentDocument.PTR63 > 0 &&
                (PSSChildDocuments.Count() == 0 ||
                ParentDocument.PTR63 != sumPSS23);

            if (assertion)
            {
                Response.Add(new ProcessMessageDocument()
                {
                    Code = "CMN.ATO.GEN.430183",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Payment Summary schedule must include Tax withheld where ABN not quoted amount",
                    LongDescription = @"If an amount greater than zero has been entered at Tax withheld from payments where ABN no quoted, then a Payment Summary schedule must be present and it must include the same total amount of Tax withheld from payments where ABN no quoted",
                    Location = "/tns:PTR/tns:RP/tns:Income/tns:BusinessIncomeAndExpenses/tns:PayAsYouGoWithholding/tns:TaxCreditForTaxWithheldWhereABNNotQuotedA",
                    Parameters = new ProcessMessageParameters
                    {
                        new ProcessMessageParameter { Name = "RuleIdentifier", Value = "VR.ATO.GEN.430183" },
                        new ProcessMessageParameter { Name = "PTR63", Value = ParentDocument.PTR63.HasValue ? ParentDocument.PTR63.GetValueOrDefault().ToString() : "null" },
                        new ProcessMessageParameter { Name = "Sum(PSS23)", Value = GetValueOrEmpty(sumPSS23)},
                    }
                });

            }
        }

        #endregion VR.ATO.PTR.430183

        #endregion PSS CrossForm Validation Rules

        #region RS CrossForm Validation Rules

        #region VR.ATO.PTR.430081

        /*
            VR.ATO.PTR.430081
            Rental schedule must be present

            Legacy Rule Format:
            (^PTR77 <> NULL OR ^PTR78 > 0 OR ^PTR79 > 0 OR ^PTR80 > 0) AND CountDocument('RS') = 0

            Technical Business Rule Format:
            (^PTR77 <> NULL OR ^PTR78 > 0 OR ^PTR79 > 0 OR ^PTR80 > 0) AND CountDocument('RS') = 0

            Data Elements:

            ^PTR77 = PTR:RP:Income:Rent:Income.Operating.RentalIncomeGross.Amount

            ^PTR78 = PTR:RP:Income:Rent:Expense.Interest.Amount

            ^PTR79 = PTR:RP:Income:Rent:Expense.CapitalWorksDeduction.Amount

            ^PTR80 = PTR:RP:Income:Rent:IncomeTax.Deduction.RentalIncomeDeductionsOtherThanInterestAndCapitalWorks.Amount
        */
        public void VRATOPTR430081()
        {
            bool assertion =
                (
                    ParentDocument.PTR77 != null ||
                    ParentDocument.PTR78.GetValueOrDefault() > 0 ||
                    ParentDocument.PTR79.GetValueOrDefault() > 0 ||
                    ParentDocument.PTR80.GetValueOrDefault() > 0
                )
                &&
                (
                    RSChildDocuments.Count() == 0
                );

            if (assertion)
            {
                Response.Add(new ProcessMessageDocument()
                {
                    Code = "CMN.ATO.GEN.430081",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Rental schedule must be present",
                    LongDescription = @"If there is a positive amount at Gross rent or at any Rental deductions item, then a Rental property schedule must be submitted for each rental property",
                    Location = "/tns:PTR/tns:RP/tns:Income/tns:Rent/tns:OperatingIncomeGrossA",
                    Parameters = new ProcessMessageParameters()
                    {
                        new ProcessMessageParameter() { Name = "RuleIdentifier", Value = "VR.ATO.PTR.430081" },
                        new ProcessMessageParameter() { Name = "PTR77", Value = GetValueOrEmpty(ParentDocument.PTR77) },
                        new ProcessMessageParameter() { Name = "PTR78", Value = GetValueOrEmpty(ParentDocument.PTR78) },
                        new ProcessMessageParameter() { Name = "PTR79", Value = GetValueOrEmpty(ParentDocument.PTR79) },
                        new ProcessMessageParameter() { Name = "PTR80", Value = GetValueOrEmpty(ParentDocument.PTR80) }
                    },
                });
            }
        }
        #endregion // VR.ATO.PTR.430081

        #region VR.ATO.PTR.430082

        /*
            VR.ATO.PTR.430082
            Gross rent and Rental deduction amounts must be present

            Legacy Rule Format:
            CountDocument('RS') > 0 AND ^PTR77 = NULL AND (^PTR78 = 0 OR ^PTR78 = NULL) AND (^PTR79 = 0 OR ^PTR79 = NULL) AND (^PTR80 = 0 OR ^PTR80 = NULL)

            Technical Business Rule Format:
            CountDocument('RS') > 0 AND ^PTR77 = NULL AND (^PTR78 = 0 OR ^PTR78 = NULL) AND (^PTR79 = 0 OR ^PTR79 = NULL) AND (^PTR80 = 0 OR ^PTR80 = NULL)

            Data Elements:

            ^PTR77 = PTR:RP:Income:Rent:Income.Operating.RentalIncomeGross.Amount

            ^PTR78 = PTR:RP:Income:Rent:Expense.Interest.Amount

            ^PTR79 = PTR:RP:Income:Rent:Expense.CapitalWorksDeduction.Amount

            ^PTR80 = PTR:RP:Income:Rent:IncomeTax.Deduction.RentalIncomeDeductionsOtherThanInterestAndCapitalWorks.Amount
        */
        public void VRATOPTR430082()
        {
            bool assertion =
                RSChildDocuments.Count() > 0 &&
                ParentDocument.PTR77 == null &&
                (ParentDocument.PTR78 == 0 || ParentDocument.PTR78 == null) &&
                (ParentDocument.PTR79 == 0 || ParentDocument.PTR79 == null) &&
                (ParentDocument.PTR80 == 0 || ParentDocument.PTR80 == null);

            if (assertion)
            {
                Response.Add(new ProcessMessageDocument()
                {
                    Code = "CMN.ATO.GEN.430082",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Gross rent and Rental deduction amounts must be present",
                    LongDescription = @"If a Rental property schedule is present, Gross rent or rental deductions must be present",
                    Location = "/tns:PTR/tns:RP/tns:Income/tns:Rent/tns:OperatingIncomeGrossA",
                    Parameters = new ProcessMessageParameters()
                    {
                        new ProcessMessageParameter() { Name = "RuleIdentifier", Value = "VR.ATO.PTR.430082" },
                        new ProcessMessageParameter() { Name = "PTR77", Value = "NULL" },
                        new ProcessMessageParameter() { Name = "PTR78", Value = GetValueOrEmpty(ParentDocument.PTR78) },
                        new ProcessMessageParameter() { Name = "PTR79", Value = GetValueOrEmpty(ParentDocument.PTR79) },
                        new ProcessMessageParameter() { Name = "PTR80", Value = GetValueOrEmpty(ParentDocument.PTR80) }
                    },
                });
            }
        }
        #endregion // VR.ATO.PTR.430082

        #region VR.ATO.PTR.430083

        /*  
            VR.ATO.PTR.430083
            Gross rent must equal the total Gross rent in the Rental Schedules

            Legacy Rule Format:
            CountDocument('RS') > 0 AND ^PTR77 <> (Sum(^RS38) + Sum(^RS39))

            Technical Business Rule Format:
            CountDocument('RS') > 0 AND ^PTR77 <> (Sum(^RS38) + Sum(^RS39))

            Data Elements:
    
            ^PTR77 = PTR:RP:Income:Rent:Income.Operating.RentalIncomeGross.Amount
    
            ^RS38 = RS:RP:bafpr2.02.04:Income.RealEstateProperty.Rental.Amount

            ^RS39 = RS:RP:bafpr2.02.04:Income.RealEstateProperty.RentalRelatedOther.Amount
        */
        public void VRATOPTR430083()
        {
            decimal? PTR77 = ParentDocument.PTR77.GetValueOrDefault();
            decimal? sumRS38 = RSChildDocuments.Sum(rentalSchedule => rentalSchedule.RS38.GetValueOrDefault());
            decimal? sumRS39 = RSChildDocuments.Sum(rentalSchedule => rentalSchedule.RS39.GetValueOrDefault());

            bool assertion = (RSChildDocuments.Count() > 0) && (PTR77 != sumRS38 + sumRS39);
            if (assertion)
            {
                Response.Add(new ProcessMessageDocument()
                {
                    Code = "CMN.ATO.GEN.430083",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Gross rent must equal the total Gross rent in the Rental Schedules",
                    LongDescription = @"The Gross rent amount in the main form must equal the total Gross rent present in all Rental property schedules",
                    Location = "/tns:PTR/tns:RP/tns:Income/tns:Rent/tns:OperatingIncomeGrossA",
                    Parameters = new ProcessMessageParameters()
                    {
                        new ProcessMessageParameter() { Name = "RuleIdentifier", Value = "VR.ATO.PTR.430083" },
                        new ProcessMessageParameter() { Name = "PTR77", Value = GetValueOrEmpty(ParentDocument.PTR77) },
                        new ProcessMessageParameter() { Name = "Sum(RS38)", Value = GetValueOrEmpty(sumRS38) },
                        new ProcessMessageParameter() { Name = "Sum(RS39)", Value = GetValueOrEmpty(sumRS39) }
                    },
                });
            }
        }
        #endregion // VR.ATO.PTR.430083

        #region VR.ATO.PTR.430084

        /*  
            VR.ATO.PTR.430084
            Net rent must equal the total net rent in the Rental Schedules

            Legacy Rule Format:
            CountDocument('RS') > 0 AND (^PTR77 - ^PTR78 - ^PTR79 - ^PTR80) <> Sum(^RS59)

            Technical Business Rule Format:
            CountDocument('RS') > 0 AND (^PTR77 - ^PTR78 - ^PTR79 - ^PTR80) <> Sum(^RS59)

            Data Elements:
    
            ^PTR77 = PTR:RP:Income:Rent:Income.Operating.RentalIncomeGross.Amount
    
            ^PTR78 = PTR:RP:Income:Rent:Expense.Interest.Amount
    
            ^PTR79 = PTR:RP:Income:Rent:Expense.CapitalWorksDeduction.Amount
    
            ^PTR80 = PTR:RP:Income:Rent:IncomeTax.Deduction.RentalIncomeDeductionsOtherThanInterestAndCapitalWorks.Amount
    
            ^RS59 = RS:RP:bafpr2.02.04:Income.RealEstateProperty.RentalNet.Amount
        */
        public void VRATOPTR430084()
        {
            decimal? PTR77 = ParentDocument.PTR77.GetValueOrDefault();
            decimal? PTR78 = ParentDocument.PTR78.GetValueOrDefault();
            decimal? PTR79 = ParentDocument.PTR79.GetValueOrDefault();
            decimal? PTR80 = ParentDocument.PTR80.GetValueOrDefault();
            decimal? sumRS59 = RSChildDocuments.Sum(rentalSchedule => rentalSchedule.RS59.GetValueOrDefault());

            bool assertion = (RSChildDocuments.Count() > 0) && (PTR77 - PTR78 - PTR79 - PTR80) != sumRS59;
            if (assertion)
            {
                Response.Add(new ProcessMessageDocument()
                {
                    Code = "CMN.ATO.GEN.430084",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Net rent must equal the total net rent in the Rental Schedules",
                    LongDescription = @"The net rent amount in the main form (Gross rent minus rental deduction amounts) must equal the total Net rent present in all Rental property schedules",
                    Location = "/tns:PTR/tns:RP/tns:Income/tns:Rent/tns:OperatingIncomeGrossA",
                    Parameters = new ProcessMessageParameters()
                    {
                        new ProcessMessageParameter() { Name = "RuleIdentifier", Value = "VR.ATO.PTR.430084" },
                        new ProcessMessageParameter() { Name = "PTR77", Value = GetValueOrEmpty(ParentDocument.PTR77) },
                        new ProcessMessageParameter() { Name = "PTR78", Value = GetValueOrEmpty(ParentDocument.PTR78) },
                        new ProcessMessageParameter() { Name = "PTR79", Value = GetValueOrEmpty(ParentDocument.PTR79) },
                        new ProcessMessageParameter() { Name = "PTR80", Value = GetValueOrEmpty(ParentDocument.PTR80) },
                        new ProcessMessageParameter() { Name = "Sum(RS59)", Value = GetValueOrEmpty(sumRS59) }
                    },
                });
            }
        }
        #endregion // VR.ATO.PTR.430084

        #region VR.ATO.PTR.430086

        /*  
            VR.ATO.PTR.430086
            Rental Interest deductions must equal the total Interest deductions in the Rental Schedules

            Legacy Rule Format:
            CountDocument('RS') > 0 AND ^PTR78 <> Sum(^RS48)

            Technical Business Rule Format:
            CountDocument('RS') > 0 AND ^PTR78 <> Sum(^RS48)

            Data Elements:
    
            ^PTR78 = PTR:RP:Income:Rent:Expense.Interest.Amount
    
            ^RS48 = RS:RP:bafpr2.02.04:Expense.RealEstateProperty.LoanInterest.Amount
        */
        public void VRATOPTR430086()
        {
            decimal? PTR78 = ParentDocument.PTR78.GetValueOrDefault();
            decimal? sumRS48 = RSChildDocuments.Sum(rentalSchedule => rentalSchedule.RS48.GetValueOrDefault());

            bool assertion = (RSChildDocuments.Count() > 0) && PTR78 != sumRS48;
            if (assertion)
            {
                Response.Add(new ProcessMessageDocument()
                {
                    Code = "CMN.ATO.GEN.430086",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Rental Interest deductions must equal the total Interest deductions in the Rental Schedules",
                    LongDescription = @"The Interest deductions amount in the main form must equal the total of all Interest deductions in the Rental property schedules",
                    Location = "/tns:PTR/tns:RP/tns:Income/tns:Rent/tns:ExpenseInterestA",
                    Parameters = new ProcessMessageParameters()
                    {
                        new ProcessMessageParameter() { Name = "RuleIdentifier", Value = "VR.ATO.PTR.430086" },
                        new ProcessMessageParameter() { Name = "PTR78", Value = GetValueOrEmpty(ParentDocument.PTR78) },
                        new ProcessMessageParameter() { Name = "Sum(RS48)", Value =  GetValueOrEmpty(sumRS48) }
                    },
                });
            }
        }
        #endregion // VR.ATO.PTR.430086

        #region VR.ATO.PTR.430088

        /*  
            VR.ATO.PTR.430088
            Capital works deductions must equal the total Capital works deductions in the Rental Schedules

            Legacy Rule Format:
            CountDocument('RS') > 0 AND ^PTR79 <> Sum(^RS54)

            Technical Business Rule Format:
            CountDocument('RS') > 0 AND ^PTR79 <> Sum(^RS54)

            Data Elements:
    
            ^PTR79 = PTR:RP:Income:Rent:Expense.CapitalWorksDeduction.Amount
    
            ^RS54 = RS:RP:bafpr2.02.04:Expense.RealEstateProperty.CapitalWorksDeduction.Amount
        */
        public void VRATOPTR430088()
        {
            decimal? PTR79 = ParentDocument.PTR79.GetValueOrDefault();
            decimal? sumRS54 = RSChildDocuments.Sum(rentalSchedule => rentalSchedule.RS54.GetValueOrDefault());

            bool assertion = (RSChildDocuments.Count() > 0) && (sumRS54) != PTR79;
            if (assertion)
            {
                Response.Add(new ProcessMessageDocument()
                {
                    Code = "CMN.ATO.GEN.430088",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Capital works deductions must equal the total Capital works deductions in the Rental Schedules",
                    LongDescription = @"The Capital works deductions amount in the main form must equal the total of all Capital works deductions in the Rental property schedules",
                    Location = "/tns:PTR/tns:RP/tns:Income/tns:Rent/tns:ExpenseCapitalWorksDeductionA",
                    Parameters = new ProcessMessageParameters()
                    {
                        new ProcessMessageParameter() { Name = "RuleIdentifier", Value = "VR.ATO.PTR.430088" },
                        new ProcessMessageParameter() { Name = "PTR79", Value = GetValueOrEmpty(ParentDocument.PTR79) },
                        new ProcessMessageParameter() { Name = "Sum(RS54)", Value = GetValueOrEmpty(sumRS54) }
                    },
                });
            }
        }
        #endregion // VR.ATO.PTR.430088

        #region VR.ATO.PTR.430090

        /*  
            VR.ATO.PTR.430090
            Other rental deductions must equal the total other deductions in the Rental Schedules

            Legacy Rule Format:
            CountDocument('RS') > 0 AND ^PTR80 <> (Sum(^RS40) + Sum(^RS41) + Sum(^RS42) + Sum(^RS43) + Sum(^RS44) + Sum(^RS45) + Sum(^RS46) + Sum(^RS47) + Sum(^RS49) + Sum(^RS50) + Sum(^RS51) + Sum(^RS52) + Sum(^RS53) + Sum(^RS55) + Sum(^RS56) + Sum(^RS57) + Sum(^RS58))

            Technical Business Rule Format:
            CountDocument('RS') > 0 AND ^PTR80 <> (Sum(^RS40) + Sum(^RS41) + Sum(^RS42) + Sum(^RS43) + Sum(^RS44) + Sum(^RS45) + Sum(^RS46) + Sum(^RS47) + Sum(^RS49) + Sum(^RS50) + Sum(^RS51) + Sum(^RS52) + Sum(^RS53) + Sum(^RS55) + Sum(^RS56) + Sum(^RS57) + Sum(^RS58))

            Data Elements:
    
            ^PTR80 = PTR:RP:Income:Rent:IncomeTax.Deduction.RentalIncomeDeductionsOtherThanInterestAndCapitalWorks.Amount
            ^RS40 = RS:RP:bafpr2.02.04:Expense.RealEstateProperty.Marketing.Amount
            ^RS41 = RS:RP:bafpr2.02.04:Expense.RealEstateProperty.BodyCorporate.Amount
            ^RS42 = RS:RP:bafpr2.02.04:Expense.RealEstateProperty.Borrowing.Amount
            ^RS43 = RS:RP:bafpr2.02.04:Expense.RealEstateProperty.Cleaning.Amount
            ^RS44 = RS:RP:bafpr2.02.04:Expense.RealEstateProperty.CouncilRates.Amount
            ^RS45 = RS:RP:bafpr1.02.04:Expense.DepreciationandAmortisation.Amount
            ^RS46 = RS:RP:bafpr2.02.04:Expense.RealEstateProperty.Gardening.Amount
            ^RS47 = RS:RP:bafpr2.02.04:Expense.RealEstateProperty.Insurance.Amount
            ^RS49 = RS:RP:bafpr1.02.00:Expense.LandTax.Amount
            ^RS50 = RS:RP:bafpr2.02.04:Expense.RealEstateProperty.LegalFees.Amount
            ^RS51 = RS:RP:bafpr2.02.04:Expense.RealEstateProperty.PestControl.Amount
            ^RS52 = RS:RP:bafpr2.02.04:Expense.RealEstateProperty.AgentFeesCommission.Amount
            ^RS53 = RS:RP:bafpr2.02.04:Expense.RealEstateProperty.RepairsAndMaintenance.Amount
            ^RS55 = RS:RP:bafpr2.02.04:Expense.RealEstateProperty.OfficeSupplies.Amount
            ^RS56 = RS:RP:bafpr1.02.00:Expense.Travel.Amount
            ^RS57 = RS:RP:bafpr2.02.04:Expense.RealEstateProperty.Water.Amount
            ^RS58 = RS:RP:bafpr2.02.04:Expense.RealEstateProperty.Sundry.Amount
        */
        public void VRATOPTR430090()
        {
            decimal? PTR80 = ParentDocument.PTR80.GetValueOrDefault();
            decimal? sumRS40 = RSChildDocuments.Sum(rentalSchedule => rentalSchedule.RS40.GetValueOrDefault());
            decimal? sumRS41 = RSChildDocuments.Sum(rentalSchedule => rentalSchedule.RS41.GetValueOrDefault());
            decimal? sumRS42 = RSChildDocuments.Sum(rentalSchedule => rentalSchedule.RS42.GetValueOrDefault());
            decimal? sumRS43 = RSChildDocuments.Sum(rentalSchedule => rentalSchedule.RS43.GetValueOrDefault());
            decimal? sumRS44 = RSChildDocuments.Sum(rentalSchedule => rentalSchedule.RS44.GetValueOrDefault());
            decimal? sumRS45 = RSChildDocuments.Sum(rentalSchedule => rentalSchedule.RS45.GetValueOrDefault());
            decimal? sumRS46 = RSChildDocuments.Sum(rentalSchedule => rentalSchedule.RS46.GetValueOrDefault());
            decimal? sumRS47 = RSChildDocuments.Sum(rentalSchedule => rentalSchedule.RS47.GetValueOrDefault());
            decimal? sumRS49 = RSChildDocuments.Sum(rentalSchedule => rentalSchedule.RS49.GetValueOrDefault());
            decimal? sumRS50 = RSChildDocuments.Sum(rentalSchedule => rentalSchedule.RS50.GetValueOrDefault());
            decimal? sumRS51 = RSChildDocuments.Sum(rentalSchedule => rentalSchedule.RS51.GetValueOrDefault());
            decimal? sumRS52 = RSChildDocuments.Sum(rentalSchedule => rentalSchedule.RS52.GetValueOrDefault());
            decimal? sumRS53 = RSChildDocuments.Sum(rentalSchedule => rentalSchedule.RS53.GetValueOrDefault());
            decimal? sumRS55 = RSChildDocuments.Sum(rentalSchedule => rentalSchedule.RS55.GetValueOrDefault());
            decimal? sumRS56 = RSChildDocuments.Sum(rentalSchedule => rentalSchedule.RS56.GetValueOrDefault());
            decimal? sumRS57 = RSChildDocuments.Sum(rentalSchedule => rentalSchedule.RS57.GetValueOrDefault());
            decimal? sumRS58 = RSChildDocuments.Sum(rentalSchedule => rentalSchedule.RS58.GetValueOrDefault());

            bool assertion =
                (RSChildDocuments.Count() > 0)
                &&
                (PTR80 != sumRS40 + sumRS41 + sumRS42 + sumRS43 + sumRS44 + sumRS45 + sumRS46 + sumRS47 +
                sumRS49 + sumRS50 + sumRS51 + sumRS52 + sumRS53 + sumRS55 + sumRS56 + sumRS57 + sumRS58);
            if (assertion)
            {
                Response.Add(new ProcessMessageDocument()
                {
                    Code = "CMN.ATO.GEN.430090",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Other rental deductions must equal the total other deductions in the Rental Schedules",
                    LongDescription = @"The Other rental deductions amount in the main form must equal the total of all rental expenses in the Rental property, excluding Interest deductions and Capital works deductions",
                    Location = "/tns:PTR/tns:RP/tns:Income/tns:Rent/tns:TaxDeductionIncomeDeductionsOtherThanInterestAndCapitalWorksA",
                    Parameters = new ProcessMessageParameters()
                    {
                        new ProcessMessageParameter() { Name = "RuleIdentifier", Value = "VR.ATO.PTR.430090" },
                        new ProcessMessageParameter() { Name = "PTR80", Value = GetValueOrEmpty(ParentDocument.PTR80) },
                        new ProcessMessageParameter() { Name = "Sum(RS40)", Value = GetValueOrEmpty(sumRS40) },
                        new ProcessMessageParameter() { Name = "Sum(RS41)", Value = GetValueOrEmpty(sumRS41) },
                        new ProcessMessageParameter() { Name = "Sum(RS42)", Value = GetValueOrEmpty(sumRS42) },
                        new ProcessMessageParameter() { Name = "Sum(RS43)", Value = GetValueOrEmpty(sumRS43) },
                        new ProcessMessageParameter() { Name = "Sum(RS44)", Value = GetValueOrEmpty(sumRS44) },
                        new ProcessMessageParameter() { Name = "Sum(RS45)", Value = GetValueOrEmpty(sumRS45) },
                        new ProcessMessageParameter() { Name = "Sum(RS46)", Value = GetValueOrEmpty(sumRS46) },
                        new ProcessMessageParameter() { Name = "Sum(RS47)", Value = GetValueOrEmpty(sumRS47) },
                        new ProcessMessageParameter() { Name = "Sum(RS49)", Value = GetValueOrEmpty(sumRS49) },
                        new ProcessMessageParameter() { Name = "Sum(RS50)", Value = GetValueOrEmpty(sumRS50) },
                        new ProcessMessageParameter() { Name = "Sum(RS51)", Value = GetValueOrEmpty(sumRS51) },
                        new ProcessMessageParameter() { Name = "Sum(RS52)", Value = GetValueOrEmpty(sumRS52) },
                        new ProcessMessageParameter() { Name = "Sum(RS53)", Value = GetValueOrEmpty(sumRS53) },
                        new ProcessMessageParameter() { Name = "Sum(RS55)", Value = GetValueOrEmpty(sumRS55) },
                        new ProcessMessageParameter() { Name = "Sum(RS56)", Value = GetValueOrEmpty(sumRS56) },
                        new ProcessMessageParameter() { Name = "Sum(RS57)", Value = GetValueOrEmpty(sumRS57) },
                        new ProcessMessageParameter() { Name = "Sum(RS58)", Value = GetValueOrEmpty(sumRS58) }
                    },
                });
            }
        }
        #endregion // VR.ATO.PTR.430090

        #endregion RS CrossForm Validation Rules
    }
}