diff --git a/SabreTools.Library/Help/Feature.cs b/SabreTools.Library/Help/Feature.cs index c02bf5d0..78360792 100644 --- a/SabreTools.Library/Help/Feature.cs +++ b/SabreTools.Library/Help/Feature.cs @@ -6,658 +6,624 @@ using SabreTools.Library.Data; namespace SabreTools.Library.Help { - public class Feature - { - #region Private instance variables - - private string _name; - private List _flags; - private string _description; - private string _longDescription; // TODO: Use this to generate README.1ST? - private FeatureType _featureType; - private Dictionary _features; - private bool _foundOnce = false; - - // Specific value types - private bool _valueBool = false; - private int _valueInt32 = Int32.MinValue; - private long _valueInt64 = Int64.MinValue; - private string _valueString = null; - private List _valueList = null; - - #endregion - - #region Publicly facing variables - - public string Name - { - get { return _name; } - } - public List Flags - { - get { return _flags; } - } - public string Description - { - get { return _description; } - } - public string LongDescription - { - get { return _longDescription; } - } - public Dictionary Features - { - get { return _features; } - } - - #endregion - - #region Constructors - - public Feature() - { - _name = null; - _flags = new List(); - _description = null; - _longDescription = null; - _featureType = FeatureType.Flag; - _features = new Dictionary(); - } - - public Feature(string name, string flag, string description, FeatureType featureType, string longDescription = null) - { - _name = name; - List flags = new List(); - flags.Add(flag); - _flags = flags; - _description = description; - _longDescription = longDescription; - _featureType = featureType; - _features = new Dictionary(); - } - - public Feature(string name, List flags, string description, FeatureType featureType, string longDescription = null) - { - _name = name; - _flags = flags; - _description = description; - _longDescription = longDescription; - _featureType = featureType; - _features = new Dictionary(); - } - - #endregion - - #region Accessors - - /// - /// Directly address a given subfeature - /// - public Feature this[string name] - { - get { return _features[name]; } - set { _features[name] = value; } - } - - /// - /// Directly address a given subfeature - /// - public Feature this[Feature subfeature] - { - get { return _features[subfeature.Name]; } - set { _features[subfeature.Name] = value; } - } - - /// - /// Add a new feature for this feature - /// - /// - public void AddFeature(Feature feature) - { - if (_features == null) - { - _features = new Dictionary(); - } - - lock(_features) - { - if (!_features.ContainsKey(feature.Name)) - { - _features.Add(feature.Name, feature); - } - else - { - _features[feature.Name] = feature; - } - } - } - - /// - /// Add a new flag for this feature - /// - /// Flag to add for this feature - public void AddFlag(string flag) - { - if (_flags == null) - { - _flags = new List(); - } - - lock (_flags) - { - _flags.Add(flag); - } - } - - /// - /// Add a set of new flags for this feature - /// - /// List of flags to add to this feature - public void AddFlags(List flags) - { - if (_flags == null) - { - _flags = new List(); - } - - lock (_flags) - { - _flags.AddRange(flags); - } - } - - /// - /// Returns if a flag exists for the current feature - /// - /// Name of the flag to check - /// True if the flag was found, false otherwise - public bool ContainsFlag(string name) - { - bool success = false; - - // Loop through the flags - foreach (string flag in _flags) - { - if (flag == name) - { - success = true; - break; - } - else if (flag.TrimStart('-') == name) - { - success = true; - break; - } - } - - return success; - } - - /// - /// Returns if the feature contains a flag that starts with the given character - /// - /// Character to check against - /// True if the flag was found, false otherwise - public bool StartsWith(char c) - { - bool success = false; - - // Loop through the flags - foreach (string flag in _flags) - { - if (flag.TrimStart('-').ToLowerInvariant()[0] == c) - { - success = true; - break; - } - } - - return success; - } - - #endregion - - #region Instance Methods - - /// - /// Output this feature only - /// - /// Positive number representing number of spaces to put in front of the feature - /// Positive number representing the column where the description should start - /// True if the long description should be formatted and output, false otherwise - public List Output(int pre = 0, int midpoint = 0, bool includeLongDescription = false) - { - // Create the output list - List outputList = new List(); - - // Build the output string first - string output = ""; - - // Add the pre-space first - output += CreatePadding(pre); - - // Preprocess the flags, if necessary - string[] newflags = new string[_flags.Count]; - _flags.CopyTo(newflags); - switch (_featureType) - { - case FeatureType.Int32: - case FeatureType.Int64: - case FeatureType.List: - case FeatureType.String: - for (int i = 0; i < newflags.Length; i++) - { - newflags[i] += "="; - } - break; - case FeatureType.Flag: - default: - // No-op - break; - } - - // Now add all flags - output += String.Join(", ", newflags); - - // If we have a midpoint set, check to see if the string needs padding - if (midpoint > 0 && output.Length < midpoint) - { - output += CreatePadding(midpoint - output.Length); - } - else - { - output += " "; - } - - // Append the description - output += _description; - - // Now append it to the list - outputList.Add(output); - - // If we are outputting the long description, format it and then add it as well - if (includeLongDescription) - { - // Get the width of the console for wrapping reference - int width = Console.WindowWidth - 1; - - // Prepare the output string - output = CreatePadding(pre + 4); - - // Now split the input description and start processing - string[] split = _longDescription.Split(' '); - for (int i = 0; i < split.Length; i++) - { - // If we have a newline character, reset the line and continue - if (split[i].Contains("\n")) - { - string[] subsplit = split[i].Replace("\r", "").Split('\n'); - for (int j = 0; j < subsplit.Length - 1; j++) - { - // Add the next word only if the total length doesn't go above the width of the screen - if (output.Length + subsplit[j].Length < width) - { - output += (output.Length == pre + 4 ? "" : " ") + subsplit[j]; - } - // Otherwise, we want to cache the line to output and create a new blank string - else - { - outputList.Add(output); - output = CreatePadding(pre + 4); - output += (output.Length == pre + 4 ? "" : " ") + subsplit[j]; - } - - outputList.Add(output); - output = CreatePadding(pre + 4); - } - - output += subsplit[subsplit.Length - 1]; - continue; - } - - // Add the next word only if the total length doesn't go above the width of the screen - if (output.Length + split[i].Length < width) - { - output += (output.Length == pre + 4 ? "" : " ") + split[i]; - } - // Otherwise, we want to cache the line to output and create a new blank string - else - { - outputList.Add(output); - output = CreatePadding(pre + 4); - output += (output.Length == pre + 4 ? "" : " ") + split[i]; - } - } - - // Add the last created output and a blank line for clarity - outputList.Add(output); - outputList.Add(""); - } - - return outputList; - } - - /// - /// Create a padding space based on the given length - /// - /// Number of padding spaces to add - /// String with requested number of blank spaces - private string CreatePadding(int spaces) - { - string blank = ""; - for (int i = 0; i < spaces; i++) - { - blank += " "; - } - return blank; - } - - /// - /// Output this feature and all subfeatures - /// - /// Level of indentation for this feature - /// Positive number representing number of spaces to put in front of the feature - /// Positive number representing the column where the description should start - /// True if the long description should be formatted and output, false otherwise - public List OutputRecursive(int tabLevel, int pre = 0, int midpoint = 0, bool includeLongDescription = false) - { - // Create the output list - List outputList = new List(); - - // Build the output string first - string output = ""; - - // Normalize based on the tab level - int preAdjusted = pre; - int midpointAdjusted = midpoint; - if (tabLevel > 0) - { - preAdjusted += 4 * tabLevel; - midpointAdjusted += 4 * tabLevel; - } - - // Add the pre-space first - output += CreatePadding(preAdjusted); - - // Preprocess the flags, if necessary - string[] newflags = new string[_flags.Count]; - _flags.CopyTo(newflags); - switch (_featureType) - { - case FeatureType.Int32: - case FeatureType.Int64: - case FeatureType.List: - case FeatureType.String: - for (int i = 0; i < newflags.Length; i++) - { - newflags[i] += "="; - } - break; - case FeatureType.Flag: - default: - // No-op - break; - } - - // Now add all flags - output += String.Join(", ", newflags); - - // If we have a midpoint set, check to see if the string needs padding - if (midpoint > 0 && output.Length < midpointAdjusted) - { - output += CreatePadding(midpointAdjusted - output.Length); - } - else - { - output += " "; - } - - // Append the description - output += _description; - - // Now append it to the list - outputList.Add(output); - - // If we are outputting the long description, format it and then add it as well - if (includeLongDescription) - { - // Get the width of the console for wrapping reference - int width = Console.WindowWidth - 1; - - // Prepare the output string - output = CreatePadding(preAdjusted + 4); - - // Now split the input description and start processing - string[] split = _longDescription.Split(' '); - for (int i = 0; i < split.Length; i++) - { - // If we have a newline character, reset the line and continue - if (split[i].Contains("\n")) - { - string[] subsplit = split[i].Replace("\r", "").Split('\n'); - for (int j = 0; j < subsplit.Length - 1; j++) - { - // Add the next word only if the total length doesn't go above the width of the screen - if (output.Length + subsplit[j].Length < width) - { - output += (output.Length == preAdjusted + 4 ? "" : " ") + subsplit[j]; - } - // Otherwise, we want to cache the line to output and create a new blank string - else - { - outputList.Add(output); - output = CreatePadding(preAdjusted + 4); - output += (output.Length == preAdjusted + 4 ? "" : " ") + subsplit[j]; - } - - outputList.Add(output); - output = CreatePadding(preAdjusted + 4); - } - - output += subsplit[subsplit.Length - 1]; - continue; - } - - // Add the next word only if the total length doesn't go above the width of the screen - if (output.Length + split[i].Length < width) - { - output += (output.Length == preAdjusted + 4 ? "" : " ") + split[i]; - } - // Otherwise, we want to cache the line to output and create a new blank string - else - { - outputList.Add(output); - output = CreatePadding(preAdjusted + 4); - output += (output.Length == preAdjusted + 4 ? "" : " ") + split[i]; - } - } - - // Add the last created output and a blank line for clarity - outputList.Add(output); - outputList.Add(""); - } - - // Now let's append all subfeatures - foreach (string feature in _features.Keys) - { - outputList.AddRange(_features[feature].OutputRecursive(tabLevel + 1, pre, midpoint, includeLongDescription)); - } - - return outputList; - } - - /// - /// Validate whether a flag is valid for this feature or not - /// - /// Input to check against - /// True if just this feature should be checked, false if all subfeatures are checked as well - /// True if the existing flag should be ignored, false otherwise - /// True if the flag was valid, false otherwise - public bool ValidateInput(string input, bool exact = false, bool ignore = false) - { - bool valid = false; - - // Determine what we should be looking for - switch (_featureType) - { - // If we have a flag, make sure it doesn't have an equal sign in it - case FeatureType.Flag: - valid = !input.Contains("=") && _flags.Contains(input); - if (valid) - { - _valueBool = true; - - // If we've already found this feature before - if (_foundOnce && !ignore) - { - valid = false; - } - - _foundOnce = true; - } - break; - // If we have an Int32, try to parse it if at all possible - case FeatureType.Int32: - valid = input.Contains("=") && _flags.Contains(input.Split('=')[0]); - if (valid) - { - if (!Int32.TryParse(input.Split('=')[1], out int value)) - { - value = Int32.MinValue; - } - _valueInt32 = value; - - // If we've already found this feature before - if (_foundOnce && !ignore) - { - valid = false; - } - - _foundOnce = true; - } - break; - // If we have an Int32, try to parse it if at all possible - case FeatureType.Int64: - valid = input.Contains("=") && _flags.Contains(input.Split('=')[0]); - if (valid) - { - if (!Int64.TryParse(input.Split('=')[1], out long value)) - { - value = Int64.MinValue; - } - _valueInt64 = value; - - // If we've already found this feature before - if (_foundOnce && !ignore) - { - valid = false; - } - - _foundOnce = true; - } - break; - // If we have an input, make sure it has an equals sign in it - case FeatureType.List: - valid = input.Contains("=") && _flags.Contains(input.Split('=')[0]); - if (valid) - { - if (_valueList == null) - { - _valueList = new List(); - } - - _valueList.Add(input.Split('=')[1]); - } - break; - case FeatureType.String: - valid = input.Contains("=") && _flags.Contains(input.Split('=')[0]); - if (valid) - { - _valueString = input.Split('=')[1]; - - // If we've already found this feature before - if (_foundOnce && !ignore) - { - valid = false; - } - - _foundOnce = true; - } - break; - } - - // If we haven't found a valid flag and we're not looking for just this feature, check to see if any of the subfeatures are valid - if (!valid && !exact) - { - foreach (string feature in _features.Keys) - { - valid = _features[feature].ValidateInput(input); - - // If we've found a valid feature, we break out - if (valid) - { - break; - } - } - } - - // If we're not valid at this point, we want to check if this flag is a file or a folder - if (!valid) - { - valid = File.Exists(input) || Directory.Exists(input); - } - - return valid; - } - - /// - /// Get the proper value associated with this feature - /// - /// Value associated with this feature - public object GetValue() - { - switch (_featureType) - { - case FeatureType.Flag: - return _valueBool; - case FeatureType.Int32: - return _valueInt32; - case FeatureType.Int64: - return _valueInt64; - case FeatureType.List: - return _valueList; - case FeatureType.String: - return _valueString; - } - - return null; - } - - /// - /// Returns if this feature has a valid value or not - /// - /// True if the feature is enabled, false otherwise - public bool IsEnabled() - { - object obj = GetValue(); - - switch (_featureType) - { - case FeatureType.Flag: - return (bool)obj; - case FeatureType.Int32: - return (int)obj != Int32.MinValue; - case FeatureType.Int64: - return (long)obj != Int64.MinValue; - case FeatureType.List: - return obj != null; - case FeatureType.String: - return obj != null; - } - - return false; - } - - #endregion - } + public class Feature + { + #region Private instance variables + + private FeatureType _featureType; + private bool _foundOnce = false; + + // Specific value types + private bool _valueBool = false; + private int _valueInt32 = Int32.MinValue; + private long _valueInt64 = Int64.MinValue; + private string _valueString = null; + private List _valueList = null; + + #endregion + + #region Publicly facing variables + + public string Name { get; private set; } + public List Flags { get; private set; } + public string Description { get; private set; } + public string LongDescription { get; private set; } // TODO: Use this to generate README.1ST? + public Dictionary Features { get; private set; } + + #endregion + + #region Constructors + + public Feature() + { + this.Name = null; + this.Flags = new List(); + this.Description = null; + this.LongDescription = null; + this._featureType = FeatureType.Flag; + this.Features = new Dictionary(); + } + + public Feature(string name, string flag, string description, FeatureType featureType, string longDescription = null) + { + this.Name = name; + this.Flags = new List(); + this.Flags.Add(flag); + this.Description = description; + this.LongDescription = longDescription; + this._featureType = featureType; + this.Features = new Dictionary(); + } + + public Feature(string name, List flags, string description, FeatureType featureType, string longDescription = null) + { + this.Name = name; + this.Flags = flags; + this.Description = description; + this.LongDescription = longDescription; + this._featureType = featureType; + this.Features = new Dictionary(); + } + + #endregion + + #region Accessors + + /// + /// Directly address a given subfeature + /// + public Feature this[string name] + { + get { return this.Features[name]; } + set { this.Features[name] = value; } + } + + /// + /// Directly address a given subfeature + /// + public Feature this[Feature subfeature] + { + get { return this.Features[subfeature.Name]; } + set { this.Features[subfeature.Name] = value; } + } + + /// + /// Add a new feature for this feature + /// + /// + public void AddFeature(Feature feature) + { + if (this.Features == null) + this.Features = new Dictionary(); + + lock(this.Features) + { + this.Features[feature.Name] = feature; + } + } + + /// + /// Add a new flag for this feature + /// + /// Flag to add for this feature + public void AddFlag(string flag) + { + if (this.Flags == null) + this.Flags = new List(); + + lock (this.Flags) + { + this.Flags.Add(flag); + } + } + + /// + /// Add a set of new flags for this feature + /// + /// List of flags to add to this feature + public void AddFlags(List flags) + { + if (this.Flags == null) + this.Flags = new List(); + + lock (this.Flags) + { + this.Flags.AddRange(flags); + } + } + + /// + /// Returns if a flag exists for the current feature + /// + /// Name of the flag to check + /// True if the flag was found, false otherwise + public bool ContainsFlag(string name) + { + bool success = false; + + // Loop through the flags + foreach (string flag in this.Flags) + { + if (flag == name) + { + success = true; + break; + } + else if (flag.TrimStart('-') == name) + { + success = true; + break; + } + } + + return success; + } + + /// + /// Returns if the feature contains a flag that starts with the given character + /// + /// Character to check against + /// True if the flag was found, false otherwise + public bool StartsWith(char c) + { + bool success = false; + + // Loop through the flags + foreach (string flag in this.Flags) + { + if (flag.TrimStart('-').ToLowerInvariant()[0] == c) + { + success = true; + break; + } + } + + return success; + } + + #endregion + + #region Instance Methods + + /// + /// Output this feature only + /// + /// Positive number representing number of spaces to put in front of the feature + /// Positive number representing the column where the description should start + /// True if the long description should be formatted and output, false otherwise + public List Output(int pre = 0, int midpoint = 0, bool includeLongDescription = false) + { + // Create the output list + List outputList = new List(); + + // Build the output string first + string output = ""; + + // Add the pre-space first + output += CreatePadding(pre); + + // Preprocess the flags, if necessary + string[] newflags = new string[this.Flags.Count]; + this.Flags.CopyTo(newflags); + switch (_featureType) + { + case FeatureType.Int32: + case FeatureType.Int64: + case FeatureType.List: + case FeatureType.String: + for (int i = 0; i < newflags.Length; i++) + { + newflags[i] += "="; + } + break; + case FeatureType.Flag: + default: + // No-op + break; + } + + // Now add all flags + output += String.Join(", ", newflags); + + // If we have a midpoint set, check to see if the string needs padding + if (midpoint > 0 && output.Length < midpoint) + { + output += CreatePadding(midpoint - output.Length); + } + else + { + output += " "; + } + + // Append the description + output += this.Description; + + // Now append it to the list + outputList.Add(output); + + // If we are outputting the long description, format it and then add it as well + if (includeLongDescription) + { + // Get the width of the console for wrapping reference + int width = Console.WindowWidth - 1; + + // Prepare the output string + output = CreatePadding(pre + 4); + + // Now split the input description and start processing + string[] split = this.LongDescription.Split(' '); + for (int i = 0; i < split.Length; i++) + { + // If we have a newline character, reset the line and continue + if (split[i].Contains("\n")) + { + string[] subsplit = split[i].Replace("\r", "").Split('\n'); + for (int j = 0; j < subsplit.Length - 1; j++) + { + // Add the next word only if the total length doesn't go above the width of the screen + if (output.Length + subsplit[j].Length < width) + { + output += (output.Length == pre + 4 ? "" : " ") + subsplit[j]; + } + // Otherwise, we want to cache the line to output and create a new blank string + else + { + outputList.Add(output); + output = CreatePadding(pre + 4); + output += (output.Length == pre + 4 ? "" : " ") + subsplit[j]; + } + + outputList.Add(output); + output = CreatePadding(pre + 4); + } + + output += subsplit[subsplit.Length - 1]; + continue; + } + + // Add the next word only if the total length doesn't go above the width of the screen + if (output.Length + split[i].Length < width) + { + output += (output.Length == pre + 4 ? "" : " ") + split[i]; + } + // Otherwise, we want to cache the line to output and create a new blank string + else + { + outputList.Add(output); + output = CreatePadding(pre + 4); + output += (output.Length == pre + 4 ? "" : " ") + split[i]; + } + } + + // Add the last created output and a blank line for clarity + outputList.Add(output); + outputList.Add(""); + } + + return outputList; + } + + /// + /// Create a padding space based on the given length + /// + /// Number of padding spaces to add + /// String with requested number of blank spaces + private string CreatePadding(int spaces) + { + string blank = ""; + for (int i = 0; i < spaces; i++) + { + blank += " "; + } + return blank; + } + + /// + /// Output this feature and all subfeatures + /// + /// Level of indentation for this feature + /// Positive number representing number of spaces to put in front of the feature + /// Positive number representing the column where the description should start + /// True if the long description should be formatted and output, false otherwise + public List OutputRecursive(int tabLevel, int pre = 0, int midpoint = 0, bool includeLongDescription = false) + { + // Create the output list + List outputList = new List(); + + // Build the output string first + string output = ""; + + // Normalize based on the tab level + int preAdjusted = pre; + int midpointAdjusted = midpoint; + if (tabLevel > 0) + { + preAdjusted += 4 * tabLevel; + midpointAdjusted += 4 * tabLevel; + } + + // Add the pre-space first + output += CreatePadding(preAdjusted); + + // Preprocess the flags, if necessary + string[] newflags = new string[this.Flags.Count]; + this.Flags.CopyTo(newflags); + switch (_featureType) + { + case FeatureType.Int32: + case FeatureType.Int64: + case FeatureType.List: + case FeatureType.String: + for (int i = 0; i < newflags.Length; i++) + { + newflags[i] += "="; + } + break; + case FeatureType.Flag: + default: + // No-op + break; + } + + // Now add all flags + output += String.Join(", ", newflags); + + // If we have a midpoint set, check to see if the string needs padding + if (midpoint > 0 && output.Length < midpointAdjusted) + { + output += CreatePadding(midpointAdjusted - output.Length); + } + else + { + output += " "; + } + + // Append the description + output += this.Description; + + // Now append it to the list + outputList.Add(output); + + // If we are outputting the long description, format it and then add it as well + if (includeLongDescription) + { + // Get the width of the console for wrapping reference + int width = Console.WindowWidth - 1; + + // Prepare the output string + output = CreatePadding(preAdjusted + 4); + + // Now split the input description and start processing + string[] split = this.LongDescription.Split(' '); + for (int i = 0; i < split.Length; i++) + { + // If we have a newline character, reset the line and continue + if (split[i].Contains("\n")) + { + string[] subsplit = split[i].Replace("\r", "").Split('\n'); + for (int j = 0; j < subsplit.Length - 1; j++) + { + // Add the next word only if the total length doesn't go above the width of the screen + if (output.Length + subsplit[j].Length < width) + { + output += (output.Length == preAdjusted + 4 ? "" : " ") + subsplit[j]; + } + // Otherwise, we want to cache the line to output and create a new blank string + else + { + outputList.Add(output); + output = CreatePadding(preAdjusted + 4); + output += (output.Length == preAdjusted + 4 ? "" : " ") + subsplit[j]; + } + + outputList.Add(output); + output = CreatePadding(preAdjusted + 4); + } + + output += subsplit[subsplit.Length - 1]; + continue; + } + + // Add the next word only if the total length doesn't go above the width of the screen + if (output.Length + split[i].Length < width) + { + output += (output.Length == preAdjusted + 4 ? "" : " ") + split[i]; + } + // Otherwise, we want to cache the line to output and create a new blank string + else + { + outputList.Add(output); + output = CreatePadding(preAdjusted + 4); + output += (output.Length == preAdjusted + 4 ? "" : " ") + split[i]; + } + } + + // Add the last created output and a blank line for clarity + outputList.Add(output); + outputList.Add(""); + } + + // Now let's append all subfeatures + foreach (string feature in this.Features.Keys) + { + outputList.AddRange(this.Features[feature].OutputRecursive(tabLevel + 1, pre, midpoint, includeLongDescription)); + } + + return outputList; + } + + /// + /// Validate whether a flag is valid for this feature or not + /// + /// Input to check against + /// True if just this feature should be checked, false if all subfeatures are checked as well + /// True if the existing flag should be ignored, false otherwise + /// True if the flag was valid, false otherwise + public bool ValidateInput(string input, bool exact = false, bool ignore = false) + { + bool valid = false; + + // Determine what we should be looking for + switch (_featureType) + { + // If we have a flag, make sure it doesn't have an equal sign in it + case FeatureType.Flag: + valid = !input.Contains("=") && this.Flags.Contains(input); + if (valid) + { + _valueBool = true; + + // If we've already found this feature before + if (_foundOnce && !ignore) + { + valid = false; + } + + _foundOnce = true; + } + break; + // If we have an Int32, try to parse it if at all possible + case FeatureType.Int32: + valid = input.Contains("=") && this.Flags.Contains(input.Split('=')[0]); + if (valid) + { + if (!Int32.TryParse(input.Split('=')[1], out int value)) + { + value = Int32.MinValue; + } + _valueInt32 = value; + + // If we've already found this feature before + if (_foundOnce && !ignore) + { + valid = false; + } + + _foundOnce = true; + } + break; + // If we have an Int32, try to parse it if at all possible + case FeatureType.Int64: + valid = input.Contains("=") && this.Flags.Contains(input.Split('=')[0]); + if (valid) + { + if (!Int64.TryParse(input.Split('=')[1], out long value)) + { + value = Int64.MinValue; + } + _valueInt64 = value; + + // If we've already found this feature before + if (_foundOnce && !ignore) + { + valid = false; + } + + _foundOnce = true; + } + break; + // If we have an input, make sure it has an equals sign in it + case FeatureType.List: + valid = input.Contains("=") && this.Flags.Contains(input.Split('=')[0]); + if (valid) + { + if (_valueList == null) + { + _valueList = new List(); + } + + _valueList.Add(input.Split('=')[1]); + } + break; + case FeatureType.String: + valid = input.Contains("=") && this.Flags.Contains(input.Split('=')[0]); + if (valid) + { + _valueString = input.Split('=')[1]; + + // If we've already found this feature before + if (_foundOnce && !ignore) + { + valid = false; + } + + _foundOnce = true; + } + break; + } + + // If we haven't found a valid flag and we're not looking for just this feature, check to see if any of the subfeatures are valid + if (!valid && !exact) + { + foreach (string feature in this.Features.Keys) + { + valid = this.Features[feature].ValidateInput(input); + + // If we've found a valid feature, we break out + if (valid) + { + break; + } + } + } + + // If we're not valid at this point, we want to check if this flag is a file or a folder + if (!valid) + { + valid = File.Exists(input) || Directory.Exists(input); + } + + return valid; + } + + /// + /// Get the proper value associated with this feature + /// + /// Value associated with this feature + public object GetValue() + { + switch (_featureType) + { + case FeatureType.Flag: + return _valueBool; + case FeatureType.Int32: + return _valueInt32; + case FeatureType.Int64: + return _valueInt64; + case FeatureType.List: + return _valueList; + case FeatureType.String: + return _valueString; + } + + return null; + } + + /// + /// Returns if this feature has a valid value or not + /// + /// True if the feature is enabled, false otherwise + public bool IsEnabled() + { + object obj = GetValue(); + + switch (_featureType) + { + case FeatureType.Flag: + return (bool)obj; + case FeatureType.Int32: + return (int)obj != Int32.MinValue; + case FeatureType.Int64: + return (long)obj != Int64.MinValue; + case FeatureType.List: + return obj != null; + case FeatureType.String: + return obj != null; + } + + return false; + } + + #endregion + } }