/* Copyright 2009 Palm, Inc.  All rights reserved. */

var MessagingUtils = {
  getServiceIconFromDomain: function(str) {
    switch(str) {
      case 'gmail':
        return CONSTANTS.GMAIL_ICON;
      break;
	  case 'GMail':
        return CONSTANTS.GMAIL_ICON;
      break;
	  case 'PHONE':
	    return CONSTANTS.PHONE_ICON;
	  break;
    }
  },
  
  getClassNameFromService : function(service){
    switch(service) {
      case 'gmail':
        return CONSTANTS.GMAIL_CLASS;
      break;
	  case 'GMail':
        return CONSTANTS.GMAIL_CLASS;
      break;
	  case 'PHONE':
	    return CONSTANTS.PHONE_CLASS;
	  break;
    }
  },
  
  getLoaderHTML: function() {
  	return Mojo.View.render({object: {},template: 'common/loader'});  
  },   
  
  findByValue : function(arr, key, value){
    for(var i = 0; i < arr.length; i++){
      if(arr[i][key] == value)
        return arr[i];
    }
    return undefined;
  },
  
  getContactDisplayName : function(buddy) {
    if(buddy.firstName || buddy.lastName)
      return buddy.firstName + " " + buddy.lastName;
	  
	if(buddy.chatAddress)
    	return buddy.chatAddress;
		
	return $L("Unknown");
  },
  	// TODO: How do we localize dates/times?
	getSimpleTime: function(dateObj) {
		var result = '';
		if (dateObj) {
			var hours = dateObj.getHours();
			var minutes = dateObj.getMinutes();
			var ampm = "am";
			if (hours > 11) 
				ampm = "pm";
			if (hours == 0) 
				hours = 12;
			if (hours > 12) 
				hours = hours - 12;
			if (minutes < 10) 
				minutes = "0" + minutes;
				
			result = hours + ':' + minutes + ampm;
		}
		return result;
	},  
  
  simpleListClick: function(targetElement,rowClassName,callback,isIDOnly) {
  	var newTarget = MessagingUtils.getClassUpChain(targetElement,rowClassName);
	if(newTarget) {
		if(isIDOnly)
			callback(newTarget.id);
		else
			callback(newTarget);
	}
  },
  
  getClassUpChain: function(targetElement,rowClassName) {
    var targetRow = targetElement;
    if (!targetRow.hasClassName(rowClassName)) {
      targetRow = targetRow.up('.' + rowClassName);
    }      
    if(targetRow && targetRow.hasClassName(rowClassName))
        return targetRow;
    else
		return null;
  },
  
  systemPathToLocalURL: function(systemPath) {
    if(systemPath && systemPath.length > 0)
      return "file://" + systemPath;
    
    return null;
  },
  
  sanitizeSystemPath: function(systemPath) {  	
    var newPath = '';
	if (!systemPath) {
		return newPath;
	}
	newPath = systemPath.strip();
    if (newPath.indexOf("file://") == 0) {
		newPath = newPath.substring(7);
	}
    return newPath;
  },
 
  renderFriendlyImage: function(imageElement,imagePath,maxWidth,maxHeight) {
    if (imageElement) {
      MessagingUtils.loadImage(imagePath, function(image){
        MessagingUtils.injectImage(imageElement, image);
        MessagingUtils.resizeImage(imageElement, maxWidth, maxHeight);
      });
    }
  },
  
  loadImage: function(path,callback) {
    var image = new Image();
    image.onload = function() {
      callback(image);
    };
    image.onerror = function() {
      Mojo.Log.info("Error loading image");
    };
    image.src = path;   
  },
  
  injectImage: function(imageElement,imageObject) {
    if (imageElement) {
      imageElement.style.width = "";
      imageElement.style.height = "";
      imageElement.src = imageObject.src;
    }
  },
  
  resizeImage: function(imageElement,maxWidth,maxHeight) {
    var imgWidth = imageElement.offsetWidth;
    var imgHeight = imageElement.offsetHeight;
    
    //Mojo.Log.info("imgWidth: " + imgWidth + " MaxWidth: " + maxWidth + " DELTA: " + (imgWidth - maxWidth));
    //Mojo.Log.info("imgHeight: " + imgHeight + " MaxHeight: " + maxHeight + " DELTA: " + (imgHeight - maxHeight));
    
    // resize based on the width
    if ((imgWidth - maxWidth) > (imgHeight - maxHeight)) { 
      if (imgWidth > maxWidth) {
        //Mojo.Log.info("RESIZING WIDTH: " + maxWidth);
        imageElement.style.width = maxWidth + "px";
      }
    } else { // resize based on the height                                                 
      if (imgHeight > maxHeight) {
        //Mojo.Log.info("RESIZING HEIGHT: " + maxHeight);
        imageElement.style.height = maxHeight + "px";
      }
    }    
  },
  
  /**
   * This method returns the best name based on
   * the data that is passed in
   * 
   * @param {Object} data = 
   * {
   *   firstName:,
   *   lastName:,
   *   address:
   * }
   * 
   */
  generateNameString: function(data) {
    if(!Object.isHash(data))
      data = $H(data);
      
  	var name = "";
  	if (data.get('firstName') || data.get('lastName')) {
  		name += new Template($L("#{firstName} #{lastName}")).evaluate({firstName:data.get('firstName'),lastName:data.get('lastName')});
  	} else {
      name += data.get('address');
    }
  	return MessagingUtils.formatPhoneNumber(name.strip());
  },
  
  /**
   * Matches a phone number against an array of phone numbers.
   * 
   * @param {String} number  - The phone number to match against the array
   * @param {Array} numberArr - The array of numbers to be matched
   * @param {String} hashIndex - Optional - This should be used when matching against an array of hash elements.
   *                                        The hashIndex is the property name of the phone number in each hash
   *                                        
   * return: an array of matched numbers.  If a hash is passed in an the hashIndex is specified, the return value
   *          will be an array of hashes                                       
   */
  findBestPhoneNumberMatches: function(number,numberArr,hashIndex) {
    var MIN_DIGITS_TO_MATCH = 0;
    var bestMatches = [];
    var maxDigitsMatched = 0;
  
    if (numberArr == null || !Object.isArray(numberArr) || numberArr.length == 0)
      return bestMatches;
    if (numberArr.length == 1)
      return numberArr;

    number = number.toLowerCase().strip();
    numberArr.each(function(candidateElement){
      var candidate;
      if(hashIndex != undefined && hashIndex != null)
        candidate = candidateElement[hashIndex];
      else
        candidate = candidateElement;
      
      candidate = candidate.toLowerCase().strip();
      
			var digitsMatched = 0;
			// This for loop counts, from right to left, the number of digits that the two strings have in common
			for (var i = MIN_DIGITS_TO_MATCH; i <= number.length && i <= candidate.length && digitsMatched == i; i++) {
				if (candidate.charAt(candidate.length - (i+1)) == number.charAt(number.length - (i+1))) {
					digitsMatched++;
				}
			}
			
			if (digitsMatched > maxDigitsMatched) {
				// this is a better match than the one we had before so reinitialize the bestMatches
				// array, add this to it and reset the maxDigitsMatched
				bestMatches.clear();
				bestMatches.push(candidateElement);
				maxDigitsMatched = digitsMatched;
			} else if (digitsMatched > 0 && digitsMatched == maxDigitsMatched){
				//this match is just as good as the previous one so add it to the list of bestMatches
				bestMatches.push(candidateElement);
			}
		});
		return bestMatches;
	},
  
  	// DEPRECATED STE HACK
	parseTextForHyperlink: function(text) {
		//Mojo.Log.info("MessagingUtils.parseTextForHyperlink() is deprecated. Use: PalmSystem.runTextIndexer()");
		var parsed = "";
		if(text && text.length > 0) {
		  parsed = text.gsub(/(http[s]{0,1}:\/\/[a-z0-9\.\/]*)/i, function(match) {
		    return "<a href='" + match[0] + "' target='_blank'>" + match[0] + "</a>";
		  });	
	  }	
		return parsed;
	},

	/*
  
  getNiceDate : function(timestamp, withoutToday) {
    var d = new Date();
    d.setTime(timestamp);     
    var hours = d.getHours();
    var minutes = d.getMinutes();
    var ampm = "am";
    var day = BucketDateFormatter.getDateBucket(d);
    if(hours > 11)
    {
      ampm = "pm";
    }
    if(hours == 0)
      hours = 12;
    if(hours > 12)
      hours = hours - 12;
      
    if(minutes < 10)
      minutes = "0" + minutes;
	
	if (withoutToday && day == "Today")  
    	return hours + ":" + minutes + ampm;
	else
		return day + " " + hours + ":" + minutes + ampm;
  },
	*/
  // DEPRECATED
  trim: function(str) { 
    Mojo.Log.info("MessagingUtils.trim() is deprecated.  Use the prototype strip() method");
    str.replace(/^\s*/, '').replace(/\s*$/, ''); 
    return str;
  },
  
  
  /**
   * This delayed updater will fire an update when it is first called.  Then it will wait for
   * the specified delaySeconds.  During this time any update calls are ignored.  At the end of the
   * timeout, another timeout will be started if any updates were ignored.
   * 
   * @param {Object} delaySeconds
   * @param {Object} updateFn
   */
  
	delayedListUpdater: function(updateFn, maximizeDelaySeconds, minimizeDelaySeconds) {
		var updateFunction = function() {
			Mojo.Log.warn('delayedListUpdater update function has not been set!');
		};
		if (updateFn) {
			updateFunction = updateFn;
		}
		
		var ONE_SECOND_IN_MILLISECONDS = 1000;
		var _maximizeDelaySeconds = maximizeDelaySeconds;
		var _minimizeDelaySeconds = minimizeDelaySeconds;
		
		var currentDelay = _maximizeDelaySeconds;
		var delayTimer;
		var ignoreCount = 0; // this is used to determine if any updates were ignored while the timer was running
						    // if this is > 0, when the timeoutFn is called it will update and start another timeout
		
		var secondsToMilliseconds = function(seconds) {
			return (seconds * ONE_SECOND_IN_MILLISECONDS);
		};	
		
		var timeoutFn = function(forceUpdate) {
			//console.log("****************** Hit Timeout Function");
			clearTimeout(delayTimer);
			delayTimer = null;
			var prevIgnoreCount = ignoreCount;
			// fire an update if we ignored any updates while the delay timer was running
			if(ignoreCount > 0 || forceUpdate) {
				updateFunction();
				createDelayTimer();
			}
			ignoreCount = 0;
		};
		
		var createDelayTimer = function() {
			//console.log("****************** Creating throttle timer for: " + currentDelay + " seconds");
			delayTimer = setTimeout(timeoutFn,secondsToMilliseconds(currentDelay));
		};			
		
		return {
			delayUpdate: function(){
				if (!delayTimer) { // if the delay timer is not running, start it and kick off an update
					//console.log("****************** Firing update and starting timer");
					updateFunction();
					createDelayTimer();
				} else {
					//console.log("****************** Throttled update");
					ignoreCount++; // keep a count of how many updates are ignored
				}
			},
			forceUpdate: function() {
				//console.log("****************** Forcing update");
				timeoutFn(true); // clear the timer, fire an update, start a new timer
			},
			maximize: function() {
				//console.log("****************** Maximize");
				currentDelay = _maximizeDelaySeconds;
				// if we have a pending update then fire immediately
				if(delayTimer) {
					this.forceUpdate();
				}
			},
			minimize: function() {
				//console.log("****************** Minimize");
				currentDelay = _minimizeDelaySeconds;
			}
		}
	}, 
  
  	sceneExistsInStack: function(stageController,sceneName) {
		if(!stageController || !sceneName) {
			return false;
		}
			
		var activeScenes = stageController.getScenes();
		var sceneExists = false;
		for(var i = 0; i < activeScenes.length; i++){
			var scene = activeScenes[i];
			if (scene.sceneName == sceneName) {
				return true;
			}
		}
		return false;	
	},
	
	handleGetOwnPhoneNumber: function(phoneNumber) {
		if(!phoneNumber || phoneNumber == "SMS Account") {
			phoneNumber = $L("SMS Account");
		}
		return phoneNumber;
	},
	
	cleanPhoneNumber: function(number) {
		var strippedNumber = '';
		if (number) {
			strippedNumber = number.replace(/[^0-9\+\*\#]*/gi, '');
		}
		return strippedNumber;
	},
	
	
	formatPhoneNumber: function(number) {
		if (number.length == 0 || typeof number !== "string") {
			// TODO: wrap in something that returns a default value?
			return "";
		} 
		
		var alphaCharRegex = new RegExp(/[a-zA-Z]+/);
		// a phone number will not contain characters
		if (!alphaCharRegex.test(number)) {
			// strip any formatting that may already exist
			var strippedNumber = MessagingUtils.cleanPhoneNumber(number);
			
			if (strippedNumber.length == 7 || strippedNumber.length >= 10) {
				number = Mojo.Format.formatPhoneNumber(strippedNumber);
			}
		}
		return number;
	},

	/**
	 * Returns an extractfs path to the specified image and applies the paramaters that are passed in
	 * @param {Object} systemPath - full system path to a jpeg
	 * @param {Object} params:
			offset: mandatory but may be 0.
			size: mandatory but may be 0 (in which case it is ignored and the whole file is used).
			width: mandatory
			height: mandatory
			crop: mandatory
				2: fit outside provided width/height with a fast crop; 
				3: fit inside provided width/height; 
				4: fit outside provided width/height]. Using the faster crop method will not return an image 
				of the precise dimensions requested, it will crop and usually use power of 2 scaling to 
				achieve the results.
	 */
	extractfs: function(systemPath, params) {
		var newPath = systemPath;
		// reject any path that contains a colon because this is probably already an extractfs path
		if (!newPath.indexOf(':') > -1) {
			var extractfsBinPath = "/var/luna/data/extractfs";
			var p = Object.extend({ // set some defaults and override them with whatever is passed in
				offset: 0,
				imgSize: 0,
				width: 50,
				height: 50,
				crop: 4
			}, params);
			newPath = extractfsBinPath + systemPath + ':' + p.offset + ':' + p.imgSize + ':' + p.width + ':' + p.height + ':' + p.crop;
		}
		return newPath;
	},

	/**
	 * Parses the target URI and returns the equivalent launch parameters for a compose scene.
	 * @param {Object} uri with scheme of either "im" or "sms"
	 */
	parseTargetUri: function(uri) {
//		MessagingUtils.parseTargetUri("sms:5551234");
//		MessagingUtils.parseTargetUri("sms:5551234,555-1212");
//		MessagingUtils.parseTargetUri("sms:5551234, 555-1212");
//		MessagingUtils.parseTargetUri("sms:5551234?body=hello%20there!");
//		MessagingUtils.parseTargetUri("sms:5551234?body%20= testola");
//		MessagingUtils.parseTargetUri("im");
//		MessagingUtils.parseTargetUri("im:eballot");
//		MessagingUtils.parseTargetUri("im:eballot@gmail.com");
//		MessagingUtils.parseTargetUri("im:eballot@gmail.com?foo=bar");
		
		Mojo.Log.info("parseTargetUri", uri);
		var params = {};
		
		try {
			var schemeEnd = uri.indexOf(":");
			
			if (schemeEnd != -1 && schemeEnd < 5) {
				var scheme = uri.substr(0, schemeEnd).toLowerCase();
				var restOfUri = uri.substr(schemeEnd + 1);
				var uriParts;

				/*
				 * im is covered by RFC3860 and will look like this:
				 *   "im:" to ["?" headers]
				 *     to = RFC2822 email address (aka eballot@yahoo.com)
				 *     headers = this will be ignored for now
				 */
				if (scheme === "im") {
					uriParts = restOfUri.split("?");
					Mojo.Log.info("im uriParts %j", uriParts)
					var emailParts = uriParts[0].split("@");
					if (emailParts.length === 2) {
						var service = emailParts[1].split(".")[0];
						params.composeRecipients = [{address: emailParts[0],serviceName: service}];
					}
				/*
				 * sms is covered on page 8 of http://tools.ietf.org/html/draft-wilde-sms-uri-19#page-8 and will look like this:
				 *   "sms:" sms-recipient *["," sms-recipient] ["?body=" escaped-text]
				 *     sms-recipient = a phone number
				 *     escaped-text = uri escaped text
				 */
				} else if (scheme === "sms") {
					var i;
					// This splits on "?body=" or "?body%20=%20" or whitespace instead of the %20
					uriParts = restOfUri.split(/\?body(?:\s|%20)?=(?:\s|%20)?/);
					Mojo.Log.info("sms uriParts %j", uriParts)
					if (uriParts.length === 2) {
						params.messageText = unescape(uriParts[1]);
					} else if (uriParts.length > 2) {
						Mojo.Log.error("Expected 2 uriParts. %j", uriParts);
					}
					
					recipients = uriParts[0].split(",");
					Mojo.Log.info("recipients %j", recipients);
					if (recipients.length > 0) {
						params.composeRecipients = [];
						for (i = 0; i < recipients.length; i++) {
							params.composeRecipients.push({
								address: recipients[i].strip()
							});
						}
					}
				}
			}
		} catch (e) {
			Mojo.Log.error("parseTargetUri failed to parse uri", uri);
			Mojo.Log.logException("parseTargetUri", e);
		}
		Mojo.Log.info("params %j", params);
		return params;
	}
};

var inspect = function(obj, title){
	if(title)
		Mojo.Log.info("** Inspecting " + title);
	Mojo.Log.info($H(obj).inspect());
}
