/** { [lib.objects.window.Phone]
* @purpose :: provides validation and re-write functionality for strings resolving to phone numbers
* @return :: object
* @creation :: Wednesday, September 24, 2008
* @dependency :: [lib.functions.window.Catch]
* @dependency :: [lib.functions.window.alphaOnly]
* @dependency :: [lib.functions.window.numOnly]
* @dependency :: [lib.functions.window.trim]
* @dependency :: [lib.functions.window.inArray]
* @version :: 1.01
* @edit :: Thursday, January 15, 2009 - Error on removing the country Code - fixed
* @edit :: Tuesday, January 27, 2009 - formatting for compile
* ///
* @author :: Scott McDonald;
* @license :: Lowen Corporation Use Only [Proprietary Script]
* ///
* <summary>
* 	takes a given phone number and performs checks based on settings.
* 	offers methods for specific tests
* </summary>
* <note>
*		Many properties have 3 choices these will always follow these rules
*			0 = Restrict (or do not allow)
*			1 = Optional (or Allow but do not force)
*			2 = Force (Required, This would trigger an invalid response if set)
* </note>
*/
window.Phone = function(num) {
	try {
		/** Const Properties
		*/
		this.typename = "lib.objects.window.Phone";
		/**
		* Properties
		*/
		/** defines the number to validate
		*/
		this.___OrigonalNumber = "";
		/** defines default country code for region - defaults to 1 for USA
		* if set to anything else, and allowCountryCode is False, then this will strip out
		* the set CountryCode and allow 1 to go through.
		*/
		this.defaultCountryCode = 1;
		/** defines if country code is allowed  [0,1,2]
		*/
		this.allowCountryCode = 1;
		/** defines if area code is allowed in number  [0,1,2]
		*/
		this.allowAreaCode = 1;
		/** defines if area codes can be wraped in paran. [0,1,2]
		*/
		this.allowParansInAreaCode = 1;
		/** defines if there can be a space rather then parans or delimiter after the area code  [0,1,2]
		*/
		this.allowSpaceAfterAreaCode = 1;
		/** defines if ALPHA phone numbers are allowed [true,false]
		*/
		this.allowAlphaNumbers = true;
		/** defines the text case which must be used in alpha numbers
		*/
		this.textCase = "";
		/** defines if delimiter is allowed in phone number  [0,1,2]
		*/
		this.allowDelimiter = 1;
		/** AS ARRAY - defines any allowed delims - if used in conjunction with allowDelimiter[2] then
		* the delim will be forced to be one of the items in this list. in that case, it will always default
		* to the 0 index; Default value set to ["-","."," "] Note: if this is set to a -1 index array and allowDilim is true
		* then it will find the user defined delim and use that
		*/
		this.formatDelimiter = []; /*["-","."," "];*/
		/** defines if an extention is allowed in the number [0,1,2]
		*/
		this.allowExtention = 0;
		/** defines default extention delimiter which must be used if extention exists and are allowed
		*/
		this.extentionDelimiter = "";

		/** holds boolean as to if the country code had been used and stripped
		*/
		this.strippedCountryCode = false;

		this.validate = function(num) {
			try {
				if (num) { this.constructor(num); };
				this.value = this.getNumber();
				/** check that country code is either allowed, or that the default country code doesn't exist in the number
				*/
				this.removeCountryCode();
				/** parse the string and determan what the delimiter passed to the script is
				*/
				this.defineDelim();
				/** check to see if the number is an alpha number. if so and alpha numbers are not allowed convert to numeric
				*/
				this.UpdateAlpha();
				/** now it's time to collect information about how the user entered the number.
				*  - did they use parans?
				*/
				this.areaCodeInParans = (this.value.charAt(0) == "(" && this.value.charAt(4) == ")");
				/** - did they use a space after the areacode
				*/
				this.spaceAfterAreaCode = (this.value.charAt(((this.areaCodeInParans) ? 5 : 3)) == " ");
				/** find and store extention
				*/
				this.findAndStoreExtention();

				/** now remove all spaces
				*/
				this.value = this.value.replace(/ /gi, "");
				var expectedDigits = this.ExpectedDigits();
				var addparans = (this.allowParansInAreaCode == 2 || (this.allowParansInAreaCode > 0 && this.areaCodeInParans));
				var addspaceafter = (this.allowSpaceAfterAreaCode == 2 || (this.allowSpaceAfterAreaCode > 0 && this.spaceAfterAreaCode));
				var useDelimiter = this.UseDelimiter();

				if (this.allowAlphaNumbers && this.usingAlphaNumber) {
					if (this.textCase != "Any" && this.textCase != "Mixed") {
						if (this.textCase == "Upper") {
							this.value = this.value.toUpperCase();
						} else if (this.textCase == "Lower") {
							this.value = this.value.toLowerCase();
						};
					};
					if (this.allowAreaCode > 0) {
						if (this.allowAreaCode == 2) {
							if (alphaOnly(this.value, "0123456789").length < 10) {
								this.error = "Not Enough Numbers - 10 Expected";
								this.valid = false;
								return;
							};
						};
						if (addparans) {
							this.value = this.value.replace(/\(/, "").replace(/\)/, "");
						};
						if (addspaceafter || addparans) {
							this.value = this.value.substr(0, 3) + " " + this.value.substr(3);
						};
						if (addparans) {
							this.value = "(" + this.value.substr(0, 3) + ")" + this.value.substr(3);
							return;
						};
					} else if (alphaOnly(this.value, "0123456789").length > 7) {
						this.error = "Number Can Not Have An Area Code";
						this.valid = false;
						return;
					} else {
						this.error = "Alpha Phone Number Appears Malformed";
						this.valid = false;
						return;
					};
					return;
				} else if (this.usingAlphaNumber) {
					this.error = "Aplha Charictors Not Allowed";
					this.valid = false;
					return;
				};

				this.value = numOnly(this.value);
				if (this.allowAreaCode == 2) {
					if (numOnly(this.value).length < 10) {
						this.error = "Area Code Required";
						this.valid = false;
						return;
					};
				};
				if (this.value.length < 7 || (this.value.length > 7 && this.value.length < 10)) {
					this.error = "Not Enough Digits, Expecting " + expectedDigits;
					this.valid = false;
					return;
				};
				if (
						(this.allowAreaCode == 0 && this.allowExtention == 0 && this.value.length > 7) ||
						(this.allowAreaCode > 1 && this.allowExtention == 0 && this.value.length > 10)
					) {
					this.error = "To Many Numbers, Expecting " + expectedDigits;
					this.valid = false;
					return;
				};
				if (this.value.length == 7) {
					this.value = this.value.substr(0, 3) + useDelimiter + this.value.substr(3);
				} else {
					this.value =
						((this.allowCountryCode == 2) ? this.defaultCountryCode + ((addparans) ? " " : useDelimiter) : "") +
						((addparans) ? "(" : "") +
						this.value.substr(0, 3) +
						((addparans) ? ")" : "") +
						((addspaceafter || addparans) ? " " : (useDelimiter)) +
						this.value.substr(3, 3) +
						(useDelimiter) +
						this.value.substr(6, 4) +
						((this.allowExtention > 0 && this.value.toString().length > 10) ? ((this.extentionDelimiter == "") ? " x" : " " + trim(this.extentionDelimiter)) + this.value.substr(10) : "");
				};
			} catch (e) { Catch(this.typename + ".validate(base)", e, true); }
		};

		this.UseDelimiter = function() {
			try {
				var _r = "";
				if (this.allowDelimiter == 0) {
					return ("");
				} else if (this.allowDelimiter == 1) {
					return ((inArray(this.formatDelimiter, this.storedDelimiter) || this.storedDelimiter == "") ? this.storedDelimiter : this.formatDelimiter[0]);
				} else if (this.allowDelimiter == 2) {
					if (this.formatDelimiter.length > 0) {
						return ((inArray(this.formatDelimiter, this.storedDelimiter)) ? this.storedDelimiter : this.formatDelimiter[0]);
					} else {
						return ((this.storedDelimiter == "") ? "-" : this.storedDelimiter);
					};
				};
			} catch (e) { Catch(this.typename + ".UseDelimiter(base)", e, true); }
		};

		this.ExpectedDigits = function() {
			try {
				var _r = "";
				if (this.allowAreaCode == 0) {
					_r = "Seven (7)";
				} else if (this.allowAreaCode == 1) {
					_r = "at least Seven (7)";
				} else {
					_r = "Ten (10)";
				}
				return (_r);
			} catch (e) { Catch(this.typename + ".ExpectedDigits(base)", e, true); }
		};

		this.findAndStoreExtention = function() {
			try {
				if (this.numberHasExtention()) {
					this.storedExtention = numOnly(this.value).substr(10);
				};
			} catch (e) { Catch(this.typename + ".findAndStoreExtention(base)", e, true); }
		};

		this.numberHasExtention = function() {
			try {
				var _r = false;
				var arr = numOnly(this.value, " ").split(" ");
				_r = false;
				_r = ((this.spaceAfterAreaCode) ? ((this.formatDelimiter[0] == " ") ? arr.length > 3 : arr.length > 2) : arr.length > 1);
				if (!_r && !this.usingAlphaNumber) { _r = (numOnly(this.value).length > 10); }
				return (_r);
			} catch (e) { Catch(this.typename + ".numberHasExtention(base)", e, true); }
		};

		this.addCountryCode = function() {
			try {
				if (this.value == "") {
					this.valid = false;
					this.error = "No Phone Number Defined";
					return;
				};
				if (this.allowCountryCode == 2) {
					if (this.value.substr(0, this.defaultCountryCode.toString().length) != this.defaultCountryCode) {
						this.value = this.defaultCountryCode.toString() + " " + this.value;
					};
				};
			} catch (e) { Catch(this.typename + ".addCountryCode(base)", e, true); }
		};

		this.removeCountryCode = function() {
			try {
				try {
					if (this.value == "") {
						this.valid = false;
						this.error = "No Phone Number Defined";
						return;
					};
				} catch (e) { Catch(this.typename + ".removeCountryCode(1);", e, true); }
				/** if(this.allowCountryCode==0){ removed for some-unknown reason, i really should learn to comment my code better*/
				/** remove the "+" from the begining of the number
				*/
				try {
					while (this.value.charAt(0) == "+") {
						this.value = this.value.substr(1);
					};
				} catch (e) { Catch(this.typename + ".removeCountryCode(2);", e, true); }
				/** remove country code from the begining of the number
				*/
				try {
					while (this.value.substr(0, this.defaultCountryCode.toString().length) == this.defaultCountryCode) {
						this.value = trim(this.value.substr(this.defaultCountryCode.toString().length));
					};
				} catch (e) { Catch(this.typename + ".removeCountryCode(3);", e, true); }

				try {
					this.strippedCountryCode = (this.value != this.getNumber());
				} catch (e) { Catch(this.typename + ".removeCountryCode(4);", e, true); }
				/** check to see if the entire number is letters. if so then this is an alphanumber
				* stop checking now
				*/
				try {
					if (numOnly(this.value) == "") { return; }
				} catch (e) { Catch(this.typename + ".removeCountryCode(5);", e, true); }
				/** remove any non numeric chars at the begining of the number
				*/
				try {
					while (
						isNaN(Number(this.value.charAt(0))) &&
						this.value.charAt(0) != "(" &&
						(alphaOnly(this.value.charAt(0) == ""))
					) {
						this.value = trim(this.value.substr(1).toString());
					};
				} catch (e) { Catch(this.typename + ".removeCountryCode(6);", e, true); }
				this.strippedCountryCode = (this.value != this.getNumber());
				/** } */
			} catch (e) { Catch(this.typename + ".removeCountryCode(base);", e, true); }
		};

		this.defineDelim = function() {
			try {
				if (this.value == "") {
					this.valid = false;
					this.error = "No Phone Number Defined";
					return;
				};
				var delim = "";
				delim = alphaOnly(numOnly(this.value, "", "returnNoneNumeric=true"), "", { returnNonAlpha: true });
				if (delim != "") {
					delim = delim.replace("(", "");
					delim = delim.replace(")", "");
					this.storedDelimiter = [((delim.charAt(0) == " " && delim.length > 1) ? delim.charAt(1) : delim.charAt(0))];
				} else {
					this.storedDelimiter = "";
				};
			} catch (e) { Catch(this.typename + ".defineDelim(base)", e, true); }
		};

		this.UpdateAlpha = function() {
			try {
				var convertedNumber = this.convertAlphaPhoneToNumber(this.value);
				var numbercount = numOnly(convertedNumber).length;
				var leftover = alphaOnly(this.value);
				if ((leftover != "" && this.value.indexOf(leftover) <= 10) && (numbercount >= 7 || numbercount >= 10)) {
					/** this is an alpha number
					* if not allowed, change the number to numeric
					*/
					if (this.allowAlphaNumbers == false) {
						this.value = convertedNumber;
					}
					this.usingAlphaNumber = true;
				};
			} catch (e) { Catch(this.typename + ".UpdateAlpha(base)", e, true); }
		};

		this.convertAlphaPhoneToNumber = function(__val) {
			try {
				__val = __val.toLowerCase();
				var __r = "";
				var mask = { a: 2, b: 2, c: 2, d: 3, e: 3, f: 3, g: 4, h: 4, i: 4, j: 5, k: 5, l: 5, m: 6, n: 6, o: 6, p: 7, q: 7, r: 7, s: 7, t: 8, u: 8, v: 8, w: 9, x: 9, y: 9, z: 9 };
				var i = 0;
				var l = __val.length;
				var v = __val.split("");
				for (i; i < l; i++) {
					__r += (mask[v[i]]) ? (mask[v[i]]) : v[i];
				};
				return (__r);
			} catch (e) { Catch(this.typename + ".convertAlphaPhoneToNumber(base)", e, true); }
		};

		/** Private Methods
		*/
		this.___ResetReturnValues = function() {
			try {
				/** default return values */
				this.value = "";
				this.error = "";
				this.storedExtention = "";
				this.storedDelimiter = "";

				this.valid = true;
				this.areaCodeInParans = false;
				this.spaceAfterAreaCode = false;
				this.usingAlphaNumber = false;
			} catch (e) { Catch(this.typename + ".___ResetReturnValues(base)", e, true); }
		};

		/** Getters and Setters
		*/
		this.setNumber = function(num) {
			try {
				this.___OrigonalNumber = num; this.___ResetReturnValues();
			} catch (e) { Catch(this.typename + ".setNumber(base)", e, true); };
		};

		this.getNumber = function() {
			try {
				return (this.___OrigonalNumber);
			} catch (e) { Catch(this.typename + ".getNumber(base)", e, true); };
		};

		this.constructor = function(num) {
			try {
				this.___ResetReturnValues();
				if (num) {
					this.___OrigonalNumber = num;
				};
			} catch (e) { Catch(this.typename + ".constructor(base)", e, true); }
		}; this.constructor(num);
	} catch (e) { Catch(this.typename + ".base", e, true) };
};
/** } [lib.objects.window.Phone] **/
