Array.prototype.insertAt = function (what, iIndex)
{
   if (iIndex < this.length) {
      var aAfter = this.splice(iIndex, 100000, what);
      for (var i = 0; i < aAfter.length; i++) {
         this.push(aAfter[i]);
      }
   } else {
      this.push(what);
   }
}

if (!Array.prototype.forEach)
{
  Array.prototype.forEach = function(fun /*, thisp*/)
  {
    var len = this.length;
    if (typeof fun != "function")
      throw new TypeError();

    var thisp = arguments[1];
    for (var i = 0; i < len; i++)
    {
      if (i in this)
        fun.call(thisp, this[i], i, this);
    }
  };
}


// Replaces all instances of the given substring.
String.prototype.replaceAll = function( 
strTarget, // The substring you want to replace
strSubString // The string you want to replace in.
){
var strText = this;
var intIndexOfMatch = strText.indexOf( strTarget );
 

// Keep looping while an instance of the target string
// still exists in the string.
while (intIndexOfMatch != -1){
// Relace out the current instance.
strText = strText.replace( strTarget, strSubString )
 

// Get the index of any next matching substring.
intIndexOfMatch = strText.indexOf( strTarget );
}
 

// Return the updated string with ALL the target strings
// replaced out with the new substring.
return( strText );
}
StringBuilder = function(stringToAdd)
{    
    var h = new Array();
    if (stringToAdd)
    {
        h[0] = stringToAdd;
    } 
    this.append = append;
    this.appendLine = appendLine;
    this.toString = toString;
    this.clear = clear;
    this.length = length;
    this.replace = replace;
    this.remove = remove;
    this.insert = insert;
    
    // Appends the string representation of a specified object to the end of this instance.
    // Parameter["stringToAppend"] - The string to append. 
    function append(stringToAppend)
    {
        h[h.length] = stringToAppend;
    } 

    // Appends the string representation of a specified object to the end of this instance with a carriage return and line feed.
    // Parameter["stringToAppend"] - The string to append. 
    function appendLine(stringToAppend)
    {
        h[h.length] = stringToAppend;
        h[h.length] = "\r\n";
    } 
  
    // Converts a StringBuilder to a String.
    function toString()
    {
        if (!h)
        { 
            return ""; 
        }
        
        if (h.length<2)
        { 
            return (h[0])?h[0]:""; 
        }
        var a = h.join('');
        h = new Array();
        h[0] = a;
        
        return a;
    }

    // Clears the StringBuilder
    function clear()
    {
        h = new Array();
    }

    // Gets the StringBuilder Length
    function length()
    {
        if(!h)
        {
            return 0;
        }
        if (h.length<2)
        { 
            return (h[0]) ? h[0].length : 0; 
        }
        var a = h.join('');
        h = new Array();
        h[0] = a;
        return a.length;
    }

    // Replaces all occurrences of a specified character or string in this instance with another specified character or string.
    // Parameter["oldValue"] - The string to replace. 
    // Parameter["newValue"] - The string that replaces oldValue. 
    // Parameter["caseSensitive"] - True or false for case replace.
    // Return Value - A reference to this instance with all instances of oldValue replaced by newValue.
    function replace(oldValue, newValue, caseSensitive)
    {
        var r = new RegExp(oldValue,(caseSensitive==true)?'g':'gi');
        var b = h.join('').replace(r, newValue);
        h = new Array();
        h[0] = b;
        return this;
    }

    // Removes the specified range of characters from this instance.
    // Parameter["startIndex"] - The position where removal begins. 
    // Parameter["length"] - The number of characters to remove.
    // Return Value - A reference to this instance after the excise operation has occurred.
    function remove(startIndex, length)
    {       
        var s = h.join('');
	    h = new Array();
	
	    if(startIndex<1){h[0]=s.substring(length, s.length);}
	    if(startIndex>s.length){h[0]=s;}
	    else
	    {
	        h[0]=s.substring(0, startIndex);  
	        h[1]=s.substring(startIndex+length, s.length);
	    }
	
        return this;
    }

    // Inserts the string representation of a specified object into this instance at a specified character position.
    // Parameter["index"] - The position at which to insert.
    // Parameter["value"] - The string to insert. 
    // Return Value - A reference to this instance after the insert operation has occurred.
    function insert(index, value)
    {
        var s = h.join('');
	    h = new Array();
	
	    if(index<1)
	    {
	        h[0]=value; 
	        h[1]=s;
	    }
	    if(index>=s.length)
	    {
	        h[0]=s; 
	        h[1]=value;
	    }
	    else
	    {
	        h[0]=s.substring(0, index); 
	        h[1]=value; 
	        h[2]=s.substring(index, s.length);
	    }
	
        return this;
    }
};

var BCS = window.BCS || {};

var __internalCache = Class.create();
__internalCache.prototype = {
    initialize: function()
    {
        this.__data = new Object();
    },
    add: function(key, value)
    {
        this.__data[key] = value;
    },
    remove: function(key)
    {
        this.__data[key] = null;
        delete this.__data[key];
    },
    value: function(key)
    {
        return this.__data[key];
    },
    clear: function()
    {
        for(var key in this.__data)
        {
            this.__data[key] = null;
            delete this.__data[key];
        }
        this.__data = null;
        this.__data = new Object();
    }
}

var __engine = Class.create();
__engine.prototype = {
    initialize: function()
    {
        // If we will put the cache instance in the window.top object, 
        // there will be single cache per page, meaninig in case that there are
        // several frames \ iframes in the same page, all will share the same cache object.
        this.cache = window.top['BCS.Core.GlobalCache'];
        if (!this.cache)
        {
            this.cache = new __internalCache();
            window.top['BCS.Core.GlobalCache'] = this.cache;
        }
    },
    
    addNamespace: function(strNameSpace) 
    {
        if (!strNameSpace || !strNameSpace.length) {
            return null;
        }

        var levels = strNameSpace.split(".");

        var currentNS = BCS;

        // BCS is implied, so it is ignored if it is included
        for (var i=(levels[0] == "BCS") ? 1 : 0; i<levels.length; ++i) {
            currentNS[levels[i]] = currentNS[levels[i]] || {};
            currentNS = currentNS[levels[i]];
        }

        return currentNS;
	}
}

var engine = new __engine()
engine.addNamespace("Core");
BCS.Core.Engine = engine;

/**
 *
 *  Following class manipulates HTTP requests to the server.
 * 
 */
BCS.Core.ConnectionManager = 
{
/**
 *
 *  Parameters:
 *      uri: The URL to address.
 *      options: An object represents a collection of parameters to the request, described as following
 *          onLoading: A method to be invoked whenever the status of the request is 'Loading'.
 *          onUninitialized: A method to be invoked whenever the status of the request is 'Uninitialized'.
 *          onLoaded: A method to be invoked whenever the status of the request is 'Loaded'.
 *          onInteractive: A method to be invoked whenever the status of the request is 'Interactive'.
 *          onException: A method to be invoked whenever there is an exception in the process of the request.
 *          onComplete: A method to be invoked whenever the request has completed.
 *          parameters: A collection of parameters to the request, 
 *              in case the mathod of the request is 'GET' they will be combined to the query string of the request, 
 *              else they will be added as a header to the 'POST' request.
 *          evalScripts: Indicates whether to treat the response text as script and evaluate it.
 *          asynchronous: Indicates whether the request is asynchronouslly executed.
 *          args: A collection of objects used as arguments to the status methods.
 *
 *  Usage sample:
 *    BCS.Core.ConnectionManager.processRequest('http://myApplicationj/default.aspx',         
 *    {
 *        onLoading:function(request)
 *       {
 *           $('indicator').innerHTML = 'Lodaing...';
 *       }, 
 *       onComplete:function(request)
 *       {
 *           $('indicator').innerHTML = o.responseText;
 *       }, 
 *       parameters:'pageId=' + encodeURIComponent('12'), 
 *       evalScripts:false, 
 *       asynchronous:true
 *    });
 */
	processRequest:function(uri, options)
	{
	
        var ajaxRequest =  new Ajax.Request(uri, options);
         
        // !!! Workaround !!! //
        // fix incase the request is synchronous the OnCompleate Event is not fire
        if (!options.asynchronous)
        {
            //we call the Ajax.Request.onStateChange to fire the event.
            ajaxRequest.onStateChange();
        }
    }
}

BCS.Core.Debugger = {
    inspectObject: function(obj)
    {
        var details = "";
        for(key in obj)
        {
            if (typeof obj[key] != 'function')
                details += 'key: ' + key + ' value: ' + obj[key] + '\n';
        }
        alert(details);
    }
}

// extend Event object to support custom Events
if (!window.Event) {
  var Event = new Object();
}

Object.extend(Event, {
  customEvents: [],
  
  registerCustomEvent: function(customEvent)
  {
    Event.customEvents.push(customEvent)
  },
  
  unloadCustomEvents: function()
  {
    for (i=0,len=Event.customEvents.length; i<len; ++i) 
    {
        var customEvent = Event.customEvents[i];
        if (customEvent)
        {
            customEvent.unsubscribeAll();
            delete Event.customEvents[i];
            customEvent = null;
        }
    }
  }
});

if (!BCS.Events)
{
    BCS.Core.Engine.addNamespace('Events');
}

BCS.Events.EventManager = Event;

BCS.Events.CustomEvent = function(eventName, ownerObject) {
    /**
     * The type of event, returned to subscribers when the event fires
     * @type string
     */
    this.eventName = eventName;

    /**
     * The scope the the event will fire from by default.  Defaults to the window 
     * obj
     * @type object
     */
    this.ownerObject = ownerObject || window;

    /**
     * The subscribers to this event
     * @type Subscriber[]
     */
    this.subscribers = [];

    // Register with the event utility for automatic cleanup.  Made optional
    // so that CustomEvent can be used independently of pe.event

    if (BCS.Events.EventManager) { 
        BCS.Events.EventManager.registerCustomEvent(this);
    }
};

BCS.Events.CustomEvent.prototype = {
    /**
     * Subscribes the caller to this event
     * @param {Function} fn       The function to execute
     * @param {Object}   obj      An object to be passed along when the event fires
     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
     *                            scope of the listener
     */
    subscribe: function(fn, obj, bOverride) {
        this.subscribers.push( new BCS.Events.Subscriber(fn, obj, bOverride) );
    },

    /**
     * Unsubscribes the caller from this event
     * @param {Function} fn  The function to execute
     * @param {Object}   obj An object to be passed along when the event fires
     * @return {boolean} True if the subscriber was found and detached.
     */
    unsubscribe: function(fn, obj) {
        var found = false;
        for (var i=0, len=this.subscribers.length; i<len; ++i) {
            var s = this.subscribers[i];
            if (s && s.contains(fn, obj)) {
                this._delete(i);
                found = true;
            }
        }

        return found;
    },

    /**
     * Notifies the subscribers.  The callback functions will be executed
     * from the scope specified when the event was created, and with the following
     * parameters:
     *   <pre>
     *   - The type of event
     *   - All of the arguments fire() was executed with as an array
     *   - The custom object (if any) that was passed into the subscribe() method
     *   </pre>
     *   
     * @param {Array} an arbitrary set of parameters to pass to the handler
     */
    fire: function() {
        for (var i=0, len=this.subscribers.length; i<len; ++i) {
            var s = this.subscribers[i];
            if (s) {
                var scope = (s.override) ? s.eventOwnerObject : this.scope;
                if (s.listenerFunction)
                    s.listenerFunction.call(scope, this.eventName, arguments, s.eventOwnerObject);
            }
        }
    },

    /**
     * Removes all listeners
     */
    unsubscribeAll: function() {
        for (var i=0, len=this.subscribers.length; i<len; ++i) {
            this._delete(i);
        }
    },

    /**
     * @private
     */
    _delete: function(index) {
        var s = this.subscribers[index];
        if (s) {
            delete s.listenerFunction;
            delete s.eventOwnerObject;
        }

        delete this.subscribers[index];
    }
};
/////////////////////////////////////////////////////////////////////

/**
 * @class Stores the subscriber information to be used when the event fires.
 * @param {Function} listenerFunction       The function to execute
 * @param {Object}   eventOwnerObject       An object to be passed along when the event fires
 * @param {boolean}  overrideExecutionscope If true, the obj passed in becomes the execution
 *                            scope of the listener
 * @constructor
 */
BCS.Events.Subscriber = function(listenerFunction, eventOwnerObject, overrideExecutionscope) {
    /**
     * The callback that will be execute when the event fires
     * @type function
     */
    this.listenerFunction = listenerFunction;

    /**
     * An optional custom object that will passed to the callback when
     * the event fires
     * @type object
     */
    this.eventOwnerObject = eventOwnerObject || null;

    /**
     * The default execution scope for the event listener is defined when the
     * event is created (usually the object which contains the event).
     * By setting override to true, the execution scope becomes the custom
     * object passed in by the subscriber
     * @type boolean
     */
    this.override = (overrideExecutionscope);
};


/**
 * Returns true if the fn and obj match this objects properties.
 * Used by the unsubscribe method to match the right subscriber.
 *
 * @param {Function} listenerFunction   the function to execute
 * @param {Object} eventOwnerObject     an object to be passed along when the event fires
 * @return {boolean}                    true if the supplied arguments match this 
 *                   subscriber's signature.
 */
BCS.Events.Subscriber.prototype.contains = function(listenerFunction, eventOwnerObject) {
    return (this.listenerFunction == listenerFunction && this.eventOwnerObject == eventOwnerObject);
};
var cacheCleanupFunction = BCS.Core.Engine.cache.clear.bind(BCS.Core.Engine.cache);

/* prevent memory leaks in IE */
// Release all custom events
Event.observe(window.top, 'unload', Event.unloadCustomEvents, false);
// Clear all cache elements
Event.observe(window.top, 'unload', cacheCleanupFunction, false);

/*------------------------------------- Start of JSON library ---------------------------------------*/
/*
    json.js
    2006-04-28
    This file adds these methods to JavaScript:

    object.toJSONString()
    
    This method produces a JSON text from an object. The
    object must not contain any cyclical references.

    array.toJSONString()
    
    This method produces a JSON text from an array. The
    array must not contain any cyclical references.

    string.parseJSON()
    
    This method parses a JSON text to produce an object or
    array. It will return false if there is an error.
*/

(function () {
    var m = {
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        },
        s = {
            array: function (x) {
                var a = ['['], b, f, i, l = x.length, v;
                for (i = 0; i < l; i += 1) {
                    v = x[i];
                    f = s[typeof v];
                    if (f) {
                        v = f(v);
                        if (typeof v == 'string') {
                            if (b) {
                                a[a.length] = ',';
                            }
                            a[a.length] = v;
                            b = true;
                        }
                    }
                }
                a[a.length] = ']';
                return a.join('');
            },
            'boolean': function (x) {
                return String(x);
            },
            'null': function (x) {
                return "null";
            },
            number: function (x) {
                return isFinite(x) ? String(x) : 'null';
            },
            object: function (x) {
                if (x) {
                    if (x instanceof Array) {
                        return s.array(x);
                    }
                    var a = ['{'], b, f, i, v;
                    for (i in x) {
                        v = x[i];
                        f = s[typeof v];
                        if (f) {
                            v = f(v);
                            if (typeof v == 'string') {
                                if (b) {
                                    a[a.length] = ',';
                                }
                                a.push(s.string(i), ':', v);
                                b = true;
                            }
                        }
                    }
                    a[a.length] = '}';
                    return a.join('');
                }
                return 'null';
            },
            string: function (x) {
                if (/["\\\x00-\x1f]/.test(x)) {
                    x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) {
                        var c = m[b];
                        if (c) {
                            return c;
                        }
                        c = b.charCodeAt();
                        return '\\u00' +
                            Math.floor(c / 16).toString(16) +
                            (c % 16).toString(16);
                    });
                }
                return '"' + x + '"';
            }
        };

    Object.extend(Object, {
    toJSONString: function (objectToJSON) {
        return s.object(objectToJSON);
    }});

    Object.extend(Array, {
        toJSONString : function (arrayToJSON) 
        {
        return s.array(arrayToJSON);
        }
    });
})();

String.prototype.parseJSON = function () {
    try {
        return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
                this.replace(/"(\\.|[^"\\])*"/g, ''))) &&
            eval('(' + this + ')');
    } catch (e) {
        return false;
    }
};
/*------------------------------------- End of JSON library ---------------------------------------*/


/*------------------------------------- Start of Date library ---------------------------------------*/
// The format string consists of the following abbreviations:
// 
// Field        | Full Form          | Short Form
// -------------+--------------------+-----------------------
// Year         | yyyy (4 digits)    | yy (2 digits), y (2 or 4 digits)
// Month        | MM (2 digits)      | M (1 or 2 digits)
// Month        | MMMM (name)        | MMM (abbr.)
// Day of Month | dd (2 digits)      | d (1 or 2 digits)
// Day of Week  | dddd (name)        | ddd (abbr)
// Hour (1-12)  | hh (2 digits)      | h (1 or 2 digits)
// Hour (0-23)  | HH (2 digits)      | H (1 or 2 digits)
// Minute       | mm (2 digits)      | m (1 or 2 digits)
// Second       | ss (2 digits)      | s (1 or 2 digits)
// AM/PM        | tt (2 letters)     | t (1 letter)
//
// NOTE THE DIFFERENCE BETWEEN MM and mm! Month=MM, not mm!
// Examples:
//  "MMM d, y" matches: January 01, 2000
//                      Dec 1, 1900
//                      Nov 20, 00
//  "M/d/yy"   matches: 01/20/00
//                      9/2/00
//  "MMM dd, yyyy hh:mm:ssa" matches: "January 01, 2000 12:30:45AM"
// ------------------------------------------------------------------

var MONTH_NAMES=new Array('January','February','March','April','May','June','July','August','September','October','November','December','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
var DAY_NAMES=new Array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sun','Mon','Tue','Wed','Thu','Fri','Sat');
function LZ(x) {return(x<0||x>9?"":"0")+x}

// ------------------------------------------------------------------
// isDate ( date_string, format_string )
// Returns true if date string matches format of format string and
// is a valid date. Else returns false.
// It is recommended that you trim whitespace around the value before
// passing it to this function, as whitespace is NOT ignored!
// ------------------------------------------------------------------
function isDate(val,format) {
	var date=getDateFromFormat(val,format);
	if (date==0) { return false; }
	return true;
	}

// -------------------------------------------------------------------
// compareDates(date1,date1format,date2,date2format)
//   Compare two date strings to see which is greater.
//   Returns:
//   1 if date1 is greater than date2
//   0 if date2 is greater than date1 of if they are the same
//  -1 if either of the dates is in an invalid format
// -------------------------------------------------------------------
function compareDates(date1,dateformat1,date2,dateformat2) {
	var d1=getDateFromFormat(date1,dateformat1);
	var d2=getDateFromFormat(date2,dateformat2);
	if (d1==0 || d2==0) {
		return -1;
		}
	else if (d1 > d2) {
		return 1;
		}
	return 0;
	}


dateFormatFunctions = {count:0};

// ------------------------------------------------------------------
// formatDate (date_object, format)
// Returns a date in the output format specified.
// The format string uses the same abbreviations as in windows regional settings
// This is a fast replacement for the old formatDate function and it's using a 
// dynamic code generation technique that creates an in-memory function specifically
// for the passed format. This function is cached and used in future invocations.
// I learned this from http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
// ------------------------------------------------------------------
function formatDate(date,format) 
{
    var func = dateFormatFunctions[format];
    if (func == null) 
    {
        createNewDateFormatFunction(format);
        func = dateFormatFunctions[format];
    }
    return func(date);
}

createNewDateFormatFunction = function(format) 
{
    var funcName = "__format" + dateFormatFunctions.count++;
    var code = funcName+ " = function(date){return ";

	var i=0;
	var c="";
	var token="";
    
	while (i < format.length) 
	{
		c=format.charAt(i);
		token="";
		while ((format.charAt(i)==c) && (i < format.length)) 
		{
			token += format.charAt(i++);
		}
		code += getFormatCode(token);
	}
    
    dateFormatFunctions[format] = eval(code.substring(0, code.length - 3) + ";}");
}

function getFormatCode(token) 
{
// Reminder: 
// Year         | yyyy (4 digits)    | yy (2 digits), y (2 or 4 digits)
// Month        | MM (2 digits)      | M (1 or 2 digits)
// Month        | MMMM (name)        | MMM (abbr.)
// Day of Month | dd (2 digits)      | d (1 or 2 digits)
// Day of Week  | dddd (name)        | ddd (abbr)
// Hour (1-12)  | hh (2 digits)      | h (1 or 2 digits)
// Hour (0-23)  | HH (2 digits)      | H (1 or 2 digits)
// Minute       | mm (2 digits)      | m (1 or 2 digits)
// Second       | ss (2 digits)      | s (1 or 2 digits)
// AM/PM        | tt (2 letters)     | t (1 letter)

    switch (token) {
        case "y":
        case "yyyy":
	        return "date.getFullYear() + ";
        case "yy":
            return "(''+date.getFullYear()).substring(2, 4) + ";
        case "M":
            return "date.getMonth()+1 + ";
        case "MM":
            return "LZ(date.getMonth()+1) + ";
        case "MMM":
            return "MONTH_NAMES[date.getMonth()+12] + ";
        case "MMMM":
            return "MONTH_NAMES[date.getMonth()] + ";
        case "d":
            return "date.getDate() + ";
        case "dd":
            return "LZ(date.getDate()) + ";
        case "ddd":
            return "DAY_NAMES[date.getDay()+7] + ";
        case "dddd":
            return "DAY_NAMES[date.getDay()] + ";
        case "h":
            return "(date.getHours() %12) + ";
        case "H":
            return "date.getHours() + ";
        case "hh":
            return "LZ(date.getHours() %12) + ";
        case "HH":
            return "LZ(date.getHours()) + ";
        case "m":
            return "date.getMinutes() + ";
        case "mm":
            return "LZ(date.getMinutes()) + ";
        case "s":
            return "date.getSeconds() + ";
        case "ss":
            return "LZ(date.getSeconds()) + ";
        case "t":
            return "(date.getHours() < 12 ? 'A' : 'P') + ";
        case "tt":
            return "(date.getHours() < 12 ? 'AM' : 'PM') + ";
        default:
            return "'" + escapeCode(token) + "' + ";
    }
}

function escapeCode(string) 
{
    return string.replace(/('|\\)/g, "\\$1");
}

// ------------------------------------------------------------------
// Utility functions for parsing in getDateFromFormat()
// ------------------------------------------------------------------
function _isInteger(val) {
	var digits="1234567890";
	for (var i=0; i < val.length; i++) {
		if (digits.indexOf(val.charAt(i))==-1) { return false; }
		}
	return true;
	}
function _getInt(str,i,minlength,maxlength) {
	for (var x=maxlength; x>=minlength; x--) {
		var token=str.substring(i,i+x);
		if (token.length < minlength) { return null; }
		if (_isInteger(token)) { return token; }
		}
	return null;
	}
	
// ------------------------------------------------------------------
// getDateFromFormat( date_string , format_string )
//
// This function takes a date string and a format string. It matches
// If the date string matches the format string, it returns the 
// getTime() of the date. If it does not match, it returns 0.
// ------------------------------------------------------------------
function getDateFromFormat(val,format) {
	val=val+"";
	format=format+"";
	var i_val=0;
	var i_format=0;
	var c="";
	var token="";
	var token2="";
	var x,y;
	var now=new Date();
	var year=now.getYear();
	var month=now.getMonth()+1;
	var date=1;
	var hh=now.getHours();
	var mm=now.getMinutes();
	var ss=now.getSeconds();
	var ampm="";
	
	while (i_format < format.length) {
		// Get next token from format string
		c=format.charAt(i_format);
		token="";
		while ((format.charAt(i_format)==c) && (i_format < format.length)) {
			token += format.charAt(i_format++);
			}
		// Extract contents of value based on format token
		if (token=="yyyy" || token=="yy" || token=="y") {
			if (token=="yyyy") { x=4;y=4; }
			if (token=="yy")   { x=2;y=2; }
			if (token=="y")    { x=2;y=4; }
			year=_getInt(val,i_val,x,y);
			if (year==null) { return 0; }
			i_val += year.length;
			if (year.length==2) {
				if (year > 70) { year=1900+(year-0); }
				else { year=2000+(year-0); }
				}
			}
		else if (token=="MMM"||token=="MMMM"){
			month=0;
			for (var i=0; i<MONTH_NAMES.length; i++) {
				var month_name=MONTH_NAMES[i];
				if (val.substring(i_val,i_val+month_name.length).toLowerCase()==month_name.toLowerCase()) {
					if (token=="MMMM"||(token=="MMM"&&i>11)) {
						month=i+1;
						if (month>12) { month -= 12; }
						i_val += month_name.length;
						break;
						}
					}
				}
			if ((month < 1)||(month>12)){return 0;}
			}
		else if (token=="dddd"||token=="ddd"){
			for (var i=0; i<DAY_NAMES.length; i++) {
				var day_name=DAY_NAMES[i];
				if (val.substring(i_val,i_val+day_name.length).toLowerCase()==day_name.toLowerCase()) {
					i_val += day_name.length;
					break;
					}
				}
			}
		else if (token=="MM"||token=="M") {
			month=_getInt(val,i_val,token.length,2);
			if(month==null||(month<1)||(month>12)){return 0;}
			i_val+=month.length;}
		else if (token=="dd"||token=="d") {
			date=_getInt(val,i_val,token.length,2);
			if(date==null||(date<1)||(date>31)){return 0;}
			i_val+=date.length;}
		else if (token=="hh"||token=="h") {
			hh=_getInt(val,i_val,token.length,2);
			if(hh==null||(hh<1)||(hh>12)){return 0;}
			i_val+=hh.length;}
		else if (token=="HH"||token=="H") {
			hh=_getInt(val,i_val,token.length,2);
			if(hh==null||(hh<0)||(hh>23)){return 0;}
			i_val+=hh.length;}
		else if (token=="mm"||token=="m") {
			mm=_getInt(val,i_val,token.length,2);
			if(mm==null||(mm<0)||(mm>59)){return 0;}
			i_val+=mm.length;}
		else if (token=="ss"||token=="s") {
			ss=_getInt(val,i_val,token.length,2);
			if(ss==null||(ss<0)||(ss>59)){return 0;}
			i_val+=ss.length;}
		else if (token=="t"||token=="tt") 
		{
		    var subString = val.substring(i_val,i_val+2,token.length).toLowerCase();
		    if (token=="t")
		        subString+="m";
		        
			if (subString=="am") {ampm="AM";}
			else if (subString=="pm") {ampm="PM";}
			else {return 0;}
			i_val+=token.length;
		}
		else {
			if (val.substring(i_val,i_val+token.length)!=token) {return 0;}
			else {i_val+=token.length;}
			}
		}
	// If there are any trailing characters left in the value, it doesn't match
	if (i_val != val.length) { return 0; }
	// Is date valid for month?
	if (month==2) {
		// Check for leap year
		if ( ( (year%4==0)&&(year%100 != 0) ) || (year%400==0) ) { // leap year
			if (date > 29){ return 0; }
			}
		else { if (date > 28) { return 0; } }
		}
	if ((month==4)||(month==6)||(month==9)||(month==11)) {
		if (date > 30) { return 0; }
		}
	// Correct hours value
	if (hh<12 && ampm=="PM") { hh=hh-0+12; }
	else if (hh>11 && ampm=="AM") { hh-=12; }
	var newdate=new Date(year,month-1,date,hh,mm,ss);
	return newdate.getTime();
	}

// ------------------------------------------------------------------
// parseDate( date_string [, prefer_euro_format] )
//
// This function takes a date string and tries to match it to a
// number of possible date formats to get the value. It will try to
// match against the following international formats, in this order:
// y-M-d   MMM d, y   MMM d,y   y-MMM-d   d-MMM-y  MMM d
// M/d/y   M-d-y      M.d.y     MMM-d     M/d      M-d
// d/M/y   d-M-y      d.M.y     d-MMM     d/M      d-M
// A second argument may be passed to instruct the method to search
// for formats like d/M/y (european format) before M/d/y (American).
// Returns a Date object or null if no patterns match.
// ------------------------------------------------------------------
function parseDate(val) {
	var preferEuro=(arguments.length==2)?arguments[1]:false;
	generalFormats=new Array('y-M-d','MMM d, y','MMM d,y','y-MMM-d','d-MMM-y','MMM d');
	monthFirst=new Array('M/d/y','M-d-y','M.d.y','MMM-d','M/d','M-d','M/d/yy','M/d/yyyy');
	dateFirst =new Array('d/M/y','d-M-y','d.M.y','d-MMM','d/M','d-M','d/M/yyyy','d/M/yy');
	var checkList=new Array('generalFormats',preferEuro?'dateFirst':'monthFirst',preferEuro?'monthFirst':'dateFirst');
	var d=null;
	for (var i=0; i<checkList.length; i++) {
		var l=window[checkList[i]];
		for (var j=0; j<l.length; j++) {
			d=getDateFromFormat(val,l[j]);
			if (d!=0) { return new Date(d); }
			}
		}
	return null;
	}

// Namespace that will gather all date format functions	
BCS.Core.Converters = {

    toJSONDate: function(date)
    {
        var jsonDate = null;
        
        if(date)        
            jsonDate = {d:date.getDate(), M:date.getMonth()+1, y:date.getFullYear(),h:date.getHours(), m:date.getMinutes(), s:date.getSeconds()}
       
        return jsonDate;
    },
    
    formattedDate: function(dateValue)
    {
        if(typeof(dateValue) == "object")
        {
              // if there is a 'd' property it means that this is out internal JSON date value.
            if (dateValue.d)
            {
                var date = null;
        
                if(dateValue.h && dateValue.m && dateValue.s)
                    date = new Date(dateValue.y, dateValue.M-1, dateValue.d, dateValue.h, dateValue.m, dateValue.s);
                else
                    date = new Date(dateValue.y, dateValue.M-1, dateValue.d);
                    
                return date;

            }
            else
                return dateValue;
          
        }
    },

    formattedDateStr: function(dateValue)
    {
        if(typeof(dateValue) == "object")
        {
            // if there is a 'd' property it means that this is out internal JSON date value.
            if (dateValue.d)
                return this.formattedDateStrFromJSONObject(dateValue);
            else
                return this.formattedDateStrFromDateObject(dateValue);
        }
        else
        {  
            // we assume that this is a string representation of a date.
            return this.formattedDateStrFromStringObject(dateValue); 
        }

    },
    
    formattedDateStrFromJSONObject: function(jsonObject) 
    { 
        // month value in javascript Date object is a zero based indexed
        var date = null;
        
        if(jsonObject.h && jsonObject.m && jsonObject.s)
            date = new Date(jsonObject.y, jsonObject.M-1, jsonObject.d, jsonObject.h, jsonObject.m, jsonObject.s);
        else
            date = new Date(jsonObject.y, jsonObject.M-1, jsonObject.d);
            
        var string = this.formattedDateStrFromDateObject(date);

        return string;
    },
    
    formattedDateStrFromDateObject: function(date) 
    { 
        if (typeof BCSConverterVars.dateFormat == "undefined")
            BCSConverterVars.dateFormat = "d/M/yyyy";
        
        return formatDate(date, BCSConverterVars.dateFormat);
    },
    
    formattedDateStrFromStringObject: function(date) 
    { 
        if (typeof BCSConverterVars.dateFormat == "undefined")
            BCSConverterVars.dateFormat = "d/M/yyyy";
        
        return getDateFromFormat(date, BCSConverterVars.dateFormat);
    },
 
    dateFormat: function()
    {
        return BCSConverterVars.dateFormat;
    },
    
    timeZone: function()
    {
        return BCSConverterVars.timeZone;
    },
    
    formattedIntegerStr: function(num)
    {
        var nf = new NumberFormat(num);
        
        if ((BCSConverterVars.numberGroupSeparator == "undefined") || (BCSConverterVars.numberGroupSeparator == ""))
            nf.setSeparators(false);
        else
            nf.setSeparators(true, BCSConverterVars.numberGroupSeparator);
            
        if (BCSConverterVars.isNegativeSignOnLeft)        
            nf.setNegativeFormat(LEFT_DASH); // "- n"
        else
            nf.setNegativeFormat(RIGHT_DASH); // "n -"            

        return nf.toFormatted();
    },

    formattedLongStr: function(num)
    {
        return formattedIntegerStr(num);
    },
    
    formattedDoubleStr: function(num)
    {
        var nf = new NumberFormat(num);
        
        if ((BCSConverterVars.numberGroupSeparator == "undefined") || (BCSConverterVars.numberGroupSeparator == ""))
            nf.setSeparators(false, BCSConverterVars.numberGroupSeparator, BCSConverterVars.numberDecimalSeparator);
        else
            nf.setSeparators(true, BCSConverterVars.numberGroupSeparator, BCSConverterVars.numberDecimalSeparator);
            
        if (BCSConverterVars.isNegativeSignOnLeft)        
            nf.setNegativeFormat(LEFT_DASH); // "- n"
        else
            nf.setNegativeFormat(RIGHT_DASH); // "n -"            
            
        nf.setPlaces(BCSConverterVars.numberDecimalDigits, false); // false - to round and not just truncate. In the future we may add user setup for that.

        return nf.toFormatted();
    },

    formattedCurrencyStr: function(num)
    {
        var nf = new NumberFormat(num);
        
        if ((BCSConverterVars.currencyGroupSeparator == "undefined") || (BCSConverterVars.currencyGroupSeparator == ""))
            nf.setSeparators(false, BCSConverterVars.currencyGroupSeparator, BCSConverterVars.currencyDecimalSeparator);
        else
            nf.setSeparators(true, BCSConverterVars.currencyGroupSeparator, BCSConverterVars.currencyDecimalSeparator);
            
        if (BCSConverterVars.isNegativeSignOnLeft)        
        {
            nf.setNegativeFormat(LEFT_DASH); // "- n"
            if (BCSConverterVars.isCurrencySignOnRight())
                nf.setCurrencyPosition(RIGHT_OUTSIDE); // 1 -> "n$"
            else
                nf.setCurrencyPosition(LEFT_OUTSIDE); // 1 -> "n$"
        }
        else
        {
            nf.setNegativeFormat(RIGHT_DASH); // "n -"            
            if (BCSConverterVars.isCurrencySignOnRight())
                nf.setCurrencyPosition(RIGHT_OUTSIDE); // 1 -> "n$"
            else
                nf.setCurrencyPosition(LEFT_OUTSIDE); // 1 -> "n$"
        }

        nf.setPlaces(BCSConverterVars.numberDecimalDigits, false); // false - to round and not just truncate. In the future we may add user setup for that.
        nf.setCurrencyPrefix(BCSConverterVars.currencySymbol);

        return nf.toFormatted();
    }
}
	
/*------------------------------------- End of Date library ---------------------------------------*/
/*********************************************
    purpose : generate random Hex number
    
    n - number of digits for the new number
***********************************************/
function $Hex(n)
{
    var h = ""; 
    for(var i = 0; i < n; i++)
        h += Math.floor(Math.random() * 0xF).toString(0xF);
    
    return h;
}

/*********************************************
    purpose : generate new GUID
    Example: {c02bda093-0041-adb7-9246-48cc4c29aa4}
***********************************************/
function newGuid()
{
	return  "{" + $Hex(9) + "-" + $Hex(4) + "-" + $Hex(4) + "-" + $Hex(4) + "-" + $Hex(11) + "}";
	
}

/***************************************************************
    purpose : generate UniqueId 
              with the number of digits post to the function
    
    n  - number of digits for the new id (default value is 16)
    
    Example: 7132b92a04965693
***************************************************************/
function newUniqueId(n)
{
    n = (typeof(n) == "undefined") ? 16:n;
    return $Hex(n);
}

/***************************************************************
    purpose : add ... at the end of string that is more then X characters 
    X  - number of characters that string will kept.
    
    parameters:
    value - original string value
    charactersLength - number of characters that new string will keep.
    
    Example: "old string example" --> "old string..."
***************************************************************/
String.prototype.getShortString = function (value, charactersLength) 
{
    var stringLength = charactersLength;
    var completionString = "...";
    try 
    {
        if(!stringLength)
            stringLength = 15-completionString.length;
        else
            stringLength = stringLength - completionString.length;
            
        if(value)
        {
            if(value.length > stringLength)
                value = value.substring(0, stringLength) + completionString;
        }
    } 
    catch (e) 
    {
        return value;
    }
    
    return value;
};

function fixApostropheString(value)
{
    var fixString = value.split("'").join("\'");

    return fixString;
} 


BCS.Core.ObjectIdentifier = Class.create();
BCS.Core.ObjectIdentifier.prototype = {
    initialize: function(classId, objectId, organizationId)
    {
        if(typeof(classId) == "string")
        {
            var identifiers = classId.split(".");
            this.classId = parseInt(identifiers[0]);
            this.objectId = parseInt(identifiers[1]);
            
            if(identifiers.length > 1)
                this.organizationId = parseInt(classId.split(".")[2]);
            else
                this.organizationId = "";
        }
        else
        {
            this.classId = parseInt(classId);
            this.objectId = parseInt(objectId);
            
            if(organizationId)
                this.organizationId = parseInt(organizationId);
            else
                this.organizationId = parseInt(organizationId);
        }
    },
    
    isEmpty: function()
    {
        return ((this.classId == 0) && (this.objectId == 0));
    },
    
    isTemp: function()
    {
        return (this.objectId<0);
    },
    
    toString: function()
    {
        var result = isNaN(this.classId)?'0':this.classId.toString();
        result += ".";
        result += isNaN(this.objectId)?'0':this.objectId.toString();
        result += isNaN(this.organizationId)?'':'.' + this.organizationId.toString();
        return result;
    }
}

BCS.Core.ObjectIdentifierCollection = Class.create();
BCS.Core.ObjectIdentifierCollection.prototype = {

    initialize: function()
    {
        this.count = 0;
    },
    
    addObject: function(objectIdentifier)
    {
        this[this.count] = objectIdentifier;
        this.count++;
    },
    getObject: function(index)
    {
        return this[index];
    }
}


BCS.Core.ClassAliasConstants = Class.create();
BCS.Core.ClassAliasConstants.prototype = {

    initialize: function()
    {
        this.USERS = "U";
        this.HUMAN_RECOURCES = "HR";
        this.ORGANIZATION_USER_SERVING = "OUS";
    }
}

BCS.Core.FieldNameConstants = Class.create();
BCS.Core.FieldNameConstants.prototype = {

    initialize: function()
    {
        this.NAME = "Name";
        this.STD_PROJECT = "STD_PROJECT";
        this.STD_FIRST_NAME = "STD_FIRST_NAME";
        this.STD_LAST_NAME = "STD_LAST_NAME";
        this.STD_IDENTIFIER = "STD_IDENTIFIER";
        this.STD_REF1 = "STD_REF1";
        this.STD_REF2 = "STD_REF2";
        this.STD_ROLE = "STD_ROLE";
        this.STD_SHORT_DISP_NAME = "STD_SHORT_DISP_NAME";
        this.STD_DEPENDENCIES_COUNTER = "STD_LC_STD_REF1_44";
        this.STD_NOTES_COUNTER = "STD_RC_81_SOURCE_OBJECT";
        this.STD_DISCUSSIONS_COUNTER = "STD_RC_82_SOURCE_OBJECT";
        this.STD_DOCUMENTS_COUNTER = "STD_LC_STD_REF1_52";
        this.STD_SOURCE_OBJECT = "STD_SOURCE_OBJECT";
        this.STD_ON_TRACK = "STD_ON_TRACK";
        this.OnTrackStatusChangedImage = "OnTrackStatusChangedImage";

        this.STD_PLANNED_DURATION = "STD_PLANNED_DURATION";
        this.STD_PLANNED_START_DATE = "STD_PLANNED_START_DATE";
        this.STD_PLANNED_END_DATE = "STD_PLANNED_END_DATE";
        this.ActualRemainingEfforts = "Remaining effort";
        this.ActualSpentEfforts = "Actual effort";
        this.CompletingPercentage = "Completing percentage";        
    }
}

//
// IMPORTANT: Must be synchronized with GridType enum in GenericLogic.Web.UI.Enums.cs!
//
BCS.Core.GridTypes = {
        
        NONE                                    : 0,
        TASKS_ACTIVE                            : 1,
        TASKS_UPCOMING                          : 2,
        TASKS_OVERDUE                           : 3,
        TASKS_ONRISK                            : 4,
        PROJECTS_UMR_MANAGED                    : 5,
        // Indicates that the grid should display Roadmap objects related to a specific object.
        ROADMAPS_PER_OBJECT                     : 6,
        // Indicates that the grid should display milestone objects related to a specific object.
        MILESTONES                              : 7,
        // Indicates that the grid should display WBS objects related to a specific object.
        WORK_BREAKDOWN_STRUCTURE                : 8,
        REFERENCE_TO_OBJECT                     : 9,
        // Zoom PopUps
        DELIVERABLE_ZOOM_POPUP                  : 10,
        DOCUMENTS_ZOOM_POPUP                    : 11,
        IMPACTING_COMPLETION_IMPACT_ZOOM_POPUP  : 12,
        RESOURCES_ZOOM_POPUP                    : 13,
        TASKS_ONHOLD                            : 14,
        ROADMAP_SELECTOR                        : 15,
        IMPACTED_COMPLETION_IMPACT_ZOOM_POPUP   : 16,
        DEPENDENCIES_ZOOM_POPUP                 : 17,
        TASKS_CURRENT                           : 18,
        USERS                                   : 19,
        TEMPLATES                               : 20,
        AVAILABLE_HUMAN_RESOURCES               : 21,
        ASSIGNED_RESOURCES                      : 22,
        ORGANIZATIONS                           : 23,
        TASKS_ALL                               : 24,
        PROJECTS_UMR_ACTIVE                     : 25,
        PROJECTS_UMR_DRAFT                      : 26,
        ALERTS                                  : 27,
        ALERTS_PER_OBJECT                       : 28,
        HIGHLIGHTS                              : 29,
        NOTES_PER_OBJECT                        : 30,
        SEARCH_RES                              : 31,
        WORK_BREAKDOWN_STRUCTURE_DEPENDENCY     : 32,
        WORK_BREAKDOWN_STRUCTURE_FILTERED       : 33,
        COMPLETNESS_DEPENDENCY                  : 34,
        TASKS_SUB_SYSTEM                        : 35,
        PROJECTS_SUB_SYSTEM                     : 36,
        TEMPLATES_SUB_SYSTEM                    : 37,
        RESOURCES_SUB_SYSTEM                    : 38,
        WBS_DEPENDENCY_WITHOUT_TASKS            : 39,
        ORGANIZATION_LICENSES_VIEW              : 40
}


//
// IMPORTANT: Must be synchronized with PredefinedFilterTypes enum in GenericLogic.Web.UI.Enums.cs!
//
BCS.Core.PredefinedFilterTypes = {
        NONE        : 0,
        ALL         : 1,
        ACTIVE      : 2,
        CANCELLED   : 3,
        DRAFT       : 4,
        COMPLETED   : 5
}

BCS.Core.UrlParametersConstants = {
    PIVOT_OBJECT: "(PO)",
    METHOD_NAME: "MN",
    METHOD_NAME_REFERENCE_TO_OBJECT_DISPLAY_VALUE: "R2ODV",
    METHOD_NAME_COMMENTS_DISPLAY_VALUE: "COM",
    METHOD_NAME_THUMBNAIL_VIEW: "View",
    METHOD_NAME_PROJUMR: "ProjUMR",
    METHOD_NAME_TASKS: "Tasks",
    METHOD_NAME_ROADMAPPEROBJECT: "RPO",
    METHOD_NAME_MILESTONES: "MST",
    METHOD_NAME_WORK_BREAKDOWN_STRUCTURE: "WBS",
    METHOD_NAME_REFERENCE_TO_OBJECT: "R2O",
    METHOD_NAME_ROADMAP_SELECTOR: "RSL",
    METHOD_NAME_ZOOM_POPUP: "ZP",
    METHOD_NAME_USERS: "USR",
    METHOD_NAME_TEMPLATES: "TPL",
    METHOD_NAME_AVAILABLE_HUMAN_RESOURCES: "AHR",
    METHOD_NAME_ASSIGNED_HUMAN_RESOURCSE: "ASHR",
    METHOD_NAME_NOTIFICATION: "NTF",
    METHOD_NAME_NOTES: "NT",
    METHOD_NAME_FULL_TEXT_SEARCH: "FTS",
    METHOD_NAME_COMPLETNESS_DEPENDENCY: "CD",
    MTHOD_NAME_PROJECTS_SUBSYSTEM: "PSS",
    MTHOD_NAME_ORGANIZATION_LICENSES: "OLV",
    METHOD_NAME_WBS_WITHOUT_TASKS: "WWT",  
    CONTROL_NAME_THUMBNAIL_VIEW: "TV", 
    CONTROL_NAME: "CN",
    CONTROL_NAME_GRID: "GR",
    CONTROL_SUMMARY_COUNTERS: "SC",
    CONTROL_NAME_PROFILE_CARD: "PC",
    CONTROL_NAME_ROADMAP: "RMP",
    CONTROL_NAME_FILTER_LIST: "FL",
    CONTROL_NAME_CLIENT_CONTROLLER: "CCC",
    
    FILTER_TYPE : "FLT", 
    GRID_TYPE: "GRT",
    RELATION_TYPE: "RT",
    OBJECTIDENTIFIER: "OID",
    REFERENCED_OBJECTIDENTIFIER: "ROID",
    PIVOT_OBJECTIDENTIFIER: "POID",
    ROOT_OBJECT_IDENTIFIER: "ROID",
    CLASS_ID: "CID",
    LEADING_OBJECT: "LO",
    SEARCH_OBJECT_TYPE: "SOT",
    SEARCH_TEXT: "ST",
    PREDEFINED_FILTER_TYPE: "PDFT",
    
    GRID_INCLUDE_HEADERS: "IH",
    GRID_OPERATION: "GOP",
    GRID_OPERATION_EXPAND: "E",
    GRID_PRE_FILTER_NAME: "PFN",
    GRID_PRE_FILTER_ALL: "PF_ALL",
    GRID_PRE_FILTER_SELECTED_OBJECT: "PF_SO",
    GRID_CUSTOM_FILTER: "CFLT",
    
    SAVE_DATA: "SD",
    NAVIGATE_URL: "navigateUrl",
    FIELD_NAME: "FN",
    SORT_COUNT: "SRC",
    SORT_ITEM: "SI",
    MAIN_OBJECT: "MO",
    CSETS: "CSETS",
    CLIENT_ID: "CLSID",
    AUTO_SAVE: "AS",
    ACCESS_TYPE: "AT",
    COMMENT_TYPE: "CT",
    ALERTS_RESOLVE_OBJECT_ID: "RSOID",
    ALERTS_DISMISS_OBJECT_ID: "DSOID",
    WORK_BREAKDOWN_STRUCTURE_FILTERED: "WBSFLT",
    ACTION_TYPE: "ACT",
    ACTION_ASSIGN_RESOURCE: "ARS",
    ACTION_NEW_DOCUMENT: "NDC"
}

BCS.Core.NLSConstants = {
    Ok: "BCS.Core.Controls.Keys.Ok",
    Cancel: "BCS.Core.Controls.Keys.Cancel",
    Add: "BCS.Core.Controls.Keys.Add",
    Delete: "BCS.Core.Controls.Keys.Delete",
    Edit: "BCS.Core.Controls.Keys.Edit"
}

BCS.Core.ProjectFilterConstants = {
    MANAGED: 0,
    DRAFT: 1,
    ACTIVE: 2
}

BCS.Core.AvailableResourcesFilterConstants = {
    ORGANIZATION_POOL: 0,
    PROJECT_POOL: 1
}

BCS.Core.ColorConstants = {
    MANUAL_UPDATED_COLOR: "blue"
}

/*
 *  The idea is that you run actsAsAspect() on any JavaScript object, 
 *  and then your object receives 3 extra methods: 
 *  before(), after(), and around(). 
 *  You then use those methods to setup the callbacks you need.
 *  By: http://beppu.lbox.org/articles/2006/09/06/actsasaspect
 */
function actsAsAspect(object) {
  object.yield = null;
  object.rv    = { };
  object.before  = function(method, f) 
  {
    var original = eval("this." + method);
    this[method] = function() 
    {
        this.rv[method] = f.apply(this, arguments);
        if (this.rv[method] == false)
            return false;
        return original.apply(this, arguments);
    };
  };
  object.after   = function(method, f) 
  {
    var original = eval("this." + method);
    this[method] = function() 
    {
      this.rv[method] = original.apply(this, arguments);
      return f.apply(this, arguments);
    }
  };
  object.around  = function(method, f) 
  {
    var original = eval("this." + method);
    this[method] = function() {
      this.yield = original;
      return f.apply(this, arguments);
    }
  };
}

// USER ACTIVITY
BCS.Core.UserActivityActions = {
    // MAIN NAVIGATION BUTTONS
    NAVIGATION_HOME: "Home navigation",
    NAVIGATION_PROJECTS: "Projects navigation",
    NAVIGATION_TASKS: "Tasks navigation",
    NAVIGATION_RESOURCES: "Resources navigation",
    NAVIGATION_TEPMLATES: "Templates navigation",
    NAVIGATION_ALERTS: "Alerts navigation",
    NAVIGATION_HIGHLIGHTS: "Highlights navigation",
    NAVIGATION_ADMIN: "Admin navigation",
    NAVIGATION_LOGOUT: "Logout navigation",
    NAVIGATION_INVITE: "Invite a friend",
    // END OF MAIN NAVIGATION BUTTONS
    ONLOAD_NAVIGATION: "Onload Navigation",
    NAVIGATION: "Navigation",
    INSERT_ROWS: "Insert rows",
    EDITING_FIELD: "Editing the field",
    SELECT_NEAR_ROADMAP: "Select near roadmap",
    UNDO_ALL: "Undo all",
    GRID_SAVE: "Grid Save",
    ADD_CHILD: "Add Child",
    GRID_ADD_NEW_OBJECT: "Grid add new object",
    PROFILE_CARD_EDIT: "Profile card edit",
    PROFILE_CARD_DELETE: "Profile card delete",
    ENLARGE_PROJECT: "Enlarge project",
    ADD_FROM_DASHBOARD: "dashboard/add_window",
    
    CHANGED_FILTER_TO: "changed_filter_type_to_",
    CHANGED_FILTER: "change_filter",
    CHANGED_SEARCH_FILTER: "changed_search_filter",
    OPEN_FILTER_MENU: "open_filter_menu",
    
    HELP_BUTTON: "help_button",
    SAVE_BUTTON: "save",
    CANCEL_BUTTON: "cancel",
    CLOSE_BUTTON: "close_window",
    SEARCH_BUTTON: "search",
    GOTO_BUTTON: "go_to",
    
    // Changed by Ori for google analytics
    ADD_CHILD_TASK: "add_child_task",
    ADD_CHILD_MILESTONE: "add_child_milestone",
    ADD_CHILD_PROJECT: "add_child_project",
    INSERT_TASK: "insert_task",
    INSERT_MILESTONE: "insert_milestone",
    GRID_DELETE_OBJECTS: "delete_selected_objects",
    GRID_MOVE_RIGHT: "move_right_button",
    GRID_MOVE_LEFT: "move_left_button",
    GRID_INSERT: "insert_button",
    GRID_COPY: "copy",
    GRID_PASTE: "paste",
    GRID_SHOW: "show",
    GRID_ACTIVATE: "activate",
    GRID_MARK_AS_DRAFT: "mark_as_draft",
    GRID_ON_HOLD: "put_on_hold",
    GRID_MARK_COMPLETE: "mark_complete",
    OPEN_DOCUMENT: "open_document",
    COMMAND_NOT_FOUND: "command_not_found",
    ADD_NEW_PROJECT: "add_new_project",
    ADD_NEW_USER: "add_new_user",
    MY_PROFILE: "my_profile",
    SELECT_ROADMAP_NEXT_MILESTONE: "roadmap/next_milestone",
    SELECT_ROADMAP_PREV_MILESTONE: "roadmap/previous_milestone",
    SELECT_ROADMAP_LAST_MILESTONE: "roadmap/last_milestone",
    SELECT_ROADMAP_FIRST_MILESTONE: "roadmap/first_milestone",
    SELECT_ROADMAP: "Roadmap",
    CLOSE_ROADMAP: "Close roadmap window",
    SAVE_AS_TEMPLATE: "Save as template",
    MENU_CLICKED: "Menu clicked",
    ACTION_RESOURCE: "Action resource usage",
    
    PROJECT_THUMB: "select_project_thumbnail",

    // PROPERTY CARD UPPER MENU
    
    VIEW_PROPERTY: "view_property",
        VIEW_ALL_PROPERTIES: "view_all_properties",
        BURN_DOWN_CHART: "burn_down_chart",
        
    VIEW_ATTACHMENTS: "View Documents",
        ADD_ATTACHMENT: "Add Document",
        
    VIEW_RESOURCES: "View Resources",
        ASSIGN_RESOURCE: "Assign Resource",
    
    VIEW_DEPENDENCIES: "View Dependencies",
        ADD_SCHEDULED_DEPENDENCY: "Add Scheduled Dependency",
        ADD_COMPLETENESS_DEPENDENCY: "Add Completeness Dependency",
        DEPENDENCY_FILTER_SCHEDULED: "Change dependency filter to Scheduled dependency",
        DEPENDENCY_FILTER_COMPLETENESS: "Change dependency filter to Completeness dependency",
        
    VIEW_ALERTS: "View Alerts",
     
    VIEW_NOTES: "view_notes",
        ADD_NOTE: "add_note",
        OPEN_DISCUSSION: "open_discussions",
        
    
    // END OF PROPERTY CARD UPPER MENU
    
    VIEW_PROJECT_PROPERTY: "view_project_property_in_property_card",
    VIEW_MILESTONE_PROPERTY: "view_milestone_property_in_property_card",
    VIEW_TASK_PROPERTY: "view_task_property_in_property_card"
    
}
BCS.Core.UserActivityPages = {
    HOME_PAGE: "home",
    PROPERTY_CARD: "propery_card/properties",
    DEPENDENCY_PROPERTY_CARD: "propery_card/dependencies",
    NOTES_PROPERTY_CARD: "propery_card/notes",
    ADVNACED_PROPERTY_CARD: "propery_card/advanced_property_card",
    SIMPLE_PROPERTY_CARD: "propery_card/simple_property_card",
    ADVNACED_PROJECT_CARD: "propery_card/advanced_project",
    ADVANCED_TASK_CARD: "propery_card/advanced_task",
    ADVANCED_MILESTONE_CARD: "propery_card/advanced_milestone",
    MAIN_NAVIGATION: "home/main_nav",
    PROJECTS_BOX: "home/projects",
    LAUNCH_PAD: "home/launch_pad",
    TASKS_BOX: "home/tasks",
    ALERTS_BOX: "home/alerts",
    HIGHLIGHTS_BOX: "home/highlights",
    GRID_PAGE: "grid"
}
BCS.Core.UserActivityMethods = {
    LEFT_MOUSE: 'left_mouse',
    ROAD_MAP_BUTTONS: "rm_toolbar_buttons",
    DROP_DOWN_MENU: 'drop_down_menu',
    MASTER_GRID_TOOLBAR_CLICK: 'master_grid_toolbar_click',
    GRID_TOOLBAR: "upper_grid_toolbar_menu",
    TOP_PROPERTY_CARD: "upper_property_card_menu"
}

BCS.Core.UserActivityAction = Class.create();
BCS.Core.UserActivityAction.prototype={
    initialize: function(page, action, method, session)
    {
//        this.page = page;
//        this.action = action;
//        this.method = method;
        // Add session ID for user only if sent to function exists
        this.value = "/app/" + ((session) ? session + "/" : "" + page + "/" + action + "/" + method + ".html");
    }
}

BCS.Core.UserActivity = Class.create();
BCS.Core.UserActivity.prototype = {

    initialize: function() {},

    addUserActivity: function(url, action, method, session)
    {
        var actionActivity = new BCS.Core.UserActivityAction(url, action, method, session);
        if (Debugger.isDebug())
            Debugger.log('actionActivity', actionActivity.value);      
        
        //Google Analytics
        //alert(actionActivity.value);
        //urchinTracker(actionActivity.value);
    }
}

var userActivityManager = new BCS.Core.UserActivity();

function getNavigationClickForUA(page , action)
{
    //alert(page+" "+action);
    userActivityManager.addUserActivity(page, action, BCS.Core.UserActivityMethods.LEFT_MOUSE);
}

function initUserActivity()
{ 
    var UATags = document.getElementsByTagName("UA");
    if (!UATags.length)
        return;
    var i = 0;          
    while (UATags[i] && UATags[i].nextSibling)
    {
        if (UATags[i].nextSibling.tagName == "A")
        {
            var activityAction = UATags[i].nextSibling.getAttribute("ua_action");
            var activityPage = UATags[i].nextSibling.getAttribute("ua_page");
            var changeFunc = new Function("", "getNavigationClickForUA('" + activityPage + "','" + activityAction + "');");
            Event.observe(UATags[i].nextSibling, 'click', changeFunc, false);
        }
        i++;
    }
}

Event.observe(window, 'load', initUserActivity, false);















BCS.Core.Navigation = Class.create();
BCS.Core.Navigation.prototype = {

    initialize: function()
    {
    },
    
    navigate: function(eventArg)
    {
        // This code will handle grid on profile card page.
        if(typeof(beforeUnload) == "function")
        {
            return beforeUnload(eventArg);
        }
        return true;
    }
}




var navigationManager = new BCS.Core.Navigation();
function navigateToUrl(eventArg)
{
    return navigationManager.navigate(eventArg);
}

/************ START handling grid confirmation ***************/
BCS.Core.GridCollection = {
    CACHE_KEY: "_gcck",
    GRIDS: new Array()
}

// In this method we check whether one or more of the presented grids has some unsaved changes.
// In case there are some unsaved changes in the grids, we will display a confirmation dialog.
// In case the user have chosen not to continue with his operation, the operation will be canceled.
function beforeUnload(eventArg, doNotAddUserActivity)
{
    if (needToDisplayconfirmationMessageForAll() == true)
    {
        if (displayConfirmationMessage() == true)
        {
            if(!doNotAddUserActivity)
            {
                userActivityManager.addUserActivity(document.location.href, BCS.Core.UserActivityActions.NAVIGATION, BCS.Core.UserActivityMethods.LEFT_MOUSE);
            }
        }
        else
        {
            if(eventArg)
            {
                Event.stop(eventArg);
            }
            return false;
        }
    }
    else
    {
        if(!doNotAddUserActivity)
        {
            userActivityManager.addUserActivity(document.location.href, BCS.Core.UserActivityActions.NAVIGATION, BCS.Core.UserActivityMethods.LEFT_MOUSE);
        }
    }    
    return true;
} 

function needToDisplayconfirmationMessageForAll()
{
    var gridCollection = BCS.Core.Engine.cache.value(BCS.Core.GridCollection.CACHE_KEY);
    
    if(gridCollection)
    {
        // Loop thru all grid in cache.
        for(i=0;i<gridCollection.length;i++)
        {
			if(needToDisplayconfirmationMessage(gridCollection[i]))
			    return true;
		}
    }
    
    return false;
}

function needToDisplayconfirmationMessage(grid)
{
    return grid.isEditStarted() || grid.isEditorOpen();
}

function displayConfirmationMessage()
{
    return confirm("There are unsaved changes. Would you like to exit without saving your work?");
}
/***************** END handling grid confirmation **************/

function Trim(STRING){
STRING = LTrim(STRING);
return RTrim(STRING);
}

function RTrim(STRING){
while(STRING.charAt((STRING.length -1))==" "){
STRING = STRING.substring(0,STRING.length-1);
}
return STRING;
}


function LTrim(STRING){
while(STRING.charAt(0)==" "){
STRING = STRING.replace(STRING.charAt(0),"");
}
return STRING;
}

BCS.Core.Exception = Class.create();
BCS.Core.Exception.prototype={
    initialize: function(controlName, message)
    {
        this.controlName = controlName || "";
        this.message = message|| "";
      
    }
}    


////////////////////////////  start of BrowserHelper ///////////////////////////////////////////////////////////////////
BCS.Core.Engine.addNamespace("Web");

BCS.Web.BrowserHelper = {

    getRunTimeValue: function(element,attributeName) 
    { 
       if(document.defaultView && document.defaultView.getComputedStyle) 
       { 
             return document.defaultView.getComputedStyle(element,null).getPropertyValue(attributeName); 
       }
       else if(typeof(document.all)!="undefined" && element.currentStyle) 
       { 
             return element.currentStyle[attributeName]; 
       } 
       else return 0; 
    },

    getPosition: function(elem)
    {
        return this.getElementPosition(elem,document);
    },
    
    getElementPosition: function(elem,doc)
    {
	    var pos = { left:0, top:0 };
	    
	    doc = (typeof(doc) == "undefined") ? document:doc;
    	
	    while (elem)
	    {
	        pos.left += elem.offsetLeft - elem.scrollLeft; 
		    pos.top  += elem.offsetTop  - elem.scrollTop;
    		
		    if (this.getRunTimeValue(elem,"position") == 'absolute')
			    break;
    			
		    elem = elem.offsetParent;
	    }
    	
	    pos.left -= (typeof(document.all) != "undefined") ? doc.body.scrollLeft:doc.documentElement.scrollLeft;
	    pos.top -= (typeof(document.all) != "undefined") ? doc.body.scrollTop:doc.documentElement.scrollTop;
	    
	    return pos;
    },
    
    // this function gets the cookie, if it exists
    getCookie: function( name ) 
    {
        var start = document.cookie.indexOf( name + "=" );
        var len = start + name.length + 1;
        if ( ( !start ) && ( name != document.cookie.substring( 0, name.length ) ) )
        {
            return null;
        }
        if ( start == -1 ) 
            return null;
        var end = document.cookie.indexOf( ";", len );
        if ( end == -1 ) 
            end = document.cookie.length;
        return unescape( document.cookie.substring( len, end ) );
    },
    
    setCookie: function(name, value)
    {
	    var date = new Date();
	    date.setTime(date.getTime()+(1*24*60*60*1000));
	    document.cookie = name+"="+ value + "; expires=" +date.toGMTString() + "; path=/";
    }
}

var Debugger = {
    start: function()
    {
        BCS.Web.BrowserHelper.setCookie('debugger', 'true');
    },
    stop: function()
    {
        BCS.Web.BrowserHelper.setCookie('debugger', 'false');
        Debugger._getMainDiv().hide();
    },
    isDebug: function()
    {
        return BCS.Web.BrowserHelper.getCookie('debugger') == 'true';
    },
    log: function(category, title, message)
    {
        Debugger._addMessage(category, title, message);
        Debugger._getMainDiv().show();
    },
    _getMainDiv: function()
    {
        var win = window.top;
        if (!win.$)
            win.$ = $;
        var debugWin = win.$('debuggerWindow');
        if (!debugWin)
        {
            debugWin = win.document.createElement('div');
            debugWin.id = 'debuggerWindow';
            var debugWinContainer = win.document.createElement('div');
            debugWinContainer.appendChild(win.document.createTextNode('Clarizen console'));
            debugWinContainer.appendChild(debugWin);
            win.document.forms[0].appendChild(debugWinContainer);
            debugWinContainer.style.position = 'absolute';
            debugWinContainer.style.overflow = 'hidden';
            Debugger.setStyle(debugWinContainer);
            Debugger.setStyle(debugWin);
            debugWin.style.width = '94%';
            debugWin.style.height = '78%';
            debugWin.style.display = '';
            debugWin.style.backgroundColor = 'black';
            debugWin.style.color = '#eee';
        }
        new Draggable(debugWin.parentNode);
        return debugWin.parentNode;
    },
    setStyle: function(ele)
    {
        ele.style.display = 'block';
        ele.style.overflow = 'auto';
        ele.style.backgroundColor = '#eee';
        ele.style.width = '90%';
        ele.style.height = '25%';
        ele.style.posLeft = '0px';
        ele.style.posTop = '0px';
        ele.style.zIndex = '99999';
        ele.style.border = '1px solid #ccc';
        ele.style.margin = '5px';
        ele.style.padding= '5px';
    },
    _addMessage: function(title, message)
    {
        var win = Debugger._getMainDiv();
        var line = win.document.createElement('div');
        var num = win.document.createElement('span');
        var time = win.document.createElement('span');
        var tit = win.document.createElement('span');
        var mes = win.document.createElement('span');
        var count = win.firstChild.nextSibling.hasChildNodes()?(win.firstChild.nextSibling.childNodes.length+1):1;
        if (typeof(message)!= 'string')
        {
            var a = win.document.createElement('a');
            Element.setText(a, message);
            a.onclick = function()
            {
                if (window.debugService)
                    window.debugService.inspect("asdasd",message);
                else
                    alert('Script Debugging is not enabled');
            }
            mes.appendChild(a);
        }
        else
            Element.setText(mes, message);
        Element.setText(num, count);
        Element.setText(time, (new Date()).toLocaleString());
        Element.setText(tit, title);
        tit.style.paddingRight = '5px';
        tit.style.paddingLeft = '5px';
        num.style.borderRight= '1px solid #ccc';
        time.style.borderRight= '1px solid #ccc';
        tit.style.borderRight= '1px solid #ccc';
        tit.style.width = '40%';
        line.appendChild(num);
        line.appendChild(time);
        line.appendChild(tit);
        line.appendChild(mes);
        if (win.firstChild.nextSibling.hasChildNodes())
            win.firstChild.nextSibling.insertBefore(line, win.firstChild.nextSibling.firstChild);
        else
            win.firstChild.nextSibling.appendChild(line);
        return win;
    }
}
