private static void MapValuesToProperties(ParseResult result, object instance, IDictionary cfgValues)
        {
            foreach (Argument arg in cfgValues.Values)
            {
                // Try with the name given.
                var configParamAttribute = (ConfigParamAttribute) paramMap[arg.Name];

                if (configParamAttribute == null)
                {
                    // If not, try mapping it from long->short or short->long to see if we find it
                    var altName = nameMap[arg.Name];

                    if (altName != null)
                        configParamAttribute = (ConfigParamAttribute) paramMap[altName];
                }

                // If it's still null, give up, there's no param identified with that name
                if (configParamAttribute == null)
                {
                    result.UpdateStatus(false, arg.Index, arg.RawValue,
                                        "Unrecognized parameter '{0}'", arg.RawName);
                    return;
                }

                // Check for required value
                if (configParamAttribute.ValueRequired && (arg.Value == null || arg.Value.Trim().Length == 0))
                {
                    result.UpdateStatus(false, arg.Index, arg.Value, "A value is required for parameter '{0}'", arg.Name);
                }

                // Check for group stuff
                if (configParamAttribute.Group != null)
                {
                    var paramGroup = (ParamGroup) groupMap[configParamAttribute.Group];

                    if (paramGroup.ValueParamName != null)
                    {
                        result.UpdateStatus(false, arg.Index, arg.Value,
                                            "Cannot specifiy more than one {0} argument (both '{1}' and '{2}' were specified)",
                                            paramGroup.Name, configParamAttribute.ParamNameLong, paramGroup.ValueParamName);

                        return;
                    }

                    paramGroup.ValueParamName = configParamAttribute.ParamNameLong;
                    paramGroup.Value = arg.Value;
                }

                if ((configParamAttribute.ValidValues != null && configParamAttribute.ValidValues.Length > 0)
                    && (arg.Value == null || arg.Value.Trim().Length == 0))
                {
                    result.UpdateStatus(false, arg.Index, arg.Value,
                                        "Value for argument '{0}' is not valid. Valid values are: {1}",
                                        arg.Name, String.Join(", ", configParamAttribute.ValidValues));

                    return;
                }

                // Verify that it's among the required values
                if (configParamAttribute.ValidValues != null)
                {
                    var valueFound = false;

                    foreach (var value in configParamAttribute.ValidValues)
                    {
                        if (String.Compare(value, arg.Value, true) != 0) continue;
                        valueFound = true;
                        break;
                    }

                    if (! valueFound)
                    {
                        result.UpdateStatus(false, arg.Index, arg.Value,
                                            "Value for argument '{0}' is not valid. Valid values are: {1}",
                                            arg.Name, String.Join(", ", configParamAttribute.ValidValues));

                        return;
                    }
                }

                // Assign the value
                object realVal;

                try
                {
                    realVal = Convert.ChangeType(arg.Value ?? configParamAttribute.DefaultValue, configParamAttribute.Property.PropertyType);
                }
                catch
                {
                    result.UpdateStatus(false, arg.Index, arg.Value, "Invalid value format (cannot parse)");
                    return;
                }

                configParamAttribute.Property.SetValue(instance, realVal, BindingFlags.Static, null, null, null);
            }
        }
        public static ParseResult ParseCommandLine(string[] args)
        {
            var cfgValues = new Hashtable(StringComparer.InvariantCulture);

            if (args == null)
                throw new ArgumentNullException("args");

            var parseResult = new ParseResult();

            for (var i = 0; i < args.Length; i++)
            {
                var argument = args[i];

                if (argument[0] == '/' || argument[0] == '-')
                {
                    var argInst = new Argument {Index = i, RawName = argument, Name = argument.Substring(1)};

                    if (argument.Length == 1)
                    {
                        parseResult.UpdateStatus(false, i, argument);
                    }

                    // Look for a value after /foo in the next arg
                    if ((i + 1) < args.Length)
                    {
                        string nextArg = args[i + 1];
                        argInst.RawValue = nextArg;

                        //make sure the next arg isn't another arg (/bar)
                        // NOTE: you can escape values that start with "/" or "-" with "//" or "--"
                        // respectively
                        if (nextArg[0] == '/')
                        {
                            if (nextArg.Length > 1)
                            {
                                if (nextArg[1] == '/')
                                {
                                    // Remove the escaped '/'
                                    argInst.Value = nextArg.Substring(1);
                                    i++;
                                }
                                // else, the next arg is an actual /foo-type command, so just
                                // let the next loop iteration pick it up
                            }
                            else
                            {
                                argInst.Value = nextArg;
                                i++;
                            }
                        }
                        else if (nextArg[0] == '-')
                        {
                            if (nextArg.Length > 1)
                            {
                                if (nextArg[1] == '-')
                                {
                                    // Remove the escaped '-'
                                    argInst.Value = nextArg.Substring(1);
                                    i++;
                                }
                                // else, the next arg is an actual -foo-type command, so just
                                // let the next loop iteration pick it up
                            }
                            else
                            {
                                argInst.Value = nextArg;
                                i++;
                            }
                        }
                        else
                        {
                            argInst.Value = nextArg;
                            i++;
                        }
                    }

                    cfgValues.Add(argInst.Name, argInst);
                }
                else
                {
                    parseResult.UpdateStatus(false, i, argument);
                    break;
                }
            }

            MapValuesToProperties(parseResult, null, cfgValues);

            // Check for unfulfilled required groups
            foreach (ParamGroup g in groupMap.Values)
            {
                if (g.Required && g.ValueParamName == null)
                {
                    parseResult.UpdateStatus(false, g.Name);
                    break;
                }
            }

            return parseResult;
        }