/*
 Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.
 For licensing, see LICENSE.html or http://ckeditor.com/license
 */

/**
 * @fileOverview Defines the {@link CKEDITOR.ajax} object, which holds ajax methods for
 *        data loading.
 */

(function () {
    CKEDITOR.plugins.add('ajax',
        {
            requires: [ 'xml' ]
        });

    /**
     * Ajax methods for data loading.
     * @namespace
     * @example
     */
    CKEDITOR.ajax = (function () {
        var createXMLHttpRequest = function () {
            // In IE, using the native XMLHttpRequest for local files may throw
            // "Access is Denied" errors.
            if (!CKEDITOR.env.ie || location.protocol != 'file:')
                try {
                    return new XMLHttpRequest();
                } catch (e) {
                }

            try {
                return new ActiveXObject('Msxml2.XMLHTTP');
            } catch (e) {
            }
            try {
                return new ActiveXObject('Microsoft.XMLHTTP');
            } catch (e) {
            }

            return null;
        };

        var checkStatus = function (xhr) {
            // HTTP Status Codes:
            //	 2xx : Success
            //	 304 : Not Modified
            //	   0 : Returned when running locally (file://)
            //	1223 : IE may change 204 to 1223 (see http://dev.jquery.com/ticket/1450)

            return ( xhr.readyState == 4 &&
                (    ( xhr.status >= 200 && xhr.status < 300 ) ||
                    xhr.status == 304 ||
                    xhr.status === 0 ||
                    xhr.status == 1223 ) );
        };

        var getResponseText = function (xhr) {
            if (checkStatus(xhr))
                return xhr.responseText;
            return null;
        };

        var getResponseXml = function (xhr) {
            if (checkStatus(xhr)) {
                var xml = xhr.responseXML;
                return new CKEDITOR.xml(xml && xml.firstChild ? xml : xhr.responseText);
            }
            return null;
        };

        var load = function (url, callback, getResponseFn) {
            var async = !!callback;

            var xhr = createXMLHttpRequest();

            if (!xhr)
                return null;

            xhr.open('GET', url, async);

            if (async) {
                // TODO: perform leak checks on this closure.
                /** @ignore */
                xhr.onreadystatechange = function () {
                    if (xhr.readyState == 4) {
                        callback(getResponseFn(xhr));
                        xhr = null;
                    }
                };
            }

            xhr.send(null);

            return async ? '' : getResponseFn(xhr);
        };

        return    /** @lends CKEDITOR.ajax */ {

            /**
             * Loads data from an URL as plain text.
             * @param {String} url The URL from which load data.
             * @param {Function} [callback] A callback function to be called on
             *        data load. If not provided, the data will be loaded
             *        synchronously.
             * @returns {String} The loaded data. For asynchronous requests, an
             *        empty string. For invalid requests, null.
             * @example
             * // Load data synchronously.
             * var data = CKEDITOR.ajax.load( 'somedata.txt' );
             * alert( data );
             * @example
             * // Load data asynchronously.
             * var data = CKEDITOR.ajax.load( 'somedata.txt', function( data )
             *     {
			 *         alert( data );
			 *     } );
             */
            load: function (url, callback) {
                return load(url, callback, getResponseText);
            },

            /**
             * Loads data from an URL as XML.
             * @param {String} url The URL from which load data.
             * @param {Function} [callback] A callback function to be called on
             *        data load. If not provided, the data will be loaded
             *        synchronously.
             * @returns {CKEDITOR.xml} An XML object holding the loaded data. For asynchronous requests, an
             *        empty string. For invalid requests, null.
             * @example
             * // Load XML synchronously.
             * var xml = CKEDITOR.ajax.loadXml( 'somedata.xml' );
             * alert( xml.getInnerXml( '//' ) );
             * @example
             * // Load XML asynchronously.
             * var data = CKEDITOR.ajax.loadXml( 'somedata.xml', function( xml )
             *     {
			 *         alert( xml.getInnerXml( '//' ) );
			 *     } );
             */
            loadXml: function (url, callback) {
                return load(url, callback, getResponseXml);
            }
        };
    })();

})();
