
// The list of common JS Routines that can be systematize and usfule in any project (not PAT only).
// Can be changed and extend.

// can be set RootFolder
// can be set ProjectType
var ProjectTypes = {
    php: 'php',
    net: 'net'
};
var Project = {
    rootFolder: '/',
    imgFolder: 'PAT/Images/',
    uploadPath: '',
    type: ProjectTypes.net,
    servicePath: '',
    getVirtualDirectory: function () {
        var spot = document.location.pathname.lastIndexOf("/");
        if (spot < 0)
            return "";
        return document.location.pathname.substring(0, spot) + "/";
    },
    init: function () {
        if (typeof (RootFolder) == "undefined") {
            this.rootFolder = this.getVirtualDirectory();
        } else {
            this.rootFolder = RootFolder;
        }

        if (typeof (ProjectType) == "undefined") {
            this.type = ProjectTypes.net;
        } else {
            this.type = ProjectType;
        }
        
        if (typeof (jQuery) == "undefined") {
            document.write('<scr' + 'ipt type="text/javascript" src="' + this.rootFolder + 'PAT/jquery/jquery.js"></scr' + 'ipt>');
            document.write('<scr' + 'ipt type="text/javascript" src="' + this.rootFolder + 'PAT/jquery/jquery.lazyload.js"></scr' + 'ipt>');
            document.write('<scr' + 'ipt type="text/javascript" src="' + this.rootFolder + 'PAT/jquery/ui/jquery-ui.js"></scr' + 'ipt>');

            document.write('<scr' + 'ipt type="text/javascript" src="' + this.rootFolder + 'PAT/jquery/jquery.mousewheel-3.0.4.pack.js"></scr' + 'ipt>');
            document.write('<scr' + 'ipt type="text/javascript" src="' + this.rootFolder + 'PAT/jquery/jquery.easing-1.3.pack.js"></scr' + 'ipt>');
            document.write('<scr' + 'ipt type="text/javascript" src="' + this.rootFolder + 'PAT/jquery/jquery.fancybox-1.3.4.pack.js"></scr' + 'ipt>');
            document.write('<scr' + 'ipt type="text/javascript" src="' + this.rootFolder + 'PAT/fileuploader.js"></scr' + 'ipt>');

            document.write('<link type="text/css" rel="stylesheet" href="' + this.rootFolder + 'PAT/jquery/ui/jquery-ui.css"></link>');
            document.write('<link type="text/css" rel="stylesheet" href="' + this.rootFolder + 'PAT/fileuploader/fileuploader.css"></link>');
            document.write('<link type="text/css" rel="stylesheet" href="' + this.rootFolder + 'PAT/fancybox/jquery.fancybox-1.3.4.css"></link>');
        }

        this.imgFolder = this.rootFolder + this.imgFolder;
        this.servicePath = this.getServicePath();
        this.uploadPath = this.getUploadPath();
    },
    getServicePath: function () {
        var url = "";
        switch (this.type) {
            case ProjectTypes.php:
                url = this.rootFolder + "PAT.php";
                break;
            case ProjectTypes.net:
                url = this.rootFolder + "Tables.asmx/BatchCallWebService";
                break;
        }
        return url;
    },
    getUploadPath: function () {
        var url = "";
        switch (this.type) {
            case ProjectTypes.php:
                url = this.rootFolder + "UploadHandler.php";
                break;
            case ProjectTypes.net:
                url = this.rootFolder + "UploadService.ashx";
                break;
        }
        return url;
    }
};
Project.init();
var patImg_Dir = Project.imgFolder;

function SetPATServiceURL(url) {
    Project.servicePath = url;
}

var	ie = document.all;
var iPad = navigator.userAgent.match(/iPad/i) != null || navigator.userAgent.match(/iPhone/i) != null;

// Should be modify to support other browsers
function Browser () 
{
    switch(navigator.appName)
    {
        case "Microsoft Internet Explorer":
            return "ie";
        case "Netscape":
        case "Opera":
            return "ff";
    }
    return null;
}


//----------------------------------------------------- Redefinition for Ajax $get function -----------------------------------------------------
if(typeof($get) == "undefined") $get = function(id) {var res = $("#" + id); return res.length > 0 ? res[0] : null; }


//----------------------------------------------------- Images stuff -----------------------------------------------------

ReDefineImagePaths(Project.imgFolder);

function ReDefineImagePaths(path) {

    patImg_Refresh = path + "refresh.gif";
    patImg_Add = path + "add.png";
    patImg_Cancel = path + "cancel.png";
    patImg_CancelD = path + "cancelGray.png";
    patImg_HideRows = path + "dc_tbl.gif";
    patImg_ShowRows = path + "ex_tbl.gif";

    patImg_Up = path + "Up.png";
    patImg_Dn = path + "Dn.png";
    patImg_UpDn = path + "UpDn.png";

    patImg_Prgr = path + "progress.gif";
}

//-------------------------------------------------- Key Code Constants --------------------------------------------------

var ESC_KEY_CODE = 27;
var ENTER_KEY_CODE = 13
var TAB_KEY_CODE = 9;

var LEFT_KEY_CODE = 37;
var RIGHT_KEY_CODE = 39;
var TOP_KEY_CODE = 38;
var BOTTOM_KEY_CODE = 40;

var DEL_KEY_CODE = 46;
var BSP_KEY_CODE = 8;

var SHIFT_KEY_CODE = 16;
var CTRL_KEY_CODE = 17;
var ALT_KEY_CODE = 18;

//---------------------------------------------------------------- JSON2 ----------------------------------------------------------------
// http://www.JSON.org/json2.js

// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.

var JSON2 = JSON2 || {};

(function () {

    function f(n) {
        // Format integers to have at least two digits.
        return n < 10 ? '0' + n : n;
    }

    if (typeof Date.prototype.toJSON !== 'function') {

        Date.prototype.toJSON = function (key) {

            return isFinite(this.valueOf()) ?
                   this.getUTCFullYear()   + '-' +
                 f(this.getUTCMonth() + 1) + '-' +
                 f(this.getUTCDate())      + 'T' +
                 f(this.getUTCHours())     + ':' +
                 f(this.getUTCMinutes())   + ':' +
                 f(this.getUTCSeconds())   + 'Z' : null;
        };

        String.prototype.toJSON =
        Number.prototype.toJSON =
        Boolean.prototype.toJSON = function (key) {
            return this.valueOf();
        };
    }

    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        gap,
        indent,
        meta = {    // table of character substitutions
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        },
        rep;


    function quote(string) {

// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.

        escapable.lastIndex = 0;
        return escapable.test(string) ?
            '"' + string.replace(escapable, function (a) {
                var c = meta[a];
                return typeof c === 'string' ? c :
                    '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
            }) + '"' :
            '"' + string + '"';
    }


    function str(key, holder) {

// Produce a string from holder[key].

        var i,          // The loop counter.
            k,          // The member key.
            v,          // The member value.
            length,
            mind = gap,
            partial,
            value = holder[key];

// If the value has a toJSON method, call it to obtain a replacement value.

        if (value && typeof value === 'object' &&
                typeof value.toJSON === 'function') {
            value = value.toJSON(key);
        }

// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.

        if (typeof rep === 'function') {
            value = rep.call(holder, key, value);
        }

// What happens next depends on the value's type.

        switch (typeof value) {
        case 'string':
            return quote(value);

        case 'number':

// JSON numbers must be finite. Encode non-finite numbers as null.

            return isFinite(value) ? String(value) : 'null';

        case 'boolean':
        case 'null':

// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.

            return String(value);

// If the type is 'object', we might be dealing with an object or an array or
// null.

        case 'object':

// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.

            if (!value) {
                return 'null';
            }

// Make an array to hold the partial results of stringifying this object value.

            gap += indent;
            partial = [];

// Is the value an array?

            if (Object.prototype.toString.apply(value) === '[object Array]') {

// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.

                length = value.length;
                for (i = 0; i < length; i += 1) {
                    partial[i] = str(i, value) || 'null';
                }

// Join all of the elements together, separated with commas, and wrap them in
// brackets.

                v = partial.length === 0 ? '[]' :
                    gap ? '[\n' + gap +
                            partial.join(',\n' + gap) + '\n' +
                                mind + ']' :
                          '[' + partial.join(',') + ']';
                gap = mind;
                return v;
            }

// If the replacer is an array, use it to select the members to be stringified.

            if (rep && typeof rep === 'object') {
                length = rep.length;
                for (i = 0; i < length; i += 1) {
                    k = rep[i];
                    if (typeof k === 'string') {
                        v = str(k, value);
                        if (v) {
                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
                        }
                    }
                }
            } else {

// Otherwise, iterate through all of the keys in the object.

                for (k in value) {
                    if (Object.hasOwnProperty.call(value, k)) {
                        v = str(k, value);
                        if (v) {
                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
                        }
                    }
                }
            }

// Join all of the member texts together, separated with commas,
// and wrap them in braces.

            v = partial.length === 0 ? '{}' :
                gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
                        mind + '}' : '{' + partial.join(',') + '}';
            gap = mind;
            return v;
        }
    }

// If the JSON object does not yet have a stringify method, give it one.

    if (typeof JSON2.stringify !== 'function') {
        JSON2.stringify = function(value, replacer, space) {

// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.

            var i;
            gap = '';
            indent = '';

// If the space parameter is a number, make an indent string containing that
// many spaces.

            if (typeof space === 'number') {
                for (i = 0; i < space; i += 1) {
                    indent += ' ';
                }

// If the space parameter is a string, it will be used as the indent string.

            } else if (typeof space === 'string') {
                indent = space;
            }

// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.

            rep = replacer;
            if (replacer && typeof replacer !== 'function' &&
                    (typeof replacer !== 'object' ||
                     typeof replacer.length !== 'number')) {
                throw new Error('JSON2.stringify');
            }

// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.

            return str('', {'': value});
        };
    }


// If the JSON object does not yet have a parse method, give it one.

    if (typeof JSON2.parse !== 'function') {
        JSON2.parse = function(text, reviver) {

// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.

            var j;

            function walk(holder, key) {

// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.

                var k, v, value = holder[key];
                if (value && typeof value === 'object') {
                    for (k in value) {
                        if (Object.hasOwnProperty.call(value, k)) {
                            v = walk(value, k);
                            if (v !== undefined) {
                                value[k] = v;
                            } else {
                                delete value[k];
                            }
                        }
                    }
                }
                return reviver.call(holder, key, value);
            }


// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.

            cx.lastIndex = 0;
            if (cx.test(text)) {
                text = text.replace(cx, function (a) {
                    return '\\u' +
                        ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
                });
            }

// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.

// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.

            if (/^[\],:{}\s]*$/.
test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {

// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.

                j = eval('(' + text + ')');

// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.

                return typeof reviver === 'function' ?
                    walk({'': j}, '') : j;
            }

// If the text is not JSON parseable, then a SyntaxError is thrown.

            throw new SyntaxError('JSON2.parse');
        };
    }
}());


//----------------------------------------------------- Some Data Serializatio Stuff -----------------------------------------------------
function DeserializeDate(val)
{
    if(val == null || val == "") return val;

    if((new RegExp("^\/Date\\(-?[0-9]*\\)\/$")).test(val)) 
	    return new Date(parseInt(val.substring(6,val.length - 2)));
	else if((new RegExp("^[0-9]{1,2}\/[0-9]{1,2}\/[0-9]{4}$")).test(val))
	    return new Date(val);

	return val;
}

function FrmtDate(d) {
    if(d.getMonth == null) return d;

    try { 
        var curr_date = "" + d.getDate();
        var curr_month = "" + (d.getMonth() + 1);
        var curr_year = "" + d.getFullYear();
        
        if(curr_date.length == 1) curr_date = "0"+curr_date;
        if(curr_month.length == 1) curr_month = "0"+curr_month;
        
        return curr_month + "/" + curr_date + "/" + curr_year;
    } catch (ex) { }  

    return "";
}

function PrsDate(val)
{
    return FrmtDate(DeserializeDate(val));
}

//------------------------------------------------ Cookie Handling Routines ------------------------------------------------

    function testSessCookie () 
    {
      document.cookie ="testSessionCookie=Enabled";
      if (getCookieValue ("testSessionCookie")=="Enabled") return true;
      return false;
    }

    function testPersCookie () 
    {
      setPersCookie ("testPersistentCookie", "Enabled", "minutes", 1);
      if (getCookieValue ("testPersistentCookie")=="Enabled") return true;  
      return false;
    }

    function setSessCookie (cookieName, cookieValue) 
    {
      if (testSessCookie()) {
        document.cookie = escape(cookieName) + "=" + escape(cookieValue) + "; path=/";
        return true;
      }
      return false;
    }

    function getCookieValue (cookieName) 
    {
      var exp = new RegExp (escape(cookieName) + "=([^;]+)");
      if (exp.test (document.cookie + ";")) {
        exp.exec (document.cookie + ";");
        return unescape(RegExp.$1);
      }
      return null;
    }

    function setPersCookie (CookieName, CookieValue, periodType, offset) 
    {
      var expireDate = new Date ();
      offset = offset / 1;
      
      var myPeriodType = periodType;
      switch (myPeriodType.toLowerCase()) {
        case "years": 
         var year = expireDate.getYear(); // Note some browsers give only the years since 1900, and some since 0.
         if (year < 1000) year = year + 1900;     
         expireDate.setYear(year + offset);
         break;
        case "months": expireDate.setMonth(expireDate.getMonth() + offset); break;
        case "days": expireDate.setDate(expireDate.getDate() + offset); break;
        case "hours": expireDate.setHours(expireDate.getHours() + offset); break;
        case "minutes": expireDate.setMinutes(expireDate.getMinutes() + offset); break;
        default: alert ("Invalid periodType parameter for setPersCookie()"); break;
      } 
      
      document.cookie = escape(CookieName ) + "=" + escape(CookieValue) + "; expires=" + expireDate.toGMTString() + "; path=/";
    }  

    function deleteCookie (cookieName) 
    {
      if (getCookieValue (cookieName)) setPersCookie (cookieName,"Pending delete","years", -1);  
      return true;     
    }


//----------------------------------------------------- Event Handling Routines -----------------------------------------------------

    function RmvHandler(object, event, handler) 
    {
        if(object == null) return;
        for(var i=0; handler.Hndls && i<handler.Hndls.length; i++)
            if(handler.Hndls[i].obj == object && handler.Hndls[i].evt == event)
                { var h = handler.Hndls[i].Fnct; handler.Hndls = handler.Hndls.slice(0,i).concat( handler.Hndls.slice(i+1) ); handler = h; break; }
        
        if (object.removeEventListener) try { object.removeEventListener(event, handler, false); } catch (ex) { }  
        else if (object.detachEvent) object.detachEvent('on' + event, handler); 
        else alert("Remove handler is not supported"); 
    }

    function AddHandler(object, event, handler, useCapture) 
    { 
        if(object == null) return;

        RmvHandler(object, event, handler);
        var hndl = new evtHndl(object, handler, event);

        if (object.addEventListener) object.addEventListener(event, hndl.Fnct, useCapture ? useCapture : false); 
        else if (object.attachEvent) object.attachEvent('on' + event, hndl.Fnct); 
        else alert("Add handler is not supported"); 
    } 

    function evtHndl(obj, hnd, evt)
    {
        var self = this;

        self.obj = obj;
        self.hnd = hnd;
        self.evt = evt;

        if(!hnd.Hndls) hnd.Hndls = new Array();
        hnd.Hndls.push(self);

        self.Fnct = function (evt)
            {
                self.hnd(self.obj, evt);
            }
    }

    function CancelBubbling(evt) 
    { 
        (evt || window.event).cancelBubble = true; 
    }


    function getEventtSrc(evt)
    {
	    var evt = evt || window.event;
	    return evt.this_ || evt.target || evt.srcElement;
    }


//----------------------------------------------- Document loaded status -----------------------------------------------------------

    var docLoaded = false;
    function OnDocumentLoaded()
    {
        docLoaded = true;
    }

    AddHandler(window, "load", OnDocumentLoaded);

//---------------------------- PopUp Routines (to show some absolute position divs as popup) ----------------------------------------
//-------------- Support only one PopUp opened (can be easily changed if exclude hiding "problem" elements) -------------------------

    var popupList = new Object(); //to hide on document event


    function HidePopUp(obj)
    {
        obj.style.display = "none";
        if(obj.id && popupList[obj.id]) delete popupList[obj.id];
	    showElements();
    }


    function HidePopUps()
    {
        for (var p in popupList) HidePopUp(popupList[p]);
    }


    function ShowPopUpByCords(obj, x, y)
    {
        HidePopUps();
        
        obj.style.left = x + "px";
        obj.style.top  = y + "px";
	    obj.style.display = "";
	    if(!popupList)popupList = new Object();
        popupList[obj.id] = obj;

        hideElements(obj);
    }

    function ShowPopUp(obj, org)
    {
        OnShowPopUp(obj);
        
	    SetDropDownPos(org, obj);
	    obj.style.display = "";

        hideElements(obj);
    }

    function OnShowPopUp(obj)
    {
        HidePopUps();
        if(!popupList)popupList = new Object();
        popupList[obj.id] = obj;
    }

    AddHandler(document, "click", HidePopUps);
    AddHandler(document, "keypress", HidePopUps);

//-------------------------- PopUp dives position (to keep it in the visible area) -------------------------------------

    function SetDropDownPos(button, drdown)
    {
        var rect = GetRect(button);

        var x=rect.x;
        var y=rect.y + rect.Height + 1;
        
        var body = GetBodySize();

        if (y + drdown.offsetHeight > body.Height)
        {
            y = body.Height - drdown.offsetHeight;
            if (y < 0) y = 0;
        }

        if (x + drdown.offsetWidth > body.Width)
        {
            x = body.Width - drdown.offsetWidth;
            if (x < 0) x = 0;
        }
        if(rect.inFixed)drdown.style.position = "fixed"; else drdown.style.position = ""; 
        drdown.style.left = x + "px";
        drdown.style.top  = y + "px";
    }


    function GetBodySize()
    {
        var doc = (document.compatMode && document.compatMode=="CSS1Compat" && !navigator.userAgent.match("WebKit")) ? document.documentElement : document.body;
        return {Height:doc.clientHeight + doc.scrollTop - 6, Width:doc.clientWidth + doc.scrollLeft - 6};       
    }


    function GetRect(el)
    {
        var res = {x:0, y:0, Width:el.offsetWidth, Height:el.offsetHeight, inFixed:false};
		
		var box = getCoords(el);
        res.x = box.x;
        res.y = box.y - 2;
        res.inFixed = box.inFixed;
        return res;
    }


    function getCoords (el) 
    {
        var coords = { x: 0, y: 0, width: el.offsetWidth, height: el.offsetHeight, inFixed: false };
        try{
            while (el) {
                coords.x += el.offsetLeft;
                coords.y += el.offsetTop;
                if(GetStyleValue(el,"position") == "fixed")
                    coords.inFixed = true;
                el = el.offsetParent;
               
            }
        }
        catch(e){}
        return coords;
    }
    
    function GetStyleValue(el, styleProp) {
           if (el.currentStyle)
                 var st = el.currentStyle[styleProp];
            else if (window.getComputedStyle)
 
            var st = document.defaultView.getComputedStyle(el, null).getPropertyValue(styleProp);
            return st;
    }
    
//-------------------------- Hidding "problem" elements under pop up div -------------------------------------

	var HiddenFields = new Array()


    /* unhides <select> and <applet> objects (for IE only) */
    function showElements( )
    {
        for( i = 0; i < HiddenFields.length; i++ )
          obj = HiddenFields[i].style.visibility = "visible";
    }


    /* hides <select> and <applet> objects (for IE only) */
    function hideElements( overDiv )
    {
	    hideElement( 'SELECT', overDiv );
	    hideElement( 'APPLET', overDiv );			
	}


    /* hides "elmID" under "overDiv" objects (for IE only) */
    function hideElement( elmID, overDiv )
    {
        if( !ie ) return;
    
        for( i = 0; i < document.all.tags( elmID ).length; i++ )
        {
          obj = document.all.tags( elmID )[i];
          if( !obj || !obj.offsetParent ) continue;
      
          // Find the element's offsetTop and offsetLeft relative to the BODY tag.
          objLeft   = obj.offsetLeft;
          objTop    = obj.offsetTop;
          objParent = obj.offsetParent;
          
          while(objParent != null && (objParent.tagName.toUpperCase() != "BODY") && (objParent.tagName.toUpperCase() != "HTML"))
          {
            objLeft  += objParent.offsetLeft;
            objTop   += objParent.offsetTop;
            objParent = objParent.offsetParent;
          }
      
          objHeight = obj.offsetHeight;
          objWidth = obj.offsetWidth;

          if(overDiv.offsetLeft + overDiv.offsetWidth > objLeft && overDiv.offsetTop + overDiv.offsetHeight > objTop &&
             overDiv.offsetTop  < objTop + objHeight && overDiv.offsetLeft < objLeft + objWidth)
          {
            obj.style.visibility = "hidden";
            HiddenFields.push(obj);
          }
        }
    }


//------------------------------------------------ Hash Object Routines ------------------------------------------------

    function Hash()
    {
        var hash = new Object();

        for(var i=0; i<arguments.length; )
            hash[arguments[i++]] = arguments[i++];

        return hash;
    }

    function AddHash(hash)
    {
        if(hash == null) hash = new Object();

        if(arguments.length == 2)
            for (var prop in arguments[1])
                hash[prop] = arguments[1][prop];
        else
            for(var i=1; i<arguments.length; )
                hash[arguments[i++]] = arguments[i++];

        return hash;
    }

    function CloneHash(hash)
    {
	    var newHash = new Object();
	    for (var key in hash)
		    newHash[key] = hash[key];
	    return newHash;
    }


//------------------------------------------------ Data Validation Routines ------------------------------------------------

    function trim(str)
    {
        return str.replace(/(^\s+)|(\s+$)/g, "");
    }

    function ValidateEMail(v)
    {
    	if (v.val != null) v = v.val; // case of object (PAT validation)
    	if (v == "") return true;
		
		var rex = new RegExp("^([-_.!#\\$%&a-z0-9])+@([-_!#\\$%&a-z0-9]+\\.)+[a-z]{2,4}$", "i");
        var arr = v.split(/,|;/);
        var flag = true;
        var str = "";
        for (var i in arr) {
        	str = arr[i];
        	if (str == "")
        		continue;

        	if (!rex.test(str)) {
        		flag = false;
        		break;
        	}
        }
        return flag;
    }

    function ValidateRequired(v)
    {
        if(v.val != null) v = v.val; // case of object (PAT validation)
        var rex = new RegExp("^\\s*$");
        return (v != null && !rex.test(v));
    }

    function ValidateInt(v)
    {
        if(v.val != null) v = v.val; // case of object (PAT validation)
        if(v == "") return true;
        res = new RegExp("^[0-9]+$");
        return (v != null && res.test(v));
    }

    function ValidateFloat(v)
    {
        if(v.val != null) v = v.val; // case of object (PAT validation)
    	res = new RegExp("^[0-9]*\.?[0-9]*$");
		return v=="" || res.test(v);
    }

    function ValidateRequiredDate(v) {
        if (!ValidateRequired(v))
            return false;
        return ValidateDate(v);
    }
    function ValidateDate(v) {
        if (v == null || v == "") return false;
        if(v.val != null) v = v.val; // case of object (PAT validation)
    	res = new RegExp("^[0-9]{2}\/[0-9]{2}\/[0-9]{4}$");
		return v=="" || res.test(v);
    }

//-------------------------------------------------- Set Text Not As HTML -------------------------------------------------------------
function SetText(elem,text)
{
   if(typeof(elem.innerText) != 'undefined')
      elem.innerText = text;
   else
      elem.textContent = text;
}

function txt2js(txt) 
{
    return txt.replace(/\\/g, "\\\\").replace(/\"/g, "\\\"").replace(/\'/g, "\\\'").replace(/\n/g, "\\n").replace(/\r/g, "");
}

function MakeLinks(text, attr) {
    return text.replace(/(<a [^>]*?)?((?:(?:https?|ftp):\/\/)(?:[a-zA-Z0-9\-.])+(?:\.)(?:[a-zA-Z0-9]){2,4}(?::\d{2,5})?(?:[a-zA-Z0-9\/+=%&_.~?\-;]*))(?![^<]*>)/g,
        function($0, $1, $2) {
            var attrStr = "";
            if (typeof attr != 'undefined') {
                for (var i in attr) {
                    attrStr += i + "='" + attr[i] + "'";
                }
            }
            return $1 ? $0 : "<a " + attrStr + " href='" + $2 + "'>" + $2 + "</a>";
        });
}

//-------------------------------------------------- Imput cursor position -------------------------------------------------------------
function getSelectionStart(o) {
	if (o.createTextRange) {
		var r = document.selection.createRange().duplicate()
		r.moveEnd('character', o.value.length)
		if (r.text == '') return o.value.length
		return o.value.lastIndexOf(r.text)
	} else return o.selectionStart
}

function getSelectionEnd(o) {
	if (o.createTextRange) {
		var r = document.selection.createRange().duplicate()
		r.moveStart('character', -o.value.length)
		return r.text.length
	} else return o.selectionEnd
}




//------------------------------------------------ Money Format Routines ------------------------------------------------
function FormatMoney(val)
{
    if(val == null || val == "null") val = "";
    val = "" + val;
    
    if(val.indexOf(".") == -1) val += ".00";
    var p = val.indexOf(".");
    
    var s1 = val.substring(0, p);
    var s2 = val.substring(p + 1);
    
    if(s1.length == 0) s1 = "0";
    if(s2.length == 0) s2 = "00";
    if(s2.length == 1) s2 += "0";
    if(s2.length > 2) s2 = s2.substring(0, 2);
    
    return s1 + "." + s2;
}

function ImpEventMoneyFormatCheck(imp, e)
{
    var p = getSelectionStart(imp);
    if((e.keyCode < 48 || e.keyCode > 57) && e.keyCode != 189 && e.keyCode != 190 && e.keyCode != ESC_KEY_CODE && e.keyCode != ENTER_KEY_CODE && e.keyCode != TAB_KEY_CODE && e.keyCode != LEFT_KEY_CODE && e.keyCode != RIGHT_KEY_CODE && e.keyCode != TOP_KEY_CODE && e.keyCode != BOTTOM_KEY_CODE && e.keyCode != DEL_KEY_CODE && e.keyCode != BSP_KEY_CODE
        && (e.keyCode < 96 || e.keyCode > 105))
    {
        e.cancelBubble = true; 
        return false;
    }
    if((e.keyCode >= 48 && e.keyCode <= 57) || (e.keyCode >= 96 && e.keyCode <= 105) || e.keyCode == 190 || e.keyCode == 189)
    {
        var ch = (e.keyCode == 190 ? "." : e.keyCode == 189 ? "-" : ((e.keyCode >= 96 && e.keyCode <= 105) ? String.fromCharCode(e.keyCode - 48) : String.fromCharCode(e.keyCode)));
        var newval = imp.value.substring(0, p) + ch + imp.value.substring(p);
        if(!/^\-?(\d)*\.?(\d){0,2}$/.test(newval))
        {
            e.cancelBubble = true; 
            return false;
        }
    }
    return true;
}


//------------------------------------------------ Call Stack Routines ------------------------------------------------
function CallStack() 
{
  var callstack = new Array();
  try {i.dont.exist+=0;} catch(e) 
  {
    if (e.stack) //Firefox
    { 
        var lines = e.stack.split("\n");
        for (var i=0, len=lines.length; i<len; i++)
        if (lines[i].match(/^\s*[A-Za-z0-9\-_\$]+\(/))
          callstack.push(lines[i]);
    }
    else if (window.opera && e.message)  //Opera
    {
        var lines = e.message.split("\n");
        for (var i=0, len=lines.length; i<len; i++)
        if (lines[i].match(/^\s*[A-Za-z0-9\-_\$]+\(/))
          callstack.push(lines[i]);
    }
    else //IE and Safari
    { 
        var funct = arguments.callee.caller, cnt = 0;
        while (funct && cnt++ < 20) 
        {
          var fn = funct.toString();
          callstack.push(fn.substring(fn.indexOf("function") + 8, fn.indexOf("(")) || "anonymous");
          funct = funct.caller;
        }
    }
  }
  return callstack;
}


//------------------------------------------------ Request string Params ------------------------------------------------
function getParam(sParamName){
    var Params = location.search.substring(1).split("&");
    var variable = "";
    for (var i = 0; i < Params.length; i++){
        if (Params[i].split("=")[0] == sParamName){
            if (Params[i].split("=").length > 1) variable = Params[i].split("=")[1];
            return variable;
        }
    }
    return "";
}


//------------------------------------------------ String compare ------------------------------------------------
function eq(str1, str2) //compare two strings case unsensative
{
    return("" + str1).toUpperCase() == ("" + str2).toUpperCase();
}


//------------------------------------------------ TinyMceInit ------------------------------------------------
function TinyMceInit(name)
{
/*
    tinyMCE_GZ.init({
	    plugins : '',
	    themes : 'simple,advanced',
	    languages : 'en',
	    disk_cache : true,
	    debug : false
    });
*/
	tinyMCE.init({
		// General options
		mode : "exact",
        elements : name,
		theme : "advanced",
		plugins : "",

		// Theme options
		theme_advanced_buttons1: "cut,copy,paste,|,undo,redo,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,styleselect,formatselect,fontselect,fontsizeselect,|,forecolor,backcolor,|,link,unlink,|,sub,sup,|,bullist,numlist",
		theme_advanced_buttons2 : "",
		theme_advanced_buttons3 : "",
		theme_advanced_toolbar_location : "top",
		theme_advanced_toolbar_align : "left",
		theme_advanced_resizing : false,

		// Example content CSS (should be your site CSS)
		content_css : "css/content.css",
		
		relative_urls : false,
		convert_urls: false,

		// Drop lists for link/image/media/template dialogs
		template_external_list_url : "lists/template_list.js",
		external_link_list_url : "lists/link_list.js",
		external_image_list_url : "lists/image_list.js",
		media_external_list_url : "lists/media_list.js"
	});

    tinyMCE.getByWnd = function TinyMceGetByFrame(wnd)
    {
        for( id in tinyMCE.editors ) 
            if(wnd == tinyMCE.get(id).getWin())
                return tinyMCE.get(id);

        return null;
    }
}


//-------------------------- jQuery DATEPICKER init -------------------------------------

function jCalendar(params) // base, val, onClose, showbtn, opened, format
{
    var p = { openOnFocus: true };
    $.extend(p, params);
    
    var input = p.base.jquery != null ? p.base : eq(p.base.tagName, "INPUT") ? $(p.base) : $("<input type='text' id='" + p.base.id + "CalendarImp' class='CalendarImp' />").appendTo($(p.base))

    var prm = { changeMonth: true, changeYear: true, showOtherMonths: true, selectOtherMonths: true };
    if (p.onClose) $.extend(prm, { onClose: function(dateText, inst) { p.onClose(inst.input[0]); } });

    var showOn = "";
    if (p.showbtn)
    {
        showOn = p.openOnFocus ? 'both' : 'button';
    }
    else
    {
        showOn = p.openOnFocus ? 'focus' : '';
    }
    $.extend(prm, { showOn: showOn });
    if (p.showbtn) $.extend(prm, { buttonImage: "PAT/Images/calendar.gif", buttonImageOnly: true });

    if (p.format) $.extend(prm, { dateFormat: p.format });
    if (p.ampm) $.extend(prm, { ampm: p.ampm });
    else $.extend(prm, { ampm: true });

    if (p.showdate && p.showtime) {
        $(function () { input.datetimepicker(prm); });
        if (p.val) input.datetimepicker("setDate", p.val);
        if (p.opened) input.datetimepicker("show");
    } if (p.showtime) {
        $(function () { input.timepicker(prm); });
        if (p.val) input.timepicker("setDate", p.val);
        if (p.opened) input.timepicker("show");
    } else {
        $(function () { input.datepicker(prm); });
        if (p.val) input.datepicker("setDate", p.val);
        if (p.opened) input.datepicker("show");
    }
    return;
}

function insertRow(elTable) {
    var row = $('<tr>');
    $(elTable).append(row);
    return row[0];
}
