/*
 * 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 {IEventEmitter, EventEmitter} from "events";

export external public interface ~IReadableStream extends IEventEmitter {
    public readable: boolean;

    public read(size: number=): union{string, Buffer};
    public setEncoding(encoding: string): void;
    public pause(): void;
    public resume(): void;
    public <T extends IWritableStream> pipe(destination: T, options: ~Object with{ end?: boolean; } =): T;
    public <T extends IWritableStream> unpipe(destination: T=): void;
    public unshift(chunk: union {string, Buffer}): void;
    public wrap(oldStream: IReadableStream): IReadableStream;
}

export external public interface ~IWritableStream extends IEventEmitter {
    public writable: boolean;

    public write(buffer: union{string, Buffer}, encoding: string=, cbOrFd: union{string, Function}=): boolean;
    public end(buffer: union{string, Buffer}, encoding: string=, cb: Function=): void;
}

export external public interface ~IReadWriteStream extends IReadableStream, IWritableStream {}
export external public interface ~Stream extends IEventEmitter {
   public <T extends IWritableStream> pipe(destination: T, options: ~Object with{ end?: boolean; }): T;
}

interface ~IBaseOptions {
    highWaterMark?: number;
    objectMode?: boolean;
}

interface ~IReadableOptions extends IBaseOptions{
    encoding?: string;
}

export external public class Readable extends EventEmitter implements IReadableStream {
    @Override public readable: boolean;
    public constructor(opts: IReadableOptions=);
    public _read(size: number): void;
    @Override public read(size: number=): union{string, Buffer};
    @Override public setEncoding(encoding: string): void;
    @Override public pause(): void;
    @Override public resume(): void;
    @Override public <T extends IWritableStream> pipe(destination: T, options: ~Object with{ end?: boolean; }=): T;
    @Override public <T extends IWritableStream> unpipe(destination: T=): void;
    @Override public unshift(chunk: any): void;
    @Override public wrap(oldStream: IReadableStream): IReadableStream;
    public push(chunk: any, encoding: string=): boolean;
}

interface ~IWritableOptions extends IBaseOptions{
    decodeStrings?: boolean;
}

export external public class Writable extends EventEmitter implements IWritableStream {
    @Override public writable: boolean;
    public constructor(opts: IWritableOptions=);
    public _write(chunk: any, encoding: string, callback: Function): void;
    @Override public write(buffer: union{string, Buffer}, encoding: string=, cbOrFd: union{string, Function}=): boolean;
    @Override public end(chunk: any=, encoding: string=, cb: Function=): void;
}

interface ~IDuplexOptions extends IReadableOptions, IWritableOptions {
    public allowHalfOpen?: boolean;
}
export external public interface ~IDuplex
    extends IReadWriteStream, IReadableStream, IEventEmitter {}
// Duplex Note extends both Readable and Writable.
export external public class Duplex extends Readable implements IDuplex {
    @Override public writable: boolean;
    public constructor(opts: IDuplexOptions=);
    public _write(chunk: any, encoding: string, callback: Function): void;
    @Override public write(buffer: union{string, Buffer}, encoding: string=, cbOrFd: union{string, Function}=): boolean;

    @Override public end(chunk: any=, encoding: string=, cb: Function=): void;
}

interface ~TransformOptions extends IReadableOptions, IWritableOptions {}

// Transform Note lacks the _read and _write methods of Readable/Writable.
export external public class Transform extends EventEmitter implements IReadWriteStream {
    @Override public readable: boolean;
    @Override public writable: boolean;
    public constructor(opts: TransformOptions=);
    public _transform: {function(chunk: any, encoding: string, callback: Function):void};
    public _flush: {function(callback: Function):void};
    @Override public read(size: number=): union{string,Buffer};
    @Override public setEncoding(encoding: string): void;
    @Override public pause(): void;
    @Override public resume(): void;
    @Override public <T extends IWritableStream> pipe(destination: T, options: ~Object with { end?: boolean; } =): T;
    @Override public <T extends IWritableStream> unpipe(destination: T=): void;
    @Override public unshift(chunk: any): void;
    @Override public wrap(oldStream: IReadableStream): IReadableStream;
    public push(chunk: any, encoding: string=): boolean;
    @Override public write(buffer: union{string, Buffer}, encoding: string=, cbOrFd: union{string, Function}=): boolean;
    @Override public end(chunk: any=, encoding: string=, cb: Function=): void;
}

export external public class PassThrough extends Transform {}


