/*
 * FileName.cs --
 *
 * Copyright (c) 2007-2012 by Joe Mistachkin.  All rights reserved.
 *
 * See the file "license.terms" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: $
 */

using System;
using System.Collections.Generic;
using System.Text;
using Eagle._Attributes;
using Eagle._Components.Private;
using Eagle._Components.Public;

namespace Eagle._Comparers
{
    [ObjectId("7300d32f-8c23-49fc-9234-8812ad5813b9")]
    internal sealed class FileName : IComparer<string>, IEqualityComparer<string>
    {
        #region Private Constants
        private static readonly StringComparison stringComparisonType =
            PathOps.ComparisonType;
        #endregion

        ///////////////////////////////////////////////////////////////////////

        #region Private Data
        private Encoding encoding;
        private PathComparisonType pathComparisonType;
        #endregion

        ///////////////////////////////////////////////////////////////////////

        #region Public Constructors
        public FileName()
            : this(PathComparisonType.Default)
        {
            // do nothing.
        }

        ///////////////////////////////////////////////////////////////////////

        public FileName(
            PathComparisonType pathComparisonType
            )
            : this(Encoding.UTF8, pathComparisonType)
        {
            // do nothing.
        }

        ///////////////////////////////////////////////////////////////////////

        public FileName(
            Encoding encoding,
            PathComparisonType pathComparisonType
            )
        {
            this.encoding = encoding;
            this.pathComparisonType = pathComparisonType;
        }
        #endregion

        ///////////////////////////////////////////////////////////////////////

        #region Private Methods
        private bool UseStringCompare()
        {
            return ((pathComparisonType == PathComparisonType.None) ||
                (pathComparisonType == PathComparisonType.String));
        }

        ///////////////////////////////////////////////////////////////////////

        private bool UseDeepestFirst()
        {
            return pathComparisonType == PathComparisonType.DeepestFirst;
        }

        ///////////////////////////////////////////////////////////////////////

        private string[] SplitFileName(
            string fileName
            )
        {
            if (fileName == null)
                return null;

            return fileName.Split(PathOps.DirectoryChars);
        }
        #endregion

        ///////////////////////////////////////////////////////////////////////

        #region IComparer<string> Members
        public int Compare(
            string x,
            string y
            )
        {
            if (UseStringCompare())
                return String.Compare(x, y, stringComparisonType);

            ///////////////////////////////////////////////////////////////////

            if ((x == null) && (y == null))
            {
                return 0;
            }
            else if (x == null)
            {
                if (UseDeepestFirst())
                    return 1;

                return -1;
            }
            else if (y == null)
            {
                if (UseDeepestFirst())
                    return -1;

                return 1;
            }
            else
            {
                string[] px = SplitFileName(x);
                string[] py = SplitFileName(y);

                int lx = px.Length;
                int ly = py.Length;

                int result = 0;

                for (int index = 0; index < Math.Min(lx, ly); index++)
                {
                    result = String.Compare(px[index], py[index],
                        stringComparisonType);

                    if (result != 0)
                        break;
                }

                if (lx == ly)
                    return result;

                if (UseDeepestFirst())
                {
                    if (lx > ly)
                        return -1;

                    return 1;
                }
                else
                {
                    if (lx > ly)
                        return 1;

                    return -1;
                }
            }
        }
        #endregion

        ///////////////////////////////////////////////////////////////////////

        #region IEqualityComparer<string> Members
        public bool Equals(
            string x,
            string y
            )
        {
            return Compare(x, y) == 0;
        }

        ///////////////////////////////////////////////////////////////////////

        public int GetHashCode(string obj)
        {
            int result = 0;

            if ((obj != null) && (encoding != null))
            {
                if (!UseStringCompare())
                    result = SplitFileName(obj).Length;

                result ^= unchecked((int)MathOps.HashFnv1UInt(
                    encoding.GetBytes(obj), true));
            }

            return result;
        }
        #endregion
    }
}
