/// <summary>
        /// This method checks if validation rules have been set properly for all rules if not returns reason explaining what has not been set.
        /// </summary>
        /// <param name="holidayRule">List of rules to be validated.</param>
        /// <returns>Text explaining what has not been set properly for which rule. If all configuration valid returns null </returns>
        public string ValidateHolidayRule(HolidayRule holidayRule)
        {
            string validationMessage                  = null;
            var    ruleConfigurationValid             = true;
            HolidayRuleValidator holidayRuleValidator = new HolidayRuleValidator();

            // Check if configuration valid for Always_Same_Day
            if (holidayRule.Always_Same_Day != null)
            {
                validationMessage = holidayRuleValidator.Validate_Rule_Always_Same_Day <Always_Same_Day>(holidayRule.Always_Same_Day);

                if (validationMessage != null)
                {
                    ruleConfigurationValid = false;
                }
            }

            // Check if configuration is valid for Always_On_Same_Day_Except_Weekend
            if (ruleConfigurationValid && holidayRule.Always_On_Same_Day_Except_Weekend != null)
            {
                validationMessage = holidayRuleValidator.Validate_Rule_Always_Same_Day <Always_On_Same_Day_Except_Weekend>(holidayRule.Always_On_Same_Day_Except_Weekend);

                if (validationMessage != null)
                {
                    ruleConfigurationValid = false;
                }
            }

            // Check if configuration is valid for Always_On_Same_Day_Except_Weekend
            if (ruleConfigurationValid && holidayRule.Nth_Occurance_Given_Month_Given_Week != null)
            {
                validationMessage = holidayRuleValidator.Validate_Rule_Nth_Occurance_Given_Month_Given_Week(holidayRule.Nth_Occurance_Given_Month_Given_Week);
            }

            return(validationMessage);
        }
        /// <summary>
        /// This takes two dates, applies rules specified for holidays and returns business days between two dates(exclusive)
        /// </summary>
        /// <param name="firstDate"> date to start counting business day from (exclusive)</param>
        /// <param name="secondDate">date to stop counting business day to (exclusive) </param>
        /// <param name="holidayRule">list of rules specifying holidays</param>
        /// <returns> tuple containing no of Business days between two dates and validation message if validation failed </returns>
        public Tuple <int, string> BusinessDaysBetweenTwoDates(DateTime firstDate, DateTime secondDate, HolidayRule holidayRule)
        {
            List <DateTime> resultDateList          = new List <DateTime>();
            List <DateTime> holidayOnWeekEndList    = new List <DateTime>();
            List <DateTime> dateRange               = new List <DateTime>();
            List <DateTime> selectedDates_Week_Days = new List <DateTime>();
            List <DateTime> selectedDates_WeekEnds  = new List <DateTime>();

            try
            {
                string validationMessage    = null;
                var    holidayRuleValidator = new HolidayRuleValidator();

                if (holidayRule != null)
                {
                    validationMessage = holidayRuleValidator.ValidateHolidayRule(holidayRule);

                    // If rules configuration is valid allow to proceed further.
                    if (validationMessage == null)
                    {
                        var DateHelper = new DateHelper();

                        dateRange = DateHelper.GetSelectedDateRange(firstDate, secondDate);
                        selectedDates_Week_Days = DateHelper.GetWeekDays(dateRange);
                        selectedDates_WeekEnds  = DateHelper.GetWeekEnds(dateRange);

                        // Find holidays which are always on same day and falls on week days.
                        foreach (Always_Same_Day always_Same_Day_Rule in holidayRule.Always_Same_Day)
                        {
                            resultDateList.AddRange(selectedDates_Week_Days.ToList().FindAll(d => d.Day == always_Same_Day_Rule.Day &&
                                                                                             d.Month == always_Same_Day_Rule.Month &&
                                                                                             !resultDateList.Any(rs => rs == d)));
                        }

                        // Find holidays which are always on same day except on weekend.
                        foreach (Always_On_Same_Day_Except_Weekend always_On_Same_Day_Except_Weekend in holidayRule.Always_On_Same_Day_Except_Weekend)
                        {
                            // Always on same day except on weekend, which are not on weekends
                            resultDateList.AddRange(selectedDates_Week_Days.ToList().FindAll(d => d.Day == always_On_Same_Day_Except_Weekend.Day &&
                                                                                             d.Month == always_On_Same_Day_Except_Weekend.Month &&
                                                                                             !resultDateList.Any(rs => rs == d)));

                            // So we are only interested in weekends which also are public holidays and are part of Always_On_Same_Day_Except_Weekend
                            holidayOnWeekEndList = selectedDates_WeekEnds.ToList().FindAll(d => d.Day == always_On_Same_Day_Except_Weekend.Day &&
                                                                                           d.Month == always_On_Same_Day_Except_Weekend.Month);
                        }

                        // Find holidays which falls on Nth occurrence of given week day in given month.
                        foreach (Nth_Occurrence_Given_Month_Given_Week objRule in holidayRule.Nth_Occurance_Given_Month_Given_Week)
                        {
                            // We only need to consider week day as week end has already been taken care of.
                            resultDateList.AddRange(selectedDates_Week_Days.ToList().FindAll(d => d.Month == objRule.Month &&
                                                                                             Convert.ToInt32(d.DayOfWeek) == objRule.DayOfWeek &&
                                                                                             d.Date == DateHelper.GetDayOfMonth(d.Date
                                                                                                                                , Convert.ToInt32(objRule.WeekOfMonth), Convert.ToInt32(objRule.DayOfWeek))));
                        }
                    }
                }

                return(Tuple.Create(selectedDates_Week_Days.Count - (resultDateList.Count + holidayOnWeekEndList.Count), validationMessage));
            }
            catch (Exception ex)
            {
                return(Tuple.Create(0, "A fatal error occurred while calculating business days"));
            }
            finally
            {
                resultDateList          = null;
                holidayOnWeekEndList    = null;
                dateRange               = null;
                selectedDates_Week_Days = null;
                selectedDates_WeekEnds  = null;
            }
        }