import * as webdriver from "./index";
import * as remote from "./remote";

declare namespace opera {
    /**
     * Creates {@link remote.DriverService} instances that manages an
     * [OperaDriver](https://github.com/operasoftware/operachromiumdriver)
     * server in a child process.
     */
    class ServiceBuilder {
        /**
         * @param {string=} opt_exe Path to the server executable to use. If omitted,
         *     the builder will attempt to locate the operadriver on the current
         *     PATH.
         * @throws {Error} If provided executable does not exist, or the operadriver
         *     cannot be found on the PATH.
         */
        constructor(opt_exe?: string);

        /**
         * Sets the port to start the OperaDriver on.
         * @param {number} port The port to use, or 0 for any free port.
         * @return {!ServiceBuilder} A self reference.
         * @throws {Error} If the port is invalid.
         */
        usingPort(port: number): ServiceBuilder;

        /**
         * Sets the path of the log file the driver should log to. If a log file is
         * not specified, the driver will log to stderr.
         * @param {string} path Path of the log file to use.
         * @return {!ServiceBuilder} A self reference.
         */
        loggingTo(path: string): ServiceBuilder;

        /**
         * Enables verbose logging.
         * @return {!ServiceBuilder} A self reference.
         */
        enableVerboseLogging(): ServiceBuilder;

        /**
         * Silence sthe drivers output.
         * @return {!ServiceBuilder} A self reference.
         */
        silent(): ServiceBuilder;

        /**
         * Defines the stdio configuration for the driver service. See
         * {@code child_process.spawn} for more information.
         * @param {(string|!Array<string|number|!stream.Stream|null|undefined>)}
         *     config The configuration to use.
         * @return {!ServiceBuilder} A self reference.
         */
        setStdio(config: string | Array<string | number | any>): ServiceBuilder;

        /**
         * Defines the environment to start the server under. This settings will be
         * inherited by every browser session started by the server.
         * @param {!Object.<string, string>} env The environment to use.
         * @return {!ServiceBuilder} A self reference.
         */
        withEnvironment(env: Object): ServiceBuilder;

        /**
         * Creates a new DriverService using this instance's current configuration.
         * @return {!remote.DriverService} A new driver service using this instance's
         *     current configuration.
         * @throws {Error} If the driver exectuable was not specified and a default
         *     could not be found on the current PATH.
         */
        build(): remote.DriverService;
    }

    /**
     * Sets the default service to use for new OperaDriver instances.
     * @param {!remote.DriverService} service The service to use.
     * @throws {Error} If the default service is currently running.
     */
    function setDefaultService(service: remote.DriverService): any;

    /**
     * Returns the default OperaDriver service. If such a service has not been
     * configured, one will be constructed using the default configuration for
     * a OperaDriver executable found on the system PATH.
     * @return {!remote.DriverService} The default OperaDriver service.
     */
    function getDefaultService(): remote.DriverService;

    /**
     * Class for managing {@linkplain Driver OperaDriver} specific options.
     */
    class Options {
        /**
         * Extracts the OperaDriver specific options from the given capabilities
         * object.
         * @param {!capabilities.Capabilities} caps The capabilities object.
         * @return {!Options} The OperaDriver options.
         */
        static fromCapabilities(caps: webdriver.Capabilities): Options;

        /**
         * Add additional command line arguments to use when launching the Opera
         * browser.  Each argument may be specified with or without the "--" prefix
         * (e.g. "--foo" and "foo"). Arguments with an associated value should be
         * delimited by an "=": "foo=bar".
         * @param {...(string|!Array.<string>)} var_args The arguments to add.
         * @return {!Options} A self reference.
         */
        addArguments(...var_args: Array<string>): Options;

        /**
         * Add additional extensions to install when launching Opera. Each extension
         * should be specified as the path to the packed CRX file, or a Buffer for an
         * extension.
         * @param {...(string|!Buffer|!Array.<(string|!Buffer)>)} var_args The
         *     extensions to add.
         * @return {!Options} A self reference.
         */
        addExtensions(...var_args: Array<any>): Options;

        /**
         * Sets the path to the Opera binary to use. On Mac OS X, this path should
         * reference the actual Opera executable, not just the application binary. The
         * binary path be absolute or relative to the operadriver server executable, but
         * it must exist on the machine that will launch Opera.
         *
         * @param {string} path The path to the Opera binary to use.
         * @return {!Options} A self reference.
         */
        setOperaBinaryPath(path: string): Options;

        /**
         * Sets the logging preferences for the new session.
         * @param {!./lib/logging.Preferences} prefs The logging preferences.
         * @return {!Options} A self reference.
         */
        setLoggingPrefs(prefs: webdriver.logging.Preferences): Options;

        /**
         * Sets the proxy settings for the new session.
         * @param {capabilities.ProxyConfig} proxy The proxy configuration to use.
         * @return {!Options} A self reference.
         */
        setProxy(proxy: webdriver.ProxyConfig): Options;

        /**
         * Converts this options instance to a {@link capabilities.Capabilities}
         *     object.
         * @param {capabilities.Capabilities=} opt_capabilities The capabilities to
         *     merge these options into, if any.
         * @return {!capabilities.Capabilities} The capabilities.
         */
        toCapabilities(opt_capabilities?: webdriver.Capabilities): webdriver.Capabilities;
    }

    class Driver extends webdriver.WebDriver {
        /**
         * @param {(capabilities.Capabilities|Options)=} opt_config The configuration
         *     options.
         * @param {remote.DriverService=} opt_service The session to use; will use
         *     the {@link getDefaultService default service} by default.
         * @param {promise.ControlFlow=} opt_flow The control flow to use,
         *     or {@code null} to use the currently active flow.
         */
        constructor(opt_config?: webdriver.Capabilities | Options, opt_service?: remote.DriverService, opt_flow?: webdriver.promise.ControlFlow);

        /**
         * This function is a no-op as file detectors are not supported by this
         * implementation.
         * @override
         */
        setFileDetector(): void;
    }
}

export = opera;