using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Text;
using System.Xml;
using System.Linq;
using System.Collections.Generic;
using DataContracts;
using System.Text.RegularExpressions;

namespace Ato.EN.IntegrationServices.CodeGenerationDISTBENTRT
{

    public partial class DISTBENTRT2024Validator
    {
        /// <summary>
        /// The max parameter name length is restricted by the SBR1 and SBR2 schemas - the lowest common denominator of SBR 1 is used as the default
        /// </summary>
        private int _maxParameterNameLength;

        /// <summary>
        /// The max parameter value length is restricted by the SBR1 and SBR2 schemas
        /// </summary>
        private int _maxParameterValueLength;

        /// <summary>
        /// The SBR1 and ebms3 schemas do not allow parameter names or values to be the empty string
        /// </summary>
        private string _emptyParameterValue;

        /// <summary>
        /// The report parameter
        /// </summary>
        private DISTBENTRT2024 report;

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

        /// <summary>
        /// Initializes a new instance of the <see cref="DISTBENTRT2024Validator" /> class.
        /// </summary>
        /// <param name="maxParameterNameLength">Maximum length of the parameter name.</param>
        /// <param name="maxParameterValueLength">Maximum length of the parameter value.</param>
        /// <param name="emptyParameterValue">This value will be used in place of any parameter values that result in a null or empty value.</param>
        public DISTBENTRT2024Validator(int maxParameterNameLength = 20, int maxParameterValueLength = 4096, string emptyParameterValue = "EMPTY")
        {
            _maxParameterNameLength = maxParameterNameLength;
            _maxParameterValueLength = maxParameterValueLength;
            _emptyParameterValue = emptyParameterValue;
            this.response = new List<ProcessMessageDocument>();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="DISTBENTRT2024Validator" /> class.
        /// </summary>
        /// <param name="report">Report variable </param>                
        /// <param name="maxParameterNameLength">Maximum length of the parameter name.</param>
        /// <param name="maxParameterValueLength">Maximum length of the parameter value.</param>
        /// <param name="emptyParameterValue">This value will be used in place of any parameter values that result in a null or empty value.</param>
        public DISTBENTRT2024Validator(DISTBENTRT2024 reportIn, int maxParameterNameLength = 20, int maxParameterValueLength = 4096, string emptyParameterValue = "EMPTY") : this(maxParameterNameLength, maxParameterValueLength, emptyParameterValue)
        {                   
            this.ConsumedReport = reportIn;                    
        }

        #region Functions
        private static IEnumerable<string> Union(IEnumerable<string> list1, IEnumerable<string> list2)
        {
            IEnumerable<string> response;

            if (list1 == null && list2 == null)
            {
                response = null;
            }
            else if (list1 == null)
            {
                response = list2.Distinct();
            }
            else if (list2 == null)
            {
                response = list1.Distinct();
            }
            else
            {
                response = list1.Union(list2);
            }

            return response;
        }

        private static bool IsMatch(int? field, string expression, RegexOptions options = RegexOptions.None)
        {
            if (field == null)
                return false;
            else
                return Regex.IsMatch(Convert.ToString(field.Value), expression, options);
        }

        private static bool IsMatch(string field, string expression, RegexOptions options = RegexOptions.None)
        {
            if (field == null)
                return false;
            else
                return Regex.IsMatch(field, expression, options);
        }

        // This is just context and tuple counts where they are integer values - easier that changing the parsing logic to just return the value
        private static int Count(int count)
        {
            return count;
        }


        private static int Count<T>(IEnumerable<T> values)
        {
            return values == null ? 0 : values.Where(f => f != null).Count();
        }


        private static int Count<T>(ICollection<T> values)
        {
            return values == null ? 0 : values.Where(f => f != null).Count();
        }

        private static bool exists(bool value)
        {
            return value;
        }

        private static string GetValueOrEmpty(bool? val)
        {
            return (val.HasValue) ? val.ToString().ToLower() : string.Empty;
        }

        private static string GetValueOrEmptyDate(DateTime? val)
        {
            return (val.HasValue) ? val.Value.ToString("yyyy-MM-dd") : string.Empty;
        }

        private static string GetValueOrEmptyDate(string val)
        {
            DateTime dateTimeOut;
            if (DateTime.TryParse(val, out dateTimeOut))
            {
                return dateTimeOut.ToString("yyyy-MM-dd");
            }
            return !string.IsNullOrWhiteSpace(val) ? val : string.Empty;
        }

        private static string GetValueOrEmptyDateTime(string val)
        {
            DateTime dateTimeOut;
            if (DateTime.TryParse(val, out dateTimeOut))
            {
                return dateTimeOut.ToString("yyyy-MM-ddTHH:mm:ssZ");
            }
            return !string.IsNullOrWhiteSpace(val) ? val : string.Empty;
        }

        private static string GetValueOrEmptyDateTime(DateTime? val)
        {
            return (val.HasValue) ? val.Value.ToString("yyyy-MM-ddTHH:mm:ssZ") : string.Empty;
        }

        private static string GetValueOrEmpty(string val)
        {
            return !string.IsNullOrWhiteSpace(val) ? val : string.Empty;
        }

        private static string GetValueOrEmpty(decimal? val)
        {
            return (val.HasValue) ? val.ToString() : string.Empty;
        }

        private static string GetValueOrEmpty(int? val)
        {
            return (val.HasValue) ? val.ToString() : string.Empty;
        }

         /// <summary>
         /// Get string value between [first] a and [last] b.
         /// </summary>
        public static string Between(string value, string a, string b)
        {
            int posA = value.IndexOf(a);
            int posB = value.LastIndexOf(b);
            if (posA == -1)
            {
                return "";
            }
            if (posB == -1)
            {
                return "";
            }
            int adjustedPosA = posA + a.Length;
            if (adjustedPosA >= posB)
            {
                return "";
            }
            return value.Substring(adjustedPosA, posB - adjustedPosA);
        }

         /// <summary>
         /// Get string value after [first] a.
         /// </summary>
        public static string Before(string value, string a)
        {
            int posA = value.IndexOf(a);
            if (posA == -1)
            {
                return "";
            }
            return value.Substring(0, posA);
        }

         /// <summary>
         /// Get string value after [last] a.
         /// </summary>
        public static string After(string value, string a)
        {
            int posA = value.LastIndexOf(a);
            if (posA == -1)
            {
                return "";
            }
            int adjustedPosA = posA + a.Length;
            if (adjustedPosA >= value.Length)
            {
                return "";
            }
            return value.Substring(adjustedPosA);
        }

        private static int Length(object field)
        {
            if (field == null)
            return 0;
            else
            return field.ToString().Trim().Length;
        }

        private static bool NotSameValues(IEnumerable<object> nodes)
        {
            if (nodes == null)
                return false;

            object[] nodesArray = nodes.Cast<object>().ToArray();
            return NotSameValues(nodesArray);
        }

        private static bool NotSameValues(params object[] nodes)
        {
            if (nodes == null)
                return false;

            return (from x in nodes select x).Distinct().Count() != 1;
        }

        private static bool HasDuplicateValues(IEnumerable<DateTime> nodes)
        {
            if (nodes == null)
                return false;

            object[] nodesArray = nodes.Cast<object>().ToArray();
            return HasDuplicateValues(nodesArray);
        }

        private static bool HasDuplicateValues(IEnumerable<DateTime?> nodes)
        {
            if (nodes == null)
                return false;

            object[] nodesArray = nodes.Cast<object>().ToArray();
            return HasDuplicateValues(nodesArray);
        }

        private static bool NotSameValues(IEnumerable<DateTime> nodes)
        {
            if (nodes == null)
                return false;

            object[] nodesArray = nodes.Cast<object>().ToArray();
            return NotSameValues(nodesArray);
        }

        private static bool NotSameValues(IEnumerable<DateTime?> nodes)
        {
            if (nodes == null)
                return false;

            object[] nodesArray = nodes.Cast<object>().ToArray();
            return NotSameValues(nodesArray);
        }

        private static bool HasDuplicateValues(IEnumerable<object> nodes)
        {
            if (nodes == null)
                return false;

            object[] nodesArray = nodes.Cast<object>().ToArray();
            return HasDuplicateValues(nodesArray);
        }

        private static bool HasDuplicateValues(params object[] nodes)
        {
           if (nodes == null)
                return false;

            nodes = nodes.Where(x => x != null).ToArray();
            return !((from x in nodes select x).Distinct().Count() == nodes.Count());
        
        }

        private int DuplicateValueIndex(IEnumerable<object> values)
        {
            int response = 0;
            var hashset = new HashSet<object>();
            foreach (var value in values)
            {
                if (!hashset.Add(value))
                {
                    return response;
                }
                response++;
            }
            return response;
        }

        private int DuplicateValueIndex<T>(IEnumerable<T?> values) where T : struct
        {
            int response = 0;
            var hashset = new HashSet<T?>();
            foreach (var value in values)
            {
                if (!hashset.Add(value))
                {
                    return response;
                }
                response++;
            }
            return response;
        }

        private static bool IsDate(object value)
        {
            DateTime dateValue;
            return (value != null && DateTime.TryParse(value.ToString(), out dateValue));
        }

        public DateTime AsDate(string dateAsString)
        {
            DateTime response = DateTime.MinValue;
            DateTime date;

            if (DateTime.TryParse(dateAsString, out date))
            {
                response = date;
            }

            return response;
        }

        public DateTime Date(DateTime? datetime)
        {                   
            return datetime.GetValueOrDefault().Date;
        }

				//The logic in After function expects "---" for day and "--" for month. 
				//Since hyphen was missing the date always returned null
        public DateTime? ConvertToDate(int day, int month, int year)
        {
					return ConvertToDate(day == 0 ? null : "---" + day.ToString(), month == 0 ? null : "--" + month.ToString(), year == 0 ? null : year.ToString());
        }

        public DateTime? ConvertToDate(string day, string month, string year)
        {
            DateTime? response;
            DateTime result;

            if (year == null || month == null || day == null)
            {
                return null;
            }
            string dateAsString = year + "-" + After(month, "--") + "-" + After(day, "---");
            if (DateTime.TryParse(dateAsString, out result))
            {
                response = result;
            }
            else
            {
                response = null;
            }
            return response;
        }


        public DateTime? ConvertToDate(string day, string month, int year)
        {
            DateTime? response;
            DateTime result;

            if (year == 0 || month == null || day == null)
            {
                return null;
            }
            string dateAsString = year.ToString() + "-" + After(month, "--") + "-" + After(day, "---");
            if (DateTime.TryParse(dateAsString, out result))
            {
                response = result;
            }
            else
            {
                response = null;
            }
            return response;
        }


        private static int Day(string dateAsString)
        {
            int response = 0;
            DateTime date;

            if (DateTime.TryParse(dateAsString, out date))
            {
                response = date.Day;
            }

            return response;
        }


        private static int Day(DateTime? date)
        {
            if (date == null)
                return 0;
            else
                return date.Value.Day;

        }


        private static string Month(string dateAsString)
        {
            string response = null;
            DateTime date;

            if (DateTime.TryParse(dateAsString, out date))
            {
                response = date.ToString("MMMM");
            }
            else
            {
                return "NotAMonth";
            }

            return response;
        }

        private static string Month(DateTime? date)
        {
            if (date == null)
                return "NotAMonth";
            else
                return date.Value.ToString("MMMM");
        }


        private static int MonthAsInt(string dateAsString)
        {
            int response = 0;
            DateTime date;

            if (DateTime.TryParse(dateAsString, out date))
            {
                response = date.Month;
            }

            return response;
        }

        private static int MonthAsInt(DateTime? date)
        {
            if (date == null)
            {
                return 0;
            }
            return date.Value.Month;
        }


        private static int Year(string dateAsString)
        {
            int response = 0;
            DateTime date;

            if (DateTime.TryParse(dateAsString, out date))
            {
                response = date.Year;
            }

            return response;
        }

        private static int Year(DateTime? date)
        {
            if (date == null)
                return 0;
            else
                return date.Value.Year;
        }


        private static int CurrentFinancialYear()
        {
            return DateToFinancialYear(DateTime.Now, 7);
        }

        private static int FinancialYear(string dateAsString)
        {
            return DateToFinancialYear(dateAsString, 7);
        }

        private static int FinancialYear(DateTime? date)
        {
            return DateToFinancialYear(date, 7);
        }

        private static int DateToFinancialYear(string dateAsString, int startingMonth)
        {
            int response = 0;
            DateTime date;
            if (DateTime.TryParse(dateAsString, out date))
            {
                response = DateToFinancialYear(date, startingMonth);
            }

            return response;
        }
        private static int DateToFinancialYear(DateTime? date, int startingMonth)
        {
            int response;
            if (date == null)
            {
                response = 0;
            }
            else
            {
                int year = date.Value.Year;
                int month = date.Value.Month;

                if (startingMonth > month)
                    response = year;
                else
                    response = year + 1;
            }
            return response;
        }


        private static int FBTYear(string dateAsString)
        {
            int response = 0;
            DateTime date;

            if (DateTime.TryParse(dateAsString, out date))
                response = FBTYear(date);
            return response;
        }

        private static int FBTYear(DateTime? date)
        {
            if (date == null)
            {
                return 0;
            }
            else
            {
                if (date.Value.Month > 3)
                    return date.Value.Year + 1;
                else
                    return date.Value.Year;
            }
        }

        private static DateTime? AddMonthsToDate(DateTime? dateTime, int months)
        {
            return dateTime == null ? null : (DateTime?)dateTime.Value.AddMonths(months);
        }

        private static bool IsNumeric(object value)
        {
            decimal numbervalue;
            return (value != null && decimal.TryParse(value.ToString(), out numbervalue));
        }

        private static bool NotMonetary(decimal? field, string sign, int digits, int decimals)
        {
            if (field == null)
            {
                return false;
            }
            else
            {
                string signExpression;
                string decimalExpression;
                int digitsToUse = digits - decimals;

                if (sign == "U")
                    signExpression = "^";
                else
                    signExpression = "^-?";

                if (decimals > 0)
                    decimalExpression = @"(\.\d{1," + decimals + "})?$";
                else
                    decimalExpression = @"$";

                return !(Regex.IsMatch(field.Value.ToString("0.#########################"), signExpression + @"\d{1," + digitsToUse + "}" + decimalExpression));
            }
        }

        private static bool NotNumeric(decimal? field, string sign, int digits, int decimals)
        {
            if (field == null)
            {
                return false;
            }
            else
            {
                string signExpression;
                string decimalExpression;
                int digitsToUse = digits - decimals;

                if (sign == "U")
                    signExpression = "^";
                else
                    signExpression = "^-?";

                if (decimals > 0)
                    decimalExpression = @"(\.\d{1," + decimals + "})?$";
                else
                    decimalExpression = @"$";

                return !(Regex.IsMatch(field.Value.ToString("0.#########################"), signExpression + @"\d{1," + digitsToUse + "}" + decimalExpression));
            }
        }

        private static bool NotNumeric(int? field, string sign, int digits, int decimals = 0)
        {
            if (field == null)
            {
                return false;
            }
            else
            {
                string signExpression;

                if (sign == "U")
                    signExpression = "^";
                else
                    signExpression = "^-?";

                return !(Regex.IsMatch(field.Value.ToString(), signExpression + @"\d{1," + digits + "}$"));
            }
        }

        private static bool NotNumeric(long? field, string sign, int digits, int decimals = 0)
        {
            if (field == null)
            {
                return false;
            }
            else
            {
                string signExpression;

                if (sign == "U")
                    signExpression = "^";
                else
                    signExpression = "^-?";

                return !(Regex.IsMatch(field.Value.ToString(), signExpression + @"\d{1," + digits + "}$"));
            }
        }


        private static bool OutsideRange(decimal field, decimal expression, int range)
        {
            bool response;

            response = (field < (expression - range)) || (field > (expression + range));

            return response;
        }


        private static bool FailsUSIAlgorithm(string usi, string abn)
        {
            bool response = true;
            if (usi == null || abn == null)
            {
                response = false;
            }
            else
            {
                usi = usi.Trim();
                abn = abn.Trim();
                if (usi.Length == 14)
                {
                    int numeric;
                    if (usi.Substring(0, 11) == abn && int.TryParse(usi.Substring(11, 3), out numeric))
                        response = false;

                }
                else if (usi.Length == 9)
                {

                    if (Regex.IsMatch(usi, @"^([a-zA-Z]{3}\d{4}[a-zA-Z]{2})$"))
                        response = false;
                }
            }
            return response;
        }

        private static bool FailsTANAlgorithm(string tan)
        {
            bool response;
            decimal decimalTan;

            if (tan == null)
                return false;

            tan = tan.Trim();

            if (!decimal.TryParse(tan, out decimalTan))
                return true;

            if (tan.Length != 8)
                return true;

            decimal tanSum =
                7 * int.Parse(tan.Substring(0, 1)) +
                9 * int.Parse(tan.Substring(1, 1)) +
                8 * int.Parse(tan.Substring(2, 1)) +
                4 * int.Parse(tan.Substring(3, 1)) +
                6 * int.Parse(tan.Substring(4, 1)) +
                3 * int.Parse(tan.Substring(5, 1)) +
                5 * int.Parse(tan.Substring(6, 1)) +
                1 * int.Parse(tan.Substring(7, 1));

            if ((tanSum % 11) == 0)
                response = false;
            else
                response = true;

            return response;
        }


        private static bool FailsABNAlgorithm(string abn)
        {
            bool response;
            decimal decimalAbn;

            if (abn == null)
                return false;

            abn = abn.Trim();

            if (!decimal.TryParse(abn, out decimalAbn))
                return true;

            if (abn.Length != 11)
                return true;

            decimal abnSum =
                10 * (int.Parse(abn.Substring(0, 1)) - 1) +
                1 * int.Parse(abn.Substring(1, 1)) +
                3 * int.Parse(abn.Substring(2, 1)) +
                5 * int.Parse(abn.Substring(3, 1)) +
                7 * int.Parse(abn.Substring(4, 1)) +
                9 * int.Parse(abn.Substring(5, 1)) +
                11 * int.Parse(abn.Substring(6, 1)) +
                13 * int.Parse(abn.Substring(7, 1)) +
                15 * int.Parse(abn.Substring(8, 1)) +
                17 * int.Parse(abn.Substring(9, 1)) +
                19 * int.Parse(abn.Substring(10, 1));

            if ((abnSum % 89) == 0)
                response = false;
            else
                response = true;

            return response;
        }
        private static bool FailsACNAlgorithm(string acn)
        {
            bool response;
            decimal decimalAbn;
            if (acn == null)
                return false;

            acn = acn.Trim();

            if (!decimal.TryParse(acn, out decimalAbn))
                return true;

            if (acn.Length != 9)
                return true;

            decimal abnSum =
                8 * int.Parse(acn.Substring(0, 1)) +
                7 * int.Parse(acn.Substring(1, 1)) +
                6 * int.Parse(acn.Substring(2, 1)) +
                5 * int.Parse(acn.Substring(3, 1)) +
                4 * int.Parse(acn.Substring(4, 1)) +
                3 * int.Parse(acn.Substring(5, 1)) +
                2 * int.Parse(acn.Substring(6, 1)) +
                1 * int.Parse(acn.Substring(7, 1));

            decimal checkDigit = int.Parse(acn.Substring(8, 1));
            decimal acnRemainder = abnSum % 10;

            if (((10 - acnRemainder) % 10) == checkDigit)
                response = false;
            else
                response = true;

            return response;
        }


        private static bool FailsTFNAlgorithm(string tfn)
        {
            bool response;
            decimal decimalTfn;

            if (tfn == null)
                return false;

            tfn = tfn.Trim();
            tfn = Regex.Replace(tfn, "^0+", "");

            if (!decimal.TryParse(tfn, out decimalTfn))
                return true;

            if (tfn.Length < 8)
                return true;


            decimal tfn1To7Sum =
                1 * int.Parse(tfn.Substring(0, 1)) +
                4 * int.Parse(tfn.Substring(1, 1)) +
                3 * int.Parse(tfn.Substring(2, 1)) +
                7 * int.Parse(tfn.Substring(3, 1)) +
                5 * int.Parse(tfn.Substring(4, 1)) +
                8 * int.Parse(tfn.Substring(5, 1)) +
                6 * int.Parse(tfn.Substring(6, 1));

            decimal tfn8 = 9 * int.Parse(tfn.Substring(7, 1));

            if (tfn.Length == 8)
            {
                decimal tFNLg8WSum9 = 10 * int.Parse(tfn.Substring(7, 1));
                decimal tFNLg8WSum = tfn1To7Sum + tFNLg8WSum9;

                if ((tFNLg8WSum % 11) == 0)
                    response = false;
                else
                    response = true;
            }
            else if (tfn.Length == 9)
            {
                decimal tfn9 = 10 * int.Parse(tfn.Substring(8, 1));
                decimal tFNLg9WSum = tfn1To7Sum + tfn8 + tfn9;

                if ((tFNLg9WSum % 11) == 0)
                    response = false;
                else
                    response = true;
            }
            else
            {
                response = true;
            }

            return response;
        }


        private static decimal ConditionalValue(bool expression, decimal? trueVal, decimal? falseVal)
        {
             return expression ? trueVal.GetValueOrDefault() : falseVal.GetValueOrDefault();
        }

        private static decimal AsNumeric(string value)
        {
             decimal numberValue;
             decimal.TryParse(value, out numberValue);
             return numberValue;
        }

        private static bool RegexMatch(int? field, string expression, string flags = "")
        {
            return IsMatch(field, expression, GetRegexOption(flags));
        }

        private static bool RegexMatch(string field, string expression, string flags = "")
        {
            return IsMatch(field, expression, GetRegexOption(flags));
        }

        private static RegexOptions GetRegexOption(string flags)
        {
            RegexOptions options = RegexOptions.None;

            char[] characters = flags.ToCharArray();

            foreach (char character in characters)
            {
                switch (character)
                {
                    case 'i':                        
                        options = options | RegexOptions.IgnoreCase;                       
                        break;
                    case 'm':                        
                        options = options | RegexOptions.Multiline;                       
                        break;
                    case 's':                        
                            options = options | RegexOptions.Singleline;                       
                        break;
                    case 'n':                        
                            options = options | RegexOptions.ExplicitCapture;                       
                        break;
                    case 'x':                       
                            options = options | RegexOptions.IgnorePatternWhitespace;                       
                        break;
                }
            }

            return options;
        }

        private static string Substring(object field, int start, int length)
        {
            return field.ToString().Substring(start, length);
        }
        
        /// <summary>
        /// Returns an occurrence index as [occurrenceIndex] of occurrenceIndex > 0, otherwise the empty string
        /// </summary>
        /// <param name="occurrenceIndex">Index of the occurrence.</param>
        /// <returns>Occurrence in XPath [#] format</returns>
        public string OccurrenceIndex(int occurrenceIndex)
        {
            return occurrenceIndex > 0 ? "[" + occurrenceIndex + "]" : "";
        }

        #endregion // Functions

        public DISTBENTRT2024 ConsumedReport { get { return report; } private set { report = value; } }

        private static Dictionary<string, ProcessMessageDocument> _processMessageDocuments = new Dictionary<string, ProcessMessageDocument>();				

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public List<ProcessMessageDocument> ValidateReport(DISTBENTRT2024 reportIn)
        {
            ProcessMessageDocument processMessage;
            ProcessMessageParameter parameter;
            bool assertion;

            this.ConsumedReport = reportIn;

            // ------------------------------------------------------------------------------
            // Validations are now done in code.
            // This version supports full validation of a report - for those rules that have successfully parsed and could be generated.
            // Generated Validations include:
            //   - Validation logic in C#.
            //   - Production of errors in EBMS, SBR and SWS format.
            // 
            // The generation at this stage does not support the following - and has to be completed manually (later versions of the generation will do this for you)
            //   - Business Rules that did not parse.  The ESR team will help support you where this happens as an effort is being made to rectify these
            //   - You will get TODO tasks for those that the parser could not cope with
            // ------------------------------------------------------------------------------

            #region Repeating report.RP_StatementOfDistributionToBeneficiaryCollection  
            if (report.RP_StatementOfDistributionToBeneficiaryCollection != null)
            {    
                int itemIndex2 = 0;
                foreach (DISTBENTRT2024.RP_StatementOfDistributionToBeneficiary statementOfDistributionToBeneficiary in report.RP_StatementOfDistributionToBeneficiaryCollection)
                {
                    itemIndex2++;
                        VRATODISTBENTRT000002(statementOfDistributionToBeneficiary, itemIndex2);
                        VRATODISTBENTRT000003(statementOfDistributionToBeneficiary, itemIndex2);
                        VRATODISTBENTRT000004(statementOfDistributionToBeneficiary, itemIndex2);
                        VRATODISTBENTRT000008(statementOfDistributionToBeneficiary, itemIndex2);
                        VRATODISTBENTRT000009(statementOfDistributionToBeneficiary, itemIndex2);
                        VRATODISTBENTRT000010(statementOfDistributionToBeneficiary, itemIndex2);
                        VRATODISTBENTRT000012(statementOfDistributionToBeneficiary, itemIndex2);
                        VRATODISTBENTRT000014(statementOfDistributionToBeneficiary, itemIndex2);
                        VRATODISTBENTRT000015(statementOfDistributionToBeneficiary, itemIndex2);
                    }
                }
        
                #endregion // Foreach loop
                VRATODISTBENTRT000011();
                VRATODISTBENTRT000013();

            foreach (ProcessMessageDocument currentProcessMessage in response)
            {
                if (currentProcessMessage.Parameters != null)
                {
                    foreach (ProcessMessageParameter currentParameter in currentProcessMessage.Parameters)
                    {
                        if (string.IsNullOrEmpty(currentParameter.Name))
                        {
                            currentParameter.Name = _emptyParameterValue;
                        }

                        if (currentParameter.Name.Length > _maxParameterNameLength)
                        {
                            currentParameter.Name = currentParameter.Name.Substring(0, _maxParameterNameLength - 1);
                        }

                        if (string.IsNullOrEmpty(currentParameter.Value))
                        {
                            currentParameter.Value = _emptyParameterValue;
                        }

                        if (currentParameter.Value.Length > _maxParameterValueLength)
                        {
                            currentParameter.Value = currentParameter.Value.Substring(0, _maxParameterValueLength - 1);
                        }
                    }
                }
            }

            return response;
        }
				
			
    
      #region VR.ATO.DISTBENTRT.000002
      [MethodImpl(MethodImplOptions.AggressiveInlining)]
      public virtual void VRATODISTBENTRT000002(DISTBENTRT2024.RP_StatementOfDistributionToBeneficiary statementOfDistributionToBeneficiary, int itemIndex2)
      {
        ProcessMessageDocument processMessage;
        bool assertion;
            
                    /*  VR.ATO.DISTBENTRT.000002
                    Australian Business Number must pass the ABN algorithm check.
    
                    Legacy Rule Format:
                    ^DISTBENTRT4 <> NULL AND FailsABNAlgorithm(^DISTBENTRT4)
        
                    Technical Business Rule Format:
                    ^DISTBENTRT4 <> NULL AND FailsABNAlgorithm(^DISTBENTRT4)
            
                    Data Elements:
            
                    ^DISTBENTRT4 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:DistributingTrust:Identifiers.AustralianBusinessNumber.Identifier
                    */
                    assertion = (statementOfDistributionToBeneficiary.DISTBENTRT4 != null && FailsABNAlgorithm(statementOfDistributionToBeneficiary.DISTBENTRT4));
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.DISTBENTRT.000002",
                            Severity = ProcessMessageSeverity.Error,
                            Description = @"Australian Business Number has failed the algorithm check",
                            Location = "/tns:DISTBENTRT/tns:RP/tns:StatementOfDistributionToBeneficiaryCollection/tns:StatementOfDistributionToBeneficiary" + OccurrenceIndex(statementOfDistributionToBeneficiary.OccurrenceIndex) + "/tns:DistributingTrust/tns:AustralianBusinessNumberId",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() { Name = "RuleIdentifier", Value = "VR.ATO.DISTBENTRT.000002" } },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "DISTBENTRT4", Value = GetValueOrEmpty(statementOfDistributionToBeneficiary.DISTBENTRT4) });
            
                        response.Add(processMessage);
                    }
              }
              #endregion 
    
      #region VR.ATO.DISTBENTRT.000003
      [MethodImpl(MethodImplOptions.AggressiveInlining)]
      public virtual void VRATODISTBENTRT000003(DISTBENTRT2024.RP_StatementOfDistributionToBeneficiary statementOfDistributionToBeneficiary, int itemIndex2)
      {
        ProcessMessageDocument processMessage;
        bool assertion;
            
                    /*  VR.ATO.DISTBENTRT.000003
                    Non-individual name field cannot contain 'Pship', 'P'ship or 'P/Ship'
    
                    Legacy Rule Format:
                    StartsWith(^DISTBENTRT5, 'T/A ') AND EndsWithSet(^DISTBENTRT5, '" Pship"," P'ship"," P/ship"')
        
                    Technical Business Rule Format:
                    StartsWith(^DISTBENTRT5, 'T/A ') AND EndsWithSet(^DISTBENTRT5, '" Pship"," P'ship"," P/ship"')
            
                    Data Elements:
            
                    ^DISTBENTRT5 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:DistributingTrust:OrganisationNameDetails.OrganisationalName.Text
                    */
                    assertion = (IsMatch(statementOfDistributionToBeneficiary.DISTBENTRT5, @"^(T/A )", RegexOptions.IgnoreCase) && IsMatch(statementOfDistributionToBeneficiary.DISTBENTRT5, @"( Pship| P'ship| P/ship)$", RegexOptions.IgnoreCase));
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.DISTBENTRT.000003",
                            Severity = ProcessMessageSeverity.Error,
                            Description = @"Non-individual name field cannot start with 'T/A' and end with 'Pship', 'P'ship or 'P/Ship'",
                            Location = "/tns:DISTBENTRT/tns:RP/tns:StatementOfDistributionToBeneficiaryCollection/tns:StatementOfDistributionToBeneficiary" + OccurrenceIndex(statementOfDistributionToBeneficiary.OccurrenceIndex) + "/tns:DistributingTrust/tns:OrganisationNameDetailsOrganisationalNameT",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() { Name = "RuleIdentifier", Value = "VR.ATO.DISTBENTRT.000003" } },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "DISTBENTRT5", Value = statementOfDistributionToBeneficiary.DISTBENTRT5 });
            
                        response.Add(processMessage);
                    }
              }
              #endregion 
    
      #region VR.ATO.DISTBENTRT.000004
      [MethodImpl(MethodImplOptions.AggressiveInlining)]
      public virtual void VRATODISTBENTRT000004(DISTBENTRT2024.RP_StatementOfDistributionToBeneficiary statementOfDistributionToBeneficiary, int itemIndex2)
      {
        ProcessMessageDocument processMessage;
        bool assertion;
            
                    /*  VR.ATO.DISTBENTRT.000004
                    Organisation name must contain at least one alpha or numeric character
    
                    Legacy Rule Format:
                    NotContainsSet(^DISTBENTRT5, '"a-z", "A-Z", "0-9"')
        
                    Technical Business Rule Format:
                    NotContainsSet(^DISTBENTRT5, '"a-z", "A-Z", "0-9"')
            
                    Data Elements:
            
                    ^DISTBENTRT5 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:DistributingTrust:OrganisationNameDetails.OrganisationalName.Text
                    */
                    assertion = !(IsMatch(statementOfDistributionToBeneficiary.DISTBENTRT5, @"[a-z]|[A-Z]|[0-9]", RegexOptions.IgnoreCase));
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.DISTBENTRT.000004",
                            Severity = ProcessMessageSeverity.Error,
                            Description = @"Organisation name must contain at least one alpha or numeric character",
                            Location = "/tns:DISTBENTRT/tns:RP/tns:StatementOfDistributionToBeneficiaryCollection/tns:StatementOfDistributionToBeneficiary" + OccurrenceIndex(statementOfDistributionToBeneficiary.OccurrenceIndex) + "/tns:DistributingTrust/tns:OrganisationNameDetailsOrganisationalNameT",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() { Name = "RuleIdentifier", Value = "VR.ATO.DISTBENTRT.000004" } },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "DISTBENTRT5", Value = statementOfDistributionToBeneficiary.DISTBENTRT5 });
            
                        response.Add(processMessage);
                    }
              }
              #endregion 
    
      #region VR.ATO.DISTBENTRT.000008
      [MethodImpl(MethodImplOptions.AggressiveInlining)]
      public virtual void VRATODISTBENTRT000008(DISTBENTRT2024.RP_StatementOfDistributionToBeneficiary statementOfDistributionToBeneficiary, int itemIndex2)
      {
        ProcessMessageDocument processMessage;
        bool assertion;
            
                    /*  VR.ATO.DISTBENTRT.000008
                    Non Individual Name cannot end with "T/A", "T/A P'ship", "T/A Pship", "T/A P/Ship" or "T/A Partnership"
    
                    Legacy Rule Format:
                    EndsWithSet(^DISTBENTRT5, '" T/A"," T/A P'ship"," T/A Pship"," T/A P/Ship"," T/A Partnership"')
        
                    Technical Business Rule Format:
                    EndsWithSet(^DISTBENTRT5, '" T/A"," T/A P'ship"," T/A Pship"," T/A P/Ship"," T/A Partnership"')
            
                    Data Elements:
            
                    ^DISTBENTRT5 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:DistributingTrust:OrganisationNameDetails.OrganisationalName.Text
                    */
                    assertion = IsMatch(statementOfDistributionToBeneficiary.DISTBENTRT5, @"( T/A| T/A P'ship| T/A Pship| T/A P/Ship| T/A Partnership)$", RegexOptions.IgnoreCase);
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.DISTBENTRT.000008",
                            Severity = ProcessMessageSeverity.Error,
                            Description = @"Non Individual Name cannot end with ""T/A"", ""T/A P'ship"", ""T/A Pship"", ""T/A P/Ship"" or ""T/A Partnership""",
                            Location = "/tns:DISTBENTRT/tns:RP/tns:StatementOfDistributionToBeneficiaryCollection/tns:StatementOfDistributionToBeneficiary" + OccurrenceIndex(statementOfDistributionToBeneficiary.OccurrenceIndex) + "/tns:DistributingTrust/tns:OrganisationNameDetailsOrganisationalNameT",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() { Name = "RuleIdentifier", Value = "VR.ATO.DISTBENTRT.000008" } },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "DISTBENTRT5", Value = statementOfDistributionToBeneficiary.DISTBENTRT5 });
            
                        response.Add(processMessage);
                    }
              }
              #endregion 
    
      #region VR.ATO.DISTBENTRT.000009
      [MethodImpl(MethodImplOptions.AggressiveInlining)]
      public virtual void VRATODISTBENTRT000009(DISTBENTRT2024.RP_StatementOfDistributionToBeneficiary statementOfDistributionToBeneficiary, int itemIndex2)
      {
        ProcessMessageDocument processMessage;
        bool assertion;
            
                    /*  VR.ATO.DISTBENTRT.000009
                    Where credit for tax withheld - foreign resident withholding (excluding capital gains) is greater than zero, there must be an amount at either share of income - primary or non-primary production or franked distributions. Beneficiary entitled.
    
                    Legacy Rule Format:
                    ^DISTBENTRT7 > 0 AND ^DISTBENTRT29 = NULL AND ^DISTBENTRT32 = NULL AND ^DISTBENTRT11 = NULL
        
                    Technical Business Rule Format:
                    ^DISTBENTRT7 > 0 AND ^DISTBENTRT29 = NULL AND ^DISTBENTRT32 = NULL AND ^DISTBENTRT11 = NULL
            
                    Data Elements:
            
                    ^DISTBENTRT7 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:IncomeTax.PayAsYouGoWithholding.CreditForAmountsWithheldFromForeignResidents.Amount
            
                    ^DISTBENTRT11 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:Income.DistributionFranked.Amount
            
                    ^DISTBENTRT29 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:ShareOfIncomePrimaryProduction:Income.BeneficiaryShare.Amount
            
                    ^DISTBENTRT32 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:ShareOfIncomeNonPrimaryProduction:Income.BeneficiaryShare.Amount
                    */
                    assertion = (statementOfDistributionToBeneficiary.DISTBENTRT7.GetValueOrDefault() > 0 && statementOfDistributionToBeneficiary.DISTBENTRT29 == null && statementOfDistributionToBeneficiary.DISTBENTRT32 == null && statementOfDistributionToBeneficiary.DISTBENTRT11 == null);
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.DISTBENTRT.000009",
                            Severity = ProcessMessageSeverity.Error,
                            Description = @"PP or Non PP Share of income or franked distributions must be present",
                            LongDescription = @"If within a Statement of Distribution there is an amount greater than zero at 'Credit for tax withheld - foreign resident withholding (excluding capital gains)', then there must be an amount at either 'Share of income - primary production'  or 'Share of income - non-primary production' or 'Franked distributions' within the Statement of Distribution.",
                            Location = "/tns:DISTBENTRT/tns:RP/tns:StatementOfDistributionToBeneficiaryCollection/tns:StatementOfDistributionToBeneficiary" + OccurrenceIndex(statementOfDistributionToBeneficiary.OccurrenceIndex) + "/tns:Information/tns:IncomeTaxPayAsYouGoWithholdingCreditForAmountsWithheldFromForeignResidentsA",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() { Name = "RuleIdentifier", Value = "VR.ATO.DISTBENTRT.000009" } },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "DISTBENTRT7", Value = GetValueOrEmpty(statementOfDistributionToBeneficiary.DISTBENTRT7) });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "DISTBENTRT29", Value = GetValueOrEmpty(statementOfDistributionToBeneficiary.DISTBENTRT29) });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "DISTBENTRT32", Value = GetValueOrEmpty(statementOfDistributionToBeneficiary.DISTBENTRT32) });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "DISTBENTRT11", Value = GetValueOrEmpty(statementOfDistributionToBeneficiary.DISTBENTRT11) });
            
                        response.Add(processMessage);
                    }
              }
              #endregion 
    
      #region VR.ATO.DISTBENTRT.000010
      [MethodImpl(MethodImplOptions.AggressiveInlining)]
      public virtual void VRATODISTBENTRT000010(DISTBENTRT2024.RP_StatementOfDistributionToBeneficiary statementOfDistributionToBeneficiary, int itemIndex2)
      {
        ProcessMessageDocument processMessage;
        bool assertion;
            
                    /*  VR.ATO.DISTBENTRT.000010
                    If an amount greater than zero is present at 'Credit for tax withheld where ABN not quoted' against a Statement of Distribution, then there must be Primary production or Non-primary production income or franked distributions amount against the beneficiary
    
                    Legacy Rule Format:
                    ^DISTBENTRT9 > 0 AND ^DISTBENTRT29 = NULL AND ^DISTBENTRT32 = NULL AND ^DISTBENTRT11 = NULL
        
                    Technical Business Rule Format:
                    ^DISTBENTRT9 > 0 AND ^DISTBENTRT29 = NULL AND ^DISTBENTRT32 = NULL AND ^DISTBENTRT11 = NULL
            
                    Data Elements:
            
                    ^DISTBENTRT9 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:IncomeTax.PayAsYouGoWithholding.CreditForTaxWithheldWhereABNNotQuoted.Amount
            
                    ^DISTBENTRT11 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:Income.DistributionFranked.Amount
            
                    ^DISTBENTRT29 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:ShareOfIncomePrimaryProduction:Income.BeneficiaryShare.Amount
            
                    ^DISTBENTRT32 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:ShareOfIncomeNonPrimaryProduction:Income.BeneficiaryShare.Amount
                    */
                    assertion = (statementOfDistributionToBeneficiary.DISTBENTRT9.GetValueOrDefault() > 0 && statementOfDistributionToBeneficiary.DISTBENTRT29 == null && statementOfDistributionToBeneficiary.DISTBENTRT32 == null && statementOfDistributionToBeneficiary.DISTBENTRT11 == null);
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.DISTBENTRT.000010",
                            Severity = ProcessMessageSeverity.Error,
                            Description = @"PP or Non-PP income distribution or franked distribution amount must be present in Statement of distribution",
                            LongDescription = @"If an amount greater than zero is present at 'Credit for tax withheld where ABN not quoted' against a Statement of Distribution, then there must be Primary production or Non-primary production income or franked distributions amount against the beneficiary.",
                            Location = "/tns:DISTBENTRT/tns:RP/tns:StatementOfDistributionToBeneficiaryCollection/tns:StatementOfDistributionToBeneficiary" + OccurrenceIndex(statementOfDistributionToBeneficiary.OccurrenceIndex) + "/tns:Information/tns:IncomeTaxPayAsYouGoWithholdingCreditForTaxWithheldWhereABNNotQuotedA",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() { Name = "RuleIdentifier", Value = "VR.ATO.DISTBENTRT.000010" } },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "DISTBENTRT9", Value = GetValueOrEmpty(statementOfDistributionToBeneficiary.DISTBENTRT9) });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "DISTBENTRT29", Value = GetValueOrEmpty(statementOfDistributionToBeneficiary.DISTBENTRT29) });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "DISTBENTRT32", Value = GetValueOrEmpty(statementOfDistributionToBeneficiary.DISTBENTRT32) });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "DISTBENTRT11", Value = GetValueOrEmpty(statementOfDistributionToBeneficiary.DISTBENTRT11) });
            
                        response.Add(processMessage);
                    }
              }
              #endregion 
    
      #region VR.ATO.DISTBENTRT.000011
      [MethodImpl(MethodImplOptions.AggressiveInlining)]
      public virtual void VRATODISTBENTRT000011()
      {
        ProcessMessageDocument processMessage;
        bool assertion;
    
            /*  VR.ATO.DISTBENTRT.000011
            Capital gains must be within +/- $5 of the total of gross capital gain minus the sum of capital losses applied, CGT discounts applied and CGT small business concessions applied.
    
            Legacy Rule Format:
            AnyOccurrence(^DISTBENTRT1002, OutsideRange(^DISTBENTRT15, ^DISTBENTRT16 - ^DISTBENTRT17 - ^DISTBENTRT18 - ^DISTBENTRT19, 5))

            Technical Business Rule Format:
            AnyOccurrence(^DISTBENTRT1002, OutsideRange(^DISTBENTRT15, ^DISTBENTRT16 - ^DISTBENTRT17 - ^DISTBENTRT18 - ^DISTBENTRT19, 5))
    
            Data Elements:
    
            ^DISTBENTRT15 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:Income.CapitalGainsNet.Amount
    
            ^DISTBENTRT16 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:Capital.Gains.Total.Amount
    
            ^DISTBENTRT17 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:Capital.Losses.Total.Amount
    
            ^DISTBENTRT18 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:TaxConcession.CapitalGains.DiscountTotal.Amount
    
            ^DISTBENTRT19 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:TaxConcession.CapitalGains.DiscountAndSmallBusinessConcessionsTotal.Amount
    
            ^DISTBENTRT1002 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary
            */
            assertion = (report.RP_StatementOfDistributionToBeneficiaryCollection == null ? false : report.RP_StatementOfDistributionToBeneficiaryCollection.Any(DISTBENTRT1002Repeat => OutsideRange(DISTBENTRT1002Repeat.DISTBENTRT15.GetValueOrDefault(), DISTBENTRT1002Repeat.DISTBENTRT16.GetValueOrDefault() - DISTBENTRT1002Repeat.DISTBENTRT17.GetValueOrDefault() - DISTBENTRT1002Repeat.DISTBENTRT18.GetValueOrDefault() - DISTBENTRT1002Repeat.DISTBENTRT19.GetValueOrDefault(), 5)));
            if (assertion)
            {
                processMessage = new ProcessMessageDocument()
                {
                    Code = "CMN.ATO.DISTBENTRT.000011",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Capital gains amount is incorrect",
                    LongDescription = @"Capital gains must be within +/- $5 of the total of gross capital gain minus the sum of capital losses applied, CGT discounts applied and CGT small business concessions applied.",
                    Location = "/tns:DISTBENTRT/tns:RP/tns:StatementOfDistributionToBeneficiaryCollection/tns:StatementOfDistributionToBeneficiary/tns:Information/tns:IncomeCapitalGainsNetA",
                    Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() { Name = "RuleIdentifier", Value = "VR.ATO.DISTBENTRT.000011" } },
                };
                processMessage.Parameters.Add(new ProcessMessageParameter
                    { Name = "DISTBENTRT15", Value = "Count(DISTBENTRT15)" });
    
                processMessage.Parameters.Add(new ProcessMessageParameter
                    { Name = "DISTBENTRT16", Value = "Count(DISTBENTRT16)" });
    
                processMessage.Parameters.Add(new ProcessMessageParameter
                    { Name = "DISTBENTRT17", Value = "Count(DISTBENTRT17)" });
    
                processMessage.Parameters.Add(new ProcessMessageParameter
                    { Name = "DISTBENTRT18", Value = "Count(DISTBENTRT18)" });
    
                processMessage.Parameters.Add(new ProcessMessageParameter
                    { Name = "DISTBENTRT19", Value = "Count(DISTBENTRT19)" });
    
                response.Add(processMessage);
            }
      }
      #endregion 
    
      #region VR.ATO.DISTBENTRT.000012
      [MethodImpl(MethodImplOptions.AggressiveInlining)]
      public virtual void VRATODISTBENTRT000012(DISTBENTRT2024.RP_StatementOfDistributionToBeneficiary statementOfDistributionToBeneficiary, int itemIndex2)
      {
        ProcessMessageDocument processMessage;
        bool assertion;
            
                    /*  VR.ATO.DISTBENTRT.000012
                    Foreign income tax offsets are greater than zero in distribution statement and there is no Attributed foreign income or Other assessable foreign source income.
    
                    Legacy Rule Format:
                    ^DISTBENTRT25 > 0 AND ^DISTBENTRT23 = NULL AND ^DISTBENTRT24 = NULL
        
                    Technical Business Rule Format:
                    ^DISTBENTRT25 > 0 AND ^DISTBENTRT23 = NULL AND ^DISTBENTRT24 = NULL
            
                    Data Elements:
            
                    ^DISTBENTRT23 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:IncomeTax.AttributedForeignIncome.Amount
            
                    ^DISTBENTRT24 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:Income.InternationalDealings.Net.Amount
            
                    ^DISTBENTRT25 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:Income.InternationalDealings.TaxOffset.Amount
                    */
                    assertion = (statementOfDistributionToBeneficiary.DISTBENTRT25.GetValueOrDefault() > 0 && statementOfDistributionToBeneficiary.DISTBENTRT23 == null && statementOfDistributionToBeneficiary.DISTBENTRT24 == null);
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.DISTBENTRT.000012",
                            Severity = ProcessMessageSeverity.Error,
                            Description = @"Attributed foreign income or Other assessable foreign source income must be present",
                            LongDescription = @"If 'Foreign income tax offsets' is greater than zero in a Statement of Distribution,  then there must be 'Attributed foreign income' or 'Other assessable foreign source income' within a beneficiary's Statement of Distribution or against the 'Income to which no beneficiary is presently entitled'",
                            Location = "/tns:DISTBENTRT/tns:RP/tns:StatementOfDistributionToBeneficiaryCollection/tns:StatementOfDistributionToBeneficiary" + OccurrenceIndex(statementOfDistributionToBeneficiary.OccurrenceIndex) + "/tns:Information/tns:IncomeTaxAttributedForeignIncomeA",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() { Name = "RuleIdentifier", Value = "VR.ATO.DISTBENTRT.000012" } },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "DISTBENTRT25", Value = GetValueOrEmpty(statementOfDistributionToBeneficiary.DISTBENTRT25) });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "DISTBENTRT23", Value = GetValueOrEmpty(statementOfDistributionToBeneficiary.DISTBENTRT23) });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "DISTBENTRT24", Value = GetValueOrEmpty(statementOfDistributionToBeneficiary.DISTBENTRT24) });
            
                        response.Add(processMessage);
                    }
              }
              #endregion 
    
      #region VR.ATO.DISTBENTRT.000013
      [MethodImpl(MethodImplOptions.AggressiveInlining)]
      public virtual void VRATODISTBENTRT000013()
      {
        ProcessMessageDocument processMessage;
        bool assertion;
    
            /*  VR.ATO.DISTBENTRT.000013
            If value is included in Name of distributing trust field, then an amount must be included at Primary production (PP) or non PP income or Franked distributions or Franking credit or TFN amounts withheld or Australian franking credit from a NZ franking company or Capital gains or Share of credit for foreign resident capital gains withholding amounts or Attributed foreign income or Other assessable foreign source income or Foreign income tax offset for each beneficiary listed in the distribution statement.
    
            Legacy Rule Format:
            AnyOccurrence(^DISTBENTRT1002, ^DISTBENTRT5 <> NULL AND ^DISTBENTRT29 = NULL AND ^DISTBENTRT32 = NULL AND ^DISTBENTRT11 = NULL AND ^DISTBENTRT12 = NULL AND ^DISTBENTRT13 = NULL AND ^DISTBENTRT8 = NULL AND ^DISTBENTRT15 = NULL AND ^DISTBENTRT22 = NULL AND ^DISTBENTRT23 = NULL AND ^DISTBENTRT24 = NULL AND ^DISTBENTRT25 = NULL)

            Technical Business Rule Format:
            AnyOccurrence(^DISTBENTRT1002, ^DISTBENTRT5 <> NULL AND ^DISTBENTRT29 = NULL AND ^DISTBENTRT32 = NULL AND ^DISTBENTRT11 = NULL AND ^DISTBENTRT12 = NULL AND ^DISTBENTRT13 = NULL AND ^DISTBENTRT8 = NULL AND ^DISTBENTRT15 = NULL AND ^DISTBENTRT22 = NULL AND ^DISTBENTRT23 = NULL AND ^DISTBENTRT24 = NULL AND ^DISTBENTRT25 = NULL)
    
            Data Elements:
    
            ^DISTBENTRT29 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:ShareOfIncomePrimaryProduction:Income.BeneficiaryShare.Amount
    
            ^DISTBENTRT5 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:DistributingTrust:OrganisationNameDetails.OrganisationalName.Text
    
            ^DISTBENTRT8 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:IncomeTax.FrankingCredits.ReceivedFromNewZealandCompanies.Amount
    
            ^DISTBENTRT11 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:Income.DistributionFranked.Amount
    
            ^DISTBENTRT12 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:IncomeTax.FrankingCredits.ReceivedFromAustralianCompanies.Amount
    
            ^DISTBENTRT13 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:IncomeTax.PayAsYouGoWithholding.CreditForAmountsWithheldWhereTFNNotQuoted.Amount
    
            ^DISTBENTRT15 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:Income.CapitalGainsNet.Amount
    
            ^DISTBENTRT22 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:IncomeTax.PayAsYouGoWithholding.CreditForCapitalGainsWithheldFromForeignResidents.Amount
    
            ^DISTBENTRT23 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:IncomeTax.AttributedForeignIncome.Amount
    
            ^DISTBENTRT24 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:Income.InternationalDealings.Net.Amount
    
            ^DISTBENTRT25 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:Income.InternationalDealings.TaxOffset.Amount
    
            ^DISTBENTRT32 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:ShareOfIncomeNonPrimaryProduction:Income.BeneficiaryShare.Amount
    
            ^DISTBENTRT1002 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary
            */
            assertion = (report.RP_StatementOfDistributionToBeneficiaryCollection == null ? false : report.RP_StatementOfDistributionToBeneficiaryCollection.Any(DISTBENTRT1002Repeat => DISTBENTRT1002Repeat.DISTBENTRT5 != null && DISTBENTRT1002Repeat.DISTBENTRT29 == null && DISTBENTRT1002Repeat.DISTBENTRT32 == null && DISTBENTRT1002Repeat.DISTBENTRT11 == null && DISTBENTRT1002Repeat.DISTBENTRT12 == null && DISTBENTRT1002Repeat.DISTBENTRT13 == null && DISTBENTRT1002Repeat.DISTBENTRT8 == null && DISTBENTRT1002Repeat.DISTBENTRT15 == null && DISTBENTRT1002Repeat.DISTBENTRT22 == null && DISTBENTRT1002Repeat.DISTBENTRT23 == null && DISTBENTRT1002Repeat.DISTBENTRT24 == null && DISTBENTRT1002Repeat.DISTBENTRT25 == null));
            if (assertion)
            {
                processMessage = new ProcessMessageDocument()
                {
                    Code = "CMN.ATO.DISTBENTRT.000013",
                    Severity = ProcessMessageSeverity.Error,
                    Description = @"Each Statement of Distribution must contain distribution amounts",
                    LongDescription = @"A Statement of distribution must include an amount against at least one of: Primary production income, Non-primary production income, Franked distributions, Franking credit, TFN amounts withheld, Australian franking credit from a NZ company, Capital gains, Share of credit for foreign resident capital gains withholding amounts, Attributed foreign income, Other assessable foreign source income, Foreign income tax offset.",
                    Location = "/tns:DISTBENTRT/tns:RP/tns:StatementOfDistributionToBeneficiaryCollection/tns:StatementOfDistributionToBeneficiary/tns:Information/tns:ShareOfIncomePrimaryProduction/tns:BeneficiaryShareA",
                    Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() { Name = "RuleIdentifier", Value = "VR.ATO.DISTBENTRT.000013" } },
                };
                processMessage.Parameters.Add(new ProcessMessageParameter
                    { Name = "DISTBENTRT5", Value = "DISTBENTRT5" });
    
                processMessage.Parameters.Add(new ProcessMessageParameter
                    { Name = "DISTBENTRT29", Value = "DISTBENTRT29" });
    
                processMessage.Parameters.Add(new ProcessMessageParameter
                    { Name = "DISTBENTRT32", Value = "DISTBENTRT32" });
    
                processMessage.Parameters.Add(new ProcessMessageParameter
                    { Name = "DISTBENTRT11", Value = "DISTBENTRT11" });
    
                processMessage.Parameters.Add(new ProcessMessageParameter
                    { Name = "DISTBENTRT12", Value = "DISTBENTRT12" });
    
                processMessage.Parameters.Add(new ProcessMessageParameter
                    { Name = "DISTBENTRT13", Value = "DISTBENTRT13" });
    
                processMessage.Parameters.Add(new ProcessMessageParameter
                    { Name = "DISTBENTRT8", Value = "DISTBENTRT8" });
    
                processMessage.Parameters.Add(new ProcessMessageParameter
                    { Name = "DISTBENTRT15", Value = "DISTBENTRT15" });
    
                processMessage.Parameters.Add(new ProcessMessageParameter
                    { Name = "DISTBENTRT22", Value = "DISTBENTRT22" });
    
                processMessage.Parameters.Add(new ProcessMessageParameter
                    { Name = "DISTBENTRT23", Value = "DISTBENTRT23" });
    
                processMessage.Parameters.Add(new ProcessMessageParameter
                    { Name = "DISTBENTRT24", Value = "DISTBENTRT24" });
    
                processMessage.Parameters.Add(new ProcessMessageParameter
                    { Name = "DISTBENTRT25", Value = "DISTBENTRT25" });
    
                response.Add(processMessage);
            }
      }
      #endregion 
    
      #region VR.ATO.DISTBENTRT.000014
      [MethodImpl(MethodImplOptions.AggressiveInlining)]
      public virtual void VRATODISTBENTRT000014(DISTBENTRT2024.RP_StatementOfDistributionToBeneficiary statementOfDistributionToBeneficiary, int itemIndex2)
      {
        ProcessMessageDocument processMessage;
        bool assertion;
            
                    /*  VR.ATO.DISTBENTRT.000014
                    Franking credit or TFN amount withheld is present in the distribution statement and there is no non-primary production income amount or franked distributions amount. Zero is acceptable when there is an overall trust loss.
    
                    Legacy Rule Format:
                    (^DISTBENTRT12 > 0 OR ^DISTBENTRT13 > 0) AND ^DISTBENTRT32 = NULL AND ^DISTBENTRT11 = NULL
        
                    Technical Business Rule Format:
                    (^DISTBENTRT12 > 0 OR ^DISTBENTRT13 > 0) AND ^DISTBENTRT32 = NULL AND ^DISTBENTRT11 = NULL
            
                    Data Elements:
            
                    ^DISTBENTRT32 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:ShareOfIncomeNonPrimaryProduction:Income.BeneficiaryShare.Amount
            
                    ^DISTBENTRT11 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:Income.DistributionFranked.Amount
            
                    ^DISTBENTRT12 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:IncomeTax.FrankingCredits.ReceivedFromAustralianCompanies.Amount
            
                    ^DISTBENTRT13 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:Information:IncomeTax.PayAsYouGoWithholding.CreditForAmountsWithheldWhereTFNNotQuoted.Amount
                    */
                    assertion = ((statementOfDistributionToBeneficiary.DISTBENTRT12.GetValueOrDefault() > 0 || statementOfDistributionToBeneficiary.DISTBENTRT13.GetValueOrDefault() > 0) && statementOfDistributionToBeneficiary.DISTBENTRT32 == null && statementOfDistributionToBeneficiary.DISTBENTRT11 == null);
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.DISTBENTRT.000014",
                            Severity = ProcessMessageSeverity.Error,
                            Description = @"Non-PP income or franked distributions amount must be present in Statement of distribution",
                            LongDescription = @"If within a Statement of Distribution ''Franking credit' or 'TFN amount withheld' is present, then there must be an amount at 'Non-primary production income' or 'Franked distributions'. Zero is acceptable if there is an overall trust loss.",
                            Location = "/tns:DISTBENTRT/tns:RP/tns:StatementOfDistributionToBeneficiaryCollection/tns:StatementOfDistributionToBeneficiary" + OccurrenceIndex(statementOfDistributionToBeneficiary.OccurrenceIndex) + "/tns:Information/tns:ShareOfIncomeNonPrimaryProduction/tns:BeneficiaryShareA",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() { Name = "RuleIdentifier", Value = "VR.ATO.DISTBENTRT.000014" } },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "DISTBENTRT12", Value = GetValueOrEmpty(statementOfDistributionToBeneficiary.DISTBENTRT12) });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "DISTBENTRT13", Value = GetValueOrEmpty(statementOfDistributionToBeneficiary.DISTBENTRT13) });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "DISTBENTRT32", Value = GetValueOrEmpty(statementOfDistributionToBeneficiary.DISTBENTRT32) });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "DISTBENTRT11", Value = GetValueOrEmpty(statementOfDistributionToBeneficiary.DISTBENTRT11) });
            
                        response.Add(processMessage);
                    }
              }
              #endregion 
    
      #region VR.ATO.DISTBENTRT.000015
      [MethodImpl(MethodImplOptions.AggressiveInlining)]
      public virtual void VRATODISTBENTRT000015(DISTBENTRT2024.RP_StatementOfDistributionToBeneficiary statementOfDistributionToBeneficiary, int itemIndex2)
      {
        ProcessMessageDocument processMessage;
        bool assertion;
            
                    /*  VR.ATO.DISTBENTRT.000015
                    Australian Company Number must pass the ACN algorithm check.
    
                    Legacy Rule Format:
                    ^DISTBENTRT41 <> NULL AND FailsACNAlgorithm(^DISTBENTRT41)
        
                    Technical Business Rule Format:
                    ^DISTBENTRT41 <> NULL AND FailsACNAlgorithm(^DISTBENTRT41)
            
                    Data Elements:
            
                    ^DISTBENTRT41 = DISTBENTRT:RP:StatementOfDistributionToBeneficiary:DistributingTrust:Identifiers.AustralianCompanyNumber.Identifier
                    */
                    assertion = (statementOfDistributionToBeneficiary.DISTBENTRT41 != null && FailsACNAlgorithm(statementOfDistributionToBeneficiary.DISTBENTRT41));
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.DISTBENTRT.000015",
                            Severity = ProcessMessageSeverity.Error,
                            Description = @"Australian Company Number has failed the algorithm check",
                            Location = "/tns:DISTBENTRT/tns:RP/tns:StatementOfDistributionToBeneficiaryCollection/tns:StatementOfDistributionToBeneficiary" + OccurrenceIndex(statementOfDistributionToBeneficiary.OccurrenceIndex) + "/tns:DistributingTrust/tns:AustralianCompanyNumberId",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() { Name = "RuleIdentifier", Value = "VR.ATO.DISTBENTRT.000015" } },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "DISTBENTRT41", Value = GetValueOrEmpty(statementOfDistributionToBeneficiary.DISTBENTRT41) });
            
                        response.Add(processMessage);
                    }
              }
              #endregion 

    }
} 
