using System;
using System.Collections.Generic;
using System.Reflection;
namespace ln.application
{
///
/// Argument container.
///
///
/// This class parses command line arguments to a list of predefined well known arguments.
/// Remaining arguments will be found in AdditionalArguments.
///
/// ArgumentContainer also provides a global command line option:
/// --change-static typename fieldname value
/// It may be used multiple times on the command line.
/// It will load the type referenced by the qualified name typename and try to set the static field fieldname to value.
/// value will be casted to field type via Convert.ChangeType(...)
///
public class ArgumentContainer
{
private Dictionary shortOptionArguments = new Dictionary();
private Dictionary longOptionArguments = new Dictionary();
public ArgumentContainer()
{
}
public ArgumentContainer(IEnumerable argumentDefinitions)
{
AddRange(argumentDefinitions);
}
public ArgumentContainer(Type type)
{
AddStaticOptions(type);
}
public IArgument this[string optionName] => longOptionArguments[optionName];
public IArgument this[char option] => shortOptionArguments[option];
public bool Contains(string optionName) =>longOptionArguments.ContainsKey(optionName);
public bool Contains(char option) => shortOptionArguments.ContainsKey(option);
public ArgumentContainer AddRange(IEnumerable arguments)
{
foreach (IArgument argument in arguments)
Add(argument);
return this;
}
public ArgumentContainer Add(IArgument argument)
{
if (argument.OptionName > 0)
shortOptionArguments.Add(argument.OptionName,argument);
if (argument.LongOptionName != null)
longOptionArguments.Add(argument.LongOptionName, argument);
return this;
}
public ArgumentContainer Add(char shortName) => Add(new Argument(shortName, null));
public ArgumentContainer Add(string longName) => Add(new Argument((char)0, longName));
public ArgumentContainer Add(char shortName, string longName) => Add(new Argument(shortName, longName));
public ArgumentContainer Add(char shortName, string longName, string defaultValue) => Add(new Argument(shortName, longName, defaultValue));
public ArgumentContainer Add(int shortName, string longName, string defaultValue) => Add(new Argument((char)shortName, longName, defaultValue));
public string[] Parse(IEnumerable args)
{
List unusedArguments = new List();
Queue q = new Queue(args);
while (q.Count > 0)
{
string currentOption = q.Dequeue();
if (currentOption[0].Equals('-'))
{
if (currentOption[1].Equals('-'))
{
String aname = currentOption.Substring(2);
if (aname.Equals("change-static"))
{
string typeName = q.Dequeue();
string fieldName = q.Dequeue();
string value = q.Dequeue();
ChangeStatic(typeName, fieldName, value);
}
else if (Contains(aname))
{
IArgument argument = this[aname];
argument.Value = argument.HasArgument ? q.Dequeue() : "";
} else
{
unusedArguments.Add("--" + aname);
}
}
else
{
foreach (char option in currentOption.Substring(1))
{
IArgument argument = this[option];
argument.Value = argument.HasArgument ? q.Dequeue() : "";
}
}
}
else
{
unusedArguments.Add(currentOption);
}
}
return unusedArguments.ToArray();
}
public void Parse(ref string[] args) => args = Parse(args);
public static string[] ApplyArguments(string[] arguments)
{
ArgumentContainer argumentContainer = new ArgumentContainer();
argumentContainer.AddStaticOptions(typeof(T));
return argumentContainer.Parse(arguments);
}
public static void ApplyArguments(ref string[] arguments)
{
arguments = ApplyArguments(arguments);
}
public static string[] ApplyArguments(T instance,string[] arguments)
{
ArgumentContainer argumentContainer = new ArgumentContainer();
argumentContainer.AddOptions(instance);
return argumentContainer.Parse(arguments);
}
public static void ApplyArguments(T instance,ref string[] arguments)
{
arguments = ApplyArguments(instance, arguments);
}
public ArgumentContainer AddStaticOptions(Type type)
{
foreach (FieldInfo fieldInfo in type.GetFields(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public))
{
if (fieldInfo.GetCustomAttribute() != null)
Add(new FieldArgument(fieldInfo, fieldInfo.GetCustomAttribute()));
}
foreach (PropertyInfo propertyInfo in type.GetProperties(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public))
{
if (propertyInfo.GetCustomAttribute() != null)
Add(new PropertyArgument(propertyInfo, propertyInfo.GetCustomAttribute()));
}
return this;
}
public ArgumentContainer AddOptions(T instance)
{
foreach (FieldInfo fieldInfo in typeof(T).GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public))
{
if (fieldInfo.GetCustomAttribute() != null)
Add(new FieldArgument(instance, fieldInfo));
}
foreach (PropertyInfo propertyInfo in typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public))
{
if (propertyInfo.GetCustomAttribute() != null)
Add(new PropertyArgument(instance, propertyInfo));
}
return this;
}
public ArgumentContainer AddStaticOptions() => AddStaticOptions(typeof(T));
public void ChangeStatic(string typeName,string fieldname,string value)
{
Type type = Type.GetType(typeName);
FieldInfo fieldInfo = type.GetField(fieldname, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
object castValue = Convert.ChangeType(value, fieldInfo.FieldType);
fieldInfo.SetValue(null,castValue);
}
}
}