<commit_before>﻿import api = require("./fs-api");
import misc = require("./fs-misc");
import sources = require("./fs-sources");
import targets = require("./fs-targets");
import util = require("./util");
import glob = require("./fs-glob");
import events = require("events");

import IFilesystem = api.IFilesystem;
import IItem = api.IItem;
import IStats = api.IStats;
import IDataSource = misc.IDataSource;
import IDataTarget = misc.IDataTarget;
import FileUtil = misc.FileUtil;
import Path = misc.Path;
import FileDataTarget = targets.FileDataTarget;
import BlobDataTarget = targets.BlobDataTarget;
import StringDataTarget = targets.StringDataTarget;
import BufferDataTarget = targets.BufferDataTarget;
import FileDataSource = sources.FileDataSource;
import toDataSource = sources.toDataSource;
import Task = util.Task;
import wrapCallback = util.wrapCallback;
import EventEmitter = events.EventEmitter;
import search = glob.search;

export interface IFilesystemExt extends FilesystemPlus {
}

export class FilesystemPlus extends EventEmitter implements IFilesystem {

    protected _fs: IFilesystem;
    protected _local: IFilesystem;

    constructor(fs: IFilesystem, local: IFilesystem) {
        super();
        this._fs = fs;
        this._local = local;
    }

    open(path: string, flags: string, attrs?: IStats, callback?: (err: Error, handle: any) => any): void {
        if (typeof attrs === 'function' && typeof callback === 'undefined') {
            callback = <any>attrs;
            attrs = null;
        }
        callback = wrapCallback(this, null, callback);

        this._fs.open(path, flags, attrs, callback);
    }

    close(handle: any, callback?: (err: Error) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.close(handle, callback);
    }

    read(handle: any, buffer: NodeBuffer, offset: number, length: number, position: number, callback?: (err: Error, bytesRead: number, buffer: NodeBuffer) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.read(handle, buffer, offset, length, position, callback);
    }

    write(handle: any, buffer: NodeBuffer, offset: number, length: number, position: number, callback?: (err: Error) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.write(handle, buffer, offset, length, position, callback);
    }

    lstat(path: string, callback?: (err: Error, attrs: IStats) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.lstat(path, callback);
    }

    fstat(handle: any, callback?: (err: Error, attrs: IStats) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.fstat(handle, callback);
    }

    setstat(path: string, attrs: IStats, callback?: (err: Error) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.setstat(path, attrs, callback);
    }

    fsetstat(handle: any, attrs: IStats, callback?: (err: Error) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.fsetstat(handle, attrs, callback);
    }

    opendir(path: string, callback?: (err: Error, handle: any) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.opendir(path, callback);
    }

    readdir(path: string, callback?: (err: Error, items: IItem[]) => any)
    readdir(handle: any, callback?: (err: Error, items: IItem[]|boolean) => any)
    readdir(handle: any, callback?: (err: Error, items: IItem[]|boolean) => any): void {
        if (typeof handle === 'string') {
            var path = <string>handle;
            this.list(path, callback); //TODO: supply an option that turns off wildcards
            return;
        }

        callback = wrapCallback(this, null, callback);

        return this._fs.readdir(handle, callback);
    }

    unlink(path: string, callback?: (err: Error) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.unlink(path, callback);
    }

    mkdir(path: string, attrs?: IStats, callback?: (err: Error) => any): void {
        if (typeof attrs === 'function' && typeof callback === 'undefined') {
            callback = <any>attrs;
            attrs = null;
        }
        callback = wrapCallback(this, null, callback);

        this._fs.mkdir(path, attrs, callback);
    }

    rmdir(path: string, callback?: (err: Error) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.rmdir(path, callback);
    }

    realpath(path: string, callback?: (err: Error, resolvedPath: string) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.realpath(path, callback);
    }

    stat(path: string, callback?: (err: Error, attrs: IStats) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.stat(path, callback);
    }

    rename(oldPath: string, newPath: string, callback?: (err: Error) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.rename(oldPath, newPath, callback);
    }

    readlink(path: string, callback?: (err: Error, linkString: string) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.readlink(path, callback);
    }

    symlink(targetpath: string, linkpath: string, callback?: (err: Error) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.symlink(targetpath, linkpath, callback);
    }

    link(oldPath: string, newPath: string, callback?: (err: Error) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.link(oldPath, newPath, callback);
    }

    list(remotePath: string, callback?: (err: Error, items: IItem[]) => any): Task {
        var task = new Task();
        callback = wrapCallback(this, task, callback);

        search(this._fs, remotePath, task, {}, callback);

        return task;
    }

    readFile(remotePath: string, options: { type?: string; encoding?: string; flag?: string; mimeType?: string; }, callback?: (err: Error, data: any) => any): Task {
        var task = new Task();
        callback = wrapCallback(this, task, callback);

        // process options
        options = options || {};
        var type = options.type;
        var encoding = options.encoding
        if (type) {
            type = (type + "").toLowerCase();
            if (type == "string" || type == "text") encoding = encoding || "utf8";
        } else {
            type = encoding ? "string" : "buffer";
        }

        // create appropriate target
        var target: IDataTarget;
        switch (type) {
            case "text":
            case "string":
                target = new StringDataTarget(encoding);
                break;
            case "array":
            case "buffer":
                target = new BufferDataTarget();
                break;
            case "blob":
                // WEB: target = new BlobDataTarget(options.mimeType);<commit_msg>Finalized readdir(string, callback) and list functions, added search and info<commit_after>﻿import api = require("./fs-api");
import misc = require("./fs-misc");
import sources = require("./fs-sources");
import targets = require("./fs-targets");
import util = require("./util");
import glob = require("./fs-glob");
import events = require("events");

import IFilesystem = api.IFilesystem;
import IItem = api.IItem;
import IStats = api.IStats;
import IDataSource = misc.IDataSource;
import IDataTarget = misc.IDataTarget;
import FileUtil = misc.FileUtil;
import Path = misc.Path;
import FileDataTarget = targets.FileDataTarget;
import BlobDataTarget = targets.BlobDataTarget;
import StringDataTarget = targets.StringDataTarget;
import BufferDataTarget = targets.BufferDataTarget;
import FileDataSource = sources.FileDataSource;
import toDataSource = sources.toDataSource;
import Task = util.Task;
import wrapCallback = util.wrapCallback;
import EventEmitter = events.EventEmitter;
import search = glob.search;
import ISearchOptionsExt = glob.ISearchOptionsExt;
import ISearchOptions = glob.ISearchOptions;

export interface IFilesystemExt extends FilesystemPlus {
}

export class FilesystemPlus extends EventEmitter implements IFilesystem {

    protected _fs: IFilesystem;
    protected _local: IFilesystem;

    constructor(fs: IFilesystem, local: IFilesystem) {
        super();
        this._fs = fs;
        this._local = local;
    }

    open(path: string, flags: string, attrs?: IStats, callback?: (err: Error, handle: any) => any): void {
        if (typeof attrs === 'function' && typeof callback === 'undefined') {
            callback = <any>attrs;
            attrs = null;
        }
        callback = wrapCallback(this, null, callback);

        this._fs.open(path, flags, attrs, callback);
    }

    close(handle: any, callback?: (err: Error) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.close(handle, callback);
    }

    read(handle: any, buffer: NodeBuffer, offset: number, length: number, position: number, callback?: (err: Error, bytesRead: number, buffer: NodeBuffer) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.read(handle, buffer, offset, length, position, callback);
    }

    write(handle: any, buffer: NodeBuffer, offset: number, length: number, position: number, callback?: (err: Error) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.write(handle, buffer, offset, length, position, callback);
    }

    lstat(path: string, callback?: (err: Error, attrs: IStats) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.lstat(path, callback);
    }

    fstat(handle: any, callback?: (err: Error, attrs: IStats) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.fstat(handle, callback);
    }

    setstat(path: string, attrs: IStats, callback?: (err: Error) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.setstat(path, attrs, callback);
    }

    fsetstat(handle: any, attrs: IStats, callback?: (err: Error) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.fsetstat(handle, attrs, callback);
    }

    opendir(path: string, callback?: (err: Error, handle: any) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.opendir(path, callback);
    }

    readdir(path: string, callback?: (err: Error, items: IItem[]) => any)
    readdir(handle: any, callback?: (err: Error, items: IItem[]|boolean) => any)
    readdir(handle: any, callback?: (err: Error, items: IItem[]|boolean) => any): void {
        if (typeof handle === 'string') {
            var path = Path.check(<string>handle, 'path');

            var options = <ISearchOptionsExt>{
                noglobstar: true,
                nowildcard: true,
                listonly: true,
                dotdirs: true,
            };

            search(this._fs, path, null, options, callback);

            return;
        }

        callback = wrapCallback(this, null, callback);

        return this._fs.readdir(handle, callback);
    }

    unlink(path: string, callback?: (err: Error) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.unlink(path, callback);
    }

    mkdir(path: string, attrs?: IStats, callback?: (err: Error) => any): void {
        if (typeof attrs === 'function' && typeof callback === 'undefined') {
            callback = <any>attrs;
            attrs = null;
        }
        callback = wrapCallback(this, null, callback);

        this._fs.mkdir(path, attrs, callback);
    }

    rmdir(path: string, callback?: (err: Error) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.rmdir(path, callback);
    }

    realpath(path: string, callback?: (err: Error, resolvedPath: string) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.realpath(path, callback);
    }

    stat(path: string, callback?: (err: Error, attrs: IStats) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.stat(path, callback);
    }

    rename(oldPath: string, newPath: string, callback?: (err: Error) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.rename(oldPath, newPath, callback);
    }

    readlink(path: string, callback?: (err: Error, linkString: string) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.readlink(path, callback);
    }

    symlink(targetpath: string, linkpath: string, callback?: (err: Error) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.symlink(targetpath, linkpath, callback);
    }

    link(oldPath: string, newPath: string, callback?: (err: Error) => any): void {
        callback = wrapCallback(this, null, callback);

        this._fs.link(oldPath, newPath, callback);
    }

    list(remotePath: string, callback?: (err: Error, items: IItem[]) => any): Task {
        var remotePath = Path.check(remotePath, 'remotePath');

        var options = <ISearchOptionsExt>{
            directories: true,
            files: true,
            nosort: false,
            dotdirs: true,
            noglobstar: true,
            listonly: true,
        };
        
        var task = new Task();
        callback = wrapCallback(this, task, callback);

        search(this._fs, remotePath, task, options, callback);

        return task;
    }

    search(remotePath: string, options?: ISearchOptions, callback?: (err: Error, items: IItem[]) => any): Task {
        var remotePath = Path.check(remotePath, 'remotePath');

        if (typeof options === 'function' && typeof callback === 'undefined') {
            callback = <any>options;
            options = null;
        }

        var task = new Task();
        callback = wrapCallback(this, task, callback);

        search(this._fs, remotePath, task, options, callback);

        return task;
    }

    info(remotePath: string, callback?: (err: Error, item: IItem) => any): Task {
        var remotePath = Path.check(remotePath, 'remotePath');

        var options = <ISearchOptionsExt>{
            itemonly: true,
        };

        var task = new Task();
        callback = wrapCallback(this, task, callback);

        search(this._fs, remotePath, task, options,(err, items) => {
            if (err) return callback(err, null);
            if (!items || items.length != 1) return callback(new Error("Unexpected result"), null);
            callback(null, items[0]);
        });

        return task;
    }


    readFile(remotePath: string, options: { type?: string; encoding?: string; flag?: string; mimeType?: string; }, callback?: (err: Error, data: any) => any): Task {
        var task = new Task();
        callback = wrapCallback(this, task, callback);

        // process options
        options = options || {};
        var type = options.type;
        var encoding = options.encoding
        if (type) {
            type = (type + "").toLowerCase();
            if (type == "string" || type == "text") encoding = encoding || "utf8";
        } else {
            type = encoding ? "string" : "buffer";
        }

        // create appropriate target
        var target: IDataTarget;
        switch (type) {
            case "text":
            case "string":
                target = new StringDataTarget(encoding);
                break;
            case "array":
            case "buffer":
                target = new BufferDataTarget();
                break;
            case "blob":
                // WEB: target = new BlobDataTarget(options.mimeType);
{'fraction_non_alphanumeric': 0.1358722976370035, 'fraction_numerical': 0.00025138260432378077, 'mean_word_length': 2.7424741298212605, 'pattern_counts': {'":': 10, '<': 13, '<?xml version=': 0, '>': 62, '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': '2180203', 'n_tokens_mistral': 4529, 'n_tokens_neox': 4410, 'n_words': 1287}