Object.extend = function(dest, source, replace) 
{
	for(prop in source) 
	{
		if(replace == false && dest[prop] != null) continue;
		dest[prop] = source[prop];
	}
	return dest;
}

Object.extend(Object, 
{
    contains: function(obj, property)
    {
        for (var prop in obj)
            if(property == prop)
                return true;
    
        return false;
    },
    
    addAsProperty: function(dest, o, name, replace) 
    {  
	    if(replace == false && dest[name] != null) return;
		dest[name] = o;
    }
});

Object.extend(Object.prototype, 
{
    clone: function(deep) 
    {
        var c = new this.constructor();
        for (var prop in this)
        {
            if (!deep)
              c[prop] = this[prop];
            else if (typeof this[prop] == 'object')
              c[prop] = this[prop].clone(deep);
            else
              c[prop] = this[prop];
        }
        return c;
    }
    
}, true);

Object.extend(Function.prototype, {

	apply: function(o, a) 
	{
		var r, x = "__fapply";
		if(typeof o != "object") 
		    o = {};
		
		o[x] = this;
		
		var s = "r = o." + x + "(";
		
		for(var i = 0; i < a.length; i++) 
		{
			if(i > 0) s += ",";
			s += "a[" + i + "]";
		}
		s += ");";
		eval(s);
		delete o[x];
		return r;
	},
	
	getArguments: function() 
	{
		var args = [];
		for(var i = 0; i < this.arguments.length; i++)
			args.push(this.arguments[i]);
		return args;
	},
	
	bind: function(o) 
	{
		if(!Function.__objs) {
			Function.__objs = [];
			Function.__funcs = [];
		}

		var objId = o.__oid;
		if(!objId)
			Function.__objs[objId = o.__oid = Function.__objs.length] = o;

		var me = this;
		var funcId = me.__fid;
		if(!funcId)
			Function.__funcs[funcId = me.__fid = Function.__funcs.length] = me;

		if(!o.__closures)
			o.__closures = [];

		var closure = o.__closures[funcId];
		if(closure)
			return closure;

		o = null;
		me = null;

		return Function.__objs[objId].__closures[funcId] = function() {
			return Function.__funcs[funcId].apply(Function.__objs[objId], arguments);
		};
	}
}, false);

document.getElementViaParent = function(id, parentElement) 
{
    parentElement = $(parentElement);
    
    if(! parentElement)
        return $(id);
    
    var children = parentElement.getElementsByTagName('*');
    
    for(var i = 0; i < children.length; i++)
    {
        var child = children[i];
        if (child.id.match(new RegExp("(^|\\s)" + id + "(\\s|$)")))
            return $(child);
	}
	
	return null;
};

var $_$ = function(id, parent) 
{
  return document.getElementViaParent(id, parent);
}

Object.extend(Array.prototype, 
{
	addRange: function(items) 
	{
		if(items.length > 0)
			for(var i = 0; i < items.length; i++)
				this.push(items[i]);
	}
}, false);

Object.extend(String.prototype, 
{
	trimLeft: function() 
	{
		return this.replace(/^\s*/, "");
	},
	
	trimRight: function() 
	{
		return this.replace(/\s*$/, "");
	},
	
	trim: function() 
	{
		return this.trimRight().trimLeft();
	},
	
	endsWith: function(s) 
	{
		if(this.length == 0 || this.length < s.length) return false;
		return (this.substr(this.length - s.length) == s);
	},
	
	startsWith: function(s) {
		if(this.length == 0 || this.length < s.length) return false;
		return (this.substr(0, s.length) == s);
	},

    left: function(len)
    {
        if(len <= 0)
            return "";
        else if (len > this.length)
            return this;
        else
            return this.substring(0, len);
    },
  
    right: function(len)
    {
        if(len <= 0)
            return "";
        else if (len > this.length)
            return this;
        else
           return this.substring(this.length, this.length - len);
    },
    
    isNullOrEmpty: function(trim) 
	{
	    var s = this;
	    if(trim)
		    s = s.trim();
		        
        if(s.length != 0)
		    return true;
		
		return false;
	},
	
	zf: function(totalDigits) 

    { 
        var n = this;
        var pd = ''; 
        var len = n.length;
        if (totalDigits > len) 
        { 
            for (i = 0; i < (totalDigits - len); i++) 
            { 
                pd += '0'; 
            } 
        } 
        return pd + n; 
    },
    
    unescapeHTML2: function() 
    {
         var conversionMap = {
            "amp" : "&",
            "lt" : "<",
            "gt" : ">",
            "apos" : "'",
            "quot" : '"'
        };

        var s = this;
        return s.replace(/&(\w+);/g, function(m, g) { return conversionMap[g] || m; });

    /*
        var div = document.createElement('div');
        if(stripTags)
        {
            div.innerHTML = this.stripTags();
            return div.childNodes[0] ? 
                (div.childNodes.length > 1 ? 
                $A(div.childNodes).inject('', function(memo, node) { return memo + node.nodeValue }) :
                div.childNodes[0].nodeValue) 
            : '';
        }
        else
        {
            div.innerHTML = this;
            return div.textContent;
        }*/
    }
 
}, false);

Object.extend(String, 
{
	format: function(s) 
	{
		for(var i = 1; i < arguments.length; i++)
			s = s.replace("{" + (i -1) + "}", arguments[i]);
		return s;
	},
	
	isNullOrEmpty: function(s, trim) 
	{
		if(s != null)
		{
		    if(trim)
		        s = s.trim();
		        
		    if(s.length != 0)
			    return true;
		}
			    
		return false;
	}
}, false);

Object.extend(Number.prototype, 
{
    zf: function(totalDigits) 
    { 
        return this.toString().zf(totalDigits);
    } 
 }, false);

Object.extend(Date.prototype, 
{
    _monthNames: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
    _dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
    
    addMilliseconds: function(milliseconds)
    {
        return this.add("ms", milliseconds);
    },

    addHours: function(hours)
    {
        return this.add("hour", hours);
    },
    
    addDays: function(days)
    {
        return this.add("day", days);
    },
    
    addMonths: function(months)
    {
        return this.add("month", months);
    },
    
    addYears: function(years)
    {
        return this.add("year", years);
    },
    
    add: function (datepart, number)
    {
      var dt = new Date(this);
      
      if(isNaN(number)) return dt;
      if (!datepart || number == 0) return dt;
      
      switch (datepart.toLowerCase())
      {
        case "ms":
        case "milliseconds":
            dt.setMilliseconds(dt.getMilliseconds() + number);
            break;
        case "s":
        case "seconds":
            dt.setSeconds(dt.getSeconds() + number);
            break;
        case "mi":
        case "n":
        case "minutes":
            dt.setMinutes(dt.getMinutes() + number);
            break;
        case "h":
        case "hour":
            dt.setHours(dt.getHours() + number);
            break;
        case "d":
        case "wd":
        case "day":
        case "weekday":
            dt.setDate(dt.getDate() + number);
            break;
        case "mo":
        case "month":
            dt.setMonth(dt.getMonth() + number);
            break;
        case "y":
        case "yyyy":
        case "year":
            dt.setFullYear(dt.getFullYear() + number);
            break;
      }
      return dt;
    },
    
    formatDate: function(format)
    {
        if (! this.valueOf())
            return '&nbsp;';

        var dt = this;
        return format.replace(/(yyyy|yy|y|MMMM|MMM|MM|M|dddd|ddd|dd|d|HH|H|hh|h|mm|m|ss|s|t)/gi,
            function($1)
            {
                switch ($1)
                {
                  case 'yyyy': return dt.getFullYear();
                  case 'yy':   return (dt.getFullYear()%100).zf(2);
                  case 'y':    return (dt.getFullYear()%100);
                  case 'MMMM': return dt._monthNames[dt.getMonth()];
                  case 'MMM':  return dt._monthNames[dt.getMonth()].substr(0, 3);
                  case 'MM':   return (dt.getMonth() + 1).zf(2);
                  case 'M':    return (dt.getMonth() + 1);
                  case 'dddd': return dt._dayNames[dt.getDay()];
                  case 'ddd':  return dt._dayNames[dt.getDay()].substr(0, 3);
                  case 'dd':   return dt.getDate().zf(2);
                  case 'd':	   return dt.getDate();
                  case 'HH':   return dt.getHours().zf(2);
                  case 'H':    return dt.getHours();
                  case 'hh':   return ((h = dt.getHours() % 12) ? h : 12).zf(2);
                  case 'h':    return ((h = dt.getHours() % 12) ? h : 12);
                  case 'mm':   return dt.getMinutes().zf(2);
                  case 'm':    return dt.getMinutes();
                  case 'ss':   return dt.getSeconds().zf(2);
                  case 's':    return dt.getSeconds();
                  case 't':	   return dt.getHours() < 12 ? 'A.M.' : 'P.M.';
                }
            }
        );
    }
}, false);

Object.extend(Element.Methods, 
{
    addClassNames: function(element, classNames) 
    {
        if (!(element = $(element))) return;
        var values = $A(arguments).without(element);
        for (var i = 0, len = values.length; i < len; i++) 
            element.addClassName(values[i]);
        return element;   
    },
    
    removeClassNames: function(element, classNames) 
    {
        if (!(element = $(element))) return;
        var values = $A(arguments).without(element);
        for (var i = 0, len = values.length; i < len; i++) 
            element.removeClassName(values[i]);
        return element;    
    }
});

Object.extend(Form, {

    serializeToCollection: function(form)
    {
        var col = new Data.NameValueCollection();
        var elements = Form.getElements($(form));
        var queryComponents = new Array();

        for (var i = 0; i < elements.length; i++)
        {
            var queryComponent = this.serializeFormElement2(elements[i]);
            if (queryComponent)
                queryComponents = queryComponents.concat(queryComponent);
        }
        
        for(var i = 0; i < queryComponents.length; i++)
        {
            if (i % 2 == 0)
			    col.add(queryComponents[i], queryComponents[i + 1]);
	    }
	    
        return col;
    },
   
    serializeFormElement: function(element) 
    {
        element = $(element);
        var method = element.tagName.toLowerCase();
        var parameter = Form.Element.CustomSerializers[method](element);

        if (parameter) 
        {
            var key = parameter[0];
            if (key.length == 0) return;

            if (parameter[1].constructor != Array)
                parameter[1] = [parameter[1]];

            return parameter[1].map(function(value) 
            {
                return key + '=' + value;
            }).join('&');
        }
    },
    
    serializeFormElement2: function(element) 
    {
        element = $(element);
        var method = element.tagName.toLowerCase();
        var parameter = Form.Element.CustomSerializers[method](element);

        if (parameter) 
        {
            var key = parameter[0];
            if (key.length == 0) return;

            if (parameter[1].constructor != Array)
                parameter[1] = [parameter[1]];

            return [key, parameter[1].map(function(value) 
            {
                return value;
            }).join('&')];
        }
    }


});

Form.Element.CustomSerializers = {
  input: function(element) {
    switch (element.type.toLowerCase()) {
      case 'checkbox':
      case 'radio':
        return Form.Element.CustomSerializers.inputSelector(element);
      default:
        return Form.Element.CustomSerializers.textarea(element);
    }
    return false;
  },

  inputSelector: function(element) {
    if (element.checked)
      return [element.name, element.value];
  },

  textarea: function(element) {
    return [element.name, element.value];
  },

  select: function(element) {
    return Form.Element.CustomSerializers[element.type == 'select-one' ?
      'selectOne' : 'selectMany'](element);
  },

  selectOne: function(element) {
    var value = '', opt, index = element.selectedIndex;
    if (index >= 0) {
      opt = Element.extend(element.options[index]);
      // Uses the new potential extension if hasAttribute isn't native.
      value = opt.hasAttribute('value') ? opt.value : opt.text;
    }
    return [element.name, value];
  },

  selectMany: function(element) {
    var value = [];
    for (var i = 0; i < element.length; i++) {
      var opt = Element.extend(element.options[i]);
      if (opt.selected)
        // Uses the new potential extension if hasAttribute isn't native.
        value.push(opt.hasAttribute('value') ? opt.value : opt.text);
    }
    return [element.name, value];
  }
}


function openDialog(URL, width, height)
{
	return window.open(URL, null, 'toolbar=no,scrollbars=yes,location=no,statusbar=no,menubar=no,resizable=yes,height=' + height + ',width=' + width + ',top=0,left=0');
}

var Debug = {};

Object.extend(Debug, {

    inspect: function(o)
    {
        if(typeof console != "undefined")
            console.log(Object.inspect(o));
    },
    
    log: function(o)
    {
        if(typeof console != "undefined")
            console.log(o);
    }

});

var Cookies = {};

Object.extend(Cookies, {

    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, expires, path, domain, secure ) 
    {
	    var today = new Date();
	    today.setTime( today.getTime() );
	    if ( expires ) {
		    expires = expires * 1000 * 60 * 60 * 24;
	    }
	    var expires_date = new Date( today.getTime() + (expires) );
	    document.cookie = name + '=' + escape( value ) +
		    ( ( expires ) ? '; expires=' + expires_date.toGMTString() : '' ) + '; path=/';//expires.toGMTString()
		    //( ( path ) ? ';path=' + path : '' )  +
		    //( ( domain ) ? ';domain=' + domain : '' ) +
		    //( ( secure ) ? ';secure' : '' );
    },

    deleteCookie: function( name, path, domain ) 
    {
	    if ( getCookie( name ) ) document.cookie = name + '=' +
			    ( ( path ) ? ';path=' + path : '') +
			    ( ( domain ) ? ';domain=' + domain : '' ) +
			    ';expires=Thu, 01-Jan-1970 00:00:01 GMT';
    }
/*
    setCookie: function(name, value, daysToExpire) 
    { 
        var expire = '';  
        if (daysToExpire) 
        {   
            var d = new Date();
            d.setTime(d.getTime() + (86400000 * parseFloat(daysToExpire)));
            expire = '; expires=' + d.toGMTString(); 
        }  
        return (document.cookie = escape(name) + '=' + escape(value || '') + expire + ';path=/');
    }, 
    
    getCookie: function(name) 
    { 
        var cookie = document.cookie.match(new RegExp('(^|;)\s*' + escape(name) + '=([^;\s]*)'));  
        return (cookie ? unescape(cookie[2]) : null); 
    },
    
    deleteCookie: function(name) 
    {
        var cookie = Cookies.getCookie(name) || true;
        Cookies.setCookie(name, '', -1);
        return cookie;
    }
    */
});

var StringBuilder = Class.create();

Object.extend(StringBuilder.prototype, 
{
    buffer: null,
    bufferLength: 0,
    
	/*** subclass constructor ***/
	initialize: function(value) 
	{
	    this.buffer = new Array();
	    this.bufferLength = 0;

	    if(value != null)
		    this.append(value);
	},
	
	append: function(value)
    {
	    if(value == null)
		    return;
    	
	    this.bufferLength += value.length;
	    this.buffer.push(value);
    },

    remove: function(start, length)
    {
	    this.buffer.splice(start, length);
    },

    removeLast: function()
    {
	    this.buffer.pop();
    },

    clear: function()
    {
	    this.buffer = new Array("");
	    this.bufferLength = 0;
    },

    length: function()
    {
	    return this.bufferLength;
    },

    toString: function()
    {
	    return this.buffer.join("");
    },
    
    toStr: function()
    {
	    return this.buffer.join("");
    }

});



var MsgBox = {}
Object.extend(MsgBox, {
   
    loading: function()
    {
        var html = "<div style='text-align:center;z-index:9999;height:100px;'><img style='z-index:9999;' src='../common/images/indicator_saving.gif' /></div>";
        
        Dialog.info(html, {windowParameters: {className: "loading", showEffect: Element.show } });	
    },
    
    info: function(text, title)
    {
        title = title || "";
        var html = "<div align='center' style='margin:1em;'>" + text  + "</div>";
        
        Dialog.info(html, {windowParameters: {className: "BlueDialog", showEffect: Element.show, title:title, width:300} });	
    },
    
    alert: function(text, title)
    {
        if(title == null || title == "")
            title = "Alert";
            
        this.show({ text:text, title:title, showCancel:false, okButton:{ clickHandler:"Dialog.closeInfo();" } });
    },
 
    confirm: function(text, title, okClickHandler, okLabel)
    {
        if(title == null || title == "")
            title = "Confirm";
        if(okLabel == null || okLabel == "")
            okLabel = "OK";
        this.show({ text:text, title:title, okButton:{ className:"button", label:okLabel, clickHandler:okClickHandler }, cancelButton:{ clickHandler:"Dialog.closeInfo();" } });
    },
    
    show: function(options)
    {
        options = Object.extend({
            text: "",
            showOK: true,
            showCancel: true,
            okButton: null,
            cancelButton: null,
            //okButton: { className:"button", label:"OK", clickHandler:null },
            //cancelButton: Object.extend({ className:"button", label:"Cancel", clickHandler:"Dialog.closeInfo();" }, options.cancelButton || {}),
            height: null,
            width: 300,
            className: "BlueDialog",
            title: ""
        }, options || {});

        options.okButton = Object.extend({ className:"button", label:"OK", clickHandler:null }, options.okButton || {});
        options.cancelButton = Object.extend({ className:"button", label:"Cancel", clickHandler:"Dialog.closeInfo();" }, options.cancelButton || {});
        
        var html = "<div align='center' style='margin:1em;'>" + options.text  + "<br clear='all'/><br clear='all'/>";
        if(options.showOK)
            html += "<input type=button class='" + options.okButton.className + "' value='" + options.okButton.label + "' onclick=\"" + options.okButton.clickHandler + "\"/>";
        if(options.showCancel)
            html += "<input type=button class='" + options.cancelButton.className + "' value='" + options.cancelButton.label + "' onclick=\"" + options.cancelButton.clickHandler + "\"/>";
        html += "</div>";
        
        Dialog.info(html, {windowParameters: { showEffect: Element.show, title:options.title, className:options.className, width:options.width} });	
    }
    
});

if(typeof addEvent == "undefined")
	addEvent = function(o, evType, f, capture) {
		if(o == null) return false;
		if(o.addEventListener) {
			o.addEventListener(evType, f, capture);
			return true;
		} else if (o.attachEvent) {
			var r = o.attachEvent("on" + evType, f);
			return r;
		} else {
			try{ o["on" + evType] = f; }catch(e){}
		}
	};
	
if(typeof removeEvent == "undefined")
	removeEvent = function(o, evType, f, capture) {
		if(o == null) return false;
		if(o.removeEventListener) {
			o.removeEventListener(evType, f, capture);
			return true;
		} else if (o.detachEvent) {
			o.detachEvent("on" + evType, f);
		} else {
			try{ o["on" + evType] = function(){}; }catch(e){}
		}
	};

Object.extend(Event, {
  _domReady : function() {
    if (arguments.callee.done) return;
    arguments.callee.done = true;

    if (this._timer)  clearInterval(this._timer);
    
    this._readyCallbacks.each(function(f) { f() });
    this._readyCallbacks = null;
},
  onDOMReady : function(f) {
    if (!this._readyCallbacks) {
      var domReady = this._domReady.bind(this);
      
      if (document.addEventListener)
        document.addEventListener("DOMContentLoaded", domReady, false);
        
        /*@cc_on @*/
        /*@if (@_win32)
            document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
            document.getElementById("__ie_onload").onreadystatechange = function() {
                if (this.readyState == "complete") domReady(); 
            };
        /*@end @*/
        
        if (/WebKit/i.test(navigator.userAgent)) { 
          this._timer = setInterval(function() {
            if (/loaded|complete/.test(document.readyState)) domReady(); 
          }, 10);
        }
        
        Event.observe(window, 'load', domReady);
        Event._readyCallbacks =  [];
    }
    Event._readyCallbacks.push(f);
  }
});

/** Set a tr to .selected */
function updateRowSelection(checkbox){
    var tr = checkbox.parentNode.parentNode;
    if(checkbox.checked)
        Element.addClassName(tr,'selected');
    else
        Element.removeClassName(tr,'selected');
        
}

/** Highlight a row on hover */
function hoverRow(tr, on){
    if(tr.className == '') tr.className = 'off';
    if(on){
        if(Element.hasClassName(tr,'off')){
            Element.removeClassName(tr,'off');
            Element.addClassName(tr,'on');
        }
    } else {
        if(Element.hasClassName(tr,'on')){
            Element.removeClassName(tr,'on');
            Element.addClassName(tr,'off');
        }
    }
}


var XsltControls = {};

Object.extend(XsltControls, {
    
    createCalendar: function(id, outputElement, toggleElement, options)
    {
        if(Globals.getValue("PageLoaded") == true)
		{
	        var cal = new XERO.widget.Calendar(id, outputElement, toggleElement, options);
		}
		else
		{				
		    addEvent(window, "load", function() {  
		        var cal = new XERO.widget.Calendar(id, outputElement, toggleElement, options);
            });
        }
    },

    createAutoCompleter: function(id, ajaxFunctionToCall)
    {
         new Autocompleter.Local(id, 
            "div" + id + "Completer", 
            ["ZZ"], 
            {
                selector: function(instance) { return XsltControls.autoCompleteSelector(ajaxFunctionToCall, instance); }, 
                frequency: 0 
            });
    },

    autoCompleteSelector: function(ajaxFunctionToCall, instance)
    {
        var results = [];
		eval("var res = " + ajaxFunctionToCall + "(instance.getToken());");
		res.value.each(function(value, index)
		{
			results[index] = "<li>" + value + "</li>";
		});
		return "<ul>" + results.join("") + "</ul>";		
    }
});

var SessionChecker = {};

Object.extend(SessionChecker, {
    
    tickerPos: 0,
    logout: true,
	
    initialise: function()
    {
        setTimeout('SessionChecker.checkSessionTimeout()', 1860000);
    },
    
    checkSessionTimeout: function()
    {
        Ajax.HasSessionTimedOut(SessionChecker.hasSessionTimedOutCallback);
    },
    
    hasSessionTimedOutCallback: function(res)
    {
        if(res.value)
        {
            SessionChecker.showLoginDialog();
        }
    },
    
    showLoginDialog: function()
    {
        var loginHtml = '<div style="padding:1em;" id="timedOutLoginContainer">' +
            '<div class="error" id="timedOutLoginError" style="display:none;clear:both;margin-top:0px;">' +
            '</div>' +
            '<div>' +
                '<label for="timedOutUserName" style="text-align:left;" class="LabelBlue">Email</label>' +
                '<input type="text" tabIndex="900" id="timedOutUserName" style="width:160px;" /><br/>' +
                '<label for="timedOutPassword" style="text-align:left;" class="LabelBlue">Password</label>' +
                '<input type="password" tabIndex="900" id="timedOutPassword" style="width:160px;" /><br/>' +
            '</div>' +
            '<div style="margin-top:5px;">' +
                '<input id="timedOutLoginButton" class="button" tabIndex="900" type="button" onclick="SessionChecker.login();" value="Log In"/>' +
                '<input class="button" tabIndex="900" type="button" onclick="location.href=\'../Login/Login.aspx?logout=true\';" value="Log Out"/>' + 
            '</div>' +
        '</div>';
    
        Dialog.info(loginHtml, {windowParameters: {className:"BlueDialog", width:400, title: "Your session has timed out!"}});
                            
        $('timedOutLoginContainer').observe('keypress', 
            function(e)
            {
                if(e.keyCode == Event.KEY_RETURN)
                    $('timedOutLoginButton').click();
            }
       );
    },
    
    login: function()
	{   
        Ajax.Login($F("timedOutUserName"), $F("timedOutPassword"), 
            function(res)
            {
                if(! res.error)
                {
                    Windows.closeAll();
                    setTimeout('SessionChecker.checkSessionTimeout()', 1860000);
                } 
                else 
                {
                    Windows.closeAll();
                    location.href = "../Login/Login.aspx?logout=true";
                }
            }
        );
	}
});

addEvent(window, "load", function() {  SessionChecker.initialise(); });
addEvent(window, "load", function() {  Globals.add("PageLoaded", true); });

