
import { CharCode } from './charCode.js';
import { isEqualOrParent as isEqualOrParent$1, toSlashes, toPosixPath, getRoot } from './extpath.js';
import { Schemas } from './network.js';
import { posix, dirname as dirname$1, normalize, relative, resolve, sep } from './path.js';
import { isWindows, isLinux } from './platform.js';
import { compare, equalsIgnoreCase } from './strings.js';
import { uriToFsPath, URI } from './uri.js';

function originalFSPath(uri) {
    return uriToFsPath(uri, true);
}
class ExtUri {
    constructor(_ignorePathCasing) {
        this._ignorePathCasing = _ignorePathCasing;
    }
    compare(uri1, uri2, ignoreFragment = false) {
        if (uri1 === uri2) {
            return 0;
        }
        return compare(
            this.getComparisonKey(uri1, ignoreFragment),
            this.getComparisonKey(uri2, ignoreFragment)
        );
    }
    isEqual(uri1, uri2, ignoreFragment = false) {
        if (uri1 === uri2) {
            return true;
        }
        if (!uri1 || !uri2) {
            return false;
        }
        return this.getComparisonKey(uri1, ignoreFragment) === this.getComparisonKey(uri2, ignoreFragment);
    }
    getComparisonKey(uri, ignoreFragment = false) {
        return ( uri.with({
            path: this._ignorePathCasing(uri) ? uri.path.toLowerCase() : undefined,
            fragment: ignoreFragment ? null : undefined
        }).toString());
    }
    ignorePathCasing(uri) {
        return this._ignorePathCasing(uri);
    }
    isEqualOrParent(base, parentCandidate, ignoreFragment = false) {
        if (base.scheme === parentCandidate.scheme) {
            if (base.scheme === Schemas.file) {
                return isEqualOrParent$1(
                    originalFSPath(base),
                    originalFSPath(parentCandidate),
                    this._ignorePathCasing(base)
                ) && base.query === parentCandidate.query && (ignoreFragment || base.fragment === parentCandidate.fragment);
            }
            if (isEqualAuthority(base.authority, parentCandidate.authority)) {
                return isEqualOrParent$1(base.path, parentCandidate.path, this._ignorePathCasing(base), "/") && base.query === parentCandidate.query && (ignoreFragment || base.fragment === parentCandidate.fragment);
            }
        }
        return false;
    }
    joinPath(resource, ...pathFragment) {
        return URI.joinPath(resource, ...pathFragment);
    }
    basenameOrAuthority(resource) {
        return basename(resource) || resource.authority;
    }
    basename(resource) {
        return posix.basename(resource.path);
    }
    extname(resource) {
        return posix.extname(resource.path);
    }
    dirname(resource) {
        if (resource.path.length === 0) {
            return resource;
        }
        let dirname;
        if (resource.scheme === Schemas.file) {
            dirname = URI.file(dirname$1(originalFSPath(resource))).path;
        } else {
            dirname = posix.dirname(resource.path);
            if (resource.authority && dirname.length && dirname.charCodeAt(0) !== CharCode.Slash) {
                console.error(`dirname("${resource.toString})) resulted in a relative path`);
                dirname = "/";
            }
        }
        return resource.with({
            path: dirname
        });
    }
    normalizePath(resource) {
        if (!resource.path.length) {
            return resource;
        }
        let normalizedPath;
        if (resource.scheme === Schemas.file) {
            normalizedPath = URI.file(normalize(originalFSPath(resource))).path;
        } else {
            normalizedPath = posix.normalize(resource.path);
        }
        return resource.with({
            path: normalizedPath
        });
    }
    relativePath(from, to) {
        if (from.scheme !== to.scheme || !isEqualAuthority(from.authority, to.authority)) {
            return undefined;
        }
        if (from.scheme === Schemas.file) {
            const relativePath = relative(originalFSPath(from), originalFSPath(to));
            return isWindows ? toSlashes(relativePath) : relativePath;
        }
        let fromPath = from.path || "/";
        const toPath = to.path || "/";
        if (this._ignorePathCasing(from)) {
            let i = 0;
            for (const len = Math.min(fromPath.length, toPath.length); i < len; i++) {
                if (fromPath.charCodeAt(i) !== toPath.charCodeAt(i)) {
                    if (fromPath.charAt(i).toLowerCase() !== toPath.charAt(i).toLowerCase()) {
                        break;
                    }
                }
            }
            fromPath = toPath.substr(0, i) + fromPath.substr(i);
        }
        return posix.relative(fromPath, toPath);
    }
    resolvePath(base, path) {
        if (base.scheme === Schemas.file) {
            const newURI = URI.file(resolve(originalFSPath(base), path));
            return base.with({
                authority: newURI.authority,
                path: newURI.path
            });
        }
        path = toPosixPath(path);
        return base.with({
            path: posix.resolve(base.path, path)
        });
    }
    isAbsolutePath(resource) {
        return !!resource.path && resource.path[0] === "/";
    }
    isEqualAuthority(a1, a2) {
        return a1 === a2 || (a1 !== undefined && a2 !== undefined && equalsIgnoreCase(a1, a2));
    }
    hasTrailingPathSeparator(resource, sep$1 = sep) {
        if (resource.scheme === Schemas.file) {
            const fsp = originalFSPath(resource);
            return fsp.length > getRoot(fsp).length && fsp[fsp.length - 1] === sep$1;
        } else {
            const p = resource.path;
            return (p.length > 1 && p.charCodeAt(p.length - 1) === CharCode.Slash) && !(/^[a-zA-Z]:(\/$|\\$)/.test(resource.fsPath));
        }
    }
    removeTrailingPathSeparator(resource, sep$1 = sep) {
        if (hasTrailingPathSeparator(resource, sep$1)) {
            return resource.with({
                path: resource.path.substr(0, resource.path.length - 1)
            });
        }
        return resource;
    }
    addTrailingPathSeparator(resource, sep$1 = sep) {
        let isRootSep = false;
        if (resource.scheme === Schemas.file) {
            const fsp = originalFSPath(resource);
            isRootSep = ((fsp !== undefined) && (fsp.length === getRoot(fsp).length) && (fsp[fsp.length - 1] === sep$1));
        } else {
            sep$1 = "/";
            const p = resource.path;
            isRootSep = p.length === 1 && p.charCodeAt(p.length - 1) === CharCode.Slash;
        }
        if (!isRootSep && !hasTrailingPathSeparator(resource, sep$1)) {
            return resource.with({
                path: resource.path + "/"
            });
        }
        return resource;
    }
}
const extUri = ( new ExtUri(() => false));
const extUriBiasedIgnorePathCase = ( new ExtUri(uri => {
    return uri.scheme === Schemas.file ? !isLinux : true;
}));
const extUriIgnorePathCase = ( new ExtUri(_ => true));
const isEqual = extUri.isEqual.bind(extUri);
const isEqualOrParent = extUri.isEqualOrParent.bind(extUri);
extUri.getComparisonKey.bind(extUri);
const basenameOrAuthority = extUri.basenameOrAuthority.bind(extUri);
const basename = extUri.basename.bind(extUri);
const extname = extUri.extname.bind(extUri);
const dirname = extUri.dirname.bind(extUri);
const joinPath = extUri.joinPath.bind(extUri);
const normalizePath = extUri.normalizePath.bind(extUri);
const relativePath = extUri.relativePath.bind(extUri);
const resolvePath = extUri.resolvePath.bind(extUri);
const isAbsolutePath = extUri.isAbsolutePath.bind(extUri);
const isEqualAuthority = extUri.isEqualAuthority.bind(extUri);
const hasTrailingPathSeparator = extUri.hasTrailingPathSeparator.bind(extUri);
const removeTrailingPathSeparator = extUri.removeTrailingPathSeparator.bind(extUri);
const addTrailingPathSeparator = extUri.addTrailingPathSeparator.bind(extUri);
function distinctParents(items, resourceAccessor) {
    const distinctParents = [];
    for (let i = 0; i < items.length; i++) {
        const candidateResource = resourceAccessor(items[i]);
        if (( items.some((otherItem, index) => {
            if (index === i) {
                return false;
            }
            return isEqualOrParent(candidateResource, resourceAccessor(otherItem));
        }))) {
            continue;
        }
        distinctParents.push(items[i]);
    }
    return distinctParents;
}
var DataUri;
(function(DataUri) {
    DataUri.META_DATA_LABEL = "label";
    DataUri.META_DATA_DESCRIPTION = "description";
    DataUri.META_DATA_SIZE = "size";
    DataUri.META_DATA_MIME = "mime";
    function parseMetaData(dataUri) {
        const metadata = ( new Map());
        const meta = dataUri.path.substring(dataUri.path.indexOf(";") + 1, dataUri.path.lastIndexOf(";"));
        meta.split(";").forEach(property => {
            const [key, value] = property.split(":");
            if (key && value) {
                metadata.set(key, value);
            }
        });
        const mime = dataUri.path.substring(0, dataUri.path.indexOf(";"));
        if (mime) {
            metadata.set(DataUri.META_DATA_MIME, mime);
        }
        return metadata;
    }
    DataUri.parseMetaData = parseMetaData;
})(DataUri || (DataUri = {}));
function toLocalResource(resource, authority, localScheme) {
    if (authority) {
        let path = resource.path;
        if (path && path[0] !== posix.sep) {
            path = posix.sep + path;
        }
        return resource.with({
            scheme: localScheme,
            authority,
            path
        });
    }
    return resource.with({
        scheme: localScheme
    });
}

export { DataUri, ExtUri, addTrailingPathSeparator, basename, basenameOrAuthority, dirname, distinctParents, extUri, extUriBiasedIgnorePathCase, extUriIgnorePathCase, extname, hasTrailingPathSeparator, isAbsolutePath, isEqual, isEqualAuthority, isEqualOrParent, joinPath, normalizePath, originalFSPath, relativePath, removeTrailingPathSeparator, resolvePath, toLocalResource };
