/// define global namespace
var AUDIOO  = {};

// globals
AUDIOO.globals = {
 default_title: 'AUDIOO - explore the difference!',
 musicUrl: '/', // should be changed to your muzlo-url
 sessionId: '' // this should store AUDIOO-SESSION cookie value, to be passed in GET 
                // to workaround FlashCookie problem and broken authenication
};


// this is a list of notification functions which are called application wide
// For feature purposes!
AUDIOO.notify = {
    
    onNewPlaylist: function(id, title) {
        //alert('New Playlist! '+title);
    },
    
    onAddToFavorites: function (id, title) {
        //alert('ID:'+id+' Title:'+title);
    },
    
    onRemoveFromFavorites: function (id, title) {
        //alert('Removed ID:'+id+' Title:'+title);
    }
    
}






// Audioo top player object
AUDIOO.player = {
    
    totalSeconds: null, // total time in seconds, should be set before playing the track
     
    // URL to the currently loaded MP3
    currentUrl: null,
    currentTrackId: null,
    firstTrackId: null, // ID of the first track in the list,
    currentTimeSource: 'elapsed', // could be 'remaining' as well
    
    lastElapsed : 0, // store last values for elapsed & remaining
    lastRemaining : 99999,
    lastLoaded: 0, // load progress
    
    lastState: 0, // stoppped
    isPlaying: 0, // indicates whether Player is in State= 2 (playing)
    internalCall: 0, // indicates weather _playTrack was called by direct User's onclick / by onTrackFinished callback
    
    
    onFinishedCallback: function (trackId) {},
    
     
    /* this is just a stub, and should be redefined to return reference to 
       Flex/Flash object for calling javascript on */
    getFlex: function () {
        return null;
    },
    
    
    /* Plays current/default track */
    playTrack: function (trackId) {
        
       if (trackId) {
           // set track's title & name
           var name    = $$('#track'+trackId+' dfn')[0];
           var time    = $$('#track'+trackId+' span')[0];
           var seconds = $$('#track'+trackId+' var')[0];
           
           $('pl_track_name').innerHTML = name.innerHTML;
           $('pl_track_time').innerHTML = time.innerHTML;
           this.totalSeconds = parseInt(seconds.innerHTML);
           this._playTrack(trackId);
       }
       this.currentTrackId = trackId;
       
       // change play button state
       $('pl_play_button').className = ($('pl_play_button').className == 'pl_play')? 'pl_pause' : 'pl_play';
	   
       
    },
    
    /* Plays previous track */
    playPrevious: function(internalCall) {
       this.internalCall = (internalCall == null) ? 0 : 1;
       var t_id          = (this.currentTrackId) ? this.currentTrackId : this.firstTrackId;
       var c_li          = $('track'+t_id).parentNode;
       var prev_li       = Element.previous(c_li);

       // check if it's not last node
       if (prev_li != undefined) {
            /id=(\")?track([0-9a-z]+)(\")?/.test(prev_li.innerHTML);
           var trackId = RegExp.$1;
           AUDIOO.player.playTrack(trackId);
       }
    },
    
    /* Plays next track */
    playNext: function(internalCall) {
       this.internalCall = (internalCall == null) ? 0 : 1;
       var t_id          = (this.currentTrackId) ? this.currentTrackId : this.firstTrackId;
       var c_li          = $('track'+t_id).parentNode;
       var next_li       = Element.next(c_li);

       // check if it's not last node
       if (next_li != undefined) {
           /id=(\")?track([0-9a-z]+)(\")?/.test(next_li.innerHTML); // this behavies differently on IE7!
           var trackId = RegExp.$2;
           AUDIOO.player.playTrack(trackId);
       }
       
    },
    
    /** This will return time in mm:ss format */
    duration: function(seconds) {
        var min = Math.floor(seconds / 60);
        var sec = (seconds % 60) + '';
        if (sec.length == 1) sec = '0'+sec;
        return min+':'+sec;
    },
    
    /* Calling this method will switch time display between Elapsed / Ramaining formats */
    changeTimeDisplay: function () {
        this.currentTimeSource = (this.currentTimeSource == 'elapsed')? 'remaining' : 'elapsed';
        this._reflectTime(this.lastElapsed, this.lastRemaining);
    },
    
    
    
    // reflects time progress
    _reflectTime: function (elapsed, remaining) {
        var seconds = (this.currentTimeSource == 'elapsed')? elapsed : remaining;
        var prefix  = (this.currentTimeSource == 'elapsed')? '' : '\u2212';
        $('pl_track_time').innerHTML = prefix+this.duration(seconds);
    },
    
    /** reflects Volume */
    _reflectVolume: function (percents) {
        var pxs   = Math.round( 25 * percents / 100);
        var delta = 1;
        $('pl_sound_control_w').style.backgroundPosition = (pxs - 25 - delta)+"px 0px"; //-25 -> 0

    },
    
    // reflects play ProgressBar for track
    _reflectProgress: function (elapsed, remaining) {
        if (remaining) {
            var pxs   = Math.round( 265 * elapsed / (elapsed + remaining));
            var delta = 1; 
            $('pl_track_name').style.backgroundPosition = (pxs - 265 - delta)+"px 1px"; //-265 -> 0
        }
    },
    
     // reflects Load ProgressBar for track
    _reflectLoadProgress: function (percents) {
        if (percents >= this.lastLoaded) {
            var pxs   = Math.round( 265 * percents / 100);
            var delta = 1; 
            $('pl_track_load').style.backgroundPosition = (pxs - 265 - delta)+"px 1px"; //-265 -> 0
        }
    },
    
    
    /* private function to send different events to SWF player */
    _sendEvent: function (typ, pr1) {
          this.getFlex().sendEvent(typ, pr1);
	},
	
	/** returns track URl */
	_getUrl: function (trackId) {
	    
	    return AUDIOO.globals.musicUrl + trackId + '/?session_id='+AUDIOO.globals.sessionId+'&'+Math.random();
	},
	
	/* this method will force top_player to load specified track at 
	 http://audioo/tracks/{trackId} */
	_playTrack: function (trackId){
	    
	    if (!trackId) return;
	    
	    var url = this._getUrl(trackId);
	
	    // load only if track is different than current
	    if (trackId != this.currentTrackId) {
	        this.isPlaying = 0;
	        this._setDefaults();
	        this._sendEvent('stop');
	        this.getFlex().loadFile({file: url, type :'mp3'});
	        
	        this.getFlex().sendEvent('playpause'); //start playing to force 'loading'
	        this.getFlex().sendEvent('playpause'); // and pause
	        // start polling 'load' status to defer track playing
	        this._startPlayEventPoller();
	    }
	    
	    this.getFlex().sendEvent('playpause'); //play/pause of currently playing track
	    
	    this.currentUrl = url;
	},

	// set some defaults
	_setDefaults: function() {
	   // set defaults
	    this.currentTimeSource = 'elapsed';
	    this.lastLoaded        = 0;
	    this.lastElapsed       = 0;
	    this.lastRemaining     = this.totalSeconds;
	    
	    this._reflectTime(0, 1);
		this._reflectProgress(this.lastElapsed, this.lastRemaining);
		this._reflectLoadProgress(this.lastLoaded);
		if ($('pl_play_button')) {
		    $('pl_play_button').className = 'pl_play';
		}
	      
	},
	
	
	/**  scrub the current item to position in percents seconds **/
	scrubTrack: function (percents) {
	     // convert to seconds
	     var seconds = Math.round(percents * this.totalSeconds / 100);
	     // don't scrub more than currently loaded
	     if (this.lastLoaded > percents) {
	         this.lastElapsed   = seconds;
	         this.lastRemaining = this.totalSeconds - seconds;
	         this._reflectTime(this.lastElapsed, this.lastRemaining);
		     this._reflectProgress(this.lastElapsed, this.lastRemaining);
	         this.getFlex().sendEvent('scrub', seconds);
	     }
	     
	},
	
	
	/** set Volume */
	
	setVolume: function (percents) {
	    // don't scrub more than currently loaded
	    this._reflectVolume(percents);
	    this.getFlex().sendEvent('volume', percents);
	},
	
	
	// a strange bug.... sendEvent('playpause') does not work
	// immedeately after track has finished playing
	// So we make here a dirty hacks -- keep sending playpause events until, we'll get state = 2(playing)

	_startPlayEventPoller: function() {
	     
	     new PeriodicalExecuter(function (pe){

	         //$('pl_playlist_name').innerHTML = AUDIOO.player.lastLoaded+'%';
	        // force playing if loaded more than 1%
	        
	        if( (AUDIOO.player.lastLoaded > 3)) {
	            
	               // this dummy scrub is for Safari on MacOS, dirty hacking
	             AUDIOO.player.getFlex().sendEvent('scrub', 1);
	             AUDIOO.player.getFlex().sendEvent('scrub', 0);
	             
	             AUDIOO.player.getFlex().sendEvent('playpause');
	                 
	            
	            // start sending 'playpause' events, until we hear playing!
	             new PeriodicalExecuter(function(pppe) {
	                
	                  //$('pl_playlist_name').innerHTML = 'Keep pl/pa (State= '+ AUDIOO.player.isPlaying;
	                
	                if (AUDIOO.player.isPlaying > 0) {
	                    //$('pl_playlist_name').innerHTML = 'stoppped PE2('+AUDIOO.player.isPlaying+'/'+AUDIOO.player.internalCall;
	                    pppe.stop();
	                    
	                    AUDIOO.player.getFlex().sendEvent('playpause');
	                    if (AUDIOO.player.internalCall) {
	                        AUDIOO.player.getFlex().sendEvent('playpause');
	                    }
	                }
	                
	                
	             }, 0.2); // was 0.1   
	            

	            //$('pl_playlist_name').innerHTML = 'stoppped PE1';
	            pe.stop();
		    }
		    
		    
		}, 2);
		
		
		
		
	},
	
	
	/*** custom Events **/
	
	/* this is called when track playing was finished ('state', 3) */
	onFinishedPlaying: function() {
	    //this._setDefaults();
	    AUDIOO.player.playNext(1);

	    // call custom callback
	    //this.onFinishedCallback(this.currentTrackId);
	},
	
	
	
	
	/**** main player events called from swfcallbacks.js by SWF player ****/
	
	onTimeChange: function (elapsed, remaining) {
	    
	    if( (this.lastState != 3) && (this.lastState != 0) ) {
	        
	        this.lastElapsed   = (this.lastElapsed <= elapsed)? elapsed : this.lastElapsed;
	        //this.lastRemaining = ((this.lastRemaining >= remaining))? remaining : this.lastRemaining;
	        this.lastRemaining = (this.totalSeconds)? (this.totalSeconds - this.lastElapsed) : this.lastRemaining;
	        
	        this._reflectTime(this.lastElapsed, this.lastRemaining);
	        this._reflectProgress(this.lastElapsed, this.lastRemaining);
	    }
	},
	
	// state=1 - buffering, state = 2, currently playing, state=0 - stoppped, state = 3 - finished playing 
	onStateChange: function(state) {
	    this.lastState = state;
	    if (state == 3) {this.onFinishedPlaying()}
	    
	    // set playing flag to true
	    if (state == 2) this.isPlaying ++;
	    
	    // change button state
	    
	    //if (state == 0)  $('pl_play_button').className = 'pl_pause';
		//alert('State:'+state);
	},
	
	// Load progress event
	onLoadChange: function (percents) {
	    this.lastLoaded = percents;
	    this._reflectLoadProgress(percents);
	},
	
	// change volume event
	onVolumeChange: function (percents) {
	    this._reflectVolume(percents);
	}
	
    
    
    
};


// Define MiniPlayer for music preview purposes

AUDIOO.miniPlayer = {};

// emulate inheritance
for (var property in AUDIOO.player) {
    AUDIOO.miniPlayer[property] = AUDIOO.player[property];
}



/* Plays/Pause current/default track */
AUDIOO.miniPlayer.playTrack = function (trackId) {
       
       //this.onStop(this.currentTrackId);  
        
       var pBut = $$('#mplay_'+trackId+' a')[0];
       
       //alert('trackId:'+trackId + ' currentId:'+this.currentTrackId);
       // this means we should reflect 'pause' state
       if (trackId == this.currentTrackId) {
           
           pBut.innerHTML                = (pBut.className == 'play')? 'Pause' : 'Play';
           $('mplay_'+trackId).className = (pBut.className == 'play')? 'act' : '';
           pBut.className                = (pBut.className == 'play')? 'pause' : 'play';
           
       } else {
           pBut.innerHTML                = 'Pause';
           $('mplay_'+trackId).className = 'act';
           pBut.className                = 'pause';
           // stop previously playing track;
           this.onStop(this.currentTrackId);  
       }
       
     
       this.domTimeContainer  = $$('#mplay_'+trackId+' var')[0];
        
       // force playing
       if (trackId) {
           var seconds       = $$('#mplay_'+trackId+' i')[0];
           this.totalSeconds = parseInt(seconds.innerHTML);
           this._playTrack(trackId);
       }
       
       
       
};


/** This is an internal event called when we send 'stop' signal to player */
AUDIOO.miniPlayer.onStop = function(trackId) {
    if ($('mplay_'+trackId)) {
       
        // restore currently stopped track's time
        $$('#mplay_'+trackId+' var')[0].innerHTML = this.duration(parseInt($$('#mplay_'+trackId+' i')[0].innerHTML));
        // restore mplayer container state
        $('mplay_'+trackId).className = '';
        var pBut = $$('#mplay_'+trackId+' a')[0];
        pBut.innerHTML = 'Play';
        pBut.className = 'play';
    }
};

/* onFinished callback */
AUDIOO.miniPlayer.onFinishedPlaying = function() {
    this.onStop(this.currentTrackId);
};

/* this method will force mini_player to load specified track at 
  http://audioo/tracks/{trackId} */

AUDIOO.miniPlayer._playTrack = function (trackId){
	    
	    if (!trackId) return;
	    
	    var url = this._getUrl(trackId);
	
	    // load only if track is different than current
	    if (trackId != this.currentTrackId) {
            this.isPlaying = 0;
	        this._setDefaults();
	        this._sendEvent('stop');
	        this.getFlex().loadFile({file: url, type :'mp3'});
	        this.getFlex().sendEvent('playpause'); //start playing to force 'loading'
	        this.currentTrackId    = trackId;
	       
	    } else {
	        this.getFlex().sendEvent('playpause'); //play/pause of currently playing track
	    }
	    
	    //alert('Going to play:'+url);
	    this.currentUrl = url;
};

// reflects time progress
AUDIOO.miniPlayer._reflectTime = function (elapsed, remaining) {
    var seconds = (this.currentTimeSource == 'elapsed')? elapsed : remaining;

    if (this.domTimeContainer) {
        this.domTimeContainer.innerHTML = this.duration(seconds);
    }
    
    

};

// reflects Load ProgressBar for track
AUDIOO.miniPlayer._reflectLoadProgress = function (percents) {
};

 /** reflects Volume */
AUDIOO.miniPlayer._reflectVolume = function (percents) {
};
    
// reflects play ProgressBar for track
AUDIOO.miniPlayer._reflectProgress = function (elapsed, remaining) {
};

        
    
 // Flex prototype object, some common code for Flex/Flash objects
AUDIOO.flexComponent = {
    _flexRef : null, // a reference to Flex object

    _initReference:  function(flexName, frameName) {   // initialize 
       if (navigator.appName.indexOf("Microsoft") != -1) {
           this._flexRef = (frameName)? frames[frameName].window[flexName] : window[flexName];
       } else {
          this._flexRef = (frameName)? frames[frameName].document[flexName] : document[flexName];
       }
       return this._flexRef;
    }
};







// Upload functionality, mainly GUI controls & interaction with SWFUpload component (http://swfupload.org)
AUDIOO.upload = {
    bottomHeight: 65, // the height of the bottom iframe block, px
    totalSize: 0, // total size of uploaded files, bytes
    totalLoadedSize: 0, // total size of currently loaded files, bytes 
    totalFiles: 0, // total number of files selected
    currentFileNumber: 0, // file number currently beeing uploaded
    
    serverResponses: [], // holds JSON server responses per particular file.id
    clientResponses: [], // holds error messages from onUploadError
    fileList: [], // hold total list of queued file objects
     
    postParams: {}, // holds postParams object for POSTing per-file
   
    _isFilesCompleted: false, // indicates wheather file upload is completed or not
    _isUrlsCompleted: false, // the same as above but for URLs
    
    isIE: function () {
        return navigator.userAgent.match(/\bMSIE\b/);
    },
    
    isSafari: function() {
        return navigator.userAgent.match(/\bSafari\b/);
    },
    
    
    /*
     Note on creating dynamic <TABLE> in IE:
     Things like c.innerHTML = '<tr><td> </td></tr>' don't work id c = '<table>'
     
     IE reports table.innerHTML as:
      
     <TABLE>
      <TBODY>
       <TR>
        <TH>Filename</TH>
        <TH>Size</TH>
       </TR>
      </TBODY>
     </TABLE>

    */
    
    /* Strips out <TABLE><TBODY>, etc. from table innerHTML */
    _getTableInnerHTML: function(html) {
      var res = html;
          res = res.replace(/\<TABLE\>/ig, '');
          res = res.replace(/\<\/TABLE\>/ig, '');
          res = res.replace(/\<TBODY\>/ig, '');
          res = res.replace(/\<\/TBODY\>/ig, '');
         return res;
    },
    
    
    // Show bottom upload panel with all stuff
    show: function () {
        
       // we have different markup for IE/non-IE browsers 
       if ( this.isIE() ) {
           top.$('content').style.paddingBottom = this.bottomHeight+'px';
           top.$('content').style.setExpression("height", "document.body.clientHeight - "+parseInt(this.bottomHeight+65));
            
       } else {
           top.$('content_container').style.paddingBottom = this.bottomHeight+'px';
       }

        top.$('upload_container').style.height =  this.bottomHeight+'px';
        //top.$('upload_container').show();
        
    },
    
    
    // Hide upload panel at the bottom
    hide: function() {
        //top.$('upload_container').hide();
        // we can't use display:none, coz SWF onload event don't work in such divs
         top.$('upload_container').style.height =  this.isSafari()? '0px':'1px';
       

        // we have different markup for IE/non-IE browsers 
       if ( this.isIE() ) {
           top.$('content').style.paddingBottom = '0px';
           top.$('content').style.setExpression("height", "document.body.clientHeight - 65");
            
       } else {
           top.$('content_container').style.paddingBottom = '0px';
       }
       
       // hide info block
       $(top.frames['upload'].document.getElementById('info')).hide();
        
    },
    
    
    /** This will open multiple files selection dialog of SWFUpload **/
    selectFiles: function () {
        AUDIOO.upload.cancelQueue(); // clear previous queue
        AUDIOO.upload.resetAll(); // reset file params
        top.frames['upload'].swfu.selectFiles();
    },
    
    /* Dynamically modifies the upload_url setting. */
    setUploadURL: function (url) {
        top.frames['upload'].swfu.setUploadURL(url);
    }, 
    
    /* Dynamically modifies the upload_url setting. */
    setPostParams: function (param_object) {
        top.frames['upload'].AUDIOO.upload.postParams = param_object;
        top.frames['content'].AUDIOO.upload.postParams = param_object;
        top.frames['upload'].swfu.setPostParams(param_object);
    }, 
    

    /** just returns human readable filesize**/
    formatFilesize: function (bytes) {
        var mbytes = bytes / (1024 * 1024);
        var mbytes = (Math.round( mbytes * 100)) / 100;
        
        return mbytes + '&nbsp;Mb';
    },
    
    /** just returns human readable time in hh:ss **/
    formatTime: function (seconds) {
        var hour = Math.floor(seconds / (60 * 60));
        var min  = Math.floor( (seconds % (60 * 60)) / 60 );
        var sec  = Math.floor( (seconds % (60 * 60)) % 60 );

        var res = (hour >0)? hour+'h ' :'';
            res+= (min > 0)? min+'m ':'';
            res+= (sec > 0)? sec+'s ':'< 1s ';
            
        return res;
        
    },
    
    
    /** updates upload estimates list for different bandwidth rates 
        More info at: http://en.wikipedia.org/wiki/List_of_device_bandwidths
    **/
    updateUploadEstimates: function() {
        // upload speeds in Kbytes/s
        var speeds = [["Modem 56 Kbit", "5.6"], 
                      ["ISDN 128 Kbit", "16"],
                      ["ADSL 768 Kbit", "96"],
                      ["T1 1.5 Mbit" , "196"],
                      ["Cable modem 38 Mbit", "4750"]
        ]; 
                     
       var c = top.frames['content'].document.getElementById('upload_estimates');
       var temp = "";
       var tempHTML = "";
                     
       c.innerHTML = "<h3>Approximate upload time</h3>";
       
       speeds.each(function(o) {
          // seconds
          temp = Math.round(AUDIOO.upload.totalSize / (parseFloat(o[1]) * 1024));
          temp = AUDIOO.upload.formatTime(temp);
          tempHTML += "<li>"+temp+'&#151;&nbsp;'+o[0]+"</li>";
       });
       
       c.innerHTML += "<ul>"+tempHTML+"</ul>";
    },
    
    /** starts upload chain **/
    startUpload: function () {
        AUDIOO.upload.hideInfoMessage();
        top.frames['upload'].swfu.startUpload();
       // show bottom window with upload progress, etc.
        AUDIOO.upload.show();
    },
    
    /** reset some common params **/
    resetAll: function () {
         AUDIOO.upload.currentFileNumber = 0;
         AUDIOO.upload.totalFiles        = 0;
         AUDIOO.upload.totalLoadedSize   = 0;
         AUDIOO.upload.totalSize         = 0;
         AUDIOO.upload.serverResponses   = [];
         AUDIOO.upload.clientResponses   = [];
         AUDIOO.upload.fileList          = [];
         AUDIOO.upload._isFilesCompleted = false;
         AUDIOO.upload._isUrlsCompleted  = false;
         
     },
    
    
/*    Stats Object

{ 
  in_progress : number // 1 or 0 indicating if a file upload is currently in progress 
  files_queued : number // The number of files currently in the queue 
  successful_uploads : number // The number of files that have uploaded successfully (caused uploadSuccess to be fired) 
  upload_errors : number // The number of files that have had errors (excluding cancelled files) 
  upload_cancelled : number // The number of files that have been cancelled 
  queue_errors : number // The number of files that caused fileQueueError to be fired 
}
*/
    getFileStats: function() {
        return top.frames['upload'].swfu.getStats();
    },
    
    // this will cancel whole upload queue!
    cancelQueue: function() {
        top.frames['content'].AUDIOO.upload.resetAll();
        top.frames['upload'].AUDIOO.upload.resetAll();
        top.frames['upload'].swfu.cancelQueue();
    },
    
    // displays small 1-string message at the bottom,
    // telling about how many files were successfully uploaded + link to full report
    showInfoMessage: function(str) {
        // Your upload is finished.  7 of 9 files & 5 of 4 URLs were uploaded.
        var c     = top.frames['upload'].document.getElementById('info_string');
        //var stats = AUDIOO.upload.getFileStats();
        
        $(c.parentNode).show();
        c.innerHTML  = str + ' '+AUDIOO.upload.currentFileNumber + ' of ' + AUDIOO.upload.totalFiles+' file(s)';
        c.innerHTML += ' were uploaded.';
    },
    
    hideInfoMessage: function() {
         var c     = top.frames['upload'].document.getElementById('info_string');
         $(c.parentNode).hide();
    },
    
    /** Updates report table showing filenames/urls with their statuses **/
    updateReportTable: function() {
        var c = top.frames['content'].document.getElementById('upload_report_table');
        // don't do anything if there are not such element
        if (!c) return;
        if (top.frames['upload'].AUDIOO.upload.fileList.length == 0) return;
        
        var lines = '';
        lines  = '<table>';
        lines += '<tr><th>File/URL</th><th>Status</th></tr>';
        
        top.frames['upload'].AUDIOO.upload.fileList.each(function(fobj) { if (fobj) {    
            var serverResponse = top.frames['upload'].AUDIOO.upload.serverResponses[fobj.id];
            var clientResponse = top.frames['upload'].AUDIOO.upload.clientResponses[fobj.id];
            // if clientResponse is null, there were no client errors for this file

            var msg = ( (serverResponse)? serverResponse.message : '') +
            ( (clientResponse)? clientResponse.message : '');

            if (msg) {
                // change className for file-line in case of error/failure
                cName = (serverResponse.code)? 'uploadError' : 'uploadSuccess';
            } else {
                cName = 'uploadPending';
                msg   = 'Pending&hellip;';
            }

            lines += '<tr class="'+cName+'"><td>'+fobj.name+'</td><td>'+msg + '</td></tr>';

               
        }});

        lines += '</table>';
        c.innerHTML = lines;
       
        
        
    },
    
    /** this should return true if all Uploads are finished (file + urls ), false otherwise **/
    allFinished: function() {
        
        return top.frames['upload'].AUDIOO.upload._isFilesCompleted;
        //return false;
    },
    
    ////////////////// basic events ///////////////////

    
    /* this is called for each selected file */
    onFileQueued: function (file) {
        // table container for file list
        var c     = top.frames['content'].document.getElementById('files_container');
        var fsize = AUDIOO.upload.formatFilesize(file.size);
        var line  = '<tr><td>'+ file.name + '</td><td>' +fsize+'</td></tr>'; 
        
        var prevContents = this._getTableInnerHTML(c.innerHTML);
        c.innerHTML = '<table>'+ prevContents + line + '</table>';
        
        
        AUDIOO.upload.totalSize += file.size;
        top.frames['upload'].AUDIOO.upload.totalSize += file.size; 
        
        AUDIOO.upload.totalFiles += 1;
        top.frames['upload'].AUDIOO.upload.totalFiles += 1; 
        
        // save this file info for Report table
        AUDIOO.upload.fileList[AUDIOO.upload.totalFiles] = file;
        top.frames['upload'].AUDIOO.upload.fileList[AUDIOO.upload.totalFiles] = file;
         
        
    },
    
    /* called just before File Dialog selection */
    onFileDialogStart: function () {
        var c    = top.frames['content'].document.getElementById('files_container');
        c.innerHTML = '<table><tr><th>Filename</th><th>Size</th></tr></table>';
        AUDIOO.upload.resetAll();
       
    }, 
    
    /* called just after File Dialog selection */
    onFileDialogComplete: function(numFilesSelected, numFilesQueued) {
       var c    = top.frames['content'].document.getElementById('files_container');
       
       var prevContents = this._getTableInnerHTML(c.innerHTML);
       var totalLine    = '<tr><td align="right">Total:</td> <td><b>'+ this.formatFilesize(this.totalSize)+'</b></td></tr>'; 
       c.innerHTML = '<table>'+ prevContents + totalLine + '</table>';
        
        if (numFilesSelected == 0) {
            c.innerHTML = '';
            
        } else {
             this.updateUploadEstimates();
        }
        
    },
    
    /** uploadStart is called immediately before the file is uploaded. This event provides an oppurtunity to 
      perform any last minute validation, add post params or do any other work before the file is uploaded. */
    onUploadStart: function (file) {
        
       return  true;
    },
    
    
    /* called at the end of file upload.
       Server returns JSON in sample format:
       
       {"type":"FileUpload","code":0,"exception":"None","message":"Successfully uploaded!"}  
       
     */
    onUploadSuccess: function(file, serverData) {
         var resp = serverData.evalJSON(true);
         //alert('Code:'+resp.code +' Msg:'+resp.message+'  Exception:'+resp.exception);
         top.frames['content'].AUDIOO.upload.serverResponses[file.id]  = resp;
         top.frames['upload'].AUDIOO.upload.serverResponses[file.id]  = resp;
         
         
         AUDIOO.upload.currentFileNumber++;
       
    },
    
    
    
    /* upload progress per file */
    onUploadProgress: function (file, bytesLoaded, bytesTotal) {
        AUDIOO.upload.totalLoadedSize += bytesLoaded; 
        
        var c = top.frames['upload'].document.getElementById('filename');
        
        var filePercent  = Math.round(bytesLoaded / bytesTotal * 100);
        var tP = (AUDIOO.upload.currentFileNumber) / AUDIOO.upload.totalFiles;
        var cP = 1 / AUDIOO.upload.totalFiles;
        var totalPercent = Math.round(( tP + cP * filePercent/100) * 100 ); 
       
        //var title   = file.name+' <b>('+filePercent + '/'+totalPercent +'% '+ AUDIOO.upload.totalFiles + ')</b>';
        var title   = file.name+' <b>('+filePercent +'% )</b>';

        var pos = Math.round(770 * totalPercent / 100);
        
        c.style.backgroundPosition = "-"+(770 - pos)+"px 0px"; // -770 -> 0

        c.innerHTML = title; 
 
    },
    
    
    /* fired when the complete upload queue is finished */
    onQueueComplete: function(numFilesUploaded) {
       // set 100% complete
       var c = top.frames['upload'].document.getElementById('filename');
       c.style.backgroundPosition = "0px 0px"; // -770 -> 0
       
       AUDIOO.upload.showInfoMessage('Your upload is finished.');

       // set internal flag to true
       top.frames['content'].AUDIOO.upload._isFilesCompleted = true;
       top.frames['upload'].AUDIOO.upload._isFilesCompleted = true;
        
    },
    
    /****************** ERROR HANDLING **************************/
    onUploadError: function(file, errorCode, message) {
        //alert('UploadError:'+file.id +' c:'+errorCode+' m:'+message);
        var obj = {};
        obj.message   = message;
        obj.errorCode = errorCode;
        obj.file      = file; 
        top.frames['content'].AUDIOO.upload.clientResponses[file.id] = obj;
        top.frames['upload'].AUDIOO.upload.clientResponses[file.id] = obj;
        
        
    }, 
    
    onFileQueueError: function(file, errorCode, message) {
        //alert('QUEUE_UploadError:'+file.id +' c:'+errorCode+' m:'+message);
        
    }
        
    
    
    
    
    
}

//alert(app)










