//------------------------------------------------------------------------------
// <copyright company="Telligent Systems">
//     Copyright (c) Telligent Systems Corporation.  All rights reserved.
// </copyright> 
//------------------------------------------------------------------------------

using System;
using System.Text;
using System.Web;
using System.Web.Caching;
using CommunityServer;

namespace CommunityServer.Components.HttpHandler {

    public class TinyUrlHttpHandler : IHttpHandler {

        public void ProcessRequest (HttpContext context) {

            string qs = null;
            string url = null;

            // do we have query string data
            if (context.Request.QueryString.Count > 0) {
                qs = context.Request.QueryString[0];

                url = LookupUrl(qs);

                if (url != null)
                    context.Response.Redirect(url, true);
				else
					context.Response.Redirect("/");

            } else {

                // do we have a referrer
                if (context.Request.UrlReferrer != null) 
                    context.Response.Redirect(context.Request.UrlReferrer.ToString());
                else
                    context.Response.End();
            }

        }

        private string LookupUrl (string qs) {

            string url = null;
            long number = Base36.Base36ToNumber(qs);

            if (number <= 0)
                return url;

			return CommonDataProvider.Instance().LookupURL(number);
        }

        public bool IsReusable {
            get {
                return false;
            }
        }

    }

    /// <summary>
    /// Class representing a Base36 number
    /// </summary>
    public struct Base36 {
        #region Public Static Methods

        /// <summary>
        /// Static method to convert a Base36 string to a long integer (base-10)
        /// </summary>
        /// <param name="Base36Value">The number to convert from</param>
        /// <returns>The long integer</returns>
        public static long Base36ToNumber(string Base36Value) {
            //Make sure we have passed something
            if(Base36Value == "") {
                throw new Exception(Base36Value);
            }

            //Make sure the number is in upper case:
            Base36Value = Base36Value.ToUpper();

            //Account for negative values:
            bool isNegative = false;

            if(Base36Value[0] == '-') {
                Base36Value = Base36Value.Substring(1);
                isNegative = true;
            }
			
            //Loop through our string and calculate its value
            try {
                //Keep a running total of the value
                long returnValue = Base36DigitToNumber(Base36Value[Base36Value.Length - 1]);

                //Loop through the character in the string (right to left) and add
                //up increasing powers as we go.
                for(int i = 1; i < Base36Value.Length; i++) {
                    returnValue += ((long)Math.Pow(36, i) * Base36DigitToNumber(Base36Value[Base36Value.Length - (i + 1)]));
                }

                //Do negative correction if required:
                if(isNegative) {
                    return returnValue * -1;
                }
                else {
                    return returnValue;
                }
            }
            catch {
                //If something goes wrong, this is not a valid number
                throw new Exception(Base36Value);
            }		
        }


        /// <summary>
        /// Public static method to convert a long integer (base-10) to a Base36 number
        /// </summary>
        /// <param name="NumericValue">The base-10 long integer</param>
        /// <returns>A Base36 representation</returns>
        public static string NumberToBase36(long NumericValue) {
            try {
                //Handle negative values:
                if(NumericValue < 0) {
                    return string.Concat("-", PositiveNumberToBase36(Math.Abs(NumericValue)));
                }
                else {
                    return PositiveNumberToBase36(NumericValue);
                }
            }
            catch {
                throw new Exception("Unable to process number");
            }
        }


        #endregion

        #region Private Static Methods

        private static string PositiveNumberToBase36(long NumericValue) {
            //This is a clever recursively called function that builds
            //the base-36 string representation of the long base-10 value
            if(NumericValue < 36) {
                //The get out clause; fires when we reach a number less than 
                //36 - this means we can add the last digit.
                return NumberToBase36Digit((byte)NumericValue).ToString();		
            }
            else {
                //Add digits from left to right in powers of 36 
                //(recursive)
                return string.Concat(PositiveNumberToBase36(NumericValue / 36), NumberToBase36Digit((byte)(NumericValue % 36)).ToString());
            }
        }


        private static byte Base36DigitToNumber(char Base36Digit) {
            //Converts one base-36 digit to it's base-10 value
            if(!char.IsLetterOrDigit(Base36Digit)) {
                throw new Exception("Not a letter or digit");
            }

            if(char.IsDigit(Base36Digit)) {
                //Handles 0 - 9
                return byte.Parse(Base36Digit.ToString());
            }
            else {
                //Handles A - Z
                return (byte)((int)Base36Digit - 55);
            }
        }


        private static char NumberToBase36Digit(byte NumericValue) {
            //Converts a number to it's base-36 value.
            //Only works for numbers <= 35.
            if(NumericValue > 35) {
                throw new Exception("Number is greater than base 36 supports");
            }

            //Numbers:
            if(NumericValue <= 9) {
                return NumericValue.ToString()[0];
            }
            else {
                //Note that A is code 65, and in this
                //scheme, A = 10.
                return (char)(NumericValue + 55);
            }
        }
			

        #endregion
    }

}
