$.theknot = function(){};
$.theknot.uw = function(){};

$.extend($.theknot,
{
	formatStr: function(FormatString, ParmString0, ParmStringN)
	{
		if(this.isUndef(FormatString) || this.isUndef(ParmString0) || FormatString.indexOf('{0}') == -1)
		{
			return;
		}
		
		var retStr = FormatString;
		for(var i = 1; i < arguments.length; ++i)
		{
		    var s = '{' + (i-1) + '}';
		    while(retStr.indexOf(s) != -1)
		    {
		        retStr = retStr.replace(s, arguments[i]);
		    }
			
		}
		return retStr;
	},
	
	isUndef: function(obj)
	{
		return (typeof(obj) === typeof(void(0)));
	},
	
	isNullOrUndef: function(obj)
	{
	    return (this.isUndef(obj) || obj == null)? true: false;
	},
	
	CreateQueryStringFrom2Objects: function(defaultObj, overrideObj)
    {
        var retStr = "";
        
        for(var o in defaultObj)
        {
            if(typeof(overrideObj[o]) !== typeof(void(0)))
            {
                // If the current item exists in the overrideObj object, then use it.
                retStr = retStr + $.theknot.formatStr("{0}={1}&", o, overrideObj[o]);
            }
            else
            {
                // Otherwise, use the default.
                retStr = retStr + $.theknot.formatStr("{0}={1}&", o, defaultObj[o]);
            }
        }
        retStr = retStr.substring(0, retStr.length-1); // retStr will always end with "&", trim it off.
        return retStr;
    },
    
    isValidEmailAddress : function(strTest)
    {
        return /^\w+([-+.'']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/.test(strTest);
    },
    
    // -------------------------------------------------------------------------| CreateQueryStringFromObject(obj)
    CreateQueryStringFromObject: function(obj)
    {
        var retStr = "";
        for(var o in obj)
        {
            retStr = retStr + $.theknot.formatStr("{0}={1}&", o, obj[o]);
        }
        retStr = retStr.substring(0, retStr.length-1); // retStr will always end with "&", trim it off.
        return retStr;
    },
    
    // -------------------------------------------------------------------------| CloneWithDataElements(obj2clone, objDataKeys2cloneAlso)
	DOMCloneWithDataElements: function(obj2clone, strarrayDataKeys2cloneAlso, boolCloneEvents)
	{
	    if(typeof(obj2clone)===typeof(void(0)) || typeof(strarrayDataKeys2cloneAlso)===typeof(void(0)))
	    {
	        return obj2clone; // Garbage in, garbage out.
	    }
	    
	    boolCloneEvents = (this.isNullOrUndef(boolCloneEvents)) ? true: boolCloneEvents;
	    var Clone = obj2clone.clone(boolCloneEvents);
        
        /*  There may be some legacy code that still passes this method a string for 
	        "strarrayDataKeys2cloneAlso" (old implementation) rather than an array of strings.
	        So we'll check and turn it into an array if it's not.
	    */
        if(typeof(strarrayDataKeys2cloneAlso)!==typeof([]) && strarrayDataKeys2cloneAlso != '')
        {
            strarrayDataKeys2cloneAlso = new Array(String(strarrayDataKeys2cloneAlso));
        }
        
        if(strarrayDataKeys2cloneAlso.length)
        {
            for(var i=0; i<strarrayDataKeys2cloneAlso.length; ++i)
            {
                if(!this.isNullOrUndef(obj2clone.data(strarrayDataKeys2cloneAlso[i])))
                {
                    Clone.data(strarrayDataKeys2cloneAlso[i], obj2clone.data(strarrayDataKeys2cloneAlso[i]));
                }
                
                obj2clone.find('*').each(function()
                {
                    if(!$.theknot.isNullOrUndef($(this).data(strarrayDataKeys2cloneAlso[i])))
                    {
                        Clone.find(this.tagName + "#" + this.id).data(strarrayDataKeys2cloneAlso[i], $(this).data(strarrayDataKeys2cloneAlso[i]));
                    }
                });
            }
        }
	    
	    return Clone;
	},
	
	// -------------------------------------------------------------------------| clearBox
	clearBox : function(docElement, valToCheck) 
    {
        if(docElement.value == valToCheck) 
        {
            docElement.value = "";
        }
    },
    
    // -------------------------------------------------------------------------| breakupLongTextWithoutSpaces
    breakupLongTextWithoutSpaces : function(strInput, breakAtHowManyChars, breakingDelimiter, boolTreatAsSingleString)
    {
        //if(typeof(console) !== typeof(void(0))) { console.log(strInput); }
        if(typeof(breakingDelimiter) === typeof(void(0))){ breakingDelimiter = '\n'; }
        if(typeof(boolTreatAsSingleString) === typeof(void(0))){ boolTreatAsSingleString = false; }
        if(strInput.length<=breakAtHowManyChars) { return strInput; }
        var retVal = '';
        
        if(!boolTreatAsSingleString)
        {
            var splats = strInput.split(' ');
            
            for(var i=0; i<splats.length; ++i)
            {
                if(splats[i].length>breakAtHowManyChars)
                {
                    var fixed = this.breakupLongTextWithoutSpaces(splats[i], breakAtHowManyChars, breakingDelimiter, true);
                    retVal += fixed;
                }
                else
                {
                    retVal += (splats.length>1 && i != 0)? ' ': '';
                    retVal += splats[i];
                }
            }
        }
        else
        {
            /*
            var aHtmlTags = strInput.match(/<(.|\n)+?>/g); //See if there are any html tags b/c we do not want to put a delimiter in the middle of one.
            var aHtmlTagContainer = new Array();
            if(aHtmlTags != null && aHtmlTags.length > 0)
            {
                var aSplitUpInput = new Array();
                for(var x=0; x<aHtmlTags.length; ++x)
                {
                    var strTag = aHtmlTags[x];
                    var iStart = strInput.indexOf(strTag);
                    var iTagLen = aHtmlTags[x].length;
                }
            }
            */
            var aInput = strInput.split(''); //new String(new Array(strInput)); // Split the entire string on every character.
            var modNum = 0;
            for(var i=0; i<aInput.length; ++i)
            {
                //modNum = (i <= breakAtHowManyChars)? i+1: i-1;
                retVal += (aInput[i] += (i != 0 && i % breakAtHowManyChars == 0)? breakingDelimiter: ''); 
            }
        }
        return retVal;
    }
});

$.theknot.InputField = function(strSelector, strFriendlyName, rexValidator, boolRequired, ErrorMessage)
{
    this.selector = strSelector;
    this.friendlyName = strFriendlyName;
    this.validator = rexValidator;
    this.required = boolRequired;
    this.error = (!$.theknot.isUndef(ErrorMessage))? ErrorMessage: '';
    this.isvalid = false;
    
    this.jqueryField = function()
    {
        return $(this.selector);
    };
    
    this.htmlField = function()
    {
        return $(this.selector)[0];
    };
    
    this.value = function()
    {
        return $(this.selector).val();
    };
    
    this.validate = function()
    {
        with($(this.selector))
        {
            if($.trim(val()).length == 0 || RegExp(this.validator).test(val()))
            {
                if(this.error.length == 0)
                {
                    this.error = $.theknot.formatStr("The '{0}' field {1} have a value.", this.friendlyName, ((this.required)? "must": "does not"));
                }
                return false;
            }
            this.isvalid = true;
            return true;
        }
    };
    
    return this;
}; 


