var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
/// <reference path="../env/UserAgent.ts" />
/// <reference path="../net/Uri.ts" />
/// <reference path="./Response.ts" />
/// <reference path="../base/BaseClass.ts"/>
/// <reference path="IRequestConfigOptions.ts"/>
/// <reference path="writer/IRequestWriter.ts"/>
/// <reference path="writer/JsonWriter.ts"/>
/// <reference path="writer/FormEncodedWriter.ts"/>
/// <reference path="reader/IResponseReader.ts"/>
/// <reference path="reader/JsonReader.ts"/>
/// <reference path="transport/ITransport.ts"/>
/// <reference path="transport/Post.ts"/>
/// <reference path="transport/Get.ts"/>
/// <reference path="transport/WindowName.ts"/>
var econda;
(function (econda) {
    var ajax;
    (function (ajax) {
        var UserAgent = econda.env.UserAgent;
        var Uri = econda.net.Uri;
        /**
         * Ajax request.
         *
         *     var r = new econda.ajax.Request({
         *         uri: 'http://www.econda.de',
         *         success: function(response) {
         *             console.log(response);
         *         }
         *     });
         *     r.send();
         *
         * We recommend using portal class {@link econda.Ajax}.
         *
         *     econda.Ajax.request( .. request config options .. );
         *
         * @class econda.ajax.Request
         */
        var Request = (function (_super) {
            __extends(Request, _super);
            function Request(cfg) {
                _super.call(this);
                /**
                 * Absolute or relative remote URI.
                 * @cfg {econda.net.Uri} uri
                 * @accessor
                 */
                this._uri = null;
                /**
                 * Request method. "get" or "post".
                 * @cfg {String} method
                 * @accessor
                 */
                this._method = 'get';
                /**
                 * Dictionary containing uri parameters and their values. See also: {@link #data}.
                 * @cfg {Object} params
                 * @accessor
                 */
                this._params = null;
                /**
                 * Object with header to append to request.
                 * @cfg {Object} headers
                 * @accessor
                 */
                this._headers = {};
                /**
                 * Request data. Only relevant for POST requests. If you want to add uri parameters, see {@link #params}.
                 * @cfg {string/Object} data
                 * @accessor
                 */
                this._data = null;
                /**
                 * Writers are responsible for writing request data to xhr request object.
                 * E.g. for json data we have to stringify the object and set application/json header.
                 * @cfg {string} writer name or instance of IRequestWriter
                 * @accessor
                 *
                 *     // use json writer
                 *     req.setWriter('json');
                 *
                 *     // use form encoded writer
                 *     req.setWriter('form-encoded');
                 */
                this._writer = null;
                /**
                 * Post processing for xhr response data
                 * @cfg {String} reader name or instance of IResponseReader
                 * @accessor
                 */
                this._reader = null;
                /**
                 * Callback on success
                 * @cfg {Function} success
                 * @accessor
                 */
                this._success = null;
                /**
                 * Callback on error
                 * @cfg {Function} error
                 * @accessor
                 */
                this._error = null;
                /**
                 * Callback that will be called after we got a response or an error
                 * @cfg {Function} callback
                 * @accessor
                 */
                this._callback = null;
                /**
                 * Callback after the request was sent.
                 * @cfg {Function} afterSend
                 * @accessor
                 */
                this._afterSend = null;
                /**
                 * seconds till timeout and abort
                 * @cfg {Number} seconds [Number=0]
                 * @accessor
                 */
                this.timeoutMilliseconds = 0;
                /**
                 * True to add withCredentials property to xhr request. This will try to send cookies for
                 * cross site requests.
                 * @private
                 * @property {Boolean} _withCredentials
                 */
                this._withCredentials = false;
                /**
                 * Reference to transport instance. Will be available after the request was executed.
                 * @cfg {String} transport
                 */
                this._transport = null;
                this._inititalized = false;
                if (cfg instanceof Request) {
                    return cfg;
                }
                else {
                    this.initConfig(cfg);
                }
            }
            Request.prototype.getUri = function () {
                return this._uri;
            };
            Request.prototype.setUri = function (uri) {
                this._uri = new Uri(uri);
                return this;
            };
            Request.prototype.getMethod = function () {
                return this._method;
            };
            Request.prototype.setMethod = function (method) {
                this._method = method.toLocaleLowerCase();
                return this;
            };
            Request.prototype.getParams = function () {
                return this._params;
            };
            Request.prototype.setParams = function (params) {
                this._params = params;
                return this;
            };
            /**
             * Add one or many parameters to request params collection
             * @param {String|Object} data
             * @param {String} [value=null]
             * @chainable
             */
            Request.prototype.addParams = function (data, value) {
                if (value === void 0) { value = null; }
                if (typeof data == 'string') {
                    this._params[data] = value;
                }
                else {
                    for (var name in data) {
                        this._params[name] = data[name];
                    }
                }
                return this;
            };
            Request.prototype.getHeaders = function () {
                return this._headers;
            };
            Request.prototype.setHeaders = function (headers, value) {
                this._headers = {};
                //noinspection TypeScriptUnresolvedVariable
                return this.addHeaders.apply(this, arguments);
            };
            Request.prototype.addHeaders = function (headers, value) {
                if (typeof headers == 'string') {
                    this._headers[headers] = value;
                }
                else {
                    for (var name in headers) {
                        this._headers[name] = headers[name];
                    }
                }
                return this;
            };
            /**
             * True if this request has additional headers
             * @returns {Boolean}
             */
            Request.prototype.hasHeaders = function () {
                if (Object.keys) {
                    return (Object.keys(this._headers).length > 0);
                }
                else {
                    var k;
                    for (k in this._headers) {
                        if (Object.prototype.hasOwnProperty.call(this._headers, k)) {
                            return true;
                        }
                    }
                    return false;
                }
            };
            Request.prototype.getData = function () {
                return this._data;
            };
            Request.prototype.setData = function (data) {
                this._data = data;
                return this;
            };
            Request.prototype.getWriter = function () {
                return this._writer;
            };
            Request.prototype.setWriter = function (writer) {
                if (typeof writer == 'string') {
                    switch (writer) {
                        case "form-encoded":
                            this._writer = new econda.ajax.writer.FormEncodedWriter();
                            break;
                        case "json":
                            this._writer = new econda.ajax.writer.JsonWriter();
                            break;
                        default:
                            throw "Unsupported writer: " + writer;
                    }
                }
                else {
                    this._writer = writer;
                }
                return this;
            };
            Request.prototype.getReader = function () {
                return this._reader;
            };
            Request.prototype.setReader = function (reader) {
                if (typeof reader == 'string') {
                    switch (reader) {
                        case 'json':
                            this._reader = new econda.ajax.reader.JsonReader();
                            break;
                        default:
                            throw "Unsupported response reader: " + reader;
                    }
                }
                else {
                    this._reader = reader;
                }
                return this;
            };
            Request.prototype.getSuccess = function () {
                return this._success;
            };
            Request.prototype.setSuccess = function (callback) {
                this._success = callback;
                return this;
            };
            Request.prototype.getError = function () {
                return this._error;
            };
            Request.prototype.setError = function (callback) {
                this._error = callback;
                return this;
            };
            Request.prototype.getCallback = function () {
                return this._callback;
            };
            Request.prototype.setCallback = function (callback) {
                this._callback = callback;
                return this;
            };
            Request.prototype.getAfterSend = function () {
                return this._afterSend;
            };
            Request.prototype.setAfterSend = function (callback) {
                this._afterSend = callback;
                return this;
            };
            Request.prototype.getTimeoutMilliseconds = function () {
                return this.timeoutMilliseconds;
            };
            Request.prototype.setTimeoutMilliseconds = function (seconds) {
                this.timeoutMilliseconds = seconds;
                return this;
            };
            /**
             * Set to true, to add withCredentials=true to xhr object. That will send cookies for
             * cross site requests. Server needs to set Allow-Credentials header.
             * @param {Boolean} withCredentials
             * @chainable
             */
            Request.prototype.setWithCredentials = function (withCredentials) {
                this._withCredentials = withCredentials;
                return this;
            };
            /**
             * Get value of withCredentials property
             * @returns {Boolean}
             */
            Request.prototype.getWithCredentials = function () {
                return this._withCredentials;
            };
            Request.prototype.setTransport = function (transport) {
                if (typeof transport === 'string') {
                    switch (transport.toLowerCase()) {
                        case 'post':
                            this._transport = new econda.ajax.transport.Post();
                            break;
                        case 'get':
                            this._transport = new econda.ajax.transport.Get();
                            break;
                        case 'windowname':
                            this._transport = new econda.ajax.transport.WindowName();
                            break;
                        default:
                            throw new Error('unknown transport: ' + transport);
                    }
                }
                else {
                    this._transport = transport;
                }
                this._transport.setRequest(this);
                return this;
            };
            /**
             * Get transport instance. Will throw an exception if transport is not initialized.
             * Call init() to initialize transport instance.
             * @returns econda.ajax.transport.ITransport instance or null
             */
            Request.prototype.getTransport = function () {
                return this._transport;
            };
            /**
             * send request
             * @method
             */
            Request.prototype.init = function () {
                if (this.getUri() == null) {
                    econda.debug.error("Trying to send request, but request has empty uri.");
                }
                if (!this._transport) {
                    this.autoDetectAndSetTransport();
                }
                this._transport.init();
                this._inititalized = true;
            };
            Request.prototype.send = function () {
                if (this._inititalized == false) {
                    this.init();
                }
                this._transport.send(this);
            };
            /**
             * Internal callback. Transport will pass response data to this function. You can overwrite this
             * method to add handling for special response types (e.g. json, xml...)
             * @param {String} responseData
             */
            Request.prototype.handleResponse = function (response) {
                var reader = this.getReader();
                if (reader) {
                    response.data = reader.read(response.responseText);
                }
                else {
                    response.data = response.responseText;
                }
                if (response.isError) {
                    if (this._error) {
                        this._error.call(this, response);
                    }
                }
                else {
                    if (this._success) {
                        this._success.apply(this, [response.data]);
                    }
                }
                if (this._callback) {
                    this._callback.call(this, response);
                }
            };
            /**
             * Detect best transport implementation and set as transport to use
             * @private
             */
            Request.prototype.autoDetectAndSetTransport = function () {
                // init only if not set due to unit tests
                if (this._transport) {
                    return;
                }
                var transport;
                switch (this._method) {
                    case 'get':
                        if (this.isXDomainRequest() && UserAgent.getName() == UserAgent.INTERNET_EXPLORER && UserAgent.getVersion() < 10) {
                            transport = new econda.ajax.transport.WindowName();
                        }
                        else {
                            transport = new econda.ajax.transport.Get();
                        }
                        break;
                    case 'post':
                        transport = new econda.ajax.transport.Post();
                        break;
                    default:
                        throw "Unsupported request method: " + this._method;
                }
                this.setTransport(transport);
            };
            Request.prototype.isSupportedRequest = function () {
                if (!this._transport) {
                    this.autoDetectAndSetTransport();
                }
                return this._transport.isSupportedRequest();
            };
            /**
             * Detects if this is a cross domain request based on request uri.
             * @returns {boolean}
             */
            Request.prototype.isXDomainRequest = function () {
                var uri = this._uri;
                var isXDomain = false;
                var matches = uri.match(/^https?\:\/\/([^\/:?#]+)(?:[\/:?#]|$)/i);
                var domain = matches && matches[1];
                if (domain && domain != location.host) {
                    isXDomain = true;
                }
                return isXDomain;
            };
            return Request;
        }(econda.base.BaseClass));
        ajax.Request = Request;
    })(ajax = econda.ajax || (econda.ajax = {}));
})(econda || (econda = {}));