var domWrite = (function(){            // by Frank Thuerigen
 // private 

 var dw = document.write,              // save document.write()
          myCalls = [],                // contains all outstanding Scripts
          t = '',                      // timeout
          checkMs,                     // checking interval for d.w() writes
                                       // ...default: 200 ms
          maxMs,                       // 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 ) {
   //if ( console ) console.log( 'startnext: '+( myCalls[0].stat!=5 ? myCalls[0].f.toString() : '' )+' Status='+myCalls[0].stat );
   switch ( myCalls[0].stat ) {
    case 0: // created
     //if ( console ) console.log( '--> START' );
     myCalls[0].start();
     startnext();
     break;
    case 1: // waiting
     //if ( console ) console.log( '--> STARTLOAD' );
     myCalls[0].startload();
     break;
    case 4:
     //if ( console ) console.log( '--> RESUME' );
     myCalls[0].resume();
     break;
    case 5:
     //if ( console ) console.log( '--> END' );
     myCalls.shift();
     //if ( console ) console.log( 'END # of myCalls left: '+myCalls.length );
     startnext();
     break;
    }
   }
  else {
   document.write=dw;                  // restore document.write()
   }
  }

 function fillStack( pCall ){    // eval embedded script tags in HTML code
  //if ( console ) console.log( 'fillStack: '+pCall.f.toString());
  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
  while ( pCall.buf !== ''  ) {
   //if ( console ) console.log( '-->'+ pCall.buf+'<--');
   hasScript = ( pCall.buf.toLowerCase() ).indexOf('<script') > -1 ? true : false; //script tag in output?
   if ( !hasScript ) { // no script tag
    //if ( console ) console.log( '--> only HTML' );
    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
     //if ( console ) console.log( '--> HTML' );
     pCall.stack.push({
      type: 'HTML',
      str: pCall.buf.substr(0, i )   
      });
     pCall.buf = pCall.buf.substr( i ); 
     }
    else { // CODE first
     //if ( console ) console.log( ''+( pCall.buf.toLowerCase() ).indexOf('src')+' '+pCall.buf.indexOf('>') );
     if ( ( ( pCall.buf.toLowerCase() ).indexOf('src') === -1 ) || 
          ( ( pCall.buf.toLowerCase() ).indexOf('src') > pCall.buf.indexOf('>') ) 
        ){
      //if ( console ) console.log( 'INLINE CODE:' );
      //if ( console ) console.log( 'CODE-->'+ pCall.buf+'<--');
      var myMatch = pCall.buf.match( regexp1 ),
          myCode = ' '+myMatch+' ';
      myCode=myCode.replace( /[^'"]*<script[^>]*>/gi, '' );     
      myCode=myCode.replace( /<\/script[^>]*>[^'"]*/gi, '' );     
      //if ( console ) console.log( 'MATCH-->'+myMatch+'<--');
      pCall.stack.push({
       type: 'CODE',
       str: myCode
       });
      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 {
      //if ( console ) console.log( 'FILE' );
      //if ( console ) console.log( 'CODE-->'+ pCall.buf+'<--');
      var myMatch = pCall.buf.match( regexp2 );     
      //if ( console ) console.log( 'MATCH-->'+myMatch+'<--');
      pCall.stack.push({
       type: 'FILE',
       str: myMatch
       });
      pCall.buf = pCall.buf.substr( pCall.buf.indexOf('>')+1); 
      pCall.buf = pCall.buf.substr( pCall.buf.indexOf('>')+1); 
      }
     }
    }
   }
  outputStack( pCall );
  }
  
 function outputStack( pCall ){
  //if ( console ) console.log( 'outputStack: '+pCall.f.toString() );
  while ( pCall.stack.length > 0 ) {
   var myPart = pCall.stack.shift();
   switch ( myPart.type ) {
    case 'HTML': 
     pCall.e.innerHTML = pCall.e.innerHTML+myPart.str; // write output to element
     break;
    case 'CODE':
     eval( myPart.str );
     pCall.e.innerHTML = pCall.e.innerHTML + pCall.buf;
     pCall.buf='';
     pCall.oldbuf='';
     break;
    case 'FILE':
     pCall.pause();  // paused
     domWrite( pCall.e, myPart.str, function(){ var a='embedded SRC= script' }, ( maxMs || 1000 ) ); 
     return;
     break;
    }
   }
  // done with stack
  pCall.stop();
  startnext();
  }

 function testDone( pCall ){                 // detect finished processing
  var myCall = pCall;
  return function(){
   //if ( console ) console.log( 'testDone: '+myCall.f.toString() );
   if ( myCall.buf !== myCall.oldbuf ){
    myCall.oldbuf = myCall.buf;
    t=window.setTimeout( testDone( myCall ), myCall.ms );
    //if ( console ) console.log( '--> still processing' );
    }
   else {
    //if ( console ) console.log( '--> start stack execution' );
    fillStack( myCall );
    }
   }
  }  
   
 function MyCall( pDiv, pSrc, pOnBefore, pContinue ){ // 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.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(){
   //if ( console ) console.log( 'myCall.start: '+this.f.toString() );
   this.stat=1;                            // status = waiting
   },
  startload: function(){
   //if ( console ) console.log( 'myCall.startload: '+this.f.toString() );
   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           
     //if ( console ) console.log( '--> start foreign script timeout' );
     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 );
      }
     };
    })();

   this.dw = document.write;

   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);
   },
  resume: function(){
   //if ( console ) console.log( 'myCall.resume: '+this.f.toString() );
   this.stat=3; // post-processing
   document.write=this.dw;
   outputStack( myCalls[0] );
   },
  pause: function(){
   //if ( console ) console.log( 'myCall.pause: '+this.f.toString() );
   this.stat=4;
   },
  stop: function(){
   //if ( console ) console.log( 'myCall.abort: '+this.f.toString() );
   window.clearTimeout( this.t );
   this.stat=5;
   }
  }
  
 return function( pDiv, pSrc, pFunc, pContinue ){  // public
  //if ( console ) console.log( 'domWrite: '+pSrc );
  var c = new MyCall( pDiv, pSrc, pFunc, pContinue );
  if (pContinue){
   myCalls.unshift( c );
   startnext();
   }
  else {
   myCalls.push( c );
   }
  //if ( console ) console.log( 'ADDED # of myCalls now: '+myCalls.length );
  if ( myCalls.length === 1 ){
   startnext();
   }
  }
 })();