/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Globalization;
using System.Reflection;
using System.Text;
#if !NETCF
using System.Web;
#endif

namespace Apache.NMS.Util
{
	/// <summary>
	/// Class to provide support for Uri query parameters which uses .Net reflection
	/// to identify and set properties.
	/// </summary>
	public class URISupport
	{
		/// <summary>
		/// Given a string that could be a Composite Uri that uses syntax not compatible
		/// with the .NET Uri class such as an ActiveMQ failover Uri formatted as
		/// "failover://(tcp://localhost:61616)", the initial '://' must be changed
		/// to ':(' so that the Uri class doesn't attempt to parse the '(tcp:' as
		/// the Uri's Authority as that is not a valid host name.
		/// </summary>
		/// <param name="uriString">
		/// A string that could be a Composite Uri that uses syntax not compatible
		/// with the .NET Uri class
		/// </param>
		public static Uri CreateCompatibleUri(string uriString)
		{
			string sanitized = uriString.Replace("://(", ":(");
			return new Uri(sanitized);
		}

		/// <summary>
		/// Parse a Uri query string of the form ?x=y&amp;z=0
		/// into a map of name/value pairs.
		/// </summary>
		/// <param name="query">The query string to parse. This string should not contain
		/// Uri escape characters.</param>
		public static StringDictionary ParseQuery(String query)
		{
			StringDictionary map = new StringDictionary();

			if(String.IsNullOrEmpty(query))
			{
				return EmptyMap;
			}

			// strip the initial "?"
			if(query.StartsWith("?"))
			{
				query = query.Substring(1);
			}

			// split the query into parameters
			string[] parameters = query.Split('&');
			foreach(string pair in parameters)
			{
				if(pair.Length > 0)
				{
					string[] nameValue = pair.Split('=');

					if(nameValue.Length != 2)
					{
						throw new NMSException(string.Format("Invalid Uri parameter: {0}", query));
					}

					map[nameValue[0]] = nameValue[1];
				}
			}

			return map;
		}

		public static StringDictionary ParseParameters(Uri uri)
		{
			return (uri.Query == null
					? EmptyMap
					: ParseQuery(StripPrefix(uri.Query, "?")));
		}

		/// <summary>
		/// Sets the public properties of a target object using a string map.
		/// This method uses .Net reflection to identify public properties of
		/// the target object matching the keys from the passed map.
		/// </summary>
		/// <param name="target">The object whose properties will be set.</param>
		/// <param name="map">Map of key/value pairs.</param>
		public static void SetProperties(object target, StringDictionary map)
		{
			Type type = target.GetType();

			foreach(string key in map.Keys)
			{
				PropertyInfo prop = type.GetProperty(key,
														BindingFlags.FlattenHierarchy
														| BindingFlags.Public
														| BindingFlags.Instance
														| BindingFlags.IgnoreCase);

				if(null != prop)
				{
					prop.SetValue(target, Convert.ChangeType(map[key], prop.PropertyType, CultureInfo.InvariantCulture), null);
				}
				else
				{
					FieldInfo field = type.GetField(key,
														BindingFlags.FlattenHierarchy
														| BindingFlags.Public
														| BindingFlags.Instance
														| BindingFlags.IgnoreCase);
					if(null != field)
					{
						field.SetValue(target, Convert.ChangeType(map[key], field.FieldType, CultureInfo.InvariantCulture));
					}
					else
					{
						throw new NMSException(string.Format("No such property or field: {0} on class: {1}", key, target.GetType().Name));
					}
				}
			}
		}

		/// <summary>
		/// Sets the public properties of a target object using a string map.
		/// This method uses .Net reflection to identify public properties of
		/// the target object matching the keys from the passed map.
		/// </summary>
		/// <param name="target">The object whose properties will be set.</param>
		/// <param name="map">Map of key/value pairs.</param>
		/// <param name="prefix">Key value prefix.  This is prepended to the property name
		/// before searching for a matching key value.</param>
		public static void SetProperties(object target, StringDictionary map, string prefix)
		{
			Type type = target.GetType();

			List<String> matches = new List<String>();

			foreach(string key in map.Keys)
			{
				if(key.StartsWith(prefix, StringComparison.InvariantCultureIgnoreCase))
				{
					string bareKey = key.Substring(prefix.Length);
					PropertyInfo prop = type.GetProperty(bareKey,
															BindingFlags.FlattenHierarchy
															| BindingFlags.Public
															| BindingFlags.Instance
															| BindingFlags.IgnoreCase);

					if(null != prop)
					{
						prop.SetValue(target, Convert.ChangeType(map[key], prop.PropertyType, CultureInfo.InvariantCulture), null);
					}
					else
					{
						FieldInfo field = type.GetField(bareKey,
															BindingFlags.FlattenHierarchy
															| BindingFlags.Public
															| BindingFlags.Instance
															| BindingFlags.IgnoreCase);
						if(null != field)
						{
							field.SetValue(target, Convert.ChangeType(map[key], field.FieldType, CultureInfo.InvariantCulture));
						}
						else
						{
							throw new NMSException(string.Format("No such property or field: {0} on class: {1}", bareKey, target.GetType().Name));
						}
					}

					// store for later removal.
					matches.Add(key);
				}
			}

			// Remove all the properties we set so they are used again later.
			foreach(string match in matches)
			{
				map.Remove(match);
			}
		}

		public static StringDictionary GetProperties(StringDictionary props, string prefix)
		{

			if(props == null)
			{
				throw new Exception("Properties Object was null");
			}

			StringDictionary result = new StringDictionary();

			foreach(string key in props.Keys)
			{
				if(key.StartsWith(prefix, StringComparison.InvariantCultureIgnoreCase))
				{
					string bareKey = key.Substring(prefix.Length);
					String value = props[key];
					result[bareKey] = value;
				}
			}

			return result;
		}

		public static StringDictionary ExtractProperties(StringDictionary props, string prefix)
		{

			if(props == null)
			{
				throw new Exception("Properties Object was null");
			}

			StringDictionary result = new StringDictionary();
			List<String> matches = new List<String>();

			foreach(string key in props.Keys)
			{
				if(key.StartsWith(prefix, StringComparison.InvariantCultureIgnoreCase))
				{
					String value = props[key];
					result[key] = value;
					matches.Add(key);
				}
			}

			foreach(string match in matches)
			{
				props.Remove(match);
			}

			return result;
		}

		public static String UrlDecode(String s)
		{
#if !NETCF
			return HttpUtility.HtmlDecode(s);
#else
            return Uri.UnescapeDataString(s);
#endif
		}

		public static String UrlEncode(String s)
		{
#if !NETCF
			return HttpUtility.HtmlEncode(s);
#else
            return Uri.EscapeUriString(s);
#endif
		}

		public static String CreateQueryString(StringDictionary options)
		{
			if(options != null && options.Count > 0)
			{
				StringBuilder rc = new StringBuilder();
				bool first = true;

				foreach(String key in options.Keys)
				{
					string value = options[key];

					if(first)
					{
						first = false;
					}
					else
					{
						rc.Append("&");
					}

					rc.Append(UrlEncode(key));
					rc.Append("=");
					rc.Append(UrlEncode(value));
				}

				return rc.ToString();
			}
			else
			{
				return "";
			}
		}

		public static Uri CreateRemainingUri(Uri originalUri, StringDictionary parameters)
		{
			string s = CreateQueryString(parameters);

			if(String.IsNullOrEmpty(s))
			{
				s = null;
			}

			return CreateUriWithQuery(originalUri, s);
		}

		public class CompositeData
		{
			private String host;
			private String scheme;
			private String path;
			private Uri[] components;
			private StringDictionary parameters;
			private String fragment;

			public Uri[] Components
			{
				get { return components; }
				set { components = value; }
			}

			public String Fragment
			{
				get { return fragment; }
				set { fragment = value; }
			}

			public StringDictionary Parameters
			{
				get { return parameters; }
				set { parameters = value; }
			}

			public String Scheme
			{
				get { return scheme; }
				set { scheme = value; }
			}

			public String Path
			{
				get { return path; }
				set { path = value; }
			}

			public String Host
			{
				get { return host; }
				set { host = value; }
			}

			public Uri toUri()
			{
				StringBuilder sb = new StringBuilder();
				if(scheme != null)
				{
					sb.Append(scheme);
					sb.Append(':');
				}

				if(!string.IsNullOrEmpty(host))
				{
					sb.Append(host);
				}
				else
				{
					sb.Append('(');
					for(int i = 0; i < components.Length; i++)
					{
						if(i != 0)
						{
							sb.Append(',');
						}
						sb.Append(components[i].ToString());
					}
					sb.Append(')');
				}

				if(path != null)
				{
					sb.Append('/');
					sb.Append(path);
				}

				if(parameters.Count != 0)
				{
					sb.Append("?");
					sb.Append(CreateQueryString(parameters));
				}

				if(fragment != null)
				{
					sb.Append("#");
					sb.Append(fragment);
				}

				return new Uri(sb.ToString());
			}
		}

		public static String StripPrefix(String value, String prefix)
		{
			if(value.StartsWith(prefix, StringComparison.InvariantCultureIgnoreCase))
			{
				return value.Substring(prefix.Length);
			}

			return value;
		}

		public static Uri CreateUriWithQuery(Uri uri, string query)
		{
			if(!String.IsNullOrEmpty(query) && !query.StartsWith("?"))
			{
				query = "?" + query;
			}

			if(String.IsNullOrEmpty(uri.Query))
			{
				return new Uri(uri.OriginalString + query);
			}
			else
			{
				string originalUri = uri.OriginalString;

				int queryDelimPos = originalUri.LastIndexOf('?');
				int compositeDelimPos = originalUri.LastIndexOf(')');

				if(queryDelimPos <= compositeDelimPos)
				{
					// No Query or the Query is part of an inner Composite.
					return new Uri(originalUri + query);
				}
				else
				{
					// Outer Uri has a Query or not a Composite Uri with a Query
					string strippedUri = originalUri.Substring(0, queryDelimPos);
					return new Uri(strippedUri + query);
				}
			}
		}

		public static Uri RemoveQuery(Uri original)
		{
			return CreateUriWithQuery(original, null);
		}

		public static CompositeData ParseComposite(Uri uri)
		{
			CompositeData rc = new CompositeData();
			rc.Scheme = uri.Scheme;

			// Start with original URI
			//String ssp = uri.Authority + uri.PathAndQuery;
			String ssp = uri.OriginalString;

			ssp = StripPrefix(ssp, rc.Scheme + ":");
			ssp = StripPrefix(ssp, "//");

			int lastPoundPos = ssp.LastIndexOf("#");
			int lastParendPos = ssp.LastIndexOf(")");

			// Only include a Fragment that's outside any Composte sections.
			if(lastPoundPos > lastParendPos)
			{
				rc.Fragment = ssp.Substring(lastPoundPos);
				ssp = ssp.Substring(0, lastPoundPos);
			}

			// Ensure any embedded URIs don't have malformed authority's by changing
			// them from '://(' which would cause the .NET Uri class to attempt to validate
			// the authority as a hostname with, ':(' which is valid.
			ssp = ssp.Replace("://(", ":(");

			// Handle the composite components
			ParseComposite(uri, rc, ssp);
			return rc;
		}

		/// <summary>
		/// </summary>
		/// <param name="uri"></param>
		/// <param name="rc"></param>
		/// <param name="ssp"></param>
		private static void ParseComposite(Uri uri, CompositeData rc, String ssp)
		{
			String componentString;
			String parms;

			if(!CheckParenthesis(ssp))
			{
				throw new NMSException(uri.ToString() + ": Not a matching number of '(' and ')' parenthesis");
			}

			int p;
			int intialParen = ssp.IndexOf("(");

			if(intialParen >= 0)
			{
				rc.Host = ssp.Substring(0, intialParen);
				p = rc.Host.IndexOf("/");
				if(p >= 0)
				{
					rc.Path = rc.Host.Substring(p);
					rc.Host = rc.Host.Substring(0, p);
				}

				p = ssp.LastIndexOf(")");
				int start = intialParen + 1;
				int len = p - start;
				componentString = ssp.Substring(start, len);
				parms = ssp.Substring(p + 1).Trim();
			}
			else
			{
				componentString = ssp;
				parms = "";
			}

			String[] components = SplitComponents(componentString);
			rc.Components = new Uri[components.Length];
			for(int i = 0; i < components.Length; i++)
			{
				rc.Components[i] = new Uri(components[i].Trim());
			}

			p = parms.IndexOf("?");
			if(p >= 0)
			{
				if(p > 0)
				{
					rc.Path = StripPrefix(parms.Substring(0, p), "/");
				}

				rc.Parameters = ParseQuery(parms.Substring(p + 1));
			}
			else
			{
				if(parms.Length > 0)
				{
					rc.Path = StripPrefix(parms, "/");
				}

				rc.Parameters = EmptyMap;
			}
		}

		private static StringDictionary EmptyMap
		{
			get { return new StringDictionary(); }
		}

		/// <summary>
		/// </summary>
		/// <param name="componentString"></param>
		private static String[] SplitComponents(String componentString)
		{
			ArrayList l = new ArrayList();

			int last = 0;
			int depth = 0;
			char[] chars = componentString.ToCharArray();
			for(int i = 0; i < chars.Length; i++)
			{
				switch(chars[i])
				{
				case '(':
					depth++;
					break;

				case ')':
					depth--;
					break;

				case ',':
					if(depth == 0)
					{
						String s = componentString.Substring(last, i - last);
						l.Add(s);
						last = i + 1;
					}
					break;

				default:
					break;
				}
			}

			String ending = componentString.Substring(last);
			if(ending.Length != 0)
			{
				l.Add(ending);
			}

			String[] rc = new String[l.Count];
			l.CopyTo(rc);
			return rc;
		}

		public static bool CheckParenthesis(String str)
		{
			bool result = true;

			if(str != null)
			{
				int open = 0;
				int closed = 0;

				int i = 0;
				while((i = str.IndexOf('(', i)) >= 0)
				{
					i++;
					open++;
				}

				i = 0;
				while((i = str.IndexOf(')', i)) >= 0)
				{
					i++;
					closed++;
				}

				result = (open == closed);
			}

			return result;
		}
	}
}
