/*
 * 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 net from "net";
import * as stream from "stream";


export external public const METHODS: string[];
export external public const STATUS_CODES: Object;

export external public const maxHeaderSize: number;
export external public let globalAgent: Agent;

export external public function createServer(options: any, requestListener: {function():void}=): Server;
export external public function get(url: string, options: RequestOptions=, callback: {function(IncomingMessage):void}=): ClientRequest;
export external public function request(url: string, options: RequestOptions=, callback: {function(IncomingMessage):void}=): ClientRequest;

export external public class RequestOptions {
    public agent: Agent|boolean;
    public auth: string;
    public createConnection: Function;
    public defaultPort: number;
    public family: number;
    public headers: Object;
    public host: string;
    public hostname: string;
    public localAddress: string;
    public lookup: Function;
    public maxHeaderSize: number;
    public method: string;
    public path: string;
    public port: number;
    public protocol: string;
    public setHost: boolean;
    public socketPath: string;
    public timeout: number;
}

export external public class Server extends events.EventEmitter {
    public listen(port: number, hostname: string=, backlog: number=, callback: Function=): Server;
    public setTimeout(msecs: number, callback: Function=): Server;
    public close(callback: any=): Server;
    public address(): ~Object with { port: number; family: string; address: string; };
    public timeout: number;
    public keepAliveTimeout: number;
    public headersTimeout: number;
    public maxHeadersCount: number;
}
export external public class ServerResponse extends events.EventEmitter implements stream.IWritableStream {
    // Extended base methods
    @Override public write(buffer: union{string, Buffer}, encoding: string=, cbOrFd: union{string, Function}=): boolean;

    public writeContinue(): void;
    public writeHead(statusCode: number, headers: any=): void;
    statusCode: number;
    statusMessage: string;
    public setHeader(name: string, value: string | string[]): void;
    sendDate: boolean;
    public getHeader(name: string): string;
    public removeHeader(name: string): void;
    public addTrailers(headers: any): void;
    // Extended base methods
    @Override public end(chunkOrBuffer: any=, encoding: string=, cb: Function=): void;
}

export external public class ClientRequest implements events.IEventEmitter, stream.IWritableStream {
    // Extended base methods
    @Override public write(buffer: union{string, Buffer}, encoding: string=, cbOrFd: union{string, Function}=): boolean;
    @Override public addListener(event: string, listener: Function): this;
    @Override public on(event: string, listener: Function): this;
    @Override public once(event: string, listener: Function): this;
    @Override public removeListener(event: string, listener: Function): this;
    @Override public removeAllListeners(event: string=): this;
    @Override public setMaxListeners(n: number): void;
    @Override public listeners(event: string): Function[];
    @Override public emit(event: string, ...args: any): boolean;

    @Override public end(chunk: any=, encoding: string=, cb: Function=): void;
}
export external public class IncomingMessage implements events.IEventEmitter, stream.IReadableStream {
    public httpVersion: string;
    public headers: any+;
    public rawHeaders: string[];
    public trailers: any;
    public rawTrailers: any;
    public setTimeout(msecs: number, callback: Function): this;

    public method?: string;
    public url?: string;
    public statusCode?: number;
    public statusMessage?: string;
    public socket: net.Socket;

    @Override public readable: boolean;
    @Override public addListener(event: string, listener: Function): this;
    @Override public on(event: string, listener: Function): this;
    @Override public once(event: string, listener: Function): this;
    @Override public removeListener(event: string, listener: Function): this;
    @Override public removeAllListeners(event: string=): this;
    @Override public setMaxListeners(n: number): void;
    @Override public listeners(event: string): Function[];
    @Override public emit(event: string, ...args: any): boolean;
    @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 stream.IWritableStream> pipe(destination: T, options: ~Object with{ end?: boolean; }=): T;
    @Override public <T extends stream.IWritableStream> unpipe(destination: T=): void;
    @Override public unshift(chunk: any): void;
    @Override public wrap(oldStream: stream.IReadableStream): stream.IReadableStream;
}

interface ~AgentOptions {
    public keepAlive?: boolean;
    public keepAliveMsecs?: number;
    public maxSockets?: number;
    public maxFreeSockets?: number;
}

export external public class Agent {
    public maxSockets: number;
    public sockets: any;
    public requests: any;

    public constructor(opts: AgentOptions=);

    public destroy(): void;
}


