using System;
using System.Linq;

namespace AdvertsingProfitControl
{
    internal class Holiday
    {
        public static Holidays IsHoliday(DateTime date)
        {
            if(IsNewYearsDay(date) == Holidays.NewYearsDay) return Holidays.NewYearsDay;
            if(IsFourthOfJuly(date) == Holidays.FourthOfJuly) return Holidays.FourthOfJuly;
            if(IsThanksgivingDay(date) == Holidays.Thanksgiving) return Holidays.Thanksgiving;
            return IsChristmasDay(date) == Holidays.Christmas ? Holidays.Christmas : Holidays.NoHoliday;
        }
        public static Holidays IsNewYearsEve(DateTime date)
        {
            return date.DayOfYear == AdjustForWeekendHoliday(new DateTime(date.Year, 12, 31)).DayOfYear ? Holidays.NewYearsEve : Holidays.NoHoliday;
        }
        public static Holidays IsNewYearsDay(DateTime date)
        {            
            return date.DayOfYear == AdjustForWeekendHoliday(new DateTime(date.Year, 1, 1)).DayOfYear ? Holidays.NewYearsDay : Holidays.NoHoliday;
        }
        public static Holidays IsMemorialDay(DateTime date)
        { //Last Monday in May
            var memorialDay = new DateTime(date.Year, 5, 31);
            var dayOfWeek = memorialDay.DayOfWeek;
            while (dayOfWeek != DayOfWeek.Monday)
            {
                memorialDay = memorialDay.AddDays(-1);
                dayOfWeek = memorialDay.DayOfWeek;
            }
            return date.DayOfYear == memorialDay.DayOfYear ? Holidays.MemorialDay : Holidays.NoHoliday;
        }
        public static Holidays IsFourthOfJuly(DateTime date)
        {
            return date.DayOfYear == AdjustForWeekendHoliday(new DateTime(date.Year, 7, 4)).DayOfYear ? Holidays.FourthOfJuly : Holidays.NoHoliday;
        }
        public static Holidays IsLaborDay(DateTime date)
        { // First Monday in September
            var laborDay = new DateTime(date.Year, 9, 1);
            var dayOfWeek = laborDay.DayOfWeek;
            while (dayOfWeek != DayOfWeek.Monday)
            {
                laborDay = laborDay.AddDays(1);
                dayOfWeek = laborDay.DayOfWeek;
            }
            return date.DayOfYear == laborDay.DayOfYear ? Holidays.LaborDay : Holidays.NoHoliday;
        }
        public static Holidays IsThanksgivingDay(DateTime date)
        {//4th Thursday in November
            var thanksgiving = (from day in Enumerable.Range(1, 30)
                                where new DateTime(date.Year, 11, day).DayOfWeek == DayOfWeek.Thursday
                                select day).ElementAt(3);
            var thanksgivingDay = new DateTime(date.Year, 11, thanksgiving);
            return date.DayOfYear == thanksgivingDay.DayOfYear ? Holidays.Thanksgiving : Holidays.NoHoliday;
        }
        public static Holidays IsChristmasEve(DateTime date)
        {
            return date.DayOfYear == AdjustForWeekendHoliday(new DateTime(date.Year, 12, 24)).DayOfYear ? Holidays.ChristmasEve : Holidays.NoHoliday;
        }
        public static Holidays IsChristmasDay(DateTime date)
        {
            return date.DayOfYear == new DateTime(date.Year, 12, 25).DayOfYear ? Holidays.Christmas : Holidays.NoHoliday;
        }
        private static DateTime AdjustForWeekendHoliday(DateTime holiday)
        {
            switch (holiday.DayOfWeek)
            {
                case DayOfWeek.Saturday:
                    return holiday.AddDays(-1);
                case DayOfWeek.Sunday:
                    return holiday.AddDays(1);
            }
            return holiday;
        }
    }
    public enum Holidays
    {
        NoHoliday = 0,
        NewYearsEve = 1,
        NewYearsDay = 2,
        MemorialDay = 3,
        FourthOfJuly = 4,
        LaborDay = 5,
        Thanksgiving = 6,
        ChristmasEve = 7,
        Christmas = 8
    }
}
