/*
 * Copyright (c) 2017 NumberFour AG.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   NumberFour AG - Initial API and implementation
 */

import * as events from "events";
import * as stream from "stream";

export external public interface ~Stats {
    public dev: number;
    public ino: number;
    public mode: number;
    public nlink: number;
    public uid: number;
    public gid: number;
    public rdev: number;
    public size: number;
    public blksize: number;
    public blocks: number;
    public atime: Date;
    public mtime: Date;
    public ctime: Date;
    public birthtime: Date;

    public isFile(): boolean;
    public isDirectory(): boolean;
    public isBlockDevice(): boolean;
    public isCharacterDevice(): boolean;
    public isSymbolicLink(): boolean;
    public isFIFO(): boolean;
    public isSocket(): boolean;
}
interface ~FSWatcher extends events.IEventEmitter {
    public close(): void;
}
export external public class ReadStream extends stream.Readable {
    public close(): void;
}
export external public class WriteStream extends stream.Writable {
    public close(): void;
    public bytesWritten: number;
}
export external public class Dirent {
    public name: string;
    public isBlockDevice(): boolean;
    public isCharacterDevice(): boolean;
    public isDirectory(): boolean;
    public isFIFO(): boolean;
    public isFile(): boolean;
    public isSocket(): boolean;
    public isSymbolicLink(): boolean;
}
export public interface ~RmdirOptions {
    public maxRetries?: number;
    public recursive?: boolean;
    public retryDelay?: number;
}

//OSX only methods. Cannot be uses on linux etc.
//export external public function lchown(string path, number uid, number gid, {function(Error?):void}? callback): void;
//export external public function lchownSync(string path, number uid, number gid): void;
//export external public function lchmod(string path, union{number,string} mode, {function(Error?):void}? callback): void;
//export external public function lchmodSync(string path, union{number,string} mode): void;

@Promisifiable
export external public function rename(oldPath: string, newPath: string, callback: {function(Error=):void}=): void;
export external public function renameSync(oldPath: string, newPath: string): void;

@Promisifiable
export external public function truncate(path: string, callback: {function(Error=):void}=): void;
export external public function truncateSync(path: string, len: number=): void;

@Promisifiable
export external public function ftruncate(fd: number, callback: {function(Error=):void}=): void;
export external public function ftruncateSync(fd: number, len: number=): void;

@Promisifiable
export external public function chown(path: string, uid: number, gid: number, callback: {function(Error=):void}=): void;
export external public function chownSync(path: string, uid: number, gid: number): void;

@Promisifiable
export external public function fchown(fd: number, uid: number, gid: number, callback: {function(Error=):void}=): void;
export external public function fchownSync(fd: number, uid: number, gid: number): void;

@Promisifiable
export external public function chmod(path: string, mode: union{number,string}, callback: {function(Error=):void}=): void;
export external public function chmodSync(path: string, mode: union{number,string}): void;

@Promisifiable
export external public function fchmod(fd: number, mode: union{number,string}, callback: {function(Error=):void}=): void;
export external public function fchmodSync(fd: number, mode: union{number,string}): void;

@Promisifiable
export external public function stat(path: string, callback: {function(Error, Stats): any}=): void;
export external public function statSync(path: string): Stats;

@Promisifiable
export external public function lstat(path: string, callback: {function(Error, Stats): any}=): void;
export external public function lstatSync(path: string): Stats;

@Promisifiable
export external public function fstat(fd: number, callback: {function(Error, Stats): any}=): void;
export external public function fstatSync(fd: number): Stats;

@Promisifiable
export external public function link(srcpath: string, dstpath: string, callback: {function(Error=):void}=): void;
export external public function linkSync(srcpath: string, dstpath: string): void;

@Promisifiable
export external public function symlink(srcpath: string, dstpath: string, type: string=, callback: {function(Error=):void}=): void;
export external public function symlinkSync(srcpath: string, dstpath: string, type: string=): void;

@Promisifiable
export external public function readlink(path: string, callback: {function(Error, string): any}=): void;
export external public function readlinkSync(path: string): string;

@Promisifiable
export external public function realpath(path: string, callback: {function(Error, string): any}=): void;

@Promisifiable
export external public function unlink(path: string, callback: {function(Error=):void}=): void;
export external public function unlinkSync(path: string): void;

@Promisifiable
export external public function rmdir(path: string, options: RmdirOptions=, callback: {function(Error=):void}=): void;
export external public function rmdirSync(path: string, options: RmdirOptions=): void;

@Promisifiable
export external public function mkdir(path: string, mode: union{number, string}=, callback: {function(Error=):void}=): void;
export external public function mkdirSync(path: string, mode: union{number, string}=): void;

@Promisifiable
export external public function mkdtemp(prefix: string, callback: {function(Error, string):void}=): void;
export external public function mkdtempSync(prefix: string): string;

@Promisifiable
export external public function copyFile(src: string, dest: string, flags: number=, callback: {function(Error, string):void}=): void;
export external public function copyFileSync(src: string, dest: string, flags: number=): string;

@Promisifiable
export external public function readdir(path: string, callback: {function(Error, string[]): void}=): void;
export external public function readdirSync(path: string, options: string | ~Object with {encoding?: string, withFileTypes?: boolean} =): string[]|Dirent[];

@Promisifiable
export external public function close(fd: number, callback: {function(Error=):void}=): void;
export external public function closeSync(fd: number): void;

@Promisifiable
export external public function open(path: string, flags: string, callback: {function(Error, number): any}=): void;
export external public function openSync(path: string, flags: string, mode: union{number, string}=): number;

@Promisifiable
export external public function utimes(path: string, atime: union{number, Date}, mtime: union{number, Date}, callback: {function(Error=):void}=): void;
export external public function utimesSync(path: string, atime: union{number, Date}, mtime: union{number, Date}): void;

@Promisifiable
export external public function futimes(fd: number, atime: union{number, Date}, mtime: union{number, Date}, callback: {function(Error=):void}=): void;
export external public function futimesSync(fd: number, atime: union{number, Date}, mtime: union{number, Date}): void;

@Promisifiable
export external public function fsync(fd: number, callback: {function(Error=):void}=): void;
export external public function fsyncSync(fd: number): void;

@Promisifiable
export external public function read(fd: number, buffer: Buffer, offset: number, length: number, position: int, callback: {function(Error, number, Buffer): void}=): void;
export external public function readSync(fd: number, buffer: Buffer, offset: number, length: number, position: int): number;

@Promisifiable
export external public function readFile(filename: string, options: ~Object with {encoding?: string; flag?: string;}, callback: {function(Error, string)}=): void;
export external public function readFileSync(filename: string, options: ~Object with { encoding?: string; flag?: string;}): string;

@Promisifiable
export external public function writeFile(filename: string, data: any, options: ~Object with {encoding?: string; mode?: union{number, string}; flag?: string; }, callback: {function(Error): void}=): void;
export external public function writeFileSync(filename: string, data: any, options: ~Object with {encoding?: string; mode?: union{number, string}; flag?: string; }): void;

@Promisifiable
export external public function appendFile(filename: string, data: any, options: ~Object with {encoding?: string; mode?: union{number, string}; flag?: string; }, callback: {function(Error): void}=): void;
export external public function appendFileSync(filename: string, data: any, options: ~Object with {encoding?: string; mode?: union{number, string}; flag?: string; }): void;

export external public function watchFile(filename: string, options: ~Object with {persistent?: boolean; listener?: number; }, listener: {function(Stats, Stats): void}): void;
export external public function unwatchFile(filename: string, listener: {function(Stats, Stats): void}=): void;
export external public function watch(filename: string, options: ~Object with {persistent?: boolean;}, listener: {function(string, string): any}=): FSWatcher;

export external public function exists(path: string, callback: {function(boolean): void}=): void;
export external public function existsSync(path: string): boolean;
export external public const F_OK: number;
export external public const R_OK: number;
export external public const W_OK: number;
export external public const X_OK: number;

@Promisifiable
export external public function access(path: string, mode: number, callback: {function(Error): void}): void;
export external public function accessSync(path: string, mode: number=): void;

export external public function createReadStream(path: string, options: ~Object with {
    flags?: string;
    encoding?: string;
    fd?: number;
    mode?: number;
    autoClose?: boolean;
}=): ReadStream;
export external public function createWriteStream(path: string, options: ~Object with {
    flags?: string;
    encoding?: string;
    fd?: number;
    mode?: number;
}=): WriteStream;

export external public const constants: ~Object with {
    F_OK: int,
    R_OK: int,
    W_OK: int,
    X_OK: int
};
