(function() {
    var timer = setInterval(function() {
        if (document.body) {
            clearInterval(timer);

            var scripts = document.getElementsByTagName('script');
            for (var i = 0, n = scripts.length; i < n; ++i) {
                if (/\bCrossDomainXMLHttpRequest\.js\b/.test(scripts[i].src)) {
                    var swf = scripts[i].src.replace(/\.js\b/, '.swf');
                    break;
                }
            }

            var div = document.createElement('div');
            div.style.position = 'absolute';
            document.body.appendChild(div);

            var params = {swf: swf,
                          id: 'externalCrossDomainXMLHttpRequest',
                          flashvars: 'nocache='+(new Date()).getTime()};
            if (navigator.plugins && navigator.mimeTypes && navigator.mimeTypes.length) { // netscape plugin architecture
                div.innerHTML = '<embed type="application/x-shockwave-flash" name="$id" quality="low" flashvars="$flashvars" src="$swf" id="$id" width="0" height="0" style="position:absolute" />'.replace(/\$(\w+)/g, function($0,$1){return params[$1]});
            } else { // PC IE
                div.innerHTML = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" id="$id" width="0" height="0" style="position:absolute"><param name="movie" value="$swf" /><param name="quality" value="low" /><param name="flashvars" value="$flashvars" /></object>'.replace(/\$(\w+)/g, function($0,$1){return params[$1]});
            }
        }
    }, 100);
})();

// http://developer.mozilla.org/ja/docs/XMLHttpRequest
function CrossDomainXMLHttpRequest() {
    this.CrossDomainXMLHttpRequest.apply(this, arguments);
}
CrossDomainXMLHttpRequest.proxy = null;
CrossDomainXMLHttpRequest.id = 0;
CrossDomainXMLHttpRequest.instance = {};
CrossDomainXMLHttpRequest.addPolicyFile = function(uri) {
    CrossDomainXMLHttpRequest.addPolicyFile.policyFiles.push(uri);
};
CrossDomainXMLHttpRequest.addPolicyFile.policyFiles = [];
CrossDomainXMLHttpRequest.prototype = {
    id: null,
    method: null,
    uri: null,
    async: false,
    requestHeaders: {},
    data: null,

    onreadystatechange: null,
    readyState: 0,
    // responseBody: null,
    // responseStream: null,
    responseText: null,
    // responseXML: null,
    status: 0,
    statusText: '',

    open: function(method, uri, async) {
        // if (!async) {
        //     throw 'NOT_IMPLEMENTED_YET';
        // }
        this.method = method;
        this.uri = uri;
        this.async = async;

        this.callback(1);
    },

    setRequestHeader: function(field, value) {
        field = field.toLowerCase().replace(/(^|[^a-z])([a-z])/g, function($0,$1,$2){return $1 + $2.toUpperCase()});
        this.requestHeaders[field] = value;
    },

    overrideMimeType: function() {
        throw 'NOT_IMPLEMENTED_YET';
    },

    send: function(data) {
        var self = this;
        // for lazy evaluation
        var timer = setInterval(function(){
            CrossDomainXMLHttpRequest.proxy = (function() {
                var tagNames = ['object', 'embed'];
                for (var i = 0; i < tagNames.length; ++i) {
                    var elements = document.getElementsByTagName(tagNames[i]);
                    for (var j = 0; j < elements.length; ++j) {
                        if (typeof elements[j].addPolicyFile != 'undefined') {
                            return elements[j];
                        }
                    }
                }
                return null;
            })();
            if (CrossDomainXMLHttpRequest.proxy) {
                clearInterval(timer);

                for (var i = 0; i < CrossDomainXMLHttpRequest.addPolicyFile.policyFiles.length; ++i) {
                    CrossDomainXMLHttpRequest.proxy.addPolicyFile(CrossDomainXMLHttpRequest.addPolicyFile.policyFiles[i]);
                }
                CrossDomainXMLHttpRequest.addPolicyFile = function(uri) {
                    CrossDomainXMLHttpRequest.proxy.addPolicyFile(uri);
                };

                CrossDomainXMLHttpRequest.prototype.send = function(data) {
                    this.data = data;
                    CrossDomainXMLHttpRequest.proxy.request('CrossDomainXMLHttpRequest.instance.' + this.id + '.callback', this.method, this.uri, this.async, this.data,
                                                            {headers: this.requestHeaders});
                    this.callback(2);
                };
                self.send = CrossDomainXMLHttpRequest.prototype.send;
                self.send(data);
            }
        }, 100);
    },

    abort: function() {
        // It should also abort URLStreamEx
        // throw 'NOT_IMPLEMENTED_YET';
    },

    callback: function(readyState) {
        this.readyState = readyState;
        if (arguments.length == 2) {
            var args = arguments[1];
            if (typeof args.status != 'undefined') {
                this.status = args.status;
            }
            if (typeof args.responseText != 'undefined') {
                this.responseText = args.responseText;
            }
        }
        if (this.onreadystatechange) {
            this.onreadystatechange();
        }
        if (this.readyState == 4) {
            delete CrossDomainXMLHttpRequest.instance[this.id];
        }
    },

    getAllResponseHeaders: function() {
        throw 'NOT_IMPLEMENTED_YET';
    },

    getResponseHeader: function(field) {
        throw 'NOT_IMPLEMENTED_YET';
    },

    CrossDomainXMLHttpRequest: function() {
        this.id = 'id' + CrossDomainXMLHttpRequest.id++;
        CrossDomainXMLHttpRequest.instance[this.id] = this;
    }
};

