// Type definitions for morgan 1.7.0
// Project: https://github.com/expressjs/morgan
// Definitions by: James Roland Cabresos <https://github.com/staticfunction>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped

/// <reference path="../express/express.d.ts" />
declare module "morgan" {

    import express = require('express');

    namespace morgan {

        export interface FormatFn extends Function {
            (tokens: TokenIndexer, req: express.Request, res: express.Response): string;
        }

        export interface TokenCallbackFn extends Function {
            (req: express.Request, res: express.Response, arg?: string | number | boolean): string;
        }

        export interface TokenIndexer {
            [tokenName: string]: TokenCallbackFn;
        }

        /**
         * Public interface of morgan logger
         */
        export interface Morgan {
            /***
             * Create a new morgan logger middleware function using the given format and options. The format argument may be a string of a predefined name (see below for the names), 
             * or a string of a format string containing defined tokens.
             * @param format
             * @param options
             */
            (format: string, options?: Options): express.RequestHandler;
            /***
             * Standard Apache combined log output.
             * :remote-addr - :remote-user [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"
             * @param format
             * @param options
             */
            (format: 'combined', options?: Options): express.RequestHandler;
            /***
             * Standard Apache common log output.
             * :remote-addr - :remote-user [:date] ":method :url HTTP/:http-version" :status :res[content-length]
             * @param format
             * @param options
             */
            (format: 'common', options?: Options): express.RequestHandler;
            /**
             * Concise output colored by response status for development use. The :status token will be colored red for server error codes, yellow for client error codes, cyan for redirection codes, and uncolored for all other codes.
             * :method :url :status :response-time ms - :res[content-length]
             * @param format
             * @param options
             */
            (format: 'dev', options?: Options): express.RequestHandler;

            /***
             * Shorter than default, also including response time.
             * :remote-addr :remote-user :method :url HTTP/:http-version :status :res[content-length] - :response-time ms
             * @param format
             * @param options
             */
            (format: 'short', options?: Options): express.RequestHandler;

            /***
             * The minimal output.
             * :method :url :status :res[content-length] - :response-time ms
             * @param format
             * @param options
             */
            (format: 'tiny', options?: Options): express.RequestHandler;

            /***
             * Create a new morgan logger middleware function using the given format and options. The format argument may be a  
             * custom format function which adheres to the signature.
             * @param format
             * @param options
             */
            (format: FormatFn, options?: Options): express.RequestHandler;

            /**
             * Define a custom token which can be used in custom morgan logging formats.
             */
            token(name: string, callback: TokenCallbackFn): Morgan;
            /**
             * Define a named custom format by specifying a format string in token notation
             */
            format(name: string, fmt: string): Morgan;

            /**
             * Define a named custom format by specifying a format function
             */
            format(name: string, fmt: FormatFn): Morgan;

            /**
             * Compile a format string in token notation into a format function
             */
            compile(format: string): FormatFn;
        }

        /**
         * Define a custom token which can be used in custom morgan logging formats.
         */
        export function token(name: string, callback: TokenCallbackFn): Morgan;

        /**
         * Define a named custom format by specifying a format string in token notation
         */
        export function format(name: string, fmt: string): Morgan;

        /**
         * Define a named custom format by specifying a format function
         */
        export function format(name: string, fmt: FormatFn): Morgan;

        /**
         * Compile a format string in token notation into a format function
         */
        export function compile(format: string): FormatFn;

        export interface StreamOptions {
            /**
             * Output stream for writing log lines
             */
            write: (str: string) => void;
        }

        /***
         * Morgan accepts these properties in the options object.
         */
        export interface Options {

            /***
             * Buffer duration before writing logs to the stream, defaults to false. When set to true, defaults to 1000 ms.
             */
            buffer?: boolean;

            /***
             * Write log line on request instead of response. This means that a requests will be logged even if the server crashes, but data from the response cannot be logged (like the response code).
             */
            immediate?: boolean;

            /***
             * Function to determine if logging is skipped, defaults to false. This function will be called as skip(req, res).
             */
            skip?: (req: express.Request, res: express.Response) => boolean;

            /***
             * Output stream for writing log lines, defaults to process.stdout.
             * @param str
             */
            stream?: StreamOptions;
        }
    }

    /***
     * Create a new morgan logger middleware function using the given format and options. The format argument may be a string of a predefined name (see below for the names), 
     * or a string of a format string containing defined tokens.
     * @param format
     * @param options
     */
    function morgan(format: string, options?: morgan.Options): express.RequestHandler;

    /***
     * Standard Apache combined log output.
     * :remote-addr - :remote-user [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"
     * @param format
     * @param options
     */
    function morgan(format: 'combined', options?: morgan.Options): express.RequestHandler;

    /***
     * Standard Apache common log output.
     * :remote-addr - :remote-user [:date] ":method :url HTTP/:http-version" :status :res[content-length]
     * @param format
     * @param options
     */
    function morgan(format: 'common', options?: morgan.Options): express.RequestHandler;

    /***
     * Concise output colored by response status for development use. The :status token will be colored red for server error codes, yellow for client error codes, cyan for redirection codes, and uncolored for all other codes.
     * :method :url :status :response-time ms - :res[content-length]
     * @param format
     * @param options
     */
    function morgan(format: 'dev', options?: morgan.Options): express.RequestHandler;

    /***
     * Shorter than default, also including response time.
     * :remote-addr :remote-user :method :url HTTP/:http-version :status :res[content-length] - :response-time ms
     * @param format
     * @param options
     */
    function morgan(format: 'short', options?: morgan.Options): express.RequestHandler;

    /***
     * The minimal output.
     * :method :url :status :res[content-length] - :response-time ms
     * @param format
     * @param options
     */
    function morgan(format: 'tiny', options?: morgan.Options): express.RequestHandler;

    /***
     * Create a new morgan logger middleware function using the given format and options. The format argument may be a  
     * custom format function which adheres to the signature.
     * @param format
     * @param options
     */
    function morgan(format: morgan.FormatFn, options?: morgan.Options): express.RequestHandler

    export = morgan;
}
