Click here to Skip to main content
15,881,172 members
Articles / Web Development / ASP.NET

Image and Location Search(aroo)

Rate me:
Please Sign up or sign in to vote.
4.96/5 (28 votes)
11 Jun 2008CPOL12 min read 202.6K   2.5K   76  
Index your website (including images and geographic data), search and display results in Google Earth.
//
// OptionDetails.cs
//
// Author: Rafael Teixeira (rafaelteixeirabr@hotmail.com)
//
// (C) 2002 Rafael Teixeira
//

//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

using System;
using System.Collections;
using System.IO;
using System.Reflection;

namespace Mono.GetOptions
{
	public enum WhatToDoNext
	{
		AbandonProgram,
		GoAhead
	}
	
	internal enum OptionProcessingResult
	{
		NotThisOption,
		OptionAlone,
		OptionConsumedParameter
	}

	internal class OptionDetails : IComparable
	{
		public string ShortForm;
		public string LongForm;
		public string AlternateForm;
		public string ShortDescription;
		public bool NeedsParameter;
		public int MaxOccurs; // negative means there is no limit
		public int Occurs;
		public bool BooleanOption;
		public Options OptionBundle;
		public MemberInfo MemberInfo;
		public ArrayList Values;
		public System.Type ParameterType;
		public string paramName = null;
		public bool VBCStyleBoolean;
		public bool SecondLevelHelp;
		public bool Hidden;
		
		public OptionDetails NextAlternate  = null;

		private string ExtractParamName(string shortDescription)
		{
			int whereBegins = shortDescription.IndexOf("{");
			if (whereBegins < 0)
				paramName = "PARAM";
			else {
				int whereEnds = shortDescription.IndexOf("}");
				if (whereEnds < whereBegins)
					whereEnds = shortDescription.Length+1;
						
				paramName = shortDescription.Substring(whereBegins + 1, whereEnds - whereBegins - 1);
				shortDescription = 
					shortDescription.Substring(0, whereBegins) + 
					paramName +
					shortDescription.Substring(whereEnds + 1);
			}
			return shortDescription;
		}

		public string ParamName { get { return paramName; } }
				
		private bool verboseParsing { get { return OptionBundle.VerboseParsingOfOptions || OptionBundle.DebuggingOfOptions; } }

//		private bool debugOptions { get { return OptionBundle.DebuggingOfOptions; } }

		private OptionsParsingMode parsingMode { get { return OptionBundle.ParsingMode; } } 
		
		private bool useGNUFormat { get { return (parsingMode & OptionsParsingMode.GNU_DoubleDash) == OptionsParsingMode.GNU_DoubleDash; } } 
		
		private bool dontSplitOnCommas { get { return OptionBundle.DontSplitOnCommas; } } 

		private string linuxLongPrefix {
			get { 
				return (useGNUFormat? "--":"-"); 
			} 
		}
		
		public string DefaultForm
		{
			get {
				string shortPrefix = "-";
				string longPrefix = linuxLongPrefix;
				if (parsingMode == OptionsParsingMode.Windows) {
					shortPrefix = "/";
					longPrefix = "/";
				}
				if (this.ShortForm != string.Empty)
					return shortPrefix+this.ShortForm;
				else
					return longPrefix+this.LongForm;
			}
		}

		private string optionHelp = null;
		
		public override string ToString()
		{
			if 	(optionHelp == null)
			{
				string shortPrefix;
				string longPrefix;
				bool hasLongForm = (this.LongForm != null && this.LongForm != string.Empty);
				if (this.OptionBundle.ParsingMode == OptionsParsingMode.Windows) {
					shortPrefix = "/";
					longPrefix = "/";
				} else {
					shortPrefix = "-";
					longPrefix = linuxLongPrefix;
				}
				optionHelp = "  ";
				optionHelp += (this.ShortForm != string.Empty) ? shortPrefix+this.ShortForm+" " : "   ";
				optionHelp += hasLongForm ? longPrefix+this.LongForm : "";
				if (NeedsParameter)	{
					if (hasLongForm)
						optionHelp += ":"; 
					optionHelp += ParamName; 
				} else if (BooleanOption && VBCStyleBoolean) {
					optionHelp += "[+|-]";
				}
				optionHelp += "\t";
				if (this.AlternateForm != string.Empty && this.AlternateForm != null)
					optionHelp += "Also "+ shortPrefix + this.AlternateForm + (NeedsParameter?(":"+ParamName):"") +". ";
				optionHelp += this.ShortDescription;
			}
			return optionHelp;
		}

		private static System.Type TypeOfMember(MemberInfo memberInfo)
		{
			if ((memberInfo.MemberType == MemberTypes.Field && memberInfo is FieldInfo))
				return ((FieldInfo)memberInfo).FieldType;

			if ((memberInfo.MemberType == MemberTypes.Property && memberInfo is PropertyInfo))
				return ((PropertyInfo)memberInfo).PropertyType;

			if ((memberInfo.MemberType == MemberTypes.Method && memberInfo is MethodInfo))
			{
				if (((MethodInfo)memberInfo).ReturnType.FullName != typeof(WhatToDoNext).FullName)
					throw new NotSupportedException("Option method must return '" + typeof(WhatToDoNext).FullName + "'");

				ParameterInfo[] parameters = ((MethodInfo)memberInfo).GetParameters();
				if ((parameters == null) || (parameters.Length == 0))
					return null;
				else
					return parameters[0].ParameterType;
			}

			throw new NotSupportedException("'" + memberInfo.MemberType + "' memberType is not supported");
		}

		public OptionDetails(MemberInfo memberInfo, OptionAttribute option, Options optionBundle)
		{
			this.ShortForm = ("" + option.ShortForm).Trim();
			if (option.LongForm == null)
				this.LongForm = string.Empty;
			else
				this.LongForm = (option.LongForm == string.Empty)? memberInfo.Name:option.LongForm;
			this.AlternateForm = option.AlternateForm;
			this.ShortDescription = ExtractParamName(option.ShortDescription);
			this.Occurs = 0;
			this.OptionBundle = optionBundle; 
			this.BooleanOption = false;
			this.MemberInfo = memberInfo;
			this.NeedsParameter = false;
			this.Values = null;
			this.MaxOccurs = 1;
			this.VBCStyleBoolean = option.VBCStyleBoolean;
			this.SecondLevelHelp = option.SecondLevelHelp;
			this.Hidden = false; // TODO: check other attributes
			
			this.ParameterType = TypeOfMember(memberInfo);

			if (this.ParameterType != null)
			{
				if (this.ParameterType.FullName != "System.Boolean")
				{
					if (this.LongForm.IndexOf(':') >= 0)
						throw new InvalidOperationException("Options with an embedded colon (':') in their visible name must be boolean!!! [" + 
									this.MemberInfo.ToString() + " isn't]");
				
					this.NeedsParameter = true;

					if (option.MaxOccurs != 1)
					{
						if (this.ParameterType.IsArray)
						{
							this.Values = new ArrayList();
							this.MaxOccurs = option.MaxOccurs;
						}
						else
						{
							if (this.MemberInfo is MethodInfo || this.MemberInfo is PropertyInfo)
								this.MaxOccurs = option.MaxOccurs;
							else
								throw new InvalidOperationException("MaxOccurs set to non default value (" + option.MaxOccurs + ") for a [" + 
											this.MemberInfo.ToString() + "] option");
						}
					}
				}
				else
				{
					this.BooleanOption = true;
					if (option.MaxOccurs != 1)
					{			
						if (this.MemberInfo is MethodInfo || this.MemberInfo is PropertyInfo)
							this.MaxOccurs = option.MaxOccurs;
						else
							throw new InvalidOperationException("MaxOccurs set to non default value (" + option.MaxOccurs + ") for a [" + 
										this.MemberInfo.ToString() + "] option");
					}
				}
			}
		}

		internal string Key
		{
			get { 
				if (useGNUFormat) {				
					string ShortID = this.ShortForm.ToUpper();
					if (ShortID == string.Empty)
						ShortID = "ZZ";
					return  ShortID + " " + this.LongForm; 
				} else
					return this.LongForm + " " + this.ShortForm; 
			}
		}

		int IComparable.CompareTo(object other)
		{
			return Key.CompareTo(((OptionDetails)other).Key);
		}

		public void TransferValues()
		{
			if (Values != null)
			{
				if (MemberInfo is FieldInfo)
				{
					((FieldInfo)MemberInfo).SetValue(OptionBundle, Values.ToArray(ParameterType.GetElementType()));
					return;
				}

				if (MemberInfo is PropertyInfo) 
				{
					((PropertyInfo)MemberInfo).SetValue(OptionBundle, Values.ToArray(ParameterType.GetElementType()), null);
					return;
				}

				if ((WhatToDoNext)((MethodInfo)MemberInfo).Invoke(OptionBundle, new object[] { Values.ToArray(ParameterType.GetElementType()) }) == WhatToDoNext.AbandonProgram)
					System.Environment.Exit(1);
			}
		}

		private int HowManyBeforeExceedingMaxOccurs(int howMany)
		{
			if (MaxOccurs > 0 && (Occurs + howMany) > MaxOccurs) {
				System.Console.Error.WriteLine("Option " + LongForm + " can be used at most " + MaxOccurs + " times. Ignoring extras...");
				howMany = MaxOccurs - Occurs;
			}
			Occurs += howMany;
			return howMany;
		}
		
		private bool AddingOneMoreExceedsMaxOccurs { get { return HowManyBeforeExceedingMaxOccurs(1) < 1; } }

		private void DoIt(bool setValue)
		{
			if (AddingOneMoreExceedsMaxOccurs) 
				return;

			if (verboseParsing)
				Console.WriteLine("<{0}> set to [{1}]", this.LongForm, setValue);

			if (MemberInfo is FieldInfo)
			{
				((FieldInfo)MemberInfo).SetValue(OptionBundle, setValue);
				return;
			}
			if (MemberInfo is PropertyInfo)
			{
				((PropertyInfo)MemberInfo).SetValue(OptionBundle, setValue, null);
				return;
			}
			if ((WhatToDoNext)((MethodInfo)MemberInfo).Invoke(OptionBundle, null) == WhatToDoNext.AbandonProgram)
				System.Environment.Exit(1);
		}
		
		private void DoIt(string parameterValue)
		{
			if (parameterValue == null)
				parameterValue = "";

			string[] parameterValues;
			
			if (dontSplitOnCommas || MaxOccurs == 1)
				parameterValues = new string[] { parameterValue };
			else
				parameterValues = parameterValue.Split(',');

			int waitingToBeProcessed = HowManyBeforeExceedingMaxOccurs(parameterValues.Length);

			foreach (string parameter in parameterValues)
			{
				if (waitingToBeProcessed-- <= 0)
					break;
					
				object convertedParameter = null;

				if (verboseParsing)
					Console.WriteLine("<" + this.LongForm + "> set to [" + parameter + "]");

				if (Values != null && parameter != null) {
					try {
						convertedParameter = Convert.ChangeType(parameter, ParameterType.GetElementType());
					} catch (Exception ex) {
						Console.WriteLine(String.Format("The value '{0}' is not convertible to the appropriate type '{1}' for the {2} option", parameter, ParameterType.GetElementType().Name, DefaultForm));						
					}
					Values.Add(convertedParameter);
					continue;
				}

				if (parameter != null) {	
					try {
						convertedParameter = Convert.ChangeType(parameter, ParameterType);
					} catch (Exception ex) {
						Console.WriteLine(String.Format("The value '{0}' is not convertible to the appropriate type '{1}' for the {2} option", parameter, ParameterType.Name, DefaultForm));												
						continue;
					}
				}

				if (MemberInfo is FieldInfo) {
					((FieldInfo)MemberInfo).SetValue(OptionBundle, convertedParameter);
					continue;
				}

				if (MemberInfo is PropertyInfo) {
					((PropertyInfo)MemberInfo).SetValue(OptionBundle, convertedParameter, null);
					continue;
				}

				if ((WhatToDoNext)((MethodInfo)MemberInfo).Invoke(OptionBundle, new object[] { convertedParameter }) == WhatToDoNext.AbandonProgram)
					System.Environment.Exit(1);
			}
		}

		private bool IsThisOption(string arg)
		{
			if (arg != null && arg != string.Empty)
			{
				arg = arg.TrimStart('-', '/');			
				if (VBCStyleBoolean)
					arg = arg.TrimEnd('-', '+');	
				return (arg == ShortForm || arg == LongForm || arg == AlternateForm);
			}
			return false;
		}

		public static void LinkAlternatesInsideList(ArrayList list)
		{
			Hashtable baseForms = new Hashtable(list.Count);
			foreach (OptionDetails option in list) {
				if (option.LongForm != null && option.LongForm.Trim().Length > 0) {
					string[] parts = option.LongForm.Split(':');
					if (parts.Length < 2) {
						baseForms.Add(option.LongForm, option);
					} else {
						OptionDetails baseForm = (OptionDetails)baseForms[parts[0]];
						if (baseForm != null) {
							// simple linked list
							option.NextAlternate = baseForm.NextAlternate;
							baseForm.NextAlternate = option;
						}
					}
				}
			}
		}

		private bool IsAlternate(string compoundArg)
		{
			OptionDetails next = NextAlternate;
			while (next != null) {
				if (next.IsThisOption(compoundArg))
					return true;
				next = next.NextAlternate;
			}
			return false;
		}

		public OptionProcessingResult ProcessArgument(string arg, string nextArg)
		{
			if (IsAlternate(arg + ":" + nextArg))
				return OptionProcessingResult.NotThisOption;
				
			if (IsThisOption(arg))
			{
				if (!NeedsParameter)
				{
					if (VBCStyleBoolean && arg.EndsWith("-"))
						DoIt(false);
					else
						DoIt(true);
					return OptionProcessingResult.OptionAlone;
				}
				else
				{
					DoIt(nextArg);
					return OptionProcessingResult.OptionConsumedParameter;
				}
			}

			if (IsThisOption(arg + ":" + nextArg))
			{
				DoIt(true);
				return OptionProcessingResult.OptionConsumedParameter;
			}

			return OptionProcessingResult.NotThisOption;
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Australia Australia
-- ooo ---
www.conceptdevelopment.net
conceptdev.blogspot.com
www.searcharoo.net
www.recipenow.net
www.racereplay.net
www.silverlightearth.com

Comments and Discussions