<commit_before>﻿using System;
using System.Collections.Generic;
using System.Linq;
using log4net;
using NDesk.Options;
using Villermen.RuneScapeCacheTools.Audio;
using Villermen.RuneScapeCacheTools.Cache;
using Villermen.RuneScapeCacheTools.Cache.Downloader;
using Villermen.RuneScapeCacheTools.Cache.RuneTek5;

namespace Villermen.RuneScapeCacheTools.CLI
{
	internal static class Program
	{
		/// <summary>
		/// Even when not used, this needs to be here to initialize the logging system.
		/// </summary>
		private static readonly ILog Logger = LogManager.GetLogger(typeof(Program));

		private static CacheBase Cache { get; set; }

        private static string CacheDirectory { get; set; }

        private static string OutputDirectory { get; set; }

        private static string TemporaryDirectory { get; set; }

        private static int TriggeredActions { get; set; }

		private static IEnumerable<Index> Indexes { get; set; }

		private static IEnumerable<int> FileIds { get; set; }

		private static bool DoExtract { get; set; }

		private static bool Overwrite { get; set; }

		private static bool Lossless { get; set; }

        private static bool DoSoundtrackCombine { get; set; }

        private static IEnumerable<string> SoundtrackNameFilter { get; set; }

        private static bool Download { get; set; }

		private static readonly OptionSet ArgumentParser = new OptionSet
		{
			{
				"cache-directory=|c",
				"The directory in which RuneScape's cache files are located. If unspecified, the default directory will be attempted.",
				value =>
				{
					CacheDirectory = value;
				}
			},
		    {
		        "download|d",
                "Download all requested files straight from Jagex's servers instead of using a local cache.",
		        value =>
		        {
		            Download = value != null;
		        }
		    },
			{
				"output-directory=|o",
				"The directory in which output files (mainly extracted files) will be stored.",
				value =>
				{
					OutputDirectory = value;
				}
			},
			{
				"temporary-directory=|t",
				"The directory in which temporary files will be stored. If unspecified, the system's default directory + \"rsct\" will be used.",
				value =>
				{
					TemporaryDirectory = value;
				}
			},
			{
				"extract|e",
				"Extract all files from the cache. You can specify which files to extract by using the index and file arguments.",
				value =>
				{
					DoExtract = (value != null);
					TriggeredActions++;
				}
			},
			{
				"index=|i",
                "A index id or range of index ids to extract. E.g. \"1-2,4,6-7\".",
				value =>
				{
					Indexes = ExpandIntegerRangeString(value).Cast<Index>();
				}
			},
			{
				"file=|f",
                "A file id or range of file ids to extract. E.g. \"1-2,4,6-7\".",
				value =>
				{
					FileIds = ExpandIntegerRangeString(value);
				}
			},
			{
				"overwrite",
                "Overwrite extracted files if they already exist.",
				value =>
				{
					Overwrite = (value != null);
				}
			},
			{
				"soundtrack-combine:|s",
                "Extract and name the soundtrack, optionally filtered by the given comma-separated name filters.",
				value =>
				{
				    DoSoundtrackCombine = true;

                    if (!string.IsNullOrWhiteSpace(value))
				    {
				        SoundtrackNameFilter = ExpandListString(value);
				    }

				    TriggeredActions++;
				}
			},
		    {
		        "lossless",
                "Use FLAC instead of OGG as audio format when combining, preventing quality loss.",
		        value =>
		        {
		            Lossless = (value != null);
		        }
		    },
			{
				"help|h|?",
                "Show this message.",
                value =>
				{
					ShowHelp();

					TriggeredActions++;
				}
			}
		};

		private static int Main(string[] args)
		{
		    var returnCode = 0;

			try
			{
				var unknownArguments = ArgumentParser.Parse(args);

				// Show supplied argument that could not be parsed
				foreach (var unknownArgument in unknownArguments)
				{
					Console.WriteLine($"Unknown argument \"{unknownArgument}\".");
				}

				if (unknownArguments.Count > 0)
				{
					Console.WriteLine();
				}

				// Show help when no action arguments are specified. This is considered an error as it is unexpected.
				if (TriggeredActions == 0 && args.Length > 0)
				{
					Console.WriteLine("No action arguments specified.");
					Console.WriteLine();
					ShowHelp();

				    returnCode = 1;
				}

                // Initialize the cache
                Cache = Download ? (CacheBase)new CacheDownloader() : new RuneTek5Cache(CacheDirectory);

			    if (OutputDirectory != null)
			    {
			        Cache.OutputDirectory = OutputDirectory;
			    }

			    if (TemporaryDirectory != null)
			    {
			        Cache.TemporaryDirectory = TemporaryDirectory;
                }

				// Perform the specified actions
				if (DoExtract)
				{
					Extract();
				}

				if (DoSoundtrackCombine)
				{
					CombineSoundtrack();
				}
			}
			catch (Exception exception) when (exception is OptionException || exception is CacheException || exception is CLIException)
			{
			    Console.WriteLine(exception);

			    returnCode = 1;
			}
			catch (Exception exception)
			{
				Console.WriteLine(exception);

			    returnCode = 1;
			}

#if DEBUG
            Console.ReadLine();
#endif

            return returnCode;
        }

        /// <summary>
        ///   Expands the given integer range into an enumerable of all individual integers.<commit_msg>Better dealing with CLI arguments<commit_after>﻿using System;
using System.Collections.Generic;
using System.Linq;
using log4net;
using NDesk.Options;
using Villermen.RuneScapeCacheTools.Audio;
using Villermen.RuneScapeCacheTools.Cache;
using Villermen.RuneScapeCacheTools.Cache.Downloader;
using Villermen.RuneScapeCacheTools.Cache.RuneTek5;

namespace Villermen.RuneScapeCacheTools.CLI
{
	internal static class Program
	{
		/// <summary>
		/// Even when not used, this needs to be here to initialize the logging system.
		/// </summary>
		private static readonly ILog Logger = LogManager.GetLogger(typeof(Program));

		private static CacheBase Cache { get; set; }

        private static string CacheDirectory { get; set; }

        private static string OutputDirectory { get; set; }

        private static string TemporaryDirectory { get; set; }

        private static int TriggeredActions { get; set; }

		private static IEnumerable<Index> Indexes { get; set; }

		private static IEnumerable<int> FileIds { get; set; }

		private static bool DoExtract { get; set; }

		private static bool Overwrite { get; set; }

		private static bool Lossless { get; set; }

        private static bool DoSoundtrackCombine { get; set; }

        private static IEnumerable<string> SoundtrackNameFilter { get; set; }

        private static bool Download { get; set; }

		private static readonly OptionSet ArgumentParser = new OptionSet
		{
			{
				"cache-directory=|c",
				"The directory in which RuneScape's cache files are located. If unspecified, the default directory will be attempted.",
				value =>
				{
					CacheDirectory = value;
				}
			},
		    {
		        "download|d",
                "Download all requested files straight from Jagex's servers instead of using a local cache.",
		        value =>
		        {
		            Download = value != null;
		        }
		    },
			{
				"output-directory=|o",
				"The directory in which output files (mainly extracted files) will be stored.",
				value =>
				{
					OutputDirectory = value;
				}
			},
			{
				"temporary-directory=|t",
				"The directory in which temporary files will be stored. If unspecified, the system's default directory + \"rsct\" will be used.",
				value =>
				{
					TemporaryDirectory = value;
				}
			},
			{
				"extract|e",
				"Extract all files from the cache. You can specify which files to extract by using the index and file arguments.",
				value =>
				{
					DoExtract = (value != null);
					TriggeredActions++;
				}
			},
			{
				"index=|i",
                "A index id or range of index ids to extract. E.g. \"1-2,4,6-7\".",
				value =>
				{
					Indexes = ExpandIntegerRangeString(value).Cast<Index>();
				}
			},
			{
				"file=|f",
                "A file id or range of file ids to extract. E.g. \"1-2,4,6-7\".",
				value =>
				{
					FileIds = ExpandIntegerRangeString(value);
				}
			},
			{
				"overwrite",
                "Overwrite extracted files if they already exist.",
				value =>
				{
					Overwrite = (value != null);
				}
			},
			{
				"soundtrack-combine:|s",
                "Extract and name the soundtrack, optionally filtered by the given comma-separated name filters.",
				value =>
				{
				    DoSoundtrackCombine = true;

                    if (!string.IsNullOrWhiteSpace(value))
				    {
				        SoundtrackNameFilter = ExpandListString(value);
				    }

				    TriggeredActions++;
				}
			},
		    {
		        "lossless",
                "Use FLAC instead of OGG as audio format when combining, preventing quality loss.",
		        value =>
		        {
		            Lossless = (value != null);
		        }
		    },
			{
				"help|h|?",
                "Show this message.",
                value =>
				{
					ShowHelp();

					TriggeredActions++;
				}
			}
		};

		private static int Main(string[] args)
		{
#if DEBUG
		    Console.WriteLine("RSCT DEBUG BUILD");
            Console.WriteLine();
#endif
            int returnCode;

			try
			{
				var unknownArguments = ArgumentParser.Parse(args);
			    var run = true;

                // Show supplied argument that could not be parsed
				if (unknownArguments.Count > 0)
				{
                    run = false;

                    foreach (var unknownArgument in unknownArguments)
                    {
                        Console.WriteLine($"Unknown argument \"{unknownArgument}\".");
                        Console.WriteLine();
                    }
				}

				// Show help when no action arguments are specified. This is considered an error as it is unexpected.
			    if (TriggeredActions == 0)
			    {
                    run = false;

                    if (args.Length > 0)
			        {
                        Console.WriteLine("No action specified.");
			            Console.WriteLine();
			        }
			    }

                // Perform the action if everything is ok
                if (run)
			    {
			        // Initialize the cache
			        Cache = Download ? (CacheBase)new CacheDownloader() : new RuneTek5Cache(CacheDirectory);

			        if (OutputDirectory != null)
			        {
			            Cache.OutputDirectory = OutputDirectory;
			        }

			        if (TemporaryDirectory != null)
			        {
			            Cache.TemporaryDirectory = TemporaryDirectory;
			        }

			        // Perform the specified actions
			        if (DoExtract)
			        {
			            Extract();
			        }

			        if (DoSoundtrackCombine)
			        {
			            CombineSoundtrack();
			        }

			        returnCode = 0;
			    }
                else
                {
                    // Show help if something went wrong during argument parsing
                    ShowHelp();

                    returnCode = 1;
                }
			}
			catch (Exception exception) when (exception is OptionException || exception is CacheException || exception is CLIException)
			{
			    Console.WriteLine(exception);

			    returnCode = 1;
			}
			catch (Exception exception)
			{
				Console.WriteLine(exception);

			    returnCode = 1;
			}

#if DEBUG
            Console.ReadLine();
#endif

            return returnCode;
        }

        /// <summary>
        ///   Expands the given integer range into an enumerable of all individual integers.
{'fraction_non_alphanumeric': 0.09733615221987316, 'fraction_numerical': 0.0033826638477801266, 'mean_word_length': 1.9301288404360752, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7567716', 'n_tokens_mistral': 4049, 'n_tokens_neox': 3127, 'n_words': 955}