var domWrite = (function(){            // by Frank Thuerigen
 // private 

 var dw = document.write,         // save document.write()
     dwln = document.writeln,     // save document.writeln()
     myCalls = [],                // contains all outstanding Scripts
     t = '',                      // timeout
     checkMs = 400,               // checking interval for d.w() writes
                                  // ...default: 200 ms
     maxMs = 2000,                // maximum execution milliseconds
                                  // ...default: 1000 ms
     maxT;                        // maximum execution timeout

 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;
    }
   }
  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
      regexp2 = /src[^=]*=[^'"]*['"]([^'"]*?)['"]/i,     // src attribute content
      regexp3 = /<script[^>]*>/gi,                       // script tag existence
      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') } 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 ),
          myCode = ' '+myMatch+' ';
      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
      pCall.buf = pCall.buf.substr( pCall.buf.indexOf('>')+1); 
      pCall.buf = pCall.buf.substr( myMatch.length ); 
      pCall.buf = pCall.buf.substr( pCall.buf.indexOf('>')+1); 
      }
     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]
       });
      if ( pCall.buf.indexOf('/>') < pCall.buf.indexOf('>') ) { //HTML5 style script file tag ?
       pCall.buf = pCall.buf.substr( pCall.buf.indexOf('>')+1); 
       pCall.buf = pCall.buf.substr( pCall.buf.indexOf('>')+1); 
       }
      else { // ... yes it is
       pCall.buf = pCall.buf.substr( pCall.buf.indexOf('/>')+2); 
       }
      }
     }
    }
   }
  outputStack( pCall );
  }
  
 function outputStack( pCall ){
  try { console.log('function outputStack()') } catch (e) {};
  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) {};
     pCall.pause();  // paused
     domWrite( pCall.e, myPart.str, null, ( maxMs || 1000 ), true );
     return;
     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,
        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;

   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();
   }
  }
 })();