// 
// Copyright (c) 2013-2016 Carsten Sonne Larsen <cs@innolan.dk>
// 
// 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.Generic;
using System.Linq;
using System.Text;

namespace Ntp.Common.Web
{
    public static class UriExtensions
    {
        public static Uri Append(this Uri uri, params string[] paths)
        {
            string basePath;
            UriKind uriKind;

            GetBase(uri, out basePath, out uriKind);
            string resPath = paths.Aggregate(
                basePath,
                (current, path) => $"{current.TrimEnd('/')}/{path.TrimStart('/')}");
            Uri newUri = new Uri(resPath, uriKind);

            return newUri;
        }

        public static Uri Append(this Uri uri, Uri relativeUri, params string[] paths)
        {
            string relativeUriText = relativeUri.IsAbsoluteUri
                ? relativeUri.AbsolutePath
                : relativeUri.ToString();
            var list = new List<string> {relativeUriText};
            list.AddRange(paths);
            return uri.Append(list.ToArray());
        }

        public static Uri Append(this Uri uri, Uri relativeUri, string path)
        {
            string relativeUriText = relativeUri.IsAbsoluteUri
                ? relativeUri.AbsolutePath
                : relativeUri.ToString();
            var list = new List<string> {relativeUriText, path};
            return uri.Append(list.ToArray());
        }

        public static Uri AppendExtension(this Uri uri, string extension)
        {
            string basePath;
            UriKind uriKind;

            GetBase(uri, out basePath, out uriKind);
            basePath = basePath.TrimEnd('/') + extension;
            Uri newUri = new Uri(basePath, uriKind);

            return newUri;
        }

        public static string DebugInfo(this Uri uri)
        {
            StringBuilder b = new StringBuilder();
            b.AppendLine($"ToString():     {uri}");
            b.AppendLine($"IsAbsoluteUri:  {uri.IsAbsoluteUri}");
            b.AppendLine($"OriginalString: {uri.OriginalString}");

            if (uri.IsAbsoluteUri)
            {
                b.AppendLine($"AbsolutePath:   {uri.AbsolutePath}");
                b.AppendLine($"AbsoluteUri:    {uri.AbsoluteUri}");
                b.AppendLine($"Authority:      {uri.Authority}");
                b.AppendLine($"DnsSafeHost:    {uri.DnsSafeHost}");
                b.AppendLine($"Fragment:       {uri.Fragment}");
                b.AppendLine($"Host:           {uri.Host}");
                b.AppendLine($"HostNameType:   {uri.HostNameType}");
                b.AppendLine($"IsDefaultPort   {uri.IsDefaultPort}");
                b.AppendLine($"IsFile:         {uri.IsFile}");
                b.AppendLine($"IsLoopback:     {uri.IsLoopback}");
                b.AppendLine($"IsUnc:          {uri.IsUnc}");
                b.AppendLine($"LocalPath:      {uri.LocalPath}");
                b.AppendLine($"PathAndQuery:   {uri.PathAndQuery}");
                b.AppendLine($"Port:           {uri.Port}");
                b.AppendLine($"Query:          {uri.Query}");
                b.AppendLine($"Scheme:         {uri.Scheme}");
                b.AppendLine($"Segments:       {uri.Segments}");
                b.AppendLine($"UserEscaped:    {uri.UserEscaped}");
                b.AppendLine($"UserInfo:       {uri.UserInfo}");
            }

            return b.ToString();
        }

        public static string ToHtmlString(this Uri uri)
        {
            return Uri.EscapeUriString(uri.ToString());
        }

        private static void GetBase(Uri uri, out string basePath, out UriKind uriKind)
        {
            string orig = uri.OriginalString.TrimStart();
            if (orig.StartsWith("/") && !orig.StartsWith("//"))
            {
                basePath = uri.IsAbsoluteUri
                    ? uri.AbsolutePath
                    : uri.ToString();
                uriKind = UriKind.Relative;
            }
            else
            {
                basePath = uri.ToString();
                uriKind = UriKind.Absolute;
            }
        }
    }
}