/*
	$Id: files.js 18644 2010-08-18 00:05:35Z mjhorne $

	This file is part of ayudaCMS
	Copyright 2007: ayuda IT
	http://www.ayuda.com.au

	For licencing details, please see LICENCE.txt in the ayudaCMS directory.
*/

var FileUploader = function(options)
{
	if(options.uploadElement == '')
	{
		options.uploadElement = options.parentElement + '_upload';
	}
	if(options.instructionsElement == '')
	{
		options.instructionsElement = options.parentElement + '_instructions';
	}
	if(options.noticeElement == '')
	{
		options.noticeElement = options.parentElement + '_notice';
	}
	if(options.responseElement == '')
	{
		options.responseElement = options.parentElement + '_response';
	}
	if(options.errorElement == '')
	{
		options.errorElement = options.parentElement + '_error';
	}
	if(options.filesElement == '')
	{
		options.filesElement = options.parentElement + '_files';
	}
	if(options.progressBarElement == '')
	{
		options.progressBarElement = options.parentElement + '_progressBarIndicator';
	}
	if(options.realm  == '')
	{
		options.realm = 'public';
	}
	if(options.validateURL  == '')
	{
		options.validateURL = null;
	}
	if(options.fileTemplate  == '')
	{
		options.fileTemplate = null;
	}

	return {

		parentElement: options.parentElement,
		progressBar: options.progressBar,
		progressBarElement: options.progressBarElement,
		uploadElement: options.uploadElement,
		responseElement: options.responseElement,
		instructionsElement: options.instructionsElement,
		noticeElement: options.noticeElement,
		errorElement: options.errorElement,
		filesElement: options.filesElement,
		uploadingMessage: 'Uploading your file, please wait ...',
		uploadErrorCount: 0,
		uploadID: null,
		baseURL: options.baseURL,
		allowedNumberOfFiles: options.allowedNumberOfFiles,
		validateURL: options.validateURL,
		fileTemplate: options.fileTemplate,
		realm: options.realm,
		stopProgress: false,

		notifyFileUploaded: function(id, options, numFiles)
		{
			this.stopProgress = true;

			$('#' + this.uploadElement).show();
			$('#' + this.responseElement).show();
			//$('#' + this.responseElement).addClass('responseError');
			$('#' + this.instructionsElement).hide();
			$('#' + this.noticeElement).hide();

			if(this.realm == 'public')
			{
				$('#' + this.responseElement).html('<span id="uploadCompleted">Your file has been uploaded</span>');
			}
			else
			{
				$('#' + this.responseElement).html('');
			}

			$('#' + this.errorElement).hide();

			this.updateFileList(id, options);

			if(this.progressBar)
			{
				$('#' + this.progressBarElement).hide();
			}

			this.validateUpload(id);
			this.toggleUpload(numFiles);
		},

		notifyFileError: function(message)
		{
			this.stopProgress = true;

			$('#' + this.uploadElement).show();
			$('#' + this.responseElement).show();
			$('#' + this.responseElement).addClass('responseError');
			$('#' + this.responseElement).html('<span id="uploadStatusNoProgress"></span>');
			$('#' + this.responseElement).hide();

			if($('#' + this.errorElement).length == 0)
			{
				$('<div class="uploadErrors" id="' + this.errorElement + '">' + message + '</div>').insertAfter('#' + this.responseElement);
			}
			$('#' + this.errorElement).html(message);
			$('#' + this.errorElement).show();

			$('#' + this.parentElement + '_wrapper iframe').attr('src', $('#' + this.parentElement + '_wrapper iframe').attr('src'));
			if($('#' + this.filesElement).find('.fileUploaded').length == 0)
			{
				$('#' + this.filesElement).hide();
			}
			$('#' + this.filesElement + ' div.filesOverlay').remove();
			$('#' + this.instructionsElement).hide();
			$('#' + this.noticeElement).hide();
		},

		notifyUploadInProgress: function(uploadID)
		{
			this.stopProgress = false;
			this.uploadID = uploadID;

			$('#' + this.filesElement).append('<div class="filesOverlay">&nbsp;</div>');

			$('#' + this.uploadElement).hide();
			$('#' + this.errorElement).hide();
			$('#' + this.responseElement).show();
			$('#' + this.responseElement).removeClass('responseError');
			$('#' + this.instructionsElement).hide();
			$('#' + this.noticeElement).show();

			if(!this.progressBar)
			{
				$('#' + this.responseElement).html('<img id="uploadStatusLoading" src="' + getBaseURL() + 'ayudacms/core/images/common/loading-small.gif" alt="Uploading your file" /><span id="uploadStatusNoProgress">' + this.uploadingMessage + '</span>');
			}
			else
			{
				$('#' + this.responseElement).html(
					'<div id="' + this.progressBarElement + '"></div>' +
					'<span id="uploadStatusProgress">' + this.uploadingMessage + '</span>' +
					'<a id="uploadCancel" href="#" onclick="return uploader_' + this.parentElement + '.cancelUpload();">cancel</a>'
				);
	
				var self = this;
				$('#' + this.progressBarElement).progressbar({value: 0});
				var callback = function() {self.updateProgressBar(0); }
				var timeout = setTimeout(callback, 5000);
			}
		},

		updateProgressBar: function(previousPercentage)
		{
			var self = this;
			if(this.realm == 'admin')
			{
				$.ajax({
					url: this.baseURL + '&action=get-upload-status-ajax',
					dataType: 'json',
					data: {'uploadID': this.uploadID},
					success: function(data, textStatus){
						self._updateProgressBar(data, previousPercentage, textStatus);
					},
					error: function(request, textStatus, errorThrown){
						self._updateProgressBarFailed(request, textStatus, errorThrown);
					}
				});
			}
			else
			{
				$.ajax({
					url: this.baseURL + '/get-upload-status-ajax/',
					dataType: 'json',
					data: {'uploadID': this.uploadID},
					success: function(data, textStatus){
						self._updateProgressBar(data, previousPercentage, textStatus);
					},
					error: function(request, textStatus, errorThrown){
						self._updateProgressBarFailed(request, textStatus, errorThrown);
					}
				});
			}
		},

		_updateProgressBar: function(data, previousPercentage, textStatus)
		{
			if(textStatus == 'success')
			{
				if(data['fileUploaded'] == true)
				{
					this.stopProgress = true;
					$('#' + this.progressBarElement).progressbar('option', 'value', data['percent']);
					$('#uploadStatusProgress').html('Upload completed (100%)');
					return;
				}
				if(data['error'])
				{
					this.stopProgress = true;
				//	alert(data['message']);
					$('#uploadStatusProgress').html('An error occured during the upload, exiting ...');
					$('#' + this.noticeElement).hide();
				}
				else
				{
					this.uploadErrorCount = 0;
					var total = "0 B";
					if(data['total'] >= Math.pow(1024, 3))
					{
						total = data['total'] / Math.pow(1024, 3);
						if(total >= 1000)
						{
							total = total.toPrecision(4);
						}
						else
						{
							total = total.toPrecision(3);
						}
						total += " GB";
					}
					else if(data['total'] >= Math.pow(1024, 2))
					{
						total = data['total'] / Math.pow(1024, 2);
						if(total >= 1000)
						{
							total = total.toPrecision(4);
						}
						else
						{
							total = total.toPrecision(3);
						}
						total += " MB";
					}
					else if(data['total'] >= Math.pow(1024, 1))
					{
						total = data['total'] / Math.pow(1024, 1);
						if(total >= 1000)
						{
							total = total.toPrecision(4);
						}
						else
						{
							total = total.toPrecision(3);
						}
						total += " KB";
					}
					else
					{
						total = data['total'] + " B";
					}

					var uploaded = "0 B";
					if(data['uploaded'] >= Math.pow(1024, 3))
					{
						uploaded = data['uploaded'] / Math.pow(1024, 3);
						if(uploaded >= 1000)
						{
							uploaded = uploaded.toPrecision(4);
						}
						else
						{
							uploaded = uploaded.toPrecision(3);
						}
						uploaded += " GB";
					}
					else if(data['uploaded'] >= Math.pow(1024, 2))
					{
						uploaded = data['uploaded'] / Math.pow(1024, 2);
						if(uploaded >= 1000)
						{
							uploaded = uploaded.toPrecision(4);
						}
						else
						{
							uploaded = uploaded.toPrecision(3);
						}
						uploaded += " MB";
					}
					else if(data['uploaded'] >= Math.pow(1024, 1))
					{
						uploaded = data['uploaded'] / Math.pow(1024, 1);
						if(uploaded >= 1000)
						{
							uploaded = uploaded.toPrecision(4);
						}
						else
						{
							uploaded = uploaded.toPrecision(3);
						}
						uploaded += " KB";
					}
					else
					{
						uploaded = data['uploaded'] + " B";
					}

					$('#' + this.progressBarElement).progressbar('option', 'value', data['percent']);
					$('#uploadStatusProgress').html('Uploading ' + uploaded + ' of ' + total + ' (' + data['percent'] + '%)');

					previousPercentage = data['percent'];
				}
			}
			else
			{
				if(++this.uploadErrorCount > 10)
				{
					this.stopProgress = true;
					$('#uploadStatusProgress').html('An error occured communicating with the server');
				}
			}

			if(!this.stopProgress)
			{
				var self = this;
				var previousPercentage = previousPercentage;
				var callback = function(){
					self.updateProgressBar(previousPercentage);
				};
				var timeout = setTimeout(callback, 5000);
			}
		},

		_updateProgressBarFailed: function(request, textStatus, errorThrown)
		{
			if(!this.stopProgress)
			{
				var self = this;
				var callback = function(){
					self.updateProgressBar(0);
				};
				var timeout = setTimeout(callback, 5000);
			}
		},

		updateFileList: function(id, options)
		{
			if(this.realm == 'admin')
			{
				var url = this.baseURL + '&action=listFile&id=' + id + '&options=' + options;
			}
			else
			{
				var url = this.baseURL + '/list-file/?id=' + id + '&options=' + options;
			}

			var self = this;

			url = url + '&parentElement=' + this.parentElement + '&options=' + options;

			if(this.fileTemplate)
			{
				url = url + '&fileTemplate=' + Base64Utils.prototype.encode(this.fileTemplate);
			}
			$.getJSON(url, {}, function(data) { 
					$('#' + self.filesElement).append('<div id="' + self.parentElement + '_' + id + '" class="fileUploaded clear">' + Base64Utils.prototype.decode(data.message) + '</div>');
					self.updateFilesInList();
					$('#' + self.filesElement + ' div.filesOverlay').remove();
					$('#' + self.filesElement).show();
			});
		},

		updateFilesInList: function()
		{
			var count = 1;
			var total = $('#' + this.filesElement + ' .fileUploaded').length;
			$('#' + this.filesElement + ' .fileUploaded').each(function() {
				if(count == 1)
				{
					$(this).find('span.disabledPromote').show();
					$(this).find('a.promote').hide();

					if(count == total)
					{
						$(this).find('span.disabledDemote').show();
						$(this).find('a.demote').hide();
					}
					else
					{
						$(this).find('span.disabledDemote').hide();
						$(this).find('a.demote').show();
					}
				}
				else if(count == total)
				{
					$(this).find('span.disabledPromote').hide();
					$(this).find('a.promote').show();
					$(this).find('span.disabledDemote').show();
					$(this).find('a.demote').hide();
				}
				else
				{
					$(this).find('span.disabledPromote').hide();
					$(this).find('span.disabledDemote').hide();
					$(this).find('a.promote').show();
					$(this).find('a.demote').show();
				}
				count++;
			});
		},

		deleteFile: function(id, options, numFiles)
		{
			$('#' + this.filesElement).append('<div class="filesOverlay">&nbsp;</div>');

			if(this.realm == 'admin')
			{
				var url = this.baseURL + '&action=deleteFile';
			}
			else
			{
				var url = this.baseURL + '/delete-file/';
			}

			var self = this;
			$.getJSON(url + '&id=' + id + '&options=' + options, {}, function(data) { 
					$('#' + self.parentElement + '_wrapper iframe').attr('src', $('#' + self.parentElement + '_wrapper iframe').attr('src'));
					if(data.success)
					{
						$('#' + self.parentElement + '_' + id).remove();
						self.toggleUpload(numFiles-1);
					}
					self.updateFilesInList();
					$('#' + self.filesElement + ' div.filesOverlay').remove();
			});
		},

		demoteFile: function(id, options)
		{
			$('#' + this.filesElement).append('<div class="filesOverlay">&nbsp;</div>');

			if(this.realm == 'admin')
			{
				var url = this.baseURL + '&action=demoteFile';
			}
			else
			{
				var url = this.baseURL + '/demote-file/';
			}

			var self = this;
			$.getJSON(url + '&id=' + id + '&options=' + options, {}, function(data) { 
					if(data.success)
					{
						self.swap($('#' + self.parentElement + '_' + id), 
								$('#' + self.parentElement + '_' + id).next());
					}
					self.updateFilesInList();
					$('#' + self.filesElement + ' div.filesOverlay').remove();
			});
		},

		promoteFile: function(id, options)
		{
			$('#' + this.filesElement).append('<div class="filesOverlay">&nbsp;</div>');

			if(this.realm == 'admin')
			{
				var url = this.baseURL + '&action=promoteFile';
			}
			else
			{
				var url = this.baseURL + '/promote-file/';
			}

			var self = this;
			$.getJSON(url + '&id=' + id + '&options=' + options, {}, function(data) { 
					if(data.success)
					{
						self.swap($('#' + self.parentElement + '_' + id), 
								$('#' + self.parentElement + '_' + id).prev());
					}
					self.updateFilesInList();
					$('#' + self.filesElement + ' div.filesOverlay').remove();
			});
		},

		swap: function(a, b)
		{
			if($(a).length > 0 && $(b).length > 0)
			{
				var domA = a[0];
				var domB = b[0];
			    var t = domA.parentNode.insertBefore(document.createTextNode(''), domA);

			    domB.parentNode.insertBefore(domA, domB);
			    t.parentNode.insertBefore(domB, t);
			    t.parentNode.removeChild(t);
			}
		},

		toggleUpload: function(numFiles) {
			if(numFiles == 0)
			{
				$('#' + this.filesElement).hide();
				$('#' + this.uploadElement).show();
				$('#' + this.instructionsElement).show();
			}
			else if(numFiles >= this.allowedNumberOfFiles)
			{
				$('#' + this.uploadElement).hide();
				$('#' + this.responseElement).hide();
				$('#' + this.instructionsElement).hide();
			}
			else
			{
				$('#' + this.uploadElement).show();
				$('#' + this.instructionsElement).hide();
			}
		},

		cancelUpload: function() {

			this.stopProgress = true;

			$('#' + this.uploadElement).show();
			$('#' + this.responseElement).hide();
			$('#' + this.errorElement).hide();

			if(this.progressBar)
			{
				$('#' + this.progressBarElement).hide();
			}

			$('#' + this.parentElement + '_wrapper iframe').attr('src', $('#' + this.parentElement + '_wrapper iframe').attr('src'));
		},

		validateUpload: function(id) {
			if(this.validateURL)
			{
				var self = this;
				$.getJSON(this.validateURL, {}, function(data) { 
					if(data['error'] == true)
					{
						$('#' + self.parentElement + '_wrapper iframe').attr('src', $('#' + self.parentElement + '_wrapper iframe').attr('src'));
						$('#' + self.parentElement + '_' + id).remove();
						self.notifyFileError(data['message']);
					}
				});
			}
			else
			{
				$('#' + this.parentElement + '_wrapper iframe').attr('src', $('#' + this.parentElement + '_wrapper iframe').attr('src'));
			}
		}
	}
}


/*************************************************************************/
/** Base64 Util class                                                   **/
/**                                                                     **/ 
/** Adapted from http://www.webtoolkit.info/javascript-base64.html      **/
/*************************************************************************/

function Base64Utils() {}

Base64Utils.prototype.keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

Base64Utils.prototype.encode =  function (input) 
{
    var output = ""; 
    var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
    var i = 0;

    input = Base64Utils.prototype.utf8_encode(input);

    while(i < input.length)
    {   
        chr1 = input.charCodeAt(i++);
        chr2 = input.charCodeAt(i++);
        chr3 = input.charCodeAt(i++);

        enc1 = chr1 >> 2;
        enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); 
        enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); 
        enc4 = chr3 & 63; 

        if(isNaN(chr2))
        {
            enc3 = enc4 = 64; 
        }
        else if (isNaN(chr3)) 
        {
            enc4 = 64; 
        }

        output = output +
        Base64Utils.prototype.keyStr.charAt(enc1) + Base64Utils.prototype.keyStr.charAt(enc2) +
        Base64Utils.prototype.keyStr.charAt(enc3) + Base64Utils.prototype.keyStr.charAt(enc4);

    }   

    return output;
}


Base64Utils.prototype.decode = function(input)
{
    var output = ""; 
    var chr1, chr2, chr3;
    var enc1, enc2, enc3, enc4;
    var i = 0;

    if(input) 
    {   
        input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
    }   
   else
    {   
        input = ""; 
    }   

    while(i < input.length)
    {   
        enc1 = Base64Utils.prototype.keyStr.indexOf(input.charAt(i++));
        enc2 = Base64Utils.prototype.keyStr.indexOf(input.charAt(i++));
        enc3 = Base64Utils.prototype.keyStr.indexOf(input.charAt(i++));
        enc4 = Base64Utils.prototype.keyStr.indexOf(input.charAt(i++));

        chr1 = (enc1 << 2) | (enc2 >> 4); 
        chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); 
        chr3 = ((enc3 & 3) << 6) | enc4;

        output = output + String.fromCharCode(chr1);

        if (enc3 != 64) 
        {
            output = output + String.fromCharCode(chr2);
        }
        if (enc4 != 64) 
        {
            output = output + String.fromCharCode(chr3);
        }

    }   

    return Base64Utils.prototype.utf8_decode(output);
}

Base64Utils.prototype.utf8_encode = function (string) 
{
    string = string.replace(/\r\n/g,"\n");
    var utftext = ""; 

    for(var n = 0; n < string.length; n++) 
    {   
        var c = string.charCodeAt(n);

        if (c < 128) 
        {
            utftext += String.fromCharCode(c);
        }
        else if((c > 127) && (c < 2048))
        {
            utftext += String.fromCharCode((c >> 6) | 192);
            utftext += String.fromCharCode((c & 63) | 128);
        }
        else
        {
            utftext += String.fromCharCode((c >> 12) | 224);
            utftext += String.fromCharCode(((c >> 6) & 63) | 128);
            utftext += String.fromCharCode((c & 63) | 128);
        }
    }

    return utftext;
}


Base64Utils.prototype.utf8_decode = function (utftext)
{
    var string = "";
    var i = 0;
    var c = c1 = c2 = 0;

    while(i < utftext.length )
    {
        c = utftext.charCodeAt(i);

        if (c < 128)
        {
            string += String.fromCharCode(c);
            i++;
        }
        else if((c > 191) && (c < 224))
        {
            c2 = utftext.charCodeAt(i+1);
            string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
            i += 2;
        }
        else
        {
            c2 = utftext.charCodeAt(i+1);
            c3 = utftext.charCodeAt(i+2);
            string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
            i += 3;
        }
    }
    return string;
}

