/******************************************************************************
* VERSION: 2.1 
*
* risews.js implements helper stereotypes for calling RISE SOAP web services
*
* risews.js depends on prototype.js (Prototype JavaScript framework)
* risews.js includes a modified version of ws.js
* risews.js includes Steven Levithan's code Date Format 1.2.2
*
* WHY INCLUDE ws.js IN THIS FILE?
* First and foremost, ws.js is free to use and does an excellent job!
* ws.js was originally written by James M Snell, IBM Corporation, and relied 
* on prototype.js version 1.3. That version of prototype.js handled the 
* request header Content-type in a way that prevented Mozilla/Firefox from 
* calling Windows web services (error 415). Later versions of prototype.js has 
* fixed this short-coming and allows the caller to specify the content type 
* (and encoding) explicitly. However, due to a change in the implementation of 
* the method "extend", in prototype.js version 1.4, ws.js isn't compatible 
* with any version of prototype.js that solves the content type problem.  
* Furthermore, Apple Safari and Google Chrome browsers contains an error in 
* XMLHttpRequest.send rendering an XML document without namespaces. This 
* version of ws.js contains code that explicitly serializes the XML envelope
* for these browsers. Finally, we've changed the namespace reference for xsi
* from www.w3.org/2000/10 to www.w3.org/2001 to allow passing null values to
* Windows web services.
*
* To avoid this version of ws.js from being confused with the original one 
* we've included it here.
* 
* Ola Hellgren, RISE to Bloome Software AB
*/

/******************************************************************************/
var WS = {
  Version :   '0.1',
  Author :    'James M Snell',
  Copyright : 'Copyright 2005, IBM Corporation',
  Revision :  '2005-09-29T18:00:00-7:00'
};

/******************************************************************************/
Function.prototype.bind2 = function(object) {
  var __method = this;
  return function() {
    return __method.apply(object, arguments);
  }
}

/******************************************************************************/
Array.prototype.each = function(method) {
  for (var n = 0; n < this.length; n++) {
    try {
      method(this[n]);
    } catch(e) {}
  }
}

/******************************************************************************/
var XML = {
  createDocumentQName : function(qname) {
    return XML.createDocument(qname.namespace,qname.value_of());
  },
  createDocument : function(namespace,nodename) {
    return Try.these(
      function() {
        var doc = new ActiveXObject('Msxml2.XMLDOM');
        var root = XML.createElementNS(doc, nodename, namespace);
        doc.documentElement = root;
        return doc;
      },
      function() {
        var doc = new ActiveXObject('Microsoft.XMLDOM')
        var root = XML.createElementNS(doc, nodename, namespace);
        doc.documentElement = root;
        return doc;
      },
      function() { 
        return document.implementation.createDocument(
        namespace,
        nodename,
        null)
      }
    ) || false;
  },
  createElementNS : function(document,nodename,namespace) {      
   	var el = Try.these(
      function() {
        var el = null;
        if (namespace) {
          el = document.createNode(1,nodename,namespace);
        } else {
          el = document.createNode(1,nodename,"");
        }
        return el;
     },
     function() {
       var el = null;
       if (namespace) {
         el = document.createElementNS(namespace,nodename);
       } else {
         el = document.createElement(nodename);
       }
       return el;
       }
     ) || false;
   return el;
  },
  createElementQName : function(document,qname) {
    return XML.createElementNS(document,qname.value_of(),qname.namespace);
  },
  createAttributeNS : function(document,nodename,namespace,value) {
    var attr = Try.these(
      function() { return document.createNode(2,nodename,namespace)},
      function() { return document.createAttributeNS(namespace,nodename)}
    ) || false;
    attr.nodeValue = value;
    return attr;
  },
  createAttributeQName : function(document,qname,value) {
    return XML.createAttributeNS(document,qname.value_of(),qname.namespace,value);
  },
  createAttribute : function(document,nodename,value) {
    var attr = Try.these(
      function() { return document.createNode(2, nodename)},
      function() { return document.createAttribute(nodename)}
    ) || false;
    attr.nodeValue = value;
    return attr;
  },
  createText : function(document,value) {
    var node = Try.these(
      function() { return document.createTextNode(value) }
    ) || false;
    return node;
  },
  createCDATA : function(document,value) {
    var node = Try.these(
      function() { return document.createCDATASection(value) }
    ) || false;
    return node;
  },
  getElementsByQName : function(element, qname) {
    var nl = null;
    if(!element.getElementsByTagNameNS) {
      nl = new Array();
      var nodes = element.getElementsByTagName(qname.value_of());
      for (var n = 0; n < nodes.length; n++) {
        if (nodes[n].namespaceURI == qname.namespace) {
          nl.push(nodes[n]);
        }
      }
    } else {
      nl = element.getElementsByTagNameNS(qname.namespace,qname.localpart);
    }
    return nl;
  }
}
    
/******************************************************************************/
WS.QName = Class.create();
WS.QName.fromElement = function() {
  var qname =
    new WS.QName(
      (this.baseName)?this.baseName:this.localName,
      this.namespaceURI,
      this.prefix
    );
  return qname;
}
WS.QName.prototype = {
  initialize : function(localpart) {
    this.localpart = localpart;
    if (arguments[1]) this.namespace = arguments[1];
    if (arguments[2]) this.prefix = arguments[2];
  },
  to_string : function() {
    return (this.namespace) ? 
      '{' + this.namespace + '}' + this.localpart : 
        this.localpart;
  },
  value_of : function() {
    return ((this.prefix)?this.prefix + ':':'') + this.localpart;
  },
  equals : function(obj) {
    return (obj instanceof WS.QName &&
            obj.localpart == this.localpart &&
            obj.namespace == this.namespace);
  }
};

/******************************************************************************/
var SOAP = {
  Version : '1.1',
  URI : 'http://schemas.xmlsoap.org/soap/envelope/',
  XSI : 'http://www.w3.org/2001/XMLSchema-instance',
  /*'http://www.w3.org/2000/10/XMLSchema-instance',*/
  XSIQNAME : new WS.QName(
    'type',
    'http://www.w3.org/2001/XMLSchema-instance','xsi'),
    /*'http://www.w3.org/2000/10/XMLSchema-instance','xsi'),*/
  XSINIL : new WS.QName(
    'nil',
    'http://www.w3.org/2001/XMLSchema-instance', 'xsi'),
    /*'http://www.w3.org/2000/10/XMLSchema-instance','xsi'),*/
  SOAPENCODING : 'http://schemas.xmlsoap.org/soap/encoding/',
  NOENCODING : null,
  ENCODINGSTYLE : new WS.QName(
    'encodingStyle',
    'http://schemas.xmlsoap.org/soap/envelope/','s')
};

/******************************************************************************/
SOAP.Element = Class.create();
SOAP.Element.prototype = {
  initialize : function() {
    if (arguments[0]) this.initialize_internal(arguments[0]);
  },
  initialize_internal : function(element) {
    this.element = element;
  },
  asElement : function() {
    return this.element;
  },
  qname : function() {
    return WS.QName.fromElement.bind2(this.element)();
  },
  set_encoding_style : function(style) {
    this.set_attribute(SOAP.ENCODINGSTYLE,style);
  },
  set_attribute : function(qname, value) {
    var attr = XML.createAttributeQName(
      this.element.ownerDocument, 
      qname, 
      value);
    if (this.element.setAttributeNodeNS) {
      this.element.setAttributeNodeNS(attr);
    } else {
      this.element.setAttributeNode(attr);
    }
  },
  get_attribute : function(qname) {
    var val = null;
    for (var n = 0; n < this.element.attributes.length; n++) {
      var attr = this.element.attributes[n];
      if (qname.equals(WS.QName.fromElement.bind2(attr)())) {
        val = attr.nodeValue;
        break;
      }
    }
    return val;
  },
  has_attribute : function(qname) {
    var val = null;
    for (var n = 0; n < this.element.attributes.length; n++) {
      var attr = this.element.attributes[n];
      if (qname.equals(WS.QName.fromElement.bind2(attr)())) {
        val = true;
        break;
      }
    }
    return val;
  },
  set_value : function(value, usecdata) {
    var doc = this.element.ownerDocument;
    if (usecdata) {
      this.element.appendChild(XML.createCDATA(doc,value));
    } else {
      this.element.appendChild(XML.createText(doc,value));
    }
  },
  get_value : function() {
    return this.element.firstChild.nodeValue;
  },
  create_child : function(qname) {
    var doc = this.element.ownerDocument;
    var el = XML.createElementQName(doc, qname);
    this.element.appendChild(el);
    var ret = new SOAP.Element(el);
    return ret;
  },
  get_children : function(qname) {
    var nodes = XML.getElementsByQName(this.element,qname);
    var childnodes = new Array();
    for (var n = 0; n < nodes.length; n++) {
      childnodes.push(new SOAP.Element(nodes[n]));
    }
    return childnodes;
  },
  get_all_children : function() {
    var nodes = this.element.childNodes;
    var childnodes = new Array();
    for (var n = 0; n < nodes.length; n++) {
      if (nodes[n].nodeType == 1) {
        childnodes.push(new SOAP.Element(nodes[n]));
      }
    }
    return childnodes;
  },
  get_binder : function() {
    return WS.Binder.get_for_qname(this.qname());
  }
};



/******************************************************************************/
SOAP.Envelope = Class.create();
SOAP.Envelope.QNAME = new WS.QName('Envelope',SOAP.URI);
SOAP.Envelope.prototype = Object.extend(new SOAP.Element(), {
  initialize : function() {
    var element = arguments[0];
    if (!element) {
      var document = 
        XML.createDocumentQName(SOAP.Envelope.QNAME);
      element = document.documentElement;
    }
    this.initialize_internal(element);
  },
  set_value : null,
  get_value : null,
  create_child : null,
  create_header : function() {
    if (!this.has_header()) {
      var doc = this.element.ownerDocument;
      var el = XML.createElementQName(doc, SOAP.Header.QNAME);
      if (this.element.firstChild) {
        this.element.insertBefore(el, this.element.firstChild);
      } else {
        this.element.appendChild(el);
      }
      var ret = new SOAP.Header(el);
      return ret;
    } else {
      return this.get_header();
    }
  },
  get_header : function() {
    var val = null;
    for (var n = 0; n < this.element.childNodes.length; n++) {
      if (this.element.childNodes[n].nodeType == 1) {
        var el = this.element.childNodes[n];
        if (SOAP.Header.QNAME.equals(WS.QName.fromElement.bind2(el)())) {
          val = new SOAP.Header(el);
          break;
        }
      }
    }
    return val;
  },
  has_header : function() {
    var val = null;
    for (var n = 0; n < this.element.childNodes.length; n++) {
      if (this.element.childNodes[n].nodeType == 1) {
        var el = this.element.childNodes[n];
        if (SOAP.Header.QNAME.equals(WS.QName.fromElement.bind2(el)())) {
          val = true;
          break;
        }
      }
    }
    return val;
  },
  create_body : function() {
    if (!this.has_body()) {
      var doc = this.element.ownerDocument;
      var el = XML.createElementQName(doc, SOAP.Body.QNAME);
      this.element.appendChild(el);
      var ret = new SOAP.Body(el);
      return ret;
    } else {
      return this.get_body();
    }
  },
  get_body : function() {
    var val = null;
    for (var n = 0; n < this.element.childNodes.length; n++) {
      if (this.element.childNodes[n].nodeType == 1) {
        var el = this.element.childNodes[n];
        if (SOAP.Body.QNAME.equals(WS.QName.fromElement.bind2(el)())) {
          val = new SOAP.Body(el);
          break;
        }
      }
    }
    return val;
  },
  has_body : function() {
    var val = null;
    for (var n = 0; n < this.element.childNodes.length; n++) {
      if (this.element.childNodes[n].nodeType == 1) {
        var el = this.element.childNodes[n];
        if (SOAP.Body.QNAME.equals(WS.QName.fromElement.bind2(el)())) {
          val = true;
          break;
        }
      }
    }
    return val;
  }
});


/******************************************************************************/
SOAP.Header = Class.create();
SOAP.Header.QNAME = new WS.QName('Header',SOAP.URI);
SOAP.Header.prototype = Object.extend(new SOAP.Element(), {
  initialize : function(element) {
    this.initialize_internal(element);
  },
  set_value : function() {},
  get_value : function() {}
});


/******************************************************************************/
SOAP.Body = Class.create();
SOAP.Body.QNAME = new WS.QName('Body',SOAP.URI);
SOAP.Body.prototype = Object.extend(new SOAP.Element(), {
  initialize : function(element) {
    this.initialize_internal(element);
  },
  set_value : function() {},
  get_value : function() {},
  set_rpc : function(method, params, encodingstyle) {
    var child = this.create_child(method);
    if (encodingstyle) {
      child.set_encoding_style(encodingstyle);
    }
    for (var n = 0; n < params.length; n++) {
      var param = params[n];
      var pchild = null;
      if (param.name instanceof WS.QName) {
        pchild = child.create_child(param.name);
      } else {
        pchild = 
          child.create_child(
            new WS.QName(param.name,method.namespace,method.prefix)
          );
      }
      if (param.value) {
        pchild.set_value(param.value);
      } else {
        pchild.set_attribute(SOAP.XSINIL,'true');
      }
      if (param.xsitype) {
        pchild.set_attribute(SOAP.XSIQNAME,param.xsitype.value_of());
      }
      if (param.encodingstyle) {
        pchild.set_encoding_style(param.encodingstyle);
      }
    }
  }
});


/******************************************************************************/
WS.Handler = Class.create();
WS.Handler.prototype = {
  initialize : function() {},
  on_request : function(call, envelope) {},
  on_response : function(call, envelope) {},
  on_error : function(call, envelope) {}
};

/******************************************************************************/
WS.Binder = Class.create();
WS.Binder.register = function(qname,type,binder) {
  if (!WS.Binder.binders) WS.Binder.binders = new Array();
  WS.Binder.binders.push({qname:qname,type:type,binder:binder});
}
WS.Binder.get_for_qname = function(qname) {
  if (!WS.Binder.binders) return null;
  var binder = null;
  for (var n = 0; n < this.binders.length; n++) {
    var b = this.binders[n];
    if (b.qname.equals(qname)) {
      binder = b.binder;
      break;
    }
  }
  return binder;
}
WS.Binder.get_for_type = function(type) {
  if (!WS.Binder.binders) return null;
  var binder = null;
  for (var n = 0; n < this.binders.length; n++) {
    var b = this.binders[n];
    if (b.type == type) {
      binder = b.binder;
      break;
    }
  }
  return binder;
}
WS.Binder.prototype = {
  initialize : function() {},
  to_soap_element : function(value_object,envelope) {},
  to_value_object : function(soap_element) {}
};


/******************************************************************************/
WS.Call = Class.create();
WS.Call.InvokeHandlers = function(call, envelope, transport, state) {
  this.each(
    function(value) {
      switch(state) {
        case 'request':
          try {
            value.on_request(call,envelope, transport);
          } catch(e) {}
          break;
        case 'response':
          try {
            value.on_response(call,envelope, transport);
          } catch(e) {}
          break;
        case 'error':
          try {
            value.on_error(call,envelope,transport);
          } catch(e) {}
          break;
      }
    }
  );
}
WS.Call.prototype = {
  initialize : function(uri) {
    this.uri = uri;
    this.handlers = new Array();
    this.invokeHandlers = WS.Call.InvokeHandlers.bind(this.handlers);
  },
  add_handler : function(handler) {
    this.handlers.push(handler);
  },
  invoke_rpc : function(qname, params, encodingstyle, callback) {
    var env = new SOAP.Envelope();
    env.create_body().set_rpc(qname,params,encodingstyle);
    this.invoke(env, callback);
  },
  invoke : function(envelope, callback) {
    this.invokeHandlers(this,envelope,null,'request');
    var call = this;
    var options = {};
    options.postBody = envelope.asElement().ownerDocument;
    options.onComplete = 
      function(transport) {
        try {
          var xml = transport.responseXML;
          if (xml) {
            var responseEnv = new SOAP.Envelope(xml.documentElement);
            call.invokeHandlers(call,responseEnv,transport, 'response');
            callback(this, responseEnv, transport.responseText);
          } else {
            call.invokeHandlers(call,null,'error');
          }
        } catch(e) {
          call.invokeHandlers(call,e,'error');
        }
      };
    options.requestHeaders = new Array();
    if (this.soapAction) {
      options.requestHeaders.push('SOAPAction');
      options.requestHeaders.push('"' + encodeURI(this.soapAction) + '"');
    } else {
      options.requestHeaders.push('SOAPAction');
      options.requestHeaders.push('""');
    }
    options.contentType = 'text/xml';
    if (navigator.userAgent.match(/Safari/)) {
        // Browser requires explicit serialization (Safari, Chrome)
        // XMLHttpRequest.send will loose namespaces when serializing
        options.postBody = new XMLSerializer().serializeToString(options.postBody);
    }
    new Ajax.Request(this.uri,options);
  }
};

/*
 * Date Format 1.2.2
 * (c) 2007-2008 Steven Levithan <stevenlevithan.com>
 * MIT license
 * Includes enhancements by Scott Trenda <scott.trenda.net> and Kris Kowal <cixar.com/~kris.kowal/>
 *
 * Accepts a date, a mask, or a date and a mask.
 * Returns a formatted version of the given date.
 * The date defaults to the current date/time.
 * The mask defaults to dateFormat.masks.default.
 */
var dateFormat = function () {
	var	token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,
		timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
		timezoneClip = /[^-+\dA-Z]/g,
		pad = function (val, len) {
			val = String(val);
			len = len || 2;
			while (val.length < len) val = "0" + val;
			return val;
		};

	// Regexes and supporting functions are cached through closure
	return function (date, mask, utc) {
		var dF = dateFormat;

		// You can't provide utc if you skip other args (use the "UTC:" mask prefix)
		if (arguments.length == 1 && (typeof date == "string" || date instanceof String) && !/\d/.test(date)) {
			mask = date;
			date = undefined;
		}

		// Passing date through Date applies Date.parse, if necessary
		date = date ? new Date(date) : new Date();
		if (isNaN(date)) throw new SyntaxError("invalid date");

		mask = String(dF.masks[mask] || mask || dF.masks["default"]);

		// Allow setting the utc argument via the mask
		if (mask.slice(0, 4) == "UTC:") {
			mask = mask.slice(4);
			utc = true;
		}

		var	_ = utc ? "getUTC" : "get",
			d = date[_ + "Date"](),
			D = date[_ + "Day"](),
			m = date[_ + "Month"](),
			y = date[_ + "FullYear"](),
			H = date[_ + "Hours"](),
			M = date[_ + "Minutes"](),
			s = date[_ + "Seconds"](),
			L = date[_ + "Milliseconds"](),
			o = utc ? 0 : date.getTimezoneOffset(),
			flags = {
				d:    d,
				dd:   pad(d),
				ddd:  dF.i18n.dayNames[D],
				dddd: dF.i18n.dayNames[D + 7],
				m:    m + 1,
				mm:   pad(m + 1),
				mmm:  dF.i18n.monthNames[m],
				mmmm: dF.i18n.monthNames[m + 12],
				yy:   String(y).slice(2),
				yyyy: y,
				h:    H % 12 || 12,
				hh:   pad(H % 12 || 12),
				H:    H,
				HH:   pad(H),
				M:    M,
				MM:   pad(M),
				s:    s,
				ss:   pad(s),
				l:    pad(L, 3),
				L:    pad(L > 99 ? Math.round(L / 10) : L),
				t:    H < 12 ? "a"  : "p",
				tt:   H < 12 ? "am" : "pm",
				T:    H < 12 ? "A"  : "P",
				TT:   H < 12 ? "AM" : "PM",
				Z:    utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),
				o:    (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),
				S:    ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]
			};

		return mask.replace(token, function ($0) {
			return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
		});
	};
}();

// Some common format strings
dateFormat.masks = {
	"default":      "ddd mmm dd yyyy HH:MM:ss",
	shortDate:      "m/d/yy",
	mediumDate:     "mmm d, yyyy",
	longDate:       "mmmm d, yyyy",
	fullDate:       "dddd, mmmm d, yyyy",
	shortTime:      "h:MM TT",
	mediumTime:     "h:MM:ss TT",
	longTime:       "h:MM:ss TT Z",
	isoDate:        "yyyy-mm-dd",
	isoTime:        "HH:MM:ss",
	isoDateTime:    "yyyy-mm-dd'T'HH:MM:ss",
	isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'"
};

// Internationalization strings
dateFormat.i18n = {
	dayNames: [
		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
		"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
	],
	monthNames: [
		"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
		"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
	]
};

// For convenience...
Date.prototype.format = function (mask, utc) {
	return dateFormat(this, mask, utc);
};

/******************************************************************************/
var RISE = {
    Version :   '1.0',
    Author :    'Ola Hellgren',
    Copyright : 'Copyright 2008, Rise to Bloome Software AB',
    get_error_if_any : function (envelope) {
		var error_message = null;
		try {
			if (envelope.get_body().get_all_children()[0].qname().localpart == 'Fault') {
				var xml_error_rec = envelope.get_body().get_all_children()[0].get_all_children();
				error_message = '';
				for (i=0; i<xml_error_rec.length; i++) {
					if (xml_error_rec[i].asElement().firstChild != null) {
					error_message += (error_message != '' ? ', ' : '') + 
						xml_error_rec[i].qname().localpart + ': ' + 
						xml_error_rec[i].get_value();
					}
				}
			}
		} catch(err) {
			error_message = 'RISEWS failed to interpret response!';
		}
		return error_message; 
    },
    element_is_null : function (element) {
		for (n=0; n<element.attributes.length; n++) {
			if (element.attributes[n] != null && 
				element.attributes[n].nodeName == 'xsi:nil' && 
				element.attributes[n].nodeValue == 'true')
			return true;
		}
		return false;
    },
    get_element_value : function(elem) {
		var result;
		if (this.element_is_null(elem.asElement())) {
			result = null;
		} else if (elem.asElement().firstChild) {
			result = elem.get_value();
		} else {
			result = '';
		}
		return result;
    },
    get_array_result : function(is_ok, envelope) {
		var result = new Array;
		if (is_ok) {
			try {
				var xml_result_set = envelope.get_body().get_all_children()[0].get_all_children()[0].get_all_children();
				for (i=0; i<xml_result_set.length; i++) {
					result[i] = new Object;
					var xml_result_rec = xml_result_set[i].get_all_children();
					for (j=0; j<xml_result_rec.length; j++) {
						result[i][xml_result_rec[j].qname().localpart] = this.get_element_value(xml_result_rec[j]);
					}      
				} 
			} catch(err)  {
				result = null; // drop results!
			}
		}
		return result;
    },
    get_scalar_result : function(is_ok, envelope) {
		var result = new Object;
		if (is_ok) {
			try {
				var xml_result_rec = envelope.get_body().get_all_children()[0].get_all_children()[0].get_all_children();
				for (j=0; j<xml_result_rec.length; j++) {
					result[xml_result_rec[j].qname().localpart] = this.get_element_value(xml_result_rec[j]);
				}      
			} catch(err)  { 
				result = null; // drop result!
			}
		}
		return result;
    },
    get_intrinsic_result : function(is_ok, envelope) {
		var result = null;
		if (is_ok) {
			try {
				var element = envelope.get_body().get_all_children()[0].get_all_children()[0];
				result = this.get_element_value(element);
			} catch(err)  { 
	            result = null; // drop result!
	        }
		}
		return result;
    },
    JSON_to_namevalue_array : function(obj) { 
        var res_array = new Array;  
        for (var prop in obj) {
            if (typeof obj != 'function' && typeof obj != 'undefined' && typeof obj != 'unknown') {
                res_array[res_array.length] = { name: prop, value: obj[prop] };
            }  
        }   
        return res_array;
    },
    toSOAP : function(obj) {
        if (obj != null) {
            if (typeof obj == 'boolean') return (obj ? '1' : '0');
            else if (typeof obj == 'number') return obj.toString();
            else if (typeof obj == 'object' && obj instanceof Date) return obj.format('isoDateTime');     
        }
        return obj;
    },
	getDate : function(isoDatetime) {
		if (typeof isoDatetime == 'string') { /* fault tolerant iso parser */
			if (isoDatetime.match(/^\d{8}/)!=null) isoDatetime = isoDatetime.substr(0,4) + '-' + isoDatetime.substr(4,2) + '-' + isoDatetime.substr(6,2) + (isoDatetime.length > 8 ? isoDatetime.substring(8) : '');
			else if (isoDatetime.match(/^\d{6}/)!=null) isoDatetime = '20' + isoDatetime.substr(0,2) + '-' + isoDatetime.substr(2,2) + '-' + isoDatetime.substr(4,2) + (isoDatetime.length > 6 ? isoDatetime.substring(6) : '');
			var dp = isoDatetime.match(/((\d{4}(-\d{1,2})?)|(\d{2}-\d{1,2}))(-\d{1,2})?/);
			var tp = isoDatetime.match(/\d{1,2}:\d{1,2}(:\d{1,2})?/);
			var d = (dp != null && dp.length > 0 ? dp[0].split('-') : []);
			var h = (tp != null && tp.length > 0 ? tp[0].split(':') : []); 
			if (d.length == 0) d = new Date().format('isoDateTime').split('T')[0].split('-');
			if (h.length == 0) h = new Date().format('isoDateTime').split('T')[1].split(':');		
			var o = {
				year: parseInt((d.length>0 ? (d[0].length == 4 ? d[0] : '20'+d[0]) : '100')), month: parseInt((d.length>1 ? (d[1].substr(0,1)=='0' ? d[1].substring(1) : d[1]) : '1'))-1, day: parseInt((d.length>2 ? (d[2].substr(0,1)=='0' ? d[2].substring(1) : d[2]) : '1')),
				hour: parseInt((h.length>0 ? (h[0].substr(0,1)=='0' ? h[0].substring(1) : h[0]) : '0')), minutes: parseInt((h.length>1 ? (h[1].substr(0,1)=='0' ? h[1].substring(1) : h[1]) : '0')), seconds: parseInt((h.length>2 ? (h[2].substr(0,1)=='0' ? h[2].substring(1) : h[2]) : '0'))
			};
			try {
				o.oDate = new Date();
				o.oDate.setFullYear(o.year, o.month, o.day); 
				o.oDate.setHours(o.hour, o.minutes, o.seconds);	
				o.iso = o.oDate.format('isoDateTime'); 
				o.date = o.iso.split('T')[0];
				o.time = o.iso.split('T')[1];
			} catch (err) { 
				o = { year: 0, month: 0, day: 0, date: '', hour: 0, minutes: 0, seconds: 0, time: '', iso: '', oDate: null };
			}
			return o;
		} else if (typeof isoDatetime == 'object' && isoDatetime instanceof Date) {
			return RISE.getDate(isoDatetime.format('isoDateTime'));
		}
		return RISE.getDate((isoDatetime == null ? '' : isoDatetime.toString()));
	},
	getValue: function(obj, valName) {
		return (obj!=null && typeof obj[valName] != 'undefined' ? obj[valName] : null); 
	}
};

/************************************************************************/

RISE.WS = Class.create();
RISE.WS.prototype = {
   initialize : function(uri) {
      this.uri = uri;
      if (arguments[1] != null) {
         this.nsuri = arguments[1];
      } else {  /* namespace generated by Community on the RISE */       
         this.nsuri = 'http://' + decodeURI(uri).match(/[^/]+\.\w*$/i)[0].replace(/\.\w*$/i, '') +'/';
      }
   },
   invoke : function(method_name,  argument_obj, callback) {
      var call = new WS.Call(this.uri); 
      var qn_op = new WS.QName(method_name,this.nsuri);
      call.soapAction = this.nsuri+  method_name;
      call.invoke_rpc(
         qn_op, 
         RISE.JSON_to_namevalue_array(argument_obj), 
         null, 
         callback
      );
   },
   invoke_new : function(method_name, argument_obj, callback) {
      this.invoke(
         method_name, 
         argument_obj, 
         function(call, envelope, body_html) {
             var error_message = RISE.get_error_if_any(envelope);
             callback(call, error_message, RISE.get_intrinsic_result(error_message==null, envelope), body_html.escapeHTML());	
         } 
      );   
   },
   invoke_delete : function(method_name,  argument_obj, callback) {
      this.invoke(
         method_name, 
         argument_obj, 
         function(call, envelope, body_html) {
             var error_message = RISE.get_error_if_any(envelope);
             callback(call, error_message, RISE.get_intrinsic_result(error_message==null, envelope), body_html.escapeHTML());	
         } 
      );   
   },
   invoke_get : function(method_name,  argument_obj, callback) {
      this.invoke(
         method_name, 
         argument_obj, 
         function(call, envelope, body_html) { 
             var error_message = RISE.get_error_if_any(envelope);
             callback(call, error_message, RISE.get_scalar_result(error_message==null, envelope), body_html.escapeHTML());	
         } 
      );   
   },
   invoke_set : function(method_name,  argument_obj, callback) {
      this.invoke(
         method_name, 
         argument_obj, 
         function(call, envelope, body_html) {
             var error_message = RISE.get_error_if_any(envelope);
             callback(call, error_message, RISE.get_intrinsic_result(error_message==null, envelope), body_html.escapeHTML());	
         } 
      );   
   },
   invoke_list : function(method_name,  argument_obj, callback) {
      this.invoke(
         method_name, 
         argument_obj, 
         function(call, envelope, body_html) {
             var error_message = RISE.get_error_if_any(envelope);
             callback(call, error_message, RISE.get_array_result(error_message==null, envelope), body_html.escapeHTML());
         } 
      );   
   },
   invoke_void : function(method_name,  argument_obj, callback) {
      this.invoke(
         method_name, 
         argument_obj, 
         function(call, envelope, body_html) {
             var error_message = RISE.get_error_if_any(envelope);
             callback(call, error_message, null, body_html.escapeHTML());
         } 
      );   
   }
};

/******************************************************************************/

RISE.AF = {
    Version :   '1.0',
    Author :    'Ola Hellgren',
    Copyright : 'Copyright 2008, Rise to Bloome Software AB'
};

RISE.AF.State = {
	nochange: 0,
	subchanged: 1,
	changed: 2,
	tocreate: 3,
	todelete: 4,
	dead: 5
};

RISE.AF.Member = Class.create({
	initialize: function(value /*, bubbleCallback, bubbleScope, clientData */ ) {
		this.bubble = (arguments.length > 1 ? arguments[1] : null);
		this.bubbleScope = (arguments.length > 2 ? arguments[2] : null);
		this.clientData = (arguments.length > 3 ? arguments[3] : null);
		this.init(value);
	},
	change: function(value) {
		if (this.value != value) {
			this.changeAlways(value);
		}
	},
	changeAlways: function(value) {
		this.value = value;
		this.state = RISE.AF.State.changed;		
		if (this.bubble != null) { 
			if (this.bubbleScope != null) { 
				this.bubble.apply(this.bubbleScope,[[this]]);
			} else {
				this.bubble.apply(this, [[this]]);
			}
		}
	},
	changeByEl: function(id /*, member */) {
		var member = (arguments.length > 1 ? arguments[1] : 'value');
		var el = document.getElementById(id); 
		if (el != null) {
			var v = el[member];
			if ((typeof v == 'boolean' && this.bool() != v) ||
				(typeof v == 'string' && !(this.isNullOrEmpty() && (v==null || v == '')))) {
				this.change(v);
			}
		}
	},
	init: function(value) {
		this.state = RISE.AF.State.nochange;
		this.value = value;
	},
	reset: function() {	
		this.state = RISE.AF.State.nochange;
	},
	isNullOrEmpty: function() {
		return (this.value == null || (typeof this.value == 'string' && this.value == ''));
	},
	ifNull: function(fallback) {
		return (this.value == null ? fallback : this.value);
	},
	ifNullOrEmpty: function(fallback) {
		return (this.isNullOrEmpty() ? fallback : this.value);
	},
	date: function(/*format*/) {
		if (this.value == null) {
			return null;
		}
		if (arguments.length > 0) {
			RISE.getDate(this.value).oDate.format(arguments[0]);
		}
		return RISE.getDate(this.value).date;
	},
	ifNullDate: function(fallback /*, format */) {
		return (arguments.length > 1 ? this.date(arguments[1]) : this.date()) || fallback;
	},
	bool: function() {
		if (this.value == null) {
			return null;
		}
		return (this.value != null && (this.value == true || this.value == 'true'));
	},
	integer: function(fallback) {
		if (this.value == null) {
			return null;
		}
		try {
			switch (typeof this.value){
				case 'string': return parseInt(this.value);
				case 'number': return Math.floor(this.value);
				default: break;
			}	
		} catch (err) { }		
		return fallback;
	}
});

RISE.AF.ObjectList = Class.create({
	initialize: function(arr /*, bubbleCallback, bubbleScope, clientData */) {
		this.bubble = (arguments.length > 1 ? arguments[1] : null);
		this.bubbleScope = (arguments.length > 2 ? arguments[2] : null);
		this.clientData = (arguments.length > 3 ? arguments[3] : null);		
		this.init(arr);
	},
	init: function(arr) {
		this.objects = [];
		if (arr != null) {
			for (var i=0; i<arr.length; i++) {
				this.objects[i] = new RISE.AF.Object(arr[i], this.bubbleCallback, this);
			}
		}
	},
	change: function(arr) {
		for (var i=0; i<arr.length && i<this.objects.length; i++) {
			this.objects[i].change(arr[i]);
		}
	},
	addObject: function(obj /*, clientData  */) {
		this.objects.push((arguments.length > 1 ? new RISE.AF.Object(obj, this.bubbleCallback, this, arguments[1]) : new RISE.AF.Object(obj, this.bubbleCallback, this)));
		return this.objects[this.objects.length-1];
	},
	getObjects: function() {
		var arr = [];
		for (var i=0; i<this.objects.length; i++) {
			if (this.objects[i].state != RISE.AF.State.dead) {
				arr.push(this.objects[i].getObject()); 
			}
		}
		return arr;
	},
	reset: function() {
		for (var i=0; i<this.objects.length; i++) {
			this.objects[i].reset();
		}
	},	
	bubbleCallback: function(chain) { 
		if (this.bubble != null) {
			chain.push(this);
			if (this.bubbleScope != null) {
				this.bubble.apply(this.bubbleScope, [chain]);
			} else {
				this.bubble.apply(this, [chain]);
			}
		}
	},
	findTopDown: function(findState /*,  arr */) {
		var tmp = (arguments.length > 1 ? arguments[1] : []);
		for (var i=0; i<this.objects.length; i++) {
			this.objects[i].findTopDown(findState, tmp);
		}
		return tmp;
	},
	findBottomUp: function(findState /*,  arr */) {
		var tmp = (arguments.length > 1 ? arguments[1] : []);
		for (var i=0; i<this.objects.length; i++) {
			this.objects[i].findBottomUp(findState, tmp);
		}
		return tmp;		
	},
	needsCreating: function() {
		return this.findTopDown(RISE.AF.State.tocreate);
	},
	needsDeleting: function() {
		return this.findBottomUp(RISE.AF.State.todelete);		
	},
	hasChanged: function() {
		return this.findTopDown(RISE.AF.State.changed);
	},
	getSaveStack: function() {
		return this.hasChanged().concat(this.needsCreating().concat(this.needsDeleting()));
	},
	getSaveList: function() {
		var tmp = [];
		for (var i=0; i<this.objects.length; i++) {
			if (this.objects[i].state > RISE.AF.State.nochange && this.objects[i].state < RISE.AF.State.dead) {
				tmp.push(this.objects[i]);
			}
		}		
		return tmp;
	},
	Type: function(child) {
		return (this.bubbleScope!= null ? this.bubbleScope.Type(this) : '/');
	}
});

RISE.AF.Object = Class.create({
	initialize: function(obj /*, bubbleCallback, bubbleScope, clientData */) {
		this.bubble = (arguments.length > 1 ? arguments[1] : null);
		this.bubbleScope = (arguments.length > 2 ? arguments[2] : null);
		this.clientData = (arguments.length > 3 ? arguments[3] : null);
		this.init(obj);
	},
	init: function(obj) {
		this.state = RISE.AF.State.nochange;
		this.content = {};
		if (obj != null) {
			for (var m in obj) {
				if (obj[m] != null && typeof obj[m] == 'object') {
					if(Object.isArray(obj[m])) {
						this.content[m] = new RISE.AF.ObjectList(obj[m], this.bubbleCallback, this);
					} else {
						this.content[m] = new RISE.AF.Object(obj[m], this.bubbleCallback, this);
					}
				} else if (typeof obj[m] != 'function') { 
					this.content[m] = new RISE.AF.Member(obj[m], this.bubbleCallback, this);
				}
			}
		}
	},
	reset: function() {
		if (this.state != RISE.AF.State.dead) {
			this.state = RISE.AF.State.nochange;
			for (var m in this.content) {
				if (typeof this.content[m] == 'object' && 
						(this.content[m] instanceof RISE.AF.Member || 
						this.content[m] instanceof RISE.AF.Object || 
						this.content[m] instanceof RISE.AF.ObjectList)) {
					this.content[m].reset();
				}
			}
		}
	},
	change: function(obj) {
		for (var m in obj) {
			if (!Object.isUndefined(this.content[m])) {
				this.content[m].change(obj[m]);
			}
		}
	},
	getObject : function() {
		var obj = {};
		for (var m in this.content) {
			if (typeof this.content[m] == 'object') {
				if (this.content[m] instanceof RISE.AF.Member) {
					obj[m] = this.content[m].value;
				} else if (this.content[m] instanceof RISE.AF.Object) {
					obj[m] = this.content[m].getObject();
				} else if (this.content[m] instanceof RISE.AF.ObjectList) {
					obj[m] = this.content[m].getObjects();
				}
			} 
		}
		return obj;
	},
	bubbleCallback: function(chain) {
		if (this.state < RISE.AF.State.changed && chain.length == 1 && chain[0] instanceof RISE.AF.Member) {
			this.state = RISE.AF.State.changed;
			chain.push(this)
			this.doBubble(chain);
		} else if (this.state == RISE.AF.State.nochange){
			this.state = RISE.AF.State.subchanged;
			chain.push(this)
			this.doBubble(chain);
		}
	},	
	findTopDown: function(findState /*,  arr */) {
		var tmp = (arguments.length > 1 ? arguments[1] : []);
		if (this.state != RISE.AF.State.dead) {
			if (this.state == findState) {
				tmp.push(this);
			}
			for (var m in this.content) {
				if (typeof this.content[m] == 'object' && this.content[m] instanceof RISE.AF.Object) {
					this.content[m].findTopDown(findState, tmp);
				} else if (typeof this.content[m] == 'object' && this.content[m] instanceof RISE.AF.ObjectList) {
					this.content[m].findTopDown(findState, tmp);
				}			
			}
		}
		return tmp;
	},
	findBottomUp: function(findState /*,  arr */) {
		var tmp = (arguments.length > 1 ? arguments[1] : []);
		if (this.state != RISE.AF.State.dead) {
			for (var m in this.content) {
				if (typeof this.content[m] == 'object' && this.content[m] instanceof RISE.AF.Object) {
					this.content[m].findBottomUp(findState, tmp);
				} else if (typeof this.content[m] == 'object' && this.content[m] instanceof RISE.AF.ObjectList) {
					this.content[m].findBottomUp(findState, tmp);
				}			
			}
			if (this.state == findState) {
				tmp.push(this);
			}
		}
		return tmp;		
	},
	needsCreating: function() {
		return this.findTopDown(RISE.AF.State.tocreate);
	},
	needsDeleting: function() {
		return this.findBottomUp(RISE.AF.State.todelete);		
	},
	hasChanged: function() {
		return this.findTopDown(RISE.AF.State.changed);
	},
	getSaveStack: function() {
		return this.hasChanged().concat(this.needsCreating().concat(this.needsDeleting()));
	},
	setToCreate: function() {
		if (this.state < RISE.AF.State.tocreate) {
			this.state = RISE.AF.State.tocreate;
			this.doBubble([this]);
		}
	},
	setToDelete: function() {
		if (this.state < RISE.AF.State.todelete) {
			if (this.state == RISE.AF.State.tocreate) {
				this.state = RISE.AF.State.dead;
			} else {
				this.state = RISE.AF.State.todelete;
			}
			this.doBubble([this]);
		}
	},
	doBubble: function(chain) {
		if (this.bubble != null) {
			if (this.bubbleScope != null) {
				this.bubble.apply(this.bubbleScope, [chain]);
			} else { 	
				this.bubble.apply(this, [chain]);
			}
		}
	},
	Type: function(child) {
		if (child != null) {
			for (var m in this.content) {
				if (child == this.content[m]) {
					return (this.bubbleScope != null ? this.bubbleScope.Type(this)  : '') + '/' + m; 
				}
			}
		} 
		return (this.bubbleScope != null ? this.bubbleScope.Type(this) : '/'); 
	},
	dump: function(style /* 'js' or 'html' */) {
		var tmp = (arguments.length == 1 ? [] : arguments[1]);		
		var ind = (arguments.length == 1 ? '' : arguments[2]);	
		var sub = (style=='js' ? '   ' : '&nbsp;&nbsp;&nbsp;'); 
		var lf = (style=='js' ? '\n' : '<br/>');
		if (arguments.length == 1 ) tmp.push(ind + '{' + lf);
		tmp.push(ind + sub + 'state: ' + this.state + lf); 
		for (var m in this.content) {
			if (this.content[m] instanceof RISE.AF.ObjectList) {
				tmp.push(ind + sub + m + ': ' + '[' + lf);
				for (var i=0; i<this.content[m].objects.length; i++) {
					tmp.push(ind + sub + sub + '{' + lf);
					this.content[m].objects[i].dump(style, tmp, ind + sub + sub);
				}
				tmp.push(ind + sub + ']' + lf);
			} else if (this.content[m] instanceof RISE.AF.Object) {
				tmp.push(ind + sub + m + ': {' + lf);
				this.content[m].dump(style, tmp, ind + sub);
			} else {
				var v = '';
				if (this.content[m].value == null) {
					v = m + ': null'; 
				} else if (typeof this.content[m].value == 'string') {
					v = m + ': \'' + this.content[m].value + '\''; 
				} else {
					v =  m + ': ' + this.content[m].value.toString(); 
				}
				tmp.push(ind + sub + '{state: ' + this.content[m].state + ', ' + v + '}' + lf);
			}
		}
		tmp.push(ind + '}' + lf);
		if (arguments.length == 1) return tmp.join('');
	}
});

RISE.AF.SoapArgument = Class.create({
	initialize: function(oInit, oStrings) {
		this.oArgument = oInit || {};
		if (oStrings != null) this.addStrings(oStrings);
	},
	addStrings: function(oStrings) {
		for (var s in oStrings) {
			this.addString(s, oStrings[s]);
		}
	},
	addString: function(argumentName, value) {
		this.add(argumentName, 'string', value);
	},
	add: function(argumentName, argumentType, value) {
		switch (argumentType) {
			case 'string':
				if (value != null) this.oArgument[argumentName] = value; 
				break;				
			default: 
				this.oArgument[argumentName] = RISE.toSOAP(value);
				break;
		}
	},
	get: function() {
		return this.oArgument;
	}
});

