﻿using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Web.Mvc.Html;
using System.Web.Routing;
using Sitecore;
using Sitecore.Data;
using Sitecore.Data.Items;
using Sitecore.Links;
using Sitecore.Mvc;
using Sitecore.Mvc.Helpers;
using Sitecore.SecurityModel;

//hmm, it's the easiest way to use extensions, but not sure if it's ok to use the system.web.mvc namespace yet
namespace System.Web.Mvc
{
    public static class ControllerExtensions
    {
        public static RedirectResult RedirectToItem(this Controller controller, object pathOrId, object routeValues = null)
        {
            var item = SitecoreExtensions.GetItem(null, pathOrId);
            string requestedPath = null;
            if (pathOrId is string && (pathOrId.ToString()).Contains("/"))
            {
                requestedPath = SitecoreExtensions.getFullPath(pathOrId as string);
            }

            return controller.RedirectToItem(item, routeValues, requestedPath);
        }
        public static RedirectResult RedirectToItem(this Controller controller, Item item, object routeValues = null, string requestedObjectPath = null)
        {
            return new RedirectResult(SitecoreExtensions.Item(null, item, routeValues, requestedObjectPath));
        }
    }
}
namespace System.Web.Mvc.Html
{
    public static class SitecoreExtensions
    {
        public static Item GetItem(this SitecoreHelper sitecoreHelper, object pathOrId)
        {
            if (pathOrId == null)
            {
                return null;
            }

            if (pathOrId is string && (pathOrId.ToString()).Contains("/"))
            {
                pathOrId = getFullPath(pathOrId as string);
            }
            return pathOrId is ID
                       ? (Context.Database ?? Context.ContentDatabase).GetItem((ID) pathOrId)
                       : (Context.Database ?? Context.ContentDatabase).GetItem(pathOrId.ToString());
        }

        internal static string getFullPath(string path)
        {
            return path != null && !(path).StartsWith("/sitecore")
                       ? Context.Site.RootPath + "/" + path.TrimStart('/')
                       : path;
        }

        public static MvcHtmlString ItemLink(this HtmlHelper html, string linkText, object id, object routeValues = null, object htmlAttributes = null)
        {
            string requestedPath = null;
            if (id is string && (id.ToString()).Contains("/"))
            {
                requestedPath = getFullPath(id as string);
            }

            var item = html.Sitecore().GetItem(id);

            return html.ItemLink(linkText, item, routeValues, htmlAttributes, requestedPath);
        }

        public static MvcHtmlString ItemLink(this HtmlHelper html, string linkText, Item item, object routeValues = null, object htmlAttributes = null, string requestedObjectPath = null)
        {
            var url = Item(null, item, routeValues, requestedObjectPath);
            var tagBuilder = new TagBuilder("a")
            {
                InnerHtml = (!String.IsNullOrEmpty(linkText)) ? HttpUtility.HtmlEncode(linkText) : String.Empty
            };
            tagBuilder.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
            tagBuilder.MergeAttribute("href", url);
            return MvcHtmlString.Create(tagBuilder.ToString(TagRenderMode.Normal));
        }

        public static string Item(this UrlHelper urlHelper, object id, object routeValues = null)
        {
            string requestedPath = null;
            if (id is string && (id.ToString()).Contains("/"))
            {
                requestedPath = getFullPath(id as string);
            }

            var item = GetItem(null, id);
            return Item(urlHelper, item, routeValues, requestedPath);
        }
        public static string Item(this UrlHelper urlHelper, Item item, object routeValues = null, string requestedObjectPath = null)
        {
            var url = item != null ? LinkManager.GetItemUrl(item) : "";
            if (item != null)
            {
                var requestedPath = requestedObjectPath == null ? new string[0] : requestedObjectPath.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
                url = VirtualPathUtility.ToAppRelative(url);
                if (url.StartsWith("~/"))
                    url = url.Substring(2);
                var values = routeValues is IDictionary<string, object>
                                 ? (IDictionary<string, object>)routeValues
                                 : HtmlHelper.AnonymousObjectToHtmlAttributes(routeValues);
                var usedValues = new List<string> { "_sitecoreitem", "item" };
                var urlparts = url.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
                var wildcardItem = item;
                var i = urlparts.Length - 1;
                using (new SecurityDisabler())
                {
                    while (wildcardItem != null && i >= 0)
                    {
                        if (wildcardItem.Name == "*" && wildcardItem.DisplayName.Length > 1)
                        {
                            string name = wildcardItem.DisplayName.TrimStart('*', '(', ' ').TrimEnd(')', ' ');
                            if (values.ContainsKey(name))
                            {
                                urlparts[i] = values[name] + "";
                            }
                            else
                            {
                                if (i < requestedPath.Length)
                                {
                                    //requestedpath is always the full path!
                                    urlparts[i] = requestedPath[wildcardItem.Paths.FullPath.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries).Length - 1];
                                }
                            }
                            usedValues.Add(name.ToLower());
                        }
                        wildcardItem = wildcardItem.Parent;
                        i--;
                    }
                }
                var newurl = new StringBuilder("~/").Append(string.Join("/", urlparts));
                var extension = Path.GetExtension(url);
                if (!string.IsNullOrEmpty(extension) && !extension.Equals(Path.GetExtension(newurl.ToString())))
                    newurl.Append(extension);

                // Add remaining new values as query string parameters to the URL 
                // Generate the query string
                bool firstParam = !newurl.ToString().Contains("?");
                var unusedValues = values.Where(v => !usedValues.Contains(v.Key.ToLower()));
                foreach (var unusedValue in unusedValues)
                {
                    newurl.Append(firstParam ? '?' : '&');
                    firstParam = false;
                    newurl.Append(Uri.EscapeDataString(unusedValue.Key));
                    newurl.Append('=');
                    newurl.Append(
                        Uri.EscapeDataString(System.Convert.ToString(unusedValue.Value, CultureInfo.InvariantCulture)));
                }

                return VirtualPathUtility.ToAbsolute(newurl.ToString());
            }

            return string.Empty;
        }
    }
}
