/// <summary>
        /// Entrypoint of this program which parses the following arguments from the CLI:
        /// <list type="bullet">
        /// <item><code>--raw-dir</code>: The path to output directory to put the raw downloaded files in</item>
        /// <item><code>--processed-dir</code>: The path to the directory to put the processed files in</item>
        /// <item><code>--fetch-url</code>: The url to download to use as raw data</item>
        /// </list>
        /// </summary>
        /// <param name="args">The arguments passed from the command line</param>
        public static void Main(string[] args)
        {
            List <string> arguments = new List <string>();

            arguments.AddRange(args);

            // Print the help section when requested
            string[] helpLong  = FindOption(arguments, "--help", 0);
            string[] helpShort = FindOption(arguments, "-h", 0);
            if (helpLong != null || helpShort != null)
            {
                PrintHelp();
                return;
            }

            // First parse the interval, if available
            string[]        intervalOption = FindOption(arguments, "--interval");
            IntervalRange[] intervalRanges = null;
            if (intervalOption != null)
            {
                intervalRanges = IntervalRange.GetIntervals(intervalOption[0], Console.Error);
                if (intervalRanges == null)
                {
                    Environment.Exit(1);
                }
            }

            DataWriterOption selectedOption = null;

            DataWriterOption[] availableOptions =
            {
                new DbDataWriterOption(), new FileDataWriterOption()
            };

            foreach (DataWriterOption option in availableOptions)
            {
                if (option.isAvailable(arguments))
                {
                    if (!option.validArguments())
                    {
                        Environment.Exit(1);
                    }
                    selectedOption = option;
                    break;
                }
            }

            // Parse the arguments
            Options options = new Options
            {
                RawDataOutput       = GetDirectory(arguments, "--raw-dir"),
                ProcessedDataOutput = GetDirectory(arguments, "--processed-dir"),
                ReaderOption        = GetEnumOption <ReaderOption>(arguments, "--reader"),
                DataWriterOption    = selectedOption,
                RemoveRawFiles      = FindOption(arguments, "--remove-raw", 0) != null
            };

            // Parse the Fetch url
            string[] urlOption = FindOption(arguments, "--fetch-url");
            if (urlOption != null)
            {
                Uri fetchUrl;
                if (!Uri.TryCreate(urlOption[0], UriKind.Absolute, out fetchUrl) ||
                    (fetchUrl.Scheme != Uri.UriSchemeHttp && fetchUrl.Scheme != Uri.UriSchemeHttps))
                {
                    Console.Error.WriteLine($"Invalid fetch url {urlOption[0]}");
                    Environment.Exit(1);
                }

                options.FetchUri = fetchUrl;
            }

            BaseAction action = new DownloadAndProcessAction(options);

            if (intervalRanges == null)
            {
                action.Execute();
            }
            else
            {
                IntervalScheduler intervalScheduler = new IntervalScheduler(action, intervalRanges);
                intervalScheduler.RunScheduler(CancellationToken.None);
            }
        }
        static void Main(string[] args)
        {
            // Check if we need to print help by checking for -h or --help at the first or second index
            // Also, when fewer arguments are available, print the help
            int shortIndex = Array.IndexOf(args, "-h");
            int longIndex  = Array.IndexOf(args, "--help");

            if (args.Length < 2 || shortIndex == 0 || shortIndex == 1 || longIndex == 0 || longIndex == 1)
            {
                PrintHelp();
                return;
            }

            int  commandIndex = 1;
            byte runOnDays    = 0;

            if (args[1] == "--days")
            {
                commandIndex += 2;
                string[] splitDays = args[2].Split(",");

                for (int i = 0; i < splitDays.Length; i++)
                {
                    if (splitDays[i].Length == 1)
                    {
                        // Attempt to parse it as an integer
                        int dayIndex;
                        if (int.TryParse(splitDays[i], out dayIndex))
                        {
                            Day?foundIntDay = DayUtils.FindDay(dayIndex);
                            if (foundIntDay.HasValue)
                            {
                                runOnDays |= (byte)foundIntDay.Value;
                                continue;
                            }
                        }
                    }
                    // Attempt to find the day as valid string
                    Day?foundStrDay = DayUtils.FindDay(splitDays[i]);
                    if (!foundStrDay.HasValue)
                    {
                        Console.Error.WriteLine($"Invalid day: {splitDays[i]}");
                        Environment.Exit(1);
                    }
                    runOnDays |= (byte)foundStrDay.Value;
                }
            }

            string commandFileName  = args[commandIndex++];
            string commandArguments = CommandAction.BuildArguments(args, commandIndex);

            IntervalRange[] intervals = IntervalRange.GetIntervals(args[0], Console.Error);
            if (intervals == null)
            {
                Environment.Exit(1);
            }

            IntervalScheduler intervalScheduler = new IntervalScheduler(
                new CommandAction(commandFileName, commandArguments), intervals);

            if (runOnDays != 0)
            {
                intervalScheduler.SetDayFlags(runOnDays);
            }

            intervalScheduler.RunScheduler(CancellationToken.None);
        }