﻿/// <reference path="../External/JSON.js" />
/// <reference path="./Agility.js" />

Agility.RegisterNamespace("Agility.UGC.API");

(function(API, $) {

	//ENUMS
	API.DataType = {
		String : 0,
		TextBlob : 1,
		Int : 2,
		Double : 3,
		DateTime : 4,
		File : 5,
		GUID : 6,
		Encrypted : 7,
		Hashed : 8,
		Boolean : 9		
	}
	
	API.RecordState = { 
		New : 0,
		Published : 1,
		Deleted : 2,
		Processing : 3,
		Declined : 4,
		Error : 5,
		All : -1
	}
	
	API.Permission = {
		Read : 0,
        Create : 1,
        Edit : 2,
        Delete : 3,
		Moderate : 4,
		Administer : 5
	}
		
	API.SortDirection = {		
		ASC : "ASC",
		DESC : "DESC"
	}
	
	API.ResponseType = {
		OK: 0,
		Error: 1
	}
	
	API.FileService =  {
		AmazonS3 : 0,
		YouTube : 1,
		Flickr : 2,
		Image : 3,
		Video : 4
	}
		
	API.FileServiceState = {
		New: 0,
		Unprocessed : 1,
		Processed : 2,
		Error : 3
	}	
	
	API.FileServiceMetaDataTypeName = "JSONPFileServiceMetaData:#Agility.UGC.API.ServiceObjects";
	
	API.YouTubeMetaField = {
		OriginalFilePath : "OriginalFilePath",
		VideoID : "VideoID",
		Description : "Description",		
		Category: "Category",
		Title: "Title",
		Keywords: "Keywords",
		Private: "Private",
		YouTubeState: "YouTubeState"
	};
	
	//from here: http://www.flickr.com/services/api/upload.api.html
		
	API.FlickrMetaField = {
		OriginalFilePath : "OriginalFilePath",
		title : "title",
		description : "description",
		tags : "tags",
		is_public : "is_public",
		is_friend : "is_friend",
		is_family : "is_family",
		safety_level: "safety_level",
		hidden : "hidden",
		photo_id : "photo_id"
		
		//other values are also appended as they are made available 
		/*
		secret
		photopage
		SquareImageUrl
		ThumbnailImageUrl
		SmallImageUrl
		MediumImageUrl
		LargeImageUrl
		*/
	};
	
    API.OnInit = function(API_Url, API_AccessKey, API_Seconds, API_RandomNumber, API_ProfileRecordID, API_Hash) {
        /// <summary>
        /// Initialize the Agility DataService API
        /// </summary>
        /// <param name="API_Url" type="String">The URL to the Agility DataService REST API.</param>        
        /// <param name="API_AccessKey" type="String">The API Key.</param>
        /// <param name="API_Seconds" type="String">The # of Seconds.</param>
        /// <param name="API_RandomNumber" type="String">A Random number.</param>        
        /// <param name="API_ProfileRecordID" type="String">The current user ID.</param>        
        /// <param name="API_Hash" type="String">The API Hash.</param>        
        
        API.APIUrl = API_Url;  
        API.APIAccessKey = API_AccessKey;  
        API.APISeconds = API_Seconds;  
        API.APIRandomNumber = API_RandomNumber;  
        API.APIProfileRecordID = API_ProfileRecordID;  
        API.APIHash = API_Hash;  
        
    }

	API.Record  = function() {
		var ID = -1;
		var CreatedOn = function(d) {}
		
		
	}
	

     API.GetAllRecordTypes = function(callback) {
        /// <summary>
        /// Get All Record Types.
        /// </summary>
        /// <param name="callback" type="Function">The method to callback to.  Has 1 parameter with the following object: {ResponseType, ResponseData, Message}.</param>      
        
        var url = _buildAPIUrl("GetAllRecordTypes", null);
                
        jQuery.getJSON(url, callback);
                        
    }
    
    API.GetRecordType = function(recordTypeID, callback) {
        /// <summary>
        /// Get All Record Types.
        /// </summary>
		/// <param name="recordTypeID">The ID of the record type to return.</param>      
        /// <param name="callback" type="Function">The method to callback to.  Has 1 parameter with the following object: {ResponseType, ResponseData, Message}.</param>      
        
        var url = _buildAPIUrl("GetRecordType", [recordTypeID]);
                
        jQuery.getJSON(url, callback);
                        
    }
    
    API.SaveRecordType = function(recordType, callback) {
        /// <summary>
        /// Saves a record type.
        /// </summary>
        /// <param name="recordType">The record type to save.</param>      
        /// <param name="callback" type="Function">The method to callback to.  Has 1 parameter with the following object: {ResponseType, ResponseData, Message}.</param>      
        
      
        var postData = JSON.encode(recordType);
        
        var url = _buildAPIUrl("SaveRecordType", null);    
        
        _submitPostData(url, postData, callback);     
                                              
    }
    
     API.DeleteRecordType = function(recordTypeID, callback) {
        /// <summary>
        /// Get All Record Types.
        /// </summary>
		/// <param name="recordTypeID">The ID of the record type to return.</param>      
        /// <param name="callback" type="Function">The method to callback to.  Has 1 parameter with the following object: {ResponseType, ResponseData, Message}.</param>      
        
        var url = _buildAPIUrl("DeleteRecordType", [recordTypeID]);
                
        jQuery.getJSON(url, callback);
                        
    }
    
    API.GetRecord = function(recordID, callback) {
        /// <summary>
        /// Gets a Record.
        /// </summary>
		/// <param name="recordID">The ID of the record to return.</param>      
        /// <param name="callback" type="Function">The method to callback to.  Has 1 parameter with the following object: {ResponseType, ResponseData, Message}.</param>      
        
        var url = _buildAPIUrl("GetRecord", [recordID]);
                
        jQuery.getJSON(url, callback);
                        
    }
    
    API.DeleteRecord = function(recordID, callback) {
        /// <summary>
        /// Deletes a Record.
        /// </summary>
		/// <param name="recordID">The ID of the record to return.</param>      
        /// <param name="callback" type="Function">The method to callback to.  Has 1 parameter with the following object: {ResponseType, ResponseData, Message}.</param>      
        
        var url = _buildAPIUrl("DeleteRecord", [recordID]);
                
        jQuery.getJSON(url, callback);
                        
    }
    
     
    API.SetRecordFlag = function(recordID, flaggedYN, callback) {
        /// <summary>
        /// Sets whether a record is flagged or not.
        /// </summary>
		/// <param name="recordID">The ID of the record to return.</param>      
		/// <param name="flaggedYN">Whether the record is flagged or not.</param>      		
        /// <param name="callback" type="Function">The method to callback to.  Has 1 parameter with the following object: {ResponseType, ResponseData, Message}.</param>      
        
        var url = _buildAPIUrl("SetRecordFlag", [recordID, flaggedYN]);
                
        jQuery.getJSON(url, callback);
                        
    }
    
    API.SetRecordState = function(recordID, recordState, reason, callback) {
        /// <summary>
        /// Sets whether a record is flagged or not.
        /// </summary>
		/// <param name="recordID">The ID of the record to return.</param>      
		/// <param name="recordState">The State of the record (from enum)</param>      
		/// <param name="reason">The reason that the record is in this state.  May be null if not an Error state.</param>      			
        /// <param name="callback" type="Function">The method to callback to.  Has 1 parameter with the following object: {ResponseType, ResponseData, Message}.</param>      
        
        var query = null;
        if (reason != null && reason != "") {
			query = "reason=" + escape(reason);
        }
        var url = _buildAPIUrl("SetRecordState", [recordID, recordState], query);
                
        jQuery.getJSON(url, callback);
                        
    }
    
    API.SetRecordFileState = function(recordID, fieldName, fileServiceState, callback) {
		/// <summary>
        /// Sets the file service state on a given file service field.
        /// </summary>
		/// <param name="recordID">The ID of the record to return.</param>      
		/// <param name="fieldName">The name of the field the file is associated with on the record.</param>      
		/// <param name="fileServiceState">The fileServiceState to set the field to.  Normally this will be FileServiceState.Unprocessed.</param>      			
        /// <param name="callback" type="Function">The method to callback to.  Has 1 parameter with the following object: {ResponseType, ResponseData, Message}.</param>      
                
        var url = _buildAPIUrl("SetRecordFileState", [recordID, fieldName, fileServiceState]);

        jQuery.getJSON(url, callback);
    }
    
    
    API.SaveRecord = function(record, callback) {
        /// <summary>
        /// Saves a record.
        /// </summary>
        /// <param name="record">The record to save.</param>      
        /// <param name="callback" type="Function">The method to callback to.  Has 1 parameter with the following object: {ResponseType, ResponseData, Message}.</param>      
        
        
        var postData = JSON.encode(record);
        
        var url = _buildAPIUrl("SaveRecord", null);    
        
        _submitPostData(url, postData, callback);     
                                              
    }
    
    API.SearchRecords = function(searchArg, callback) {
		/// <summary>
        /// Searches for records based on a SearchArg object.
        /// </summary>
        /// <param name="searchArg">The search arg object.</param>      
        /// <param name="callback" type="Function">The method to callback to.  Has 1 parameter with the following object: {ResponseType, ResponseData, Message}.</param>      
         
		 
		var argStr = JSON.encode(searchArg);
		var url = _buildAPIUrl("SearchRecords");
		url += "&s=" + escape(argStr);

		jQuery.getJSON(url, callback);
        
    }    
    
    var _settingsCache = null;
    
    API.GetSettings = function(callback, ignoreCache) {
        /// <summary>
        /// Get the Settings.
        /// </summary>
        /// <param name="callback" type="Function">The method to callback to.  Has 1 parameter with the following object: {ResponseType, ResponseData, Message}.</param>      
        /// <param name="ignoreCache" type="Boolean">Whether to ignore the cached value and get the settings from the server every time.<param>
        
        if (_settingsCache == null || ignoreCache == false) {
        
			var url = _buildAPIUrl("GetSettings", null);
                
			jQuery.getJSON(url, function(data) {
				if (data.ResponseType != API.ResponseType.OK) {
					callback(data);
				} else {
					_settingsCache = data.ResponseData;
					callback(data);
				}
			});
        } else {
        
			//use the cached value...
			callback({ 
				ResponseType: API.ResponseType.OK,
				ResponseData: _settingsCache
			});
        }
                        
    }
    
    API.SaveSettings = function(settings, callback) {
        /// <summary>
        /// Saves the Settings
        /// </summary>
        /// <param name="settings">The settings to save.</param>      
        /// <param name="callback" type="Function">The method to callback to.  Has 1 parameter with the following object: {ResponseType, ResponseData, Message}.</param>      
        
        _settingsCache = null;
        
        var postData = JSON.encode(settings);
        
        var url = _buildAPIUrl("SaveSettings", null);    
        
        _submitPostData(url, postData, callback);     
                                              
    }
    
    API.GetAllSystemAccess = function(callback) {
        /// <summary>
        /// Gets all of the System Access names in the system/
        /// </summary>
        /// <param name="callback" type="Function">The method to callback to.  Has 1 parameter with the following object: {ResponseType, ResponseData, Message}.</param>      
        
        var url = _buildAPIUrl("GetAllSystemAccess", null);
                
        jQuery.getJSON(url, callback);
                        
    }
    
     API.GetGUID = function (callback) {      
        /// <summary>
        /// Get a GUID.
        /// </summary>
        /// <param name="callback" type="Function">The method to callback to.  Has 1 parameter with the following object: {ResponseType, ResponseData, Message}.</param>      
        
        var url = _buildAPIUrl("GetGUID", null);
                
        jQuery.getJSON(url, callback);
     }
     
     
    
    API.GetAmazonS3Signature = function(policy, callback) {
		/// <summary>
        /// Deletes a file from the Amazon S3 bucket
        /// </summary>
        /// <param name="key" type="String">The full key that points to the file in S3.</param>      
        /// <param name="callback" type="Function">The method to callback to.  Has 1 parameter with the following object: {ResponseType, ResponseData, Message}.</param>
		
		var url = _buildAPIUrl("GetAmazonS3Signature", null, "policy=" + escape(policy));

        jQuery.getJSON(url, callback);
		
	} 
	
	API.DeleteFile = function(key, callback) {
		/// <summary>
        /// Deletes a file from the Amazon S3 bucket
        /// </summary>
        /// <param name="key" type="String">The full key that points to the file in S3.</param>      
        /// <param name="callback" type="Function">The method to callback to.  Has 1 parameter with the following object: {ResponseType, ResponseData, Message}.</param>
		
		var url = _buildAPIUrl("DeleteFile", null, "key=" + escape(key));

        jQuery.getJSON(url, callback);
		
	} 
	
	var _fileSizeCache = {};
	
	API.GetFileSize = function(key, callback) {
		/// <summary>
        /// Get the file size from a file in the Amazon S3 bucket.
        /// </summary>
        /// <param name="key" type="String">The full key that points to the file in S3.</param>      
        /// <param name="callback" type="Function">The method to callback to.  Has 1 parameter with the following object: {ResponseType, ResponseData, Message}.</param>
		
		var url = _buildAPIUrl("GetFileSize", null, "key=" + escape(key));

		if (_fileSizeCache[key] == undefined) {
			jQuery.getJSON(url, function(data) {
				if (data.ResponseType == API.ResponseType.OK) {
					_fileSizeCache[key] = new Number(data.ResponseData);
				}
				callback(data);
			});
        } else {        
			callback({ 
				ResponseType: API.ResponseType.OK,
				ResponseData: new Number(_fileSizeCache[key])
			});						
        }
		
	}



	//Osvel: added the uploadError function
	API.GetAmazonS3Form = function(options) { 
	
		/// <summary>
        /// Builds the SWF form uploader that will upload data to Amazon S3.  The HTML will be appended to the jQuery element that is passed into the options argument (options.fieldPanel)
        /// </summary>
        /// <param name="options">The options for this input. Has the following properties: fieldName, inputID, fieldType  fieldPanel, swfUploadUrl, beforeUpload, uploadComplete, uploadError, uploadProgress, uploadButtonImageUrl, uploadButtonImageHeight, uploadButtonImageWidth, </param>        
		
		if (options == undefined || options == null || typeof(options) == "string") {
			throw new Error("The Amazon S3 form parameters have not been set correctly.");
		}
		
		var returnUrl = location.href;		
		var inputID = options.inputID;
		var fieldPanel = options.fieldPanel;							
		var fieldName = options.fieldName;
		
		var fieldType = null;
		
											
		if (options.fieldType != undefined) fieldType = options.fieldType;
		
		//get the settings...    
		API.GetSettings(function(data) {					
			
			var html = null;
															
			if (data.ResponseType != API.ResponseType.OK) {
				html = jQuery("<span>There was an error building the " + options.fieldName + " input: " + data.Message + "</span>");
				html.appendTo(fieldPanel);
				return;
			} else {
				
				var settings = data.ResponseData;

				//get a new GUID
				API.GetGUID(function (dataGUID) {

					if (dataGUID.ResponseType != API.ResponseType.OK) {
						html = jQuery("<span>There was an error building the " + options.fieldName + " input: " + dataGUID.Message + "</span>");
						html.appendTo(fieldPanel);
						return;
					} else {

						var GUID = dataGUID.ResponseData;
						
						//get the current filename stored in the field
						var currentFileKey = $("#" + inputID).val();												

						//build the unique ids
						var uniqueID = Agility.UniqueID("post_AmazonFileForm");		
						var uniqueFormID = uniqueID + "_form";
						var uniqueFileUploadID = uniqueID + "_fileupload";
						var uniqueSwfUploadID = uniqueID + "_swfupload";
						var uniqueIFrameID = uniqueID + "_iframe";
						var uniqueUploadProgressID = uniqueID + "_progress";

						//check for flash version...						
						var flashVersion = Agility.GetFlashVersion();

						//build the return url to come back to the blank.htm page
						
						returnUrl = returnUrl.substring(0, returnUrl.indexOf("/", returnUrl.indexOf("//") + 2));
						returnUrl += Agility.ResolveUrl("~/blank.htm");
				        
						var blankUrl = Agility.ResolveUrl("~/blank.htm");
				        
						var amazonS3Url = settings.AmazonS3BaseUrl;				
						if (amazonS3Url == undefined || amazonS3Url == null || amazonS3Url == "") {
							html = jQuery("The Amazon S3 Base Url settings value has not be provided.");
							html.appendTo(fieldPanel);
							return;
						}
				        
						if (amazonS3Url.lastIndexOf("/") != amazonS3Url.length -1) amazonS3Url += "/";
				        
						//yyyy-MM-dd\\THH:mm:ss.fff\\Z 
						var exDate = new Date();				
						exDate.setDate(exDate.getDate() + 1);
						var expiration = exDate.getFullYear() + "-" + (exDate.getMonth() + 1) + "-" + exDate.getDate() + "T" + exDate.getHours() + ":" + exDate.getMinutes() + ":" + exDate.getSeconds() + "." + exDate.getTimezoneOffset() + "Z";
				        
				        var baseDirectory = "AgilityUGC/" + GUID;

						var contentLengthRangeMin = 0;
						var contentLengthRangeMax = 0;
						if (fieldType != null && fieldType.MaxLength > 0) {
							//convert from kb to bytes...
							contentLengthRangeMax = fieldType.MaxLength * 1024;
						}

						var policy = '{ "expiration": "' + expiration + '", ';
						policy += '"conditions": [  ';
						policy += '	{"bucket": "'+ settings.AmazonS3Bucket +'"}, ';
						policy += '	["starts-with", "$key", "' + baseDirectory  + '"], ';
						policy += '	{"acl": "public-read"}, ';
						if (flashVersion <= 8) {
							policy += '	{"success_action_redirect": "'+ returnUrl +'"}, ';
						} else {
							policy += '	{"success_action_status": "201"}, ';
							 
						}
						policy += '	 ["starts-with", "$Content-Type", ""], [ "starts-with", "$filename", "" ], ';										
						if (contentLengthRangeMax > 0) {
							policy += ' ["content-length-range", '+ contentLengthRangeMin +', '+ contentLengthRangeMax +'], ';
						}

						policy += '] }';
																		
						
						
						//build the key
						var awsSecretKey = settings.AmazonS3SecretKey;
						var awskey = settings.AmazonS3AccessKey;
												
						//get the signature from the UGC Server
						API.GetAmazonS3Signature(policy, function(data) {
							var policySig = data.ResponseData;							
							
															
							var fileTypes = null;
							//assume that the file extensions are the validation.... eg: .*([\.jpg]|[\.gif]|[\.jpeg]|[\.png])						
							if (fieldType != null && fieldType.ValidationRegEx != undefined && fieldType.ValidationRegEx != "") {
								
								var validExp = fieldType.ValidationRegEx;
								validExp = validExp.replace(".*([\\", "");
								validExp = validExp.replace("])", "");
								
								while (validExp.indexOf("]|[\\") != -1) {
									validExp = validExp.replace("]|[\\", ";");				
								}
								fileTypes = validExp.replace(/\./g,"*.");
								
							}
							
							//IF FLASH IS ENABLED....
							
							if (Agility.GetFlashVersion() > 8) {
								html = jQuery("<span id='" + uniqueSwfUploadID + "'></span>");
								
								html.appendTo(fieldPanel);								
								
								var postParams = {
										"key": baseDirectory + "/${filename}",
										"AWSAccessKeyId": awskey,
										"policy": policySig.PolicyBase64,
										"acl": "public-read", 
										"Signature": policySig.Signature,
										"success_action_status": "201"																				
										};
								
								
								//build the upload swf
								var swfu = new SWFUpload({
									// Backend Settings
									upload_url: amazonS3Url,
									file_post_name: "file",
									post_params : postParams,

									// File Upload Settings
									file_size_limit : contentLengthRangeMax / 1024,
									file_types : fileTypes,
									file_types_description : "Valid File Types",
									file_upload_limit : "0",    // Zero means unlimited


									// Event Handler Settings - these functions as defined in Handlers.js
									//  The handlers are not part of SWFUpload but are part of my website and control how
									//  my website reacts to the SWFUpload events.
									file_queue_error_handler : function (file, errorCode, message) {
										jQuery("#" + options.inputID).data("uploading", false); 
										if (options.uploadError != undefined && jQuery.isFunction(options.uploadError)) {
											options.uploadError(file, errorCode, message);
										}	
									},
									file_dialog_complete_handler : function (numFilesSelected, numFilesQueued){
										if (numFilesQueued > 0) {
											var file = this.getFile();
											if (file == null) return;
																					
											var filename = file.name;
											var mimetype = API.GetMIMEtype(filename);
											this.addPostParam("Content-Type", API.GetMIMEtype(filename));
											if (options.beforeUpload != undefined && jQuery.isFunction(options.beforeUpload)) {
												if (options.beforeUpload(filename, mimetype, file.size, this) == false) {
													return;
												}
											}
											
											jQuery("#" + options.inputID).data("uploading", true);
											this.startUpload();
										}
																				
									},
									upload_progress_handler : function (file, bytesLoaded) {
										if (options.uploadProgress != undefined && jQuery.isFunction(options.uploadProgress)) {
											options.uploadProgress(file, bytesLoaded);
										}
									},
									upload_success_handler : function (file, serverData) {
																		
										//success - set the value of the input and call the event.
										var uploadedKey = baseDirectory + "/" + file.name;
										jQuery("#" + options.inputID).val(uploadedKey);
										jQuery("#" + options.inputID).data("uploading", false);
										if (options.uploadComplete != undefined && jQuery.isFunction(options.uploadComplete)) {
											options.uploadComplete(uploadedKey, file.size);
										}
									},
									upload_complete_handler : function (file){
										jQuery("#" + options.inputID).data("uploading", false);
									},
										
									upload_error_handler : function uploadError(file, errorCode, message) {
										jQuery("#" + options.inputID).data("uploading", false);
										if (options.uploadError != undefined && jQuery.isFunction(options.uploadError)) {
											options.uploadError(file, errorCode, message);
										}										
									},
									swfupload_loaded_handler : function() {
										
									},

									// Button settings
									button_image_url : options.uploadButtonImageUrl,
									button_placeholder_id : uniqueSwfUploadID,																	
									button_width: options.uploadButtonImageWidth,
									button_height: options.uploadButtonImageHeight,
									button_window_mode: SWFUpload.WINDOW_MODE.OPAQUE, 
									button_action : SWFUpload.BUTTON_ACTION.SELECT_FILE, 
									button_cursor : SWFUpload.CURSOR.HAND, 
									

									// Flash Settings
									prevent_swf_caching : false, 
									flash_url : options.swfUploadUrl,	// Relative to this file
									
									// Debug Settings
									debug: false
								});						        
													
								
							
							} else {
								
								//flash not enabled...
								
								//build the html for the form and iframe
								var formHtml = "<form  enctype=\"multipart/form-data\" id=\""+uniqueFormID+"\" method=\"post\" action=\""+amazonS3Url+"\" target=\""+ uniqueIFrameID +"\"  style=\"display:inline\">";
								formHtml += "<input type=\"hidden\" name=\"key\" />";						
								formHtml += "<input type=\"hidden\" name=\"AWSAccessKeyId\" />";
								formHtml += "<input type=\"hidden\" name=\"Content-Type\" value=\"\">";					
								formHtml += "<input type=\"hidden\" name=\"success_action_redirect\" value=\""+ returnUrl +"\" />";
								formHtml += "<input type=\"hidden\" name=\"acl\" value=\"public-read\" />";
								formHtml += "<input type=\"hidden\" name=\"policy\" value=\"\" />";
								formHtml += "<input type=\"hidden\" name=\"filename\" value=\"\" />";								
								formHtml += "<input type=\"hidden\" name=\"Signature\" size=\"100\" value=\"\" />";																					
								formHtml += "<input id='"+uniqueFileUploadID+"' type=\"file\" name=\"file\" />";							
								formHtml += "</form>"				
								formHtml += "<iframe id=\""+uniqueIFrameID+"\" name=\""+uniqueIFrameID+"\" src=\""+ blankUrl +"\" style='position:absolute; height:1px; width: 1px; top:-1px; left: -10000px; overflow:hidden'></iframe>";
							
								//build the jQuery object for the form							
								html = jQuery(formHtml);
								
								//add the form to the field panel..							
								html.appendTo(fieldPanel);
								
								//set the field values...							
								jQuery("input[name='key']", html).val( baseDirectory + "/${filename}");
								jQuery("input[name='AWSAccessKeyId']", html).val(awskey);
								jQuery("input[name='policy']", html).val(policySig.PolicyBase64);
								jQuery("input[name='Signature']", html).val(policySig.Signature);																			
													
								
														
								var uploadedFileName = null;
								
								//listen to frame load events																			
								jQuery("#" + uniqueIFrameID).load(function() {
									//load event of the iframe...

									jQuery("input[name='file']", html).show();
									
									try {
										var loc = $(this.contentDocument.location)
										var href = loc.attr("href");
										
										var key = Agility.QueryString("key", href);
										if (key != null && key != "") {				
											var url = amazonS3Url + key;
																															
											//update the input file...
											jQuery("#" + inputID).val(key);
											$("#" + inputID).data("uploading", false);
											
											//call the uploadComplete event, pass it the key
											if (options.uploadComplete != undefined && jQuery.isFunction(options.uploadComplete)) {
												options.uploadComplete(key, -1);
											}
										}
									} catch (Error) {
										$("#" + inputID).data("uploading", false);

										
										//call the uploadError event, pass it the Error object
										var errorMsg = "An error occurred while uploading."
										if (contentLengthRangeMax > 0) {
											errorMsg += " Please ensure the file is less than " + (contentLengthRangeMax / 1024) + "kb.";
										}
										
										if (options.uploadError != undefined && jQuery.isFunction(options.uploadError)) {
											options.uploadError("", -1, errorMsg);
											throw Error;
										} else {
											alert(errorMsg);								    
											throw Error;
										}
									}
								});
																			
								//listen to file name changed events...							
								jQuery("input[name='file']", html).change(function() {
									uploadedFileName = $(this).val();
									
									if (uploadedFileName != "") {
									
										//check that filename is of the allowable types...
										if (fieldType != null) {
											try {
												var vldExp = fieldType.ValidationRegEx;
												if (vldExp != null && vldExp != "") {
													var rEx  =  new RegExp(vldExp);
													rEx.ignoreCase = true;
													if (uploadedFileName.search(rEx) == -1) {
																									
														if (options.uploadError != undefined && jQuery.isFunction(uoptions.ploadError)) {
															options.uploadError(uploadedFileName, SWFUpload.QUEUE_ERROR.INVALID_FILETYPE, fieldType.ValidationMessage);
														}
																																								
														$(this).val("");
														return;
													}
												}
											} catch (ex3) {
												return;
											}
										}
										
																												
										//get the mimeType of the file
										var mimeType = API.GetMIMEtype(uploadedFileName);
										
										//fire the beforeUpload event
										if (options.beforeUpload != undefined && jQuery.isFunction(options.beforeUpload)) {
											if (options.beforeUpload(uploadedFileName, mimeType, -1, null) == false) {
												try {
													$(this).val("");
												} catch (ex2) {}
												return;
											}
										}
										
										
										//put a marker on the file to show that it has changed...
										$("#" + inputID).data("uploading", true);
										$("#" + uniqueFormID + " input[name='Content-Type']").val(mimeType);
										
										//submit the form
										var f = jQuery("#" + uniqueFormID);
										f.submit();
																			
										//clear out the input and hide it
										try {
											$(this).val("");
										} catch (ex1) {}
										$(this).hide();
									}
									
								});	
								
							}										
													
						});
																																														
					}
					
				});
				
			}

		});				
				
	
	
		//bind a "live" event to the remove link (this will work for ANY remove link...);		
		if (API._liveAttachmentRemoveHandlerBound != true) {
			
			API._liveAttachmentRemoveHandlerBound = true;
											
			jQuery("form a.UploadedFileRemove").live("click", function() {
				if (confirm("Do you wish to delete this file?\n\nYou will not be able to recover this file, and any links to it will be broken")) {					
			
					//get the associated field ID from the <form> tag
					var associatedFieldID = jQuery(this).parents("form").data("associatedFieldID");
					
					var elem = jQuery(this).parent("span.UploadedFileContainer")
					elem.html("Deleting file...");
					
					var key = jQuery("#" + associatedFieldID).val();
					API.DeleteFile(key, function(data) {					
						if (data.ResponseType != 0) {
							elem.html("An error occurred: " + data.Message);
						} else {
							elem.html("");
							jQuery("#" + associatedFieldID).val("");
						}
					});					
				}							
			});							
		}												
    }
       
    //global variable used to track whether the  live attachment remove randler event has been bound
    API._liveAttachmentRemoveHandlerBound = false;
     
    function  _buildAPIUrl(methodName, args, query) {
        var url = API.APIUrl;
        
        //query should be in the form "q1=q1val&s2=s2val
        
        //ensure the url ends with /
        if (url.lastIndexOf("/") != url.length - 1) url += "/";
        
        //create the base url for the call
        url += methodName + "/" + API.APIAccessKey + "/" + API.APISeconds + "/" + API.APIRandomNumber + "/" + API.APIHash + "/" + API.APIProfileRecordID;
        
        //add the arguments for call
        if (args != undefined && $.isArray(args) && args.length > 0) 
        {            
            jQuery.each(args, function(index,arg) {
                url += "/" + escape(arg);    
            });                        
        }
        
        //add the "method" param
        url += "?method=?";
        
        //add the query strings
        if (query != undefined && query != "") {
			url += "&" + query;
        }
        
        return url;        
    }  
    
   
    
    function _submitPostData(url, postData, callback) {
    
		//build the unique ids
		var uniqueID = Agility.UniqueID("postDataForm");		
		
		var uniqueFormID = uniqueID + "_form";
		var uniqueIFrameID = uniqueID + "_iframe";
		
		//build the return url to come back to the blank.htm page
		var returnUrl = location.href;
        returnUrl = returnUrl.substring(0, returnUrl.indexOf("/", returnUrl.indexOf("//") + 2));
        returnUrl += Agility.ResolveUrl("~/blank.htm");
        
        var blankUrl = Agility.ResolveUrl("~/blank.htm");
        
        //remove the method callback from the url
        url = url.replace("?method=?", "?method=post");
        
        //build the html for the form and iframe
		var formHtml = "<div id=\""+uniqueID+"\" style='display:none'><form id=\""+uniqueFormID+"\" method=\"post\" action=\""+url+"\" target=\""+ uniqueIFrameID +"\">";
		formHtml += "<input type=\"text\" name=\"postdata\" />";
		formHtml += "<input type=\"text\" name=\"url\" />";
		formHtml += "</form>"
		formHtml += "<iframe id=\""+uniqueIFrameID+"\" name=\""+uniqueIFrameID+"\" src=\""+ blankUrl +"\"></iframe>";
		formHtml += "</div>";
		
		
		//add the elements to the DOM
		var thisBody = jQuery(document.body);
		jQuery(thisBody).append(formHtml);		
		     
		//create the actual DOM elements
		var div = jQuery("#" + uniqueID);
		var form = jQuery("#" + uniqueFormID);
		var iframe = jQuery("#" + uniqueIFrameID);
		
		$("input[name=postdata]", form).val(postData);
        $("input[name=url]", form).val(returnUrl); 
								
		//capture the load event of the form.
		jQuery(iframe).load(function() {
									
			var frm = window.frames[uniqueIFrameID];
				
			var responseType = responseType = API.ResponseType.Error;
			
				var loc = frm.location;
				
				if (loc != null) {				
					var href = loc.href;
				
					responseType = parseInt(Agility.QueryString("ResponseType", href)); 
					if (isNaN(responseType)) responseType = API.ResponseType.Error;			
				}
			
			
			var data = {
				ResponseType: responseType,
				Message: Agility.QueryString("Message", href),
				ResponseData: Agility.QueryString("ResponseData", href)
			};
									
			//call the callback
			setTimeout(function() { 
				callback(data);
			}, 0);
			
			//remove the elements...						
			setTimeout(function() {
				div.empty();
			}, 0);
				
		});
		
		//submit the form
		form.submit();
    }
     
    API.GetMIMEtype = function (filename) {
		/// <summary>
        /// Gets the mime-type of a file based on a filename.
        /// </summary>
        /// <param name="filename" type="String">The file name (from a file upload...)</param>
			
		
		var fn = new String(filename);
		var fn1 = new String();
		fn1 = fn.match(/[\/\\][^\/\\]*$/);
		if(fn1!=null && fn1.length>0) fn = fn1 + "";

		fn = fn.toLowerCase();
		
		if(fn.search(/^.*\.ai$/)>=0) {
			return("application/illustrator"); }
		if(fn.search(/^.*\.bin$/)>=0) {
			return("application/octet-stream"); }
		if(fn.search(/^.*\.pdf$/)>=0) {
			return("application/pdf"); }
		if(fn.search(/^.*\.ps$/)>=0) {
			return("application/postscript"); }
		if(fn.search(/^.*\.rtf$/)>=0) {
			return("application/rtf"); }
		if(fn.search(/^.*\.sit$/)>=0) {
			return("application/stuffit"); }
		if(fn.search(/^.*\.flv$/)>=0) {
			return("video/x-flv"); }
		if(fn.search(/^.*\.mdb$/)>=0) {
			return("application/vnd.ms-access"); }
		if(fn.search(/^.*\.xls$/)>=0) {
			return("application/vnd.ms-excel"); }
		if(fn.search(/^.*\.ppt$/)>=0) {
			return("application/vnd.ms-powerpoint"); }
		if(fn.search(/^.*\.pps$/)>=0) {
			return("application/vnd.ms-powerpoint"); }
		if(fn.search(/^.*\.pot$/)>=0) {
			return("application/vnd.ms-powerpoint"); }
		if(fn.search(/^.*\.xps$/)>=0) {
			return("application/vnd.ms-xpsdocument"); }
		if(fn.search(/^.*\.doc$/)>=0) {
			return("application/msword"); }
		if(fn.search(/^.*\.7z$/)>=0) {
			return("application/x-7z-compressed"); }
		if(fn.search(/^.*\.torrent$/)>=0) {
			return("application/x-bittorrent"); }
		if(fn.search(/^.*\.tar\.gz$/)>=0) {
			return("application/x-compressed-tar"); }
		if(fn.search(/^.*\.tgz$/)>=0) {
			return("application/x-compressed-tar"); }
		if(fn.search(/^.*\.ttf$/)>=0) {
			return("application/x-font-ttf"); }
		if(fn.search(/^.*\.gz$/)>=0) {
			return("application/x-gzip"); }
		if(fn.search(/^.*\.pdf\.gz$/)>=0) {
			return("application/x-gzpdf"); }
		if(fn.search(/^.*\.ps\.gz$/)>=0) {
			return("application/x-gzpostscript"); }
		if(fn.search(/^.*\.jar$/)>=0) {
			return("application/x-java-archive"); }
		if(fn.search(/^.*\.js$/)>=0) {
			return("application/javascript"); }
		if(fn.search(/^.*\.lzh$/)>=0) {
			return("application/x-lha"); }
		if(fn.search(/^.*\.mkv$/)>=0) {
			return("video/x-matroska"); }
		if(fn.search(/^.*\.exe$/)>=0) {
			return("application/x-ms-dos-executable"); }
		if(fn.search(/^.*\.ogg$/)>=0) {
			return("application/ogg"); }
		if(fn.search(/^.*\.ogx$/)>=0) {
			return("application/ogg"); }
		if(fn.search(/^.*\.oga$/)>=0) {
			return("audio/ogg"); }
		if(fn.search(/^.*\.ogv$/)>=0) {
			return("video/ogg"); }
		if(fn.search(/^.*\.ogg$/)>=0) {
			return("audio/x-vorbis+ogg"); }
		if(fn.search(/^.*\.ogg$/)>=0) {
			return("audio/x-flac+ogg"); }
		if(fn.search(/^.*\.ogg$/)>=0) {
			return("audio/x-speex+ogg"); }
		if(fn.search(/^.*\.spx$/)>=0) {
			return("audio/x-speex"); }
		if(fn.search(/^.*\.ogg$/)>=0) {
			return("video/x-theora+ogg"); }
		if(fn.search(/^.*\.ogm$/)>=0) {
			return("video/x-ogm+ogg"); }
		if(fn.search(/^.*\.qtl$/)>=0) {
			return("application/x-quicktime-media-link"); }
		if(fn.search(/^.*\.tar$/)>=0) {
			return("application/x-tar"); }
		if(fn.search(/^.*\.theme$/)>=0) {
			return("application/x-theme"); }
		if(fn.search(/^.*\.der$/)>=0) {
			return("application/x-x509-ca-cert"); }
		if(fn.search(/^.*\.cer$/)>=0) {
			return("application/x-x509-ca-cert"); }
		if(fn.search(/^.*\.crt$/)>=0) {
			return("application/x-x509-ca-cert"); }
		if(fn.search(/^.*\.cert$/)>=0) {
			return("application/x-x509-ca-cert"); }
		if(fn.search(/^.*\.pem$/)>=0) {
			return("application/x-x509-ca-cert"); }
		if(fn.search(/^.*\.xhtml$/)>=0) {
			return("application/xhtml+xml"); }
		if(fn.search(/^.*\.zip$/)>=0) {
			return("application/zip"); }
		if(fn.search(/^.*\.ac3$/)>=0) {
			return("audio/ac3"); }
		if(fn.search(/^.*\.aiff$/)>=0) {
			return("audio/x-aiff"); }
		if(fn.search(/^.*\.aif$/)>=0) {
			return("audio/x-aiff"); }
		if(fn.search(/^.*\.aifc$/)>=0) {
			return("audio/x-aiff"); }
		if(fn.search(/^.*\.flac$/)>=0) {
			return("audio/x-flac"); }
		if(fn.search(/^.*\.mid$/)>=0) {
			return("audio/midi"); }
		if(fn.search(/^.*\.midi$/)>=0) {
			return("audio/midi"); }
		if(fn.search(/^.*\.kar$/)>=0) {
			return("audio/midi"); }
		if(fn.search(/^.*\.m4a$/)>=0) {
			return("audio/mp4"); }
		if(fn.search(/^.*\.aac$/)>=0) {
			return("audio/mp4"); }
		if(fn.search(/^.*\.mp4$/)>=0) {
			return("video/mp4"); }
		if(fn.search(/^.*\.m4v$/)>=0) {
			return("video/mp4"); }
		if(fn.search(/^.*\.m4b$/)>=0) {
			return("audio/x-m4b"); }
		if(fn.search(/^.*\.3gp$/)>=0) {
			return("video/3gpp"); }
		if(fn.search(/^.*\.3gpp$/)>=0) {
			return("video/3gpp"); }
		if(fn.search(/^.*\.amr$/)>=0) {
			return("video/3gpp"); }
		if(fn.search(/^.*\.mp2$/)>=0) {
			return("audio/mp2"); }
		if(fn.search(/^.*\.mp3$/)>=0) {
			return("audio/mpeg"); }
		if(fn.search(/^.*\.mpga$/)>=0) {
			return("audio/mpeg"); }
		if(fn.search(/^.*\.m3u$/)>=0) {
			return("audio/x-mpegurl"); }
		if(fn.search(/^.*\.vlc$/)>=0) {
			return("audio/x-mpegurl"); }
		if(fn.search(/^.*\.asx$/)>=0) {
			return("audio/x-ms-asx"); }
		if(fn.search(/^.*\.wax$/)>=0) {
			return("audio/x-ms-asx"); }
		if(fn.search(/^.*\.wvx$/)>=0) {
			return("audio/x-ms-asx"); }
		if(fn.search(/^.*\.wmx$/)>=0) {
			return("audio/x-ms-asx"); }
		if(fn.search(/^.*\.psf$/)>=0) {
			return("audio/x-psf"); }
		if(fn.search(/^.*\.wma$/)>=0) {
			return("audio/x-ms-wma"); }
		if(fn.search(/^.*\.ra$/)>=0) {
			return("audio/vnd.rn-realaudio"); }
		if(fn.search(/^.*\.rax$/)>=0) {
			return("audio/vnd.rn-realaudio"); }
		if(fn.search(/^.*\.ram$/)>=0) {
			return("application/ram"); }
		if(fn.search(/^.*\.rv$/)>=0) {
			return("video/vnd.rn-realvideo"); }
		if(fn.search(/^.*\.rvx$/)>=0) {
			return("video/vnd.rn-realvideo"); }
		if(fn.search(/^.*\.wav$/)>=0) {
			return("audio/x-wav"); }
		if(fn.search(/^.*\.bmp$/)>=0) {
			return("image/bmp"); }
		if(fn.search(/^.*\.wbmp$/)>=0) {
			return("image/vnd.wap.wbmp"); }
		if(fn.search(/^.*\.gif$/)>=0) {
			return("image/gif"); }
		if(fn.search(/^.*\.jpeg$/)>=0) {
			return("image/jpeg"); }
		if(fn.search(/^.*\.jpg$/)>=0) {
			return("image/jpeg"); }
		if(fn.search(/^.*\.jpe$/)>=0) {
			return("image/jpeg"); }		
		if(fn.search(/^.*\.png$/)>=0) {
			return("image/png"); }
		if(fn.search(/^.*\.rle$/)>=0) {
			return("image/rle"); }
		if(fn.search(/^.*\.svg$/)>=0) {
			return("image/svg+xml"); }
		if(fn.search(/^.*\.svgz$/)>=0) {
			return("image/svg+xml-compressed"); }
		if(fn.search(/^.*\.tif$/)>=0) {
			return("image/tiff"); }
		if(fn.search(/^.*\.tiff$/)>=0) {
			return("image/tiff"); }
		if(fn.search(/^.*\.eps$/)>=0) {
			return("image/x-eps"); }
		if(fn.search(/^.*\.ico$/)>=0) {
			return("image/x-ico"); }
		if(fn.search(/^.*\.psd$/)>=0) {
			return("image/x-psd"); }
		if(fn.search(/^.*\.vcs$/)>=0) {
			return("text/calendar"); }
		if(fn.search(/^.*\.ics$/)>=0) {
			return("text/calendar"); }
		if(fn.search(/^.*\.css$/)>=0) {
			return("text/css"); }
		if(fn.search(/^.*\.CSSL$/)>=0) {
			return("text/css"); }
		if(fn.search(/^.*\.rtx$/)>=0) {
			return("text/richtext"); }
		if(fn.search(/^.*\.rss$/)>=0) {
			return("application/rss+xml"); }
		if(fn.search(/^.*\.atom$/)>=0) {
			return("application/atom+xml"); }
		if(fn.search(/^.*\.opml$/)>=0) {
			return("text/x-opml+xml"); }
		if(fn.search(/^.*\.sgml$/)>=0) {
			return("text/sgml"); }
		if(fn.search(/^.*\.sgm$/)>=0) {
			return("text/sgml"); }
		if(fn.search(/^.*\.dtd$/)>=0) {
			return("text/x-dtd"); }
		if(fn.search(/^.*\.html$/)>=0) {
			return("text/html"); }
		if(fn.search(/^.*\.htm$/)>=0) {
			return("text/html"); }
		if(fn.search(/^.*\.log$/)>=0) {
			return("text/x-log"); }
		if(fn.search(/^README*$/)>=0) {
			return("text/x-readme"); }
		if(fn.search(/^.*\.uri$/)>=0) {
			return("text/x-uri"); }
		if(fn.search(/^.*\.url$/)>=0) {
			return("text/x-uri"); }
		if(fn.search(/^.*\.fo$/)>=0) {
			return("text/x-xslfo"); }
		if(fn.search(/^.*\.xslfo$/)>=0) {
			return("text/x-xslfo"); }
		if(fn.search(/^.*\.xml$/)>=0) {
			return("application/xml"); }
		if(fn.search(/^.*\.xsl$/)>=0) {
			return("application/xml"); }
		if(fn.search(/^.*\.xslt$/)>=0) {
			return("application/xml"); }
		if(fn.search(/^.*\.xbl$/)>=0) {
			return("application/xml"); }
		if(fn.search(/^.*\.mpeg$/)>=0) {
			return("video/mpeg"); }
		if(fn.search(/^.*\.mpg$/)>=0) {
			return("video/mpeg"); }
		if(fn.search(/^.*\.mp2$/)>=0) {
			return("video/mpeg"); }
		if(fn.search(/^.*\.mpe$/)>=0) {
			return("video/mpeg"); }
		if(fn.search(/^.*\.vob$/)>=0) {
			return("video/mpeg"); }
		if(fn.search(/^.*\.m2t$/)>=0) {
			return("video/mpeg"); }
		if(fn.search(/^.*\.qt$/)>=0) {
			return("video/quicktime"); }
		if(fn.search(/^.*\.mov$/)>=0) {
			return("video/quicktime"); }
		if(fn.search(/^.*\.moov$/)>=0) {
			return("video/quicktime"); }
		if(fn.search(/^.*\.qtvr$/)>=0) {
			return("video/quicktime"); }
		if(fn.search(/^.*\.qtif$/)>=0) {
			return("image/x-quicktime"); }
		if(fn.search(/^.*\.qif$/)>=0) {
			return("image/x-quicktime"); }
		if(fn.search(/^.*\.viv$/)>=0) {
			return("video/vivo"); }
		if(fn.search(/^.*\.vivo$/)>=0) {
			return("video/vivo"); }
		if(fn.search(/^.*\.anim[1-9j]$/)>=0) {
			return("video/x-anim"); }
		if(fn.search(/^.*\.fli$/)>=0) {
			return("video/x-flic"); }
		if(fn.search(/^.*\.flc$/)>=0) {
			return("video/x-flic"); }
		if(fn.search(/^.*\.hwp$/)>=0) {
			return("application/x-hwp"); }
		if(fn.search(/^.*\.hwt$/)>=0) {
			return("application/x-hwt"); }
		if(fn.search(/^.*\.mng$/)>=0) {
			return("video/x-mng"); }
		if(fn.search(/^.*\.asf$/)>=0) {
			return("video/x-ms-asf"); }
		if(fn.search(/^.*\.nsc$/)>=0) {
			return("application/x-netshow-channel"); }
		if(fn.search(/^.*\.wmv$/)>=0) {
			return("video/x-ms-wmv"); }
		if(fn.search(/^.*\.avi$/)>=0) {
			return("video/x-msvideo"); }
		if(fn.search(/^.*\.divx$/)>=0) {
			return("video/x-msvideo"); }
		return("binary/octet-stream");
	};   
		

})(Agility.UGC.API, jQuery);