using Swan.Reflection;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Swan.Parsers {
///
/// Provides methods to parse command line arguments.
/// Based on CommandLine (Copyright 2005-2015 Giacomo Stelluti Scala and Contributors.).
///
///
/// The following example shows how to parse CLI arguments into objects.
///
/// class Example
/// {
/// using System;
/// using Swan.Parsers;
///
/// static void Main(string[] args)
/// {
/// // parse the supplied command-line arguments into the options object
/// var res = Runtime.ArgumentParser.ParseArguments(args, out var options);
/// }
///
/// class Options
/// {
/// [ArgumentOption('v', "verbose", HelpText = "Set verbose mode.")]
/// public bool Verbose { get; set; }
///
/// [ArgumentOption('u', Required = true, HelpText = "Set user name.")]
/// public string Username { get; set; }
///
/// [ArgumentOption('n', "names", Separator = ',',
/// Required = true, HelpText = "A list of files separated by a comma")]
/// public string[] Files { get; set; }
///
/// [ArgumentOption('p', "port", DefaultValue = 22, HelpText = "Set port.")]
/// public int Port { get; set; }
///
/// [ArgumentOption("color", DefaultValue = ConsoleColor.Red,
/// HelpText = "Set a color.")]
/// public ConsoleColor Color { get; set; }
/// }
/// }
///
/// The following code describes how to parse CLI verbs.
///
/// class Example2
/// {
/// using Swan;
/// using Swan.Parsers;
///
/// static void Main(string[] args)
/// {
/// // create an instance of the VerbOptions class
/// var options = new VerbOptions();
///
/// // parse the supplied command-line arguments into the options object
/// var res = Runtime.ArgumentParser.ParseArguments(args, options);
///
/// // if there were no errors parsing
/// if (res)
/// {
/// if(options.Run != null)
/// {
/// // run verb was selected
/// }
///
/// if(options.Print != null)
/// {
/// // print verb was selected
/// }
/// }
///
/// // flush all error messages
/// Terminal.Flush();
/// }
///
/// class VerbOptions
/// {
/// [VerbOption("run", HelpText = "Run verb.")]
/// public RunVerbOption Run { get; set; }
///
/// [VerbOption("print", HelpText = "Print verb.")]
/// public PrintVerbOption Print { get; set; }
/// }
///
/// class RunVerbOption
/// {
/// [ArgumentOption('o', "outdir", HelpText = "Output directory",
/// DefaultValue = "", Required = false)]
/// public string OutDir { get; set; }
/// }
///
/// class PrintVerbOption
/// {
/// [ArgumentOption('t', "text", HelpText = "Text to print",
/// DefaultValue = "", Required = false)]
/// public string Text { get; set; }
/// }
/// }
///
///
public partial class ArgumentParser {
///
/// Initializes a new instance of the class.
///
public ArgumentParser() : this(new ArgumentParserSettings()) {
}
///
/// Initializes a new instance of the class,
/// configurable with using a delegate.
///
/// The parse settings.
public ArgumentParser(ArgumentParserSettings parseSettings) => this.Settings = parseSettings ?? throw new ArgumentNullException(nameof(parseSettings));
///
/// Gets the current.
///
///
/// The current.
///
public static ArgumentParser Current { get; } = new ArgumentParser();
///
/// Gets the instance that implements in use.
///
///
/// The settings.
///
public ArgumentParserSettings Settings {
get;
}
///
/// Parses a string array of command line arguments constructing values in an instance of type .
///
/// The type of the options.
/// The arguments.
/// The instance.
///
/// true if was converted successfully; otherwise, false.
///
///
/// The exception that is thrown when a null reference (Nothing in Visual Basic)
/// is passed to a method that does not accept it as a valid argument.
///
///
/// The exception that is thrown when a method call is invalid for the object's current state.
///
public Boolean ParseArguments(IEnumerable args, out T instance) {
instance = Activator.CreateInstance();
return this.ParseArguments(args, instance);
}
///
/// Parses a string array of command line arguments constructing values in an instance of type .
///
/// The type of the options.
/// The arguments.
/// The instance.
///
/// true if was converted successfully; otherwise, false.
///
///
/// The exception that is thrown when a null reference (Nothing in Visual Basic)
/// is passed to a method that does not accept it as a valid argument.
///
///
/// The exception that is thrown when a method call is invalid for the object's current state.
///
public Boolean ParseArguments(IEnumerable args, T instance) {
if(args == null) {
throw new ArgumentNullException(nameof(args));
}
if(Equals(instance, default(T))) {
throw new ArgumentNullException(nameof(instance));
}
TypeResolver typeResolver = new TypeResolver(args.FirstOrDefault());
Object options = typeResolver.GetOptionsObject(instance);
if(options == null) {
ReportUnknownVerb();
return false;
}
if(typeResolver.Properties == null) {
throw new InvalidOperationException($"Type {typeof(T).Name} is not valid");
}
Validator validator = new Validator(typeResolver.Properties, args, options, this.Settings);
if(validator.IsValid()) {
return true;
}
this.ReportIssues(validator);
return false;
}
private static void ReportUnknownVerb() {
Terminal.WriteLine("No verb was specified", ConsoleColor.Red);
Terminal.WriteLine("Valid verbs:", ConsoleColor.Cyan);
PropertyTypeCache.DefaultCache.Value.RetrieveAllProperties(true).Select(x => AttributeCache.DefaultCache.Value.RetrieveOne(x)).Where(x => x != null).ToList().ForEach(x => Terminal.WriteLine(x.ToString(), ConsoleColor.Cyan));
}
private void ReportIssues(Validator validator) {
if(this.Settings.WriteBanner) {
Terminal.WriteWelcomeBanner();
}
IEnumerable options = validator.GetPropertiesOptions();
foreach(ArgumentOptionAttribute option in options) {
Terminal.WriteLine(String.Empty);
// TODO: If Enum list values
String shortName = String.IsNullOrWhiteSpace(option.ShortName) ? String.Empty : $"-{option.ShortName}";
String longName = String.IsNullOrWhiteSpace(option.LongName) ? String.Empty : $"--{option.LongName}";
String comma = String.IsNullOrWhiteSpace(shortName) || String.IsNullOrWhiteSpace(longName) ? String.Empty : ", ";
String defaultValue = option.DefaultValue == null ? String.Empty : $"(Default: {option.DefaultValue}) ";
Terminal.WriteLine($" {shortName}{comma}{longName}\t\t{defaultValue}{option.HelpText}", ConsoleColor.Cyan);
}
Terminal.WriteLine(String.Empty);
Terminal.WriteLine(" --help\t\tDisplay this help screen.", ConsoleColor.Cyan);
if(validator.UnknownList.Any()) {
Terminal.WriteLine($"Unknown arguments: {String.Join(", ", validator.UnknownList)}", ConsoleColor.Red);
}
if(validator.RequiredList.Any()) {
Terminal.WriteLine($"Required arguments: {String.Join(", ", validator.RequiredList)}", ConsoleColor.Red);
}
}
}
}