function SlickUpload_ProgressDisplay(clientId, progressLocation, uploadId, uploadFrameId)
{
    // TODO: null circular reference in dispose
    this.id = clientId;
    this.progressArea = document.getElementById(clientId);
    
    this.uploadFrameId = uploadFrameId;
    
    this.progressInterval = null;
    this.progressRequest = null;
    
    if (uploadId == null)
    {
        uploadId = SlickUpload_GenerateGuid();
        
        var uploadIdString = "uploadId=" + uploadId;
            
        var form = document.getElementsByTagName("form")[0];
        
        if (form.action.indexOf("?") != -1)
        {
            var querystart = form.action.indexOf("?");        
            var query = form.action.substr(querystart + 1);
            var uploadIdstart = query.indexOf("uploadId=");
            
            if (uploadIdstart == -1)
                form.action += "&" + uploadIdString;
            else
            {
                var uploadIdend = query.indexOf("&", uploadIdstart);
                
                if (uploadIdend == -1)
                    uploadIdend = query.length;
                
                uploadIdString = query.substr(uploadIdstart, uploadIdend - uploadIdstart);
            }
        }
        else
            form.action += "?" + uploadIdString;
    }
    
    this.progressLocation = progressLocation + "?" + "uploadId=" + uploadId;
        
    this.isComplete = false;
    this.inProgress = false;
       
    this.ImportProgressElements();
    
    // TODO: hook up dispose
}

SlickUpload_ProgressDisplay.prototype.ImportProgressElements = function()
{
    if (this.progressArea == null)
        return;
        
    //var progressElements = SlickUpload_GetElementsByClassNameStartsWith(this.progressArea, "su");
    var progressElements = SlickUpload_GetElementsByClassNameStartsWith(document.body, "su");
    
    this.currentFileElements = new Array();
    this.currentFileIndexElements = new Array();
    this.fileCountElements = new Array();
    this.fileCountTextElements = new Array();
    this.speedTextElements = new Array();
    this.timeRemainingTextElements = new Array();
    this.contentLengthTextElements = new Array();
    this.progressBarElements = new Array();
    this.submitButtonElements = new Array();
    this.cancelButtonElements = new Array();
    
    for (var i = 0; i < progressElements.length; i++)
    {
        switch (progressElements[i].className.toLowerCase())
        {
            case "sucurrentfilename":
                this.currentFileElements.push(progressElements[i]);
                            
                break;
            case "sucurrentfileindex":
                this.currentFileIndexElements.push(progressElements[i]);
                            
                break;
            case "sufilecount":
                this.fileCountElements.push(progressElements[i]);
                            
                break;
            case "sufilecounttext":
                this.fileCountTextElements.push(progressElements[i]);
                            
                break;
            case "suspeedtext":
                this.speedTextElements.push(progressElements[i]);
                            
                break;
            case "sutimeremainingtext":
                this.timeRemainingTextElements.push(progressElements[i]);
                            
                break;
            case "sucontentlengthtext":
                this.contentLengthTextElements.push(progressElements[i]);
                            
                break;
            case "suprogressbar":
                this.progressBarElements.push(progressElements[i]);
                            
                break;
            case "susubmitbutton":
                this.submitButtonElements.push(progressElements[i]);
                            
                break;
            case "sucancelbutton":
                this.cancelButtonElements.push(progressElements[i]);
                            
                break;
        }
    }
}

SlickUpload_ProgressDisplay.prototype.OnSubmit = function()
{
    if (this.uploadFrameId != null)
    {
        this.iframe = document.getElementById(this.uploadFrameId);
    
        if (this.iframe.contentWindow != null)
            this.doc = this.iframe.contentWindow.document;
        else
            this.doc = window.frames[clientId].document;        
    }
    else
    {
        this.doc = document;
    }
    
    this.inProgress = true;
    
    this.fileCount = 0;
    
    var uploadBoxes = this.doc.getElementsByTagName("input");
    var firstFileText;
    
    for (var i = 0; i < uploadBoxes.length; i++)
    {
        var value = uploadBoxes[i].value;

        if (uploadBoxes[i].type.toLowerCase() == "file" && value != null && value.length > 0)
        {
            this.fileCount++;
            
            if (this.fileCount == 1)
            {               
                var startPos = value.lastIndexOf("\\");
                
                if (startPos == -1)
                    startPos = value.lastIndexOf("/");                
                
                firstFileText = value.substr(startPos + 1);
            }
        }
    }
    
    for (var i = 0; i < SlickUpload_ProgressDisplayList.length; i++)
    {
        if (SlickUpload_ProgressDisplayList[i] == this)
        {
            this.index = i;
            
            break;
        }
    }

    if (this.fileCount > 0)
    {
        this.fileCountText = this.fileCount + (this.fileCount == 1 ? " file" : " files");
        
        SlickUpload_UpdateInnerHTML(firstFileText, this.currentFileElements);
        SlickUpload_UpdateInnerHTML(1, this.currentFileIndexElements);
        SlickUpload_UpdateInnerHTML(this.fileCount, this.fileCountElements);
        SlickUpload_UpdateInnerHTML(this.fileCountText, this.fileCountTextElements);	        
        SlickUpload_UpdateInnerHTML("[calculating]", this.speedTextElements);
        SlickUpload_UpdateInnerHTML("[calculating]", this.timeRemainingTextElements);
        SlickUpload_UpdateInnerHTML("[calculating]", this.contentLengthTextElements);

        SlickUpload_SetDisplay(false, this.submitButtonElements);
        SlickUpload_SetDisplay(true, this.cancelButtonElements);
    }
    
    this.updateProgressMethod = "SlickUpload_ProgressDisplayList[" + this.index + "].UpdateProgress()";
       
    this.UpdateProgress();

    if (this.fileCount > 0)
    {        
        if (this.progressArea != null)
            this.progressArea.style.display = "block";
    }
}

SlickUpload_ProgressDisplay.prototype.UpdateProgress = function()
{
    if (this.progressRequest == null)
    {           
        this.progressRequest = new XMLHttpRequest();
    }
    /*else if (this.progressRequest.abort != null)
    {
        this.progressRequest.abort();
    }*/
    
	this.progressRequest.open("GET", this.progressLocation);
	//if (this.progressRequest.onreadystatechange == null)
	//{
        var stateChangeMethod = "SlickUpload_ProgressDisplayList[" + this.index + "].progressRequest_StateChange()";
	
        this.progressRequest.onreadystatechange = function() {eval(stateChangeMethod)};
    //}
    this.progressRequest.send("");
}

SlickUpload_ProgressDisplay.prototype.progressRequest_StateChange = function()
{
    if (this.progressRequest.readyState == 4)
    {
        var isValidRequest = false;
        
        try
        {
            isValidRequest = (this.progressRequest.status == 200 && this.progressRequest.responseXML != null);
        }
        catch (ex)
        {
            isValidRequest = false;
        }
        
        if (isValidRequest)
        {
            var el = this.progressRequest.responseXML.documentElement;
            
	        if (el != null && el.attributes.length > 0)
	        {
	            if (this.progressArea != null)
	            {
                    var percentComplete = el.getAttribute("percentComplete") + "%";
                    
	                SlickUpload_UpdateInnerHTML(el.getAttribute("currentFile"), this.currentFileElements);
	                SlickUpload_UpdateInnerHTML(el.getAttribute("currentFileIndex"), this.currentFileIndexElements);
	                SlickUpload_UpdateInnerHTML(this.fileCount, this.fileCountElements);
	                SlickUpload_UpdateInnerHTML(this.fileCountText, this.fileCountTextElements);	        
	                SlickUpload_UpdateInnerHTML(el.getAttribute("speedText"), this.speedTextElements);
	                SlickUpload_UpdateInnerHTML(el.getAttribute("timeRemainingText"), this.timeRemainingTextElements);
	                SlickUpload_UpdateInnerHTML(el.getAttribute("contentLengthText"), this.contentLengthTextElements);
                    
                    for (var i = 0; i < this.progressBarElements.length; i++)
                        this.progressBarElements[i].style.width = percentComplete;
	            }
        	    
	            var state = el.getAttribute("state");
        	    
	            if (state == "Complete" || state == "Terminated")
	            {
	                if (this.uploadFrameId != null)
	                {
	                    for (var i = 0; i < SlickUpload_UploadManagerList.length; i++)
                        {
                            SlickUpload_UploadManagerList[i].SubmitParent();
                        }
	                }
	            }
	        }
        }
        	    
        if (!this.isComplete)
        {
            window.setTimeout(this.updateProgressMethod, 1000);
        }	    
    }    
}