<commit_before>﻿using Pchp.Core;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Pchp.Library
{
    /// <summary>
	/// The flags indicating which fields the <see cref="PhpPath.GetInfo"/>
	/// method should fill in the result array.
	/// </summary>
	[Flags]
    public enum PathInfoOptions
    {
        /// <summary>
        /// Fill the "dirname" field in results.
        /// </summary>
        //[ImplementsConstant("PATHINFO_DIRNAME")]
        DirName = 1,

        /// <summary>
        /// Fill the "basename" field in results.
        /// </summary>
        //[ImplementsConstant("PATHINFO_BASENAME")]
        BaseName = 2,

        /// <summary>
        /// Fill the "extension" field in results.
        /// </summary>
        //[ImplementsConstant("PATHINFO_EXTENSION")]
        Extension = 4,

        /// <summary>
        /// Fill the "filename" field in results. Since PHP 5.2.0.
        /// </summary>
        //[ImplementsConstant("PATHINFO_FILENAME")]
        FileName = 8,

        /// <summary>
        /// All the four options result in an array returned by <see cref="PhpPath.GetInfo"/>.
        /// </summary>
        All = DirName | BaseName | Extension | FileName
    }

    public static class PhpPath
    {
        #region Scheme, Url, Absolute Path

        /// <summary>
        /// Wrapper-safe method of getting the schema portion from an URL.
        /// </summary>
        /// <param name="path">A <see cref="string"/> containing an URL or a local filesystem path.</param>
        /// <returns>
        /// The schema portion of the given <paramref name="path"/> or <c>"file"</c>
        /// for a local filesystem path.
        /// </returns>
        /// <exception cref="ArgumentException">Invalid path.</exception>
        internal static string GetScheme(string/*!*/ path)
        {
            int colon_index = path.IndexOf(':');

            // When there is not scheme present (or it's a local path) return "file".
            if (colon_index == -1 || Path.IsPathRooted(path))
                return "file";

            // Otherwise assume that it's the string before first ':'.
            return path.Substring(0, colon_index);
        }

        /// <summary>
        /// Concatenates a scheme with the given absolute path if necessary.
        /// </summary>
        /// <param name="absolutePath">Absolute path.</param>
        /// <returns>The given url or absolute path preceded by a <c>file://</c>.</returns>
        /// <exception cref="ArgumentException">Invalid path.</exception>
        internal static string GetUrl(string/*!*/ absolutePath)
        {
            // Assert that the path is absolute
            //Debug.Assert(
            //    !string.IsNullOrEmpty(absolutePath) &&
            //    (absolutePath.IndexOf(':') > 0 ||   // there is a protocol (http://) or path is rooted (c:\)
            //        (Path.VolumeSeparatorChar != ':' && // or on linux, if there is no protocol, file path is rooted
            //            (absolutePath[0] == Path.DirectorySeparatorChar || absolutePath[0] == Path.AltDirectorySeparatorChar)))
            //    );

            if (Path.IsPathRooted(absolutePath))
                return String.Concat("file://", absolutePath);

            // Otherwise assume that it's the string before first ':'.
            return absolutePath;
        }

        /// <summary>
        /// Returns the given filesystem url without the scheme.
        /// </summary>
        /// <param name="path">A path or url of a local filesystem file.</param>
        /// <returns>The filesystem path or <b>null</b> if the <paramref name="path"/> is not a local file.</returns>
        /// <exception cref="ArgumentException">Invalid path.</exception>
        internal static string GetFilename(string/*!*/ path)
        {
            if (path.IndexOf(':') == -1 || Path.IsPathRooted(path)) return path;
            if (path.IndexOf("file://") == 0) return path.Substring("file://".Length);
            return null;
        }

        /// <summary>
        /// Check if the given path is a path to a local file.
        /// </summary>
        /// <param name="url">The path to test.</param>
        /// <returns><c>true</c> if it's not a fully qualified name of a remote resource.</returns>
        /// <exception cref="ArgumentException">Invalid path.</exception>
        internal static bool IsLocalFile(string/*!*/ url)
        {
            return GetScheme(url) == "file";
        }

        /// <summary>
        /// Check if the given path is a remote url.
        /// </summary>
        /// <param name="url">The path to test.</param>
        /// <returns><c>true</c> if it's a fully qualified name of a remote resource.</returns>
        /// <exception cref="ArgumentException">Invalid path.</exception>
        internal static bool IsRemoteFile(string/*!*/ url)
        {
            return GetScheme(url) != "file";
        }

        /// <summary>
        /// Merges the path with the current working directory
        /// to get a canonicalized absolute pathname representing the same path
        /// (local files only). If the provided <paramref name="path"/>
        /// is absolute (rooted local path or an URL) it is returned unchanged.
        /// </summary>
        /// <param name="path">An absolute or relative path to a directory or an URL.</param>
        /// <returns>Canonicalized absolute path in case of a local directory or the original 
        /// <paramref name="path"/> in case of an URL.</returns>
        internal static string AbsolutePath(string path)
        {
            // Don't combine remote file paths with CWD.
            try
            {
                if (IsRemoteFile(path))
                    return path;

                // Remove the file:// schema if any.
                path = GetFilename(path);

                //// Combine the path and simplify it.
                //string combinedPath = Path.Combine(PhpDirectory.GetWorking(), path);

                //// Note: GetFullPath handles "C:" incorrectly
                //if (combinedPath[combinedPath.Length - 1] == ':') combinedPath += PathUtils.DirectorySeparator;
                //return Path.GetFullPath(combinedPath);
                throw new NotImplementedException();
            }
            catch (Exception)
            {
                //PhpException.Throw(PhpError.Notice, LibResources.GetString("invalid_path", FileSystemUtils.StripPassword(path)));
                //return null;
                throw;
            }
        }

        #endregion

        #region basename, dirname, pathinfo

        /// <summary>
        /// Returns path component of path.
        /// </summary>
        /// <param name="path">A <see cref="string"/> containing a path to a file.</param>
        /// <returns>The path conponent of the given <paramref name="path"/>.</returns>
        /// <exception cref="ArgumentException">Invalid path.</exception>
        public static string basename(string path) => basename(path, null);

        /// <summary>
        /// Returns path component of path.
        /// </summary>
        /// <remarks>
        /// Given a <see cref="string"/> containing a path to a file, this function will return the base name of the file. 
        /// If the path ends in this will also be cut off. 
        /// On Windows, both slash (/) and backslash (\) are used as path separator character. 
        /// In other environments, it is the forward slash (/). 
        /// </remarks>
        /// <param name="path">A <see cref="string"/> containing a path to a file.</param>
        /// <param name="suffix">A <see cref="string"/> containing suffix to be cut off the path if present.</param>
        /// <returns>The path conponent of the given <paramref name="path"/>.</returns>
        public static string basename(string path, string suffix)
        {
            if (String.IsNullOrEmpty(path)) return string.Empty;

            int end = path.Length - 1;
            while (end >= 0 && path[end].IsDirectorySeparator()) end--;

            int start = end;
            while (start >= 0 && !path[start].IsDirectorySeparator()) start--;
            start++;<commit_msg>PATHINFO constants<commit_after>﻿using Pchp.Core;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Pchp.Library
{
    public static class PhpPath
    {
        #region Constants

        /// <summary>
        /// Fill the "dirname" field in results.
        /// </summary>
        public const int PATHINFO_DIRNAME = (int)PathInfoOptions.DirName;

        /// <summary>
        /// Fill the "basename" field in results.
        /// </summary>
        public const int PATHINFO_BASENAME = (int)PathInfoOptions.BaseName;

        /// <summary>
        /// Fill the "extension" field in results.
        /// </summary>
        public const int PATHINFO_EXTENSION = (int)PathInfoOptions.Extension;

        /// <summary>
        /// Fill the "filename" field in results. Since PHP 5.2.0.
        /// </summary>
        public const int PATHINFO_FILENAME = (int)PathInfoOptions.FileName;

        #endregion

        #region Scheme, Url, Absolute Path

        /// <summary>
        /// Wrapper-safe method of getting the schema portion from an URL.
        /// </summary>
        /// <param name="path">A <see cref="string"/> containing an URL or a local filesystem path.</param>
        /// <returns>
        /// The schema portion of the given <paramref name="path"/> or <c>"file"</c>
        /// for a local filesystem path.
        /// </returns>
        /// <exception cref="ArgumentException">Invalid path.</exception>
        internal static string GetScheme(string/*!*/ path)
        {
            int colon_index = path.IndexOf(':');

            // When there is not scheme present (or it's a local path) return "file".
            if (colon_index == -1 || Path.IsPathRooted(path))
                return "file";

            // Otherwise assume that it's the string before first ':'.
            return path.Substring(0, colon_index);
        }

        /// <summary>
        /// Concatenates a scheme with the given absolute path if necessary.
        /// </summary>
        /// <param name="absolutePath">Absolute path.</param>
        /// <returns>The given url or absolute path preceded by a <c>file://</c>.</returns>
        /// <exception cref="ArgumentException">Invalid path.</exception>
        internal static string GetUrl(string/*!*/ absolutePath)
        {
            // Assert that the path is absolute
            //Debug.Assert(
            //    !string.IsNullOrEmpty(absolutePath) &&
            //    (absolutePath.IndexOf(':') > 0 ||   // there is a protocol (http://) or path is rooted (c:\)
            //        (Path.VolumeSeparatorChar != ':' && // or on linux, if there is no protocol, file path is rooted
            //            (absolutePath[0] == Path.DirectorySeparatorChar || absolutePath[0] == Path.AltDirectorySeparatorChar)))
            //    );

            if (Path.IsPathRooted(absolutePath))
                return String.Concat("file://", absolutePath);

            // Otherwise assume that it's the string before first ':'.
            return absolutePath;
        }

        /// <summary>
        /// Returns the given filesystem url without the scheme.
        /// </summary>
        /// <param name="path">A path or url of a local filesystem file.</param>
        /// <returns>The filesystem path or <b>null</b> if the <paramref name="path"/> is not a local file.</returns>
        /// <exception cref="ArgumentException">Invalid path.</exception>
        internal static string GetFilename(string/*!*/ path)
        {
            if (path.IndexOf(':') == -1 || Path.IsPathRooted(path)) return path;
            if (path.IndexOf("file://") == 0) return path.Substring("file://".Length);
            return null;
        }

        /// <summary>
        /// Check if the given path is a path to a local file.
        /// </summary>
        /// <param name="url">The path to test.</param>
        /// <returns><c>true</c> if it's not a fully qualified name of a remote resource.</returns>
        /// <exception cref="ArgumentException">Invalid path.</exception>
        internal static bool IsLocalFile(string/*!*/ url)
        {
            return GetScheme(url) == "file";
        }

        /// <summary>
        /// Check if the given path is a remote url.
        /// </summary>
        /// <param name="url">The path to test.</param>
        /// <returns><c>true</c> if it's a fully qualified name of a remote resource.</returns>
        /// <exception cref="ArgumentException">Invalid path.</exception>
        internal static bool IsRemoteFile(string/*!*/ url)
        {
            return GetScheme(url) != "file";
        }

        /// <summary>
        /// Merges the path with the current working directory
        /// to get a canonicalized absolute pathname representing the same path
        /// (local files only). If the provided <paramref name="path"/>
        /// is absolute (rooted local path or an URL) it is returned unchanged.
        /// </summary>
        /// <param name="path">An absolute or relative path to a directory or an URL.</param>
        /// <returns>Canonicalized absolute path in case of a local directory or the original 
        /// <paramref name="path"/> in case of an URL.</returns>
        internal static string AbsolutePath(string path)
        {
            // Don't combine remote file paths with CWD.
            try
            {
                if (IsRemoteFile(path))
                    return path;

                // Remove the file:// schema if any.
                path = GetFilename(path);

                //// Combine the path and simplify it.
                //string combinedPath = Path.Combine(PhpDirectory.GetWorking(), path);

                //// Note: GetFullPath handles "C:" incorrectly
                //if (combinedPath[combinedPath.Length - 1] == ':') combinedPath += PathUtils.DirectorySeparator;
                //return Path.GetFullPath(combinedPath);
                throw new NotImplementedException();
            }
            catch (Exception)
            {
                //PhpException.Throw(PhpError.Notice, LibResources.GetString("invalid_path", FileSystemUtils.StripPassword(path)));
                //return null;
                throw;
            }
        }

        #endregion

        #region basename, dirname, pathinfo

        /// <summary>
        /// The flags indicating which fields the <see cref="pathinfo(string, PathInfoOptions)"/>
        /// method should fill in the result array.
        /// </summary>
        [Flags]
        public enum PathInfoOptions
        {
            /// <summary>
            /// Fill the "dirname" field in results.
            /// </summary>
            DirName = 1,

            /// <summary>
            /// Fill the "basename" field in results.
            /// </summary>
            BaseName = 2,

            /// <summary>
            /// Fill the "extension" field in results.
            /// </summary>
            Extension = 4,

            /// <summary>
            /// Fill the "filename" field in results. Since PHP 5.2.0.
            /// </summary>
            FileName = 8,

            /// <summary>
            /// All the four options result in an array returned by <see cref="PhpPath.GetInfo"/>.
            /// </summary>
            All = DirName | BaseName | Extension | FileName
        }

        /// <summary>
        /// Returns path component of path.
        /// </summary>
        /// <param name="path">A <see cref="string"/> containing a path to a file.</param>
        /// <returns>The path conponent of the given <paramref name="path"/>.</returns>
        /// <exception cref="ArgumentException">Invalid path.</exception>
        public static string basename(string path) => basename(path, null);

        /// <summary>
        /// Returns path component of path.
        /// </summary>
        /// <remarks>
        /// Given a <see cref="string"/> containing a path to a file, this function will return the base name of the file. 
        /// If the path ends in this will also be cut off. 
        /// On Windows, both slash (/) and backslash (\) are used as path separator character. 
        /// In other environments, it is the forward slash (/). 
        /// </remarks>
        /// <param name="path">A <see cref="string"/> containing a path to a file.</param>
        /// <param name="suffix">A <see cref="string"/> containing suffix to be cut off the path if present.</param>
        /// <returns>The path conponent of the given <paramref name="path"/>.</returns>
        public static string basename(string path, string suffix)
        {
            if (String.IsNullOrEmpty(path)) return string.Empty;

            int end = path.Length - 1;
            while (end >= 0 && path[end].IsDirectorySeparator()) end--;

            int start = end;
            while (start >= 0 && !path[start].IsDirectorySeparator()) start--;
            start++;
{'fraction_non_alphanumeric': 0.13369045561891596, 'fraction_numerical': 0.0022464143770520133, 'mean_word_length': 1.7890763052208836, 'pattern_counts': {'":': 0, '<': 209, '<?xml version=': 0, '>': 217, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5319900', 'n_tokens_mistral': 4488, 'n_tokens_neox': 4317, 'n_words': 1471}