var domWrite = (function() { // by Frank Thuerigen
    var dw = document.write; // save document.write()
    var dwln = document.writeln; // save document.writeln()
    var myCalls = []; // contains all outstanding Scripts
    var t = ''; // timeout
    var checkMs = 400; // checking interval for d.w() writes
    // ...default: 200 ms
    var maxMs = 2000; // maximum execution milliseconds
    // ...default: 1000 ms
    var maxT; // maximum execution timeout

    function getad(adurl) {
        var p = 'AjaxAdAction=getad';
        p = p + '&AjaxAdUrl=' + escape(adurl);

        var opt = {
            asynchronous: false,
            method: 'post',
            postBody: p,
            onSuccess: function(t) {
                var s = document.createElement('script');
                s.setAttribute('language', 'javascript');
                s.setAttribute('type', 'text/javascript');
                s.text = t.responseText;

                document.getElementsByTagName('head')[0].appendChild(s);
            },
            onFailure: function(t) {
            }
        }

        //try { console.log('GetAd Begin : ' + adurl); } catch (e) { };
        new Ajax.Request(window.location.pathname, opt);
        //try { console.log('GetAd End : ' + adurl); } catch (e) { };
    }

    function getid() {
        var myDate = new Date();
        return '_' + myDate.getTime() + '_' + Math.random().toString().replace(/\./, '');
    }

    function startnext() { // start next call in pipeline
        if (myCalls.length > 0) {
            //try { console.log('function startnext: Status=' + myCalls[0].stat) } catch (e) { };
            switch (myCalls[0].stat) {
                case 0: // created
                    //try { console.log('startnext.start') } catch (e) { };
                    myCalls[0].start();
                    startnext();
                    break;
                case 1: // waiting
                    //try { console.log('startnext.startload') } catch (e) { };
                    myCalls[0].startload();
                    break;
                case 4:
                    //try { console.log('startnext.resume') } catch (e) { };
                    myCalls[0].resume();
                    break;
                case 5:
                    myCalls.shift();
                    //try { console.log('startnext.end # of myCalls left: ' + myCalls.length) } catch (e) { };
                    startnext();
                    break;
                default:
                    break;
            }
        }
        else {
            //try { console.log('startnext.END ALL: restore document.write functions') } catch (e) { };
            document.write = dw; // restore document.write()
            document.writeln = dwln;  // restore document.writeln()
        }
    }

    function fillStack(pCall) { // eval embedded script tags in HTML code
        //try { console.log('function fillStack()') } catch (e) { };
        var regexp1 = /[^'"]*<script[^>]*>([\s\S]*?)<\/script[^>]*>[^'"]*/gi; // script tag inline code
        var regexp2 = /src[^=]*=[^'"]*['"]([^'"]*?)['"]/i;     // src attribute content
        var regexp3 = /<script[^>]*>/gi; // script tag existence
        var regexp4 = /language=['"]*vbscript['"]*/gi;
        var regexp5 = /type=['"]*vb['"]*/gi;
        var regexp6 = /type=['"]*vbscript['"]*/gi;
        var hasScript;
        // fill stack

        //try { console.log(pCall.buf) } catch (e) { };
        while (pCall.buf !== '') {
            hasScript = (pCall.buf.toLowerCase()).indexOf('<script') > -1 ? true : false; //script tag in output?

            if (!hasScript) { // no script tag
                //try { console.log('-->fillStack: ONLY HTML: ' + pCall.buf) } catch (e) { };

                pCall.stack.push({
                    type: 'HTML',
                    str: pCall.buf
                });

                pCall.buf = '';
            }
            else {
                var i = (pCall.buf.toLowerCase()).indexOf('<script');

                if (i !== 0) { // it does not begin with a script tag -> HTML
                    //try { console.log('fillStack.HTML PART: ' + pCall.buf.substr(0, i)) } catch (e) { };
                    pCall.stack.push({
                        type: 'HTML',
                        str: pCall.buf.substr(0, i)
                    });

                    pCall.buf = pCall.buf.substr(i);
                }
                else { // CODE first
                    //try { console.log('--> CODE') } catch (e) { };
                    if (((pCall.buf.toLowerCase()).indexOf('src') === -1) || ((pCall.buf.toLowerCase()).indexOf('src') > pCall.buf.indexOf('>'))) {
                        var myMatch = pCall.buf.match(regexp1);
                        var myCode = ' ' + myMatch + ' ';
                        var vbScript1 = pCall.buf.match(regexp4);
                        var vbScript2 = pCall.buf.match(regexp5);
                        var vbScript3 = pCall.buf.match(regexp6);

                        var processIt = true;

                        if (vbScript1 != undefined && vbScript1.length > 0) processIt = false;
                        if (vbScript2 != undefined && vbScript2.length > 0) processIt = false;
                        if (vbScript3 != undefined && vbScript3.length > 0) processIt = false;

                        if (processIt == true) {
                            myCode = myCode.replace(/[^'"]*<script[^>]*>/gi, '');
                            myCode = myCode.replace(/<\/script[^>]*>[^'"]*/gi, '');

                            //try { console.log('fillStack.INLINE CODE: ' + myCode) } catch (e) { };
                            pCall.stack.push({
                                type: 'CODE',
                                str: myCode
                            });
                        }

                        // cut code part from buffer
                        if (pCall.buf.indexOf('</script>') >= 0) {
                            //try { console.log('1) pCall.buf: ' + pCall.buf) } catch (e) { };
                            pCall.buf = pCall.buf.substr(pCall.buf.indexOf('</script>') + 9);
                            //try { console.log('1) pCall.buf: ' + pCall.buf) } catch (e) { };
                        }
                        else if (pCall.buf.indexOf('/>') >= 0) {
                            //try { console.log('2) pCall.buf: ' + pCall.buf) } catch (e) { };
                            pCall.buf = pCall.buf.substr(pCall.buf.indexOf('/>') + 2);
                            //try { console.log('2) pCall.buf: ' + pCall.buf) } catch (e) { };
                        }
                        else {
                            //try { console.log('3) pCall.buf: ' + pCall.buf) } catch (e) { };
                            pCall.buf = pCall.buf.substr(pCall.buf.indexOf('>') + 1);
                            //try { console.log('3) pCall.buf: ' + pCall.buf) } catch (e) { };
                            pCall.buf = pCall.buf.substr(myMatch.length);
                            //try { console.log('3) pCall.buf: ' + pCall.buf) } catch (e) { };
                            pCall.buf = pCall.buf.substr(pCall.buf.indexOf('>') + 1);
                            //try { console.log('3) pCall.buf: ' + pCall.buf) } catch (e) { };
                        }
                    }
                    else {
                        //try { console.log('CODE-->' + pCall.buf + '<--') } catch (e) { };
                        var myMatch = pCall.buf.match(regexp2);

                        //try { console.log('fillStack.FILE: ' + myMatch[1]) } catch (e) { };
                        pCall.stack.push({
                            type: 'FILE',
                            str: myMatch[1]
                        });

                        //try { console.log('pCall.buf: ' + pCall.buf) } catch (e) { };
                        //try { console.log('pCall.buf.indexOf(\'\/>\'): ' + pCall.buf.indexOf('/>')) } catch (e) { };
                        //try { console.log('pCall.buf.indexOf(\'>\'): ' + pCall.buf.indexOf('>')) } catch (e) { };

                        if (pCall.buf.indexOf('/>') < pCall.buf.indexOf('>') && pCall.buf.indexOf('/>') >= 0) { //HTML5 style script file tag ?
                            pCall.buf = pCall.buf.substr(pCall.buf.indexOf('/>') + 2);
                        }
                        else { // ... yes it is
                            pCall.buf = pCall.buf.substr(pCall.buf.indexOf('>') + 1);
                            pCall.buf = pCall.buf.substr(pCall.buf.indexOf('>') + 1);
                        }

                        //try { console.log('pCall.buf: ' + pCall.buf) } catch (e) { };
                    }
                }
            }
        }

        outputStack(pCall);
    }

    function outputStack(pCall) {
        //try { console.log('function outputStack()') } catch (e) { };
        var deleted = false;

        while (pCall.stack.length > 0) {
            var myPart = pCall.stack.shift();

            switch (myPart.type) {
                case 'HTML':
                    //try { console.log('outputstack.HTML: ' + myPart.str) } catch (e) { };
                    pCall.e.innerHTML = pCall.e.innerHTML + myPart.str; // write output to element
                    break;
                case 'CODE':
                    //try { console.log('outputstack.CODE: ' + myPart.str) } catch (e) { };
                    eval(myPart.str);
                    pCall.e.innerHTML = pCall.e.innerHTML + pCall.buf;
                    pCall.buf = '';
                    pCall.oldbuf = '';
                    break;
                case 'FILE':
                    //try { console.log('outputstack.FILE: ' + myPart.str) } catch (e) { };
                    if (typeof innity_zone != "undefined") {
                        try { window.eval("delete document.innity_global_avp_zone_" + innity_zone); deleted = true; } catch (e) { deleted = false; };

                        if (deleted == false) {
                            try { window.eval("document.innity_global_avp_zone_" + innity_zone + " = undefined;"); } catch (e) { };
                        }
                    }

                    pCall.pause(); // paused
                    domWrite(pCall.e, myPart.str, null, (maxMs || 1000), true);
                    return;
                    break;
                default:
                    break;
            }
        }

        // done with stack
        pCall.stop();
        startnext();
    }

    function testDone(pCall) { // detect finished processing
        var myCall = pCall;

        return function() {
            //try { console.log('function testDone()') } catch (e) { };
            if (myCall.buf !== myCall.oldbuf) {
                myCall.oldbuf = myCall.buf;
                t = window.setTimeout(testDone(myCall), myCall.ms);
                //try { console.log('testdone: still processing') } catch (e) { };
            }
            else {
                //try { console.log('testdone: start stack execution') } catch (e) { };
                fillStack(myCall);
            }
        }
    }

    function MyCall(pDiv, pSrc, pOnBefore, pContinue, pForce) { // Class
        this.e = (typeof pDiv == 'string' ? document.getElementById(pDiv) : pDiv), // the div element
        this.f = pOnBefore || function() { }, // onbefore function
        this.cont = pContinue || false, // continue timeout length (ms)
        // ...if zero: waiting for first domwrite 
        this.force = pForce || false, // do not delay this execution,
        this.stat = 0, // 0=idle, 1=waiting, 2=loading, 
        // 3=processing, 4=paused, 5=finished
        this.dw, // my document write function
        this.src = pSrc, // script source address
        this.buf = '', // output string buffer
        this.oldbuf = '', // compare buffer
        this.ms = checkMs || 200, // milliseconds
        this.scripttag, // the script tag 
        this.t, // my timeout
        this.stack = []; // array will contain HTML strings OR 
        // <script>inlinecode</script> OR
        // <script src="..."></script>
    }

    MyCall.prototype = {
        start: function() {
            //try { console.log('myCall.start...') } catch (e) { };
            this.stat = 1; // status = waiting
        },
        startload: function() {
            //try { console.log('myCall.startload...') } catch (e) { };
            this.stat = 2; // loading-executing
            this.f.apply(window); // execute settings function
            var that = this;

            document.write = (function() {
                var o = that;
                var cb = testDone(o);

                if (o.cont !== false) { // timeout has been defined           
                    //try { console.log('myCall.startload --> start foreign script timeout') } catch (e) { };
                    window.setTimeout(
                        function() { // after timeout fill stack
                            o.stat = 5; // status = done
                            fillStack(o); // fill div
                        },
                        o.cont
                    );
                }

                return function(pString) { // overload document.write()
                    o.stat = 3; // status = processing

                    if (o.cont === false) {
                        window.clearTimeout(o.t);
                    }

                    o.oldbuf = o.buf;
                    o.buf += pString; // add string to buffer

                    if (o.cont === false) {
                        o.t = window.setTimeout(cb, o.ms);
                    }
                };
            })();

            document.writeln = document.write;

            this.dw = document.write;
            this.dwln = document.writeln;

            getad(this.src);

            //var s = document.createElement('script');
            //s.setAttribute('language', 'javascript');
            //s.setAttribute('type', 'text/javascript');
            //s.setAttribute('src', this.src);

            //document.getElementsByTagName('head')[0].appendChild(s);
            //try { console.log('myCall.startload --> script appended: ' + this.src) } catch (e) { };
        },
        resume: function() {
            //try { console.log('myCall.resume... document.write(), .writeln() reset to object functions...') } catch (e) { };
            this.stat = 3; // post-processing
            document.write = this.dw;
            document.writeln = this.dwln;
            outputStack(myCalls[0]);
        },
        pause: function() {
            //try { console.log('myCall.pause...') } catch (e) { };
            this.stat = 4;
        },
        stop: function() {
            //try { console.log('myCall.stop...') } catch (e) { };
            window.clearTimeout(this.t);
            this.stat = 5;
        }
    }

    return function(pDiv, pSrc, pFunc, pContinue, pForce) { // public
        if (myCalls.length > 0 && pForce !== true) {
            //try { console.log('==> domWrite call POSTPONED: ' + pDiv) } catch (e) { };
            window.setTimeout(
                function() { domWrite(pDiv, pSrc, pFunc, pContinue); },
                1000
            );

            return;
        }

        //try { console.log('==> domWrite call: ' + pSrc) } catch (e) { };
        var c = new MyCall(pDiv, pSrc, pFunc, pContinue);

        if (pContinue) {
            myCalls.unshift(c);
            startnext();
        }
        else {
            myCalls.push(c);
        }

        //try { console.log('==> ADDED # of myCalls now: ' + myCalls.length) } catch (e) { };
        if (myCalls.length === 1) {
            startnext();
        }
    }
})();