// Inheritance method
if(!Function.inherits){
	Function.prototype.inherits = function(superclass){
		var x = function(){
		};
		x.prototype = superclass.prototype;
		this.prototype = new x();
	}
}

// An HTML display object class encapsulating various methods to allow style manipulation and hierarchy tracking

function DisplayObject(domElement){

	this.domElement = domElement;// DOM object container;

	this.attributes = new Object();// Object to hold attributes.

	this.parentObj = null;// Object to hold parent DisplayObject

	this.opacity = 100;// default opacity

	this.transformations = new Array();// array to hold current list of
										// transformations
	this.transformationStarted = false;

	this.transformationEndFunctions = new Object;

	this.displayStyle = null;

	this.toggledOpen = true;

	// Style Methods

	this.setClass = function(className){

		if (this.domElement != null) {
			this.domElement.className = className;
		}

	}

	this.setStyle = function(style, value){// method to set style of domElement (CSS styles e.g. border-width will be converted to javascript compatible).

		if(this.domElement != null){

			var pattern = /\-([a-z])/;

			while (String(style).match(pattern)){

				style = String(style).replace(pattern,
						String(RegExp.$1).toUpperCase());

			}

			this.domElement.style[style] = value;

		}

	}

	/*this.getStyle = function(style){

		if(this.domElement != null){

			var pattern = /\-([a-z])/;

			while (String(style).match(pattern)){

				style = String(style).replace(pattern,
						String(RegExp.$1).toUpperCase());

			}

			return this.domElement.style[style];

		}

		return null;

	}*/

	this.getStyle = function(strCssRule,domElement){

		if(!domElement){
			domElement = this.domElement;
		}

		var strValue = "";
		if(document.defaultView && document.defaultView.getComputedStyle){
			strValue = document.defaultView.getComputedStyle(domElement, "").getPropertyValue(strCssRule);
		}
		else if(domElement.currentStyle){
			strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1){
				return p1.toUpperCase();
			});
			strValue = domElement.currentStyle[strCssRule];
		}
		return strValue;
	}



	/// SIZE METHODS

	this.getWidth = function(domElement){
		if(domElement == null){
			domElement = this.domElement;
		}
		if (domElement != null) {
			if (domElement.style.pixelWidth) {
				return domElement.style.pixelWidth;
			}else if (domElement.offsetWidth){
				return domElement.offsetWidth;
			}else{
				return domElement.clientWidth;
			}
		}
		return null;
	}

	this.getHeight = function(domElement){
		if(domElement ==  null){
			domElement = this.domElement;
		}
		if (domElement != null) {
			if (domElement.style.pixelHeight) {
				return domElement.style.pixelHeight;
			}else if (domElement.offsetHeight){
				return domElement.offsetHeight;
			}else{
				return domElement.clientHeight;
			}
		}
		return null;
	}

	this.getPageSizeObject = function(){

		var xScroll, yScroll;

		if(window.innerHeight && window.scrollMaxY){
			xScroll = document.body.scrollWidth;
			yScroll = window.innerHeight + window.scrollMaxY;
		}else if(document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
			xScroll = document.body.scrollWidth;
			yScroll = document.body.scrollHeight;
		}else{ // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
			xScroll = document.body.offsetWidth;
			yScroll = document.body.offsetHeight;
		}

		var windowWidth, windowHeight;
		if(self.innerHeight){ // all except Explorer
			windowWidth = self.innerWidth;
			windowHeight = self.innerHeight;
		}else if(document.documentElement
				&& document.documentElement.clientHeight){ // Explorer 6 Strict Mode
			windowWidth = document.documentElement.clientWidth;
			windowHeight = document.documentElement.clientHeight;
		}else if(document.body){ // other Explorers
			windowWidth = document.body.clientWidth;
			windowHeight = document.body.clientHeight;
		}

		// for small pages with total height less then height of the viewport
		if(yScroll < windowHeight){
			pageHeight = windowHeight;
		}else{
			pageHeight = yScroll;
		}

		// for small pages with total width less then width of the viewport
		if(xScroll < windowWidth){
			pageWidth = windowWidth;
		}else{
			pageWidth = xScroll;
		}

		return {
			pageWidth : pageWidth,
			pageHeight : pageHeight,
			windowWidth : windowWidth,
			windowHeight : windowHeight
		};
	}

	this.getYScroll = function(){


		var yScroll;

		if (self.pageYOffset) {
			yScroll = self.pageYOffset;
		} else if (document.documentElement && document.documentElement.scrollTop){	 // Explorer 6 Strict
			yScroll = document.documentElement.scrollTop;
		} else if (document.body) {// all other Explorers
			yScroll = document.body.scrollTop;
		}

		return yScroll;

	}

	// DOM element methods

	this.createDOMElement = function(tag, className){

		if(tag == null){
			tag = "div";
		}

		this.domElement = document.createElement(tag);

		if(className != null){
			this.domElement.className = className;

		}

		//this.domElement['displayObject'] = this;

	}

	this.setDOMElement = function(domElement){

		this.domElement = domElement;

	}

	this.getDOMElement = function(){

		return this.domElement;

	}

	this.setDOMAttribute = function(a, v){

		if(this.domElement != null){

			this.domElement.setAttribute(a, v);

		}

	}

	this.setID = function(id){

		this.setDOMAttribute("id", id);

	}

	this.setHTML = function(html){

		if(this.domElement != null){
			this.domElement.innerHTML = html;
		}

	}

	// Child methods

	this.addDisplayObject = function(tag, className){

		var displayObject = new DisplayObject();
		displayObject.setParent(this);
		displayObject.createDOMElement(tag);

		if(className != null){
			displayObject.setClass(className);
		}

		this.domElement.appendChild(displayObject.getDOMElement());

		return displayObject;

	}

	this.attachDisplayObject = function(displayObject){

		displayObject.setParent(this);

		this.domElement.appendChild(displayObject.getDOMElement());

		return displayObject;

	}

	this.addElement = function(tag, html){// method to add element. Arguments [3] onwards can be attribute pairs

		var element = document.createElement(tag);

		if(arguments.length > 2){

			for( var i = 2; i < arguments.length; i += 2){
				element.setAttribute(arguments[i], arguments[i + 1]);
			}

		}

		if(html != null){

			element.innerHTML = html;

		}

		this.domElement.appendChild(element);

		return element;

	}

	this.removeElement = function(element){

		if (this.domElement != null && element != null) {

			this.domElement.removeChild(element);

		}

	}

	this.remove = function(){
		if(typeof(this.domElement.parentNode) != 'undefined'){
			this.domElement.parentNode.removeChild(this.domElement);
		}
	}

	this.addText = function(text){// method to add element.

		var textNode = document.createTextNode(text);

		this.domElement.appendChild(textNode);

		return textNode;

	}

	this.clearContents = function(){

		if(this.domElement != null){

			if(this.domElement.hasChildNodes()){
				while (this.domElement.childNodes.length >= 1){
					this.domElement.removeChild(this.domElement.firstChild);
				}
			}

		}
	}

	this.appendToElement = function(element){

		if(element != null && this.getDOMElement() != null){

			element.appendChild(this.getDOMElement());

		}

	}

	this.removeFromElement = function(element){

		if(element != null && this.domElement != null && this.domElement.parentNode == element){

			element.removeChild(this.getDOMElement());

		}

	}

	this.detach = function(){
		if(this.domElement != null && this.domElement.parentNode != null){
			this.domElement.parentNode.removeChild(this.domElement);
		}
	}

	this.appendChild = function(node){

		if(this.domElement != null){

			this.domElement.appendChild(node);

		}
	}

	// Parent methods

	this.getParent = function(){

		return this.parentObj;

	}

	this.setParent = function(parent){

		this.parentObj = parent;

	}

	// Settings methods

	this.setAttribute = function(attribute, value){

		this.attributes[attribute] = value;

	}

	this.getAttribute = function(attribute){

		if(this.attributes[attribute] != null){

			return this.attributes[attribute];

		}else if(this.parentObj != null){

			return this.parentObj.getAttribute(attribute);

		}

		return null;

	}

	// Transformation methods

	this.setOpacity = function(opacity,element){

		if (element == null) {
			this.opacity = opacity;
			element = this.domElement;
		}


		if (opacity == 100 && element.style.removeAttribute != null) {
			element.style.removeAttribute('filter');
		} else {
			element.style.filter='progid:DXImageTransform.Microsoft.Alpha(Opacity=' + opacity + ')';
			//element.style.filter = "alpha(style=0,opacity:" + opacity + ")"; // <=IE7
		}
		element.style.KHTMLOpacity = opacity / 100; // Konqueror
		element.style.MozOpacity = opacity / 100; // Mozilla (old)
		element.style.opacity = opacity / 100; // Mozilla (new)
	}

	this.changeOpacity = function(newOpacity, increment, callback){

		if(callback != null){
			this.transformationEndFunctions["opacity"] = callback;
		}

		increment = (increment == null) ? 10 : increment;
		var i = 0;
		// determine the direction for the blending
		if(this.opacity > newOpacity){
			for( var o = this.opacity; o >= newOpacity; o -= increment){// add opacities to transformation array
				if(this.transformations[i] == null){
					this.transformations[i] = {
						opacity : o
					};// create new transformation object
				}else{
					this.transformations[i]["opacity"] = o;// add opacity to
															// existing
															// transformation
															// object
				}
				i++;
			}
		}else{
			for( var o = this.opacity; o <= newOpacity; o += increment){
				if(this.transformations[i] == null){
					this.transformations[i] = {
						opacity : o
					};
				}else{
					this.transformations[i]["opacity"] = o;
				}
				i++;
			}
		}

		while(typeof(this.transformations[i]) != "undefined" && typeof(this.transformations[i]["opacity"]) != "undefined"){// remove remaining old transformations
			delete(this.transformations[i]["opacity"]);
			i++;
		}

		this.startTransform();
	}

	this.changeDimension = function(dimension, newValue, steps, easing, callback){

		this.transformationEndFunctions[dimension] = callback;

		steps = (steps == null) ? 10 : steps;

		var oldValue = (this.domElement.style[dimension]) ? parseInt(this.domElement.style[dimension].replace(/\D/,'')) : 0;

		var change = newValue-oldValue;

		var increment = change/steps;

		for(var i=0;i<steps;i++){
			if(this.transformations[i] == null){
				this.transformations[i] = new Object();
			}
			if(easing && easing.toLowerCase() == "in"){
				this.transformations[i][dimension] = this.easeInQuad(i,oldValue,change,steps)
			}else if(easing && easing.toLowerCase() == "out"){
				this.transformations[i][dimension] = this.easeOutQuad(i,oldValue,change,steps)
			}else{
				this.transformations[i][dimension] = oldValue + increment*(i+1);
			}
		}

		while(typeof(this.transformations[i]) != "undefined" && typeof(this.transformations[i][dimension]) != "undefined"){// remove remaining old transformations
			delete(this.transformations[i][dimension]);
			i++;
		}

		this.startTransform();
	}


	this.slideToggle = function(speed,easing,callback,direction){

		if(typeof(jQuery) != "undefined"){

			var element = this.domElement;

			if(direction == "show"){
				$(element).slideDown(speed,easing,callback);
			}else if(direction == "hide"){
				$(element).slideUp(speed,easing,callback);
			}else{
				$(element).slideToggle(speed,easing,callback);
			}

			return;

		}

		if(direction == null){
			direction = (this.toggledOpen) ? "hide" : "show"
		}

		if(direction == "show" && !this.toggledOpen){

			this.show();
			if(callback != null){
				callback(this);
			}
			this.toggledOpen = true;

		}else if(this.toggledOpen){

			this.hide();
			if (callback != null) {
				callback(this);
			}
			this.toggledOpen = false;

		}
	}


	this.startTransform = function(){

		if(!this.transformationStarted){

		var thisObj = this;

		window.setTimeout( function(){thisObj.doTransformation()}, 50);

		this.transformationStarted = true;

		}

	}

	this.show = function(){

		if(typeof(jQuery) != null){
			$(this.domElement).show();
			return;
		}

		this.setStyle("display", "block");

	}

	this.hide = function(){

		if(typeof(jQuery) != null){
			$(this.domElement).hide();
			return;
		}

		this.setStyle("display", "none");

	}

	this.hideElement = function(element){

		this.setElementDisplay(element, "none");

	}

	this.showElement = function(element){

		this.setElementDisplay(element, "block");

	}

	this.setElementDisplay = function(element, display){

		if(element != null){
			element.style.display = display;
		}
	}

	this.doTransformation = function(){

		if(this.transformations.length > 0){

			var transformation = this.transformations.shift();

			for( var i in transformation){
				switch(i){
					case "opacity":
						this.setOpacity(transformation[i]);
						break;
					case "left":
					case "right":
					case "top":
					case "bottom":
					case "width":
					case "height":
						this.setStyle(i, transformation[i]+"px");
						break;
				}
				if((this.transformations.length == 0 || typeof(this.transformations[0][i]) == "undefined") && this.transformationEndFunctions[i] != null){
					this.transformationEndFunctions[i](this);
				}

			}

			if(this.transformations.length > 0){
				var thisObj = this;
				window.setTimeout( function(){thisObj.doTransformation()}, 40);
			}else{
				this.transformationStarted = false;
			}

		}

	}

	// listening methods

	this.addEventListener = function(event, func){

		if(this.domElement != null){

			this.domElement[event] = func;

		}

	}

	// Mouse methods

	this.getMousePosition = function(event){
		return {
			x : event.clientX,
			y : event.clientY
		};
	}

	this.getPosition = function(element){

		if (element == null) {
			element = this.domElement;
		}

		if (element != null) {

			var x = y = width = height = null;

			if (element.style.pixelWidth) {
				width = element.style.pixelWidth;
				height = element.style.pixelHeight;
			} else
				if (element.offsetWidth) {
					width = element.offsetWidth;
					height = element.offsetHeight;
				} else {
					width = element.clientWidth;
					height = element.clientHeight;
				}

			if (element.offsetParent) {
				do {
					x += element.offsetLeft;
					y += element.offsetTop;
				} while (element = element.offsetParent);

			} else {
				return null;
			}

			return {
				x: x,
				y: y,
				width: width,
				height: height
			};

		}

		return null;

	}

}


function OverlayObject(container){

	DisplayObject.call(this);

	this.zIndex = 1000;
	this.containerObj = null;
	this.opacity = 80;
	this.color = "#000";
	this.removeOnClick = true;

	this.onRemoveFunction = null;

	if(container != null){
		this.containerObj = container;
	}

	this.OverlayObject = function(){

		this.createDOMElement("div","DTDOverlay");
		//this.setStyle("position","absolute");

	}

	this.displayContent = function(){

		this.setStyle("top", "0");
		this.setStyle("left", "0");
		this.setStyle("z-index", this.zIndex);
		this.setStyle("width", "100%");
		this.setStyle("height", "100%");
		this.setStyle("display", 'block');
		this.setStyle("background-color", this.color);
		this.setOpacity(this.opacity);


		if(this.containerObj == null){// container is body, create full size with click off function
			this.containerObj = document.getElementsByTagName("body").item(0);
			this.addOnClickRemove();
			var pageSizes = this.getPageSizeObject();
			this.setStyle("height",pageSizes.pageHeight+"px");
		}else{
			this.setStyle("width",this.containerObj.clientWidth+"px");
			this.setStyle("height",this.containerObj.clientHeight+"px");
		}

		if(this.containerObj.firstChild != null){
			this.containerObj.insertBefore(this.domElement, this.containerObj.firstChild);
		}else{
			this.containerObj.appendChild(this.domElement);
		}


	}

	this.onUserClick = function(e){
		if(this.onRemoveFunction != null){

			this.onRemoveFunction(e);

		}else{
			if(this.removeOnClick){
				this.remove();
			}
		}
	}

	this.addOnClickRemove = function(){

		var thisObj = this;
		this.addEventListener("onclick", function(e){
			thisObj.onUserClick(e);
			return false;
		});

	}

	this.remove = function(){

		this.clearContents();

		this.containerObj.removeChild(this.domElement);

	}

	this.setContainer = function(container){
		this.containerObj = container;
	}

	this.OverlayObject();

}

OverlayObject.inherits(DisplayObject);
function StreetViewButtonObject(){

	this.onClickFunction = null;
	this.onDisplay = null;
	this.parentObj = null;
	this.latLng = null

	this.label = "StreetView";

	DisplayObject.call(this);

	this.load = function(location){

		var regex = /^-?[\d\.]+,-?[\d\.]+$/;

		if(String(typeof location).toLowerCase() == "object"){// assume GLatLng has been passed

			this.latLng = location;

			this.checkAvailability();

		}else if (regex.test(location)) {// we've been passed geocodes

			location = location.split(",");

			this.latLng = new google.maps.LatLng(location[0],location[1]);

			this.checkAvailability();

		}else{// assume we've been passed address - try for geocodes

			var geocoder = new google.maps.Geocoder();

			var geocodeRequest = {address: location};

			var thisObj = this;
			var onGeocodeLookup = function(results){
				thisObj.onGeocodeLookup(results);
			}
			geocoder.geocode(geocodeRequest,onGeocodeLookup);
		}

	}

	this.onGeocodeLookup = function(resultArr){

		if(typeof(resultArr) == "object" && resultArr.length > 0){
			this.latLng = resultArr[0].geometry.location;
			this.checkAvailability();
		}

	}

	this.checkAvailability = function(){

		var streetViewClient = new google.maps.StreetViewService();
		var thisObj = this;
		var onAvailabilityCheck = function(point){
			thisObj.onAvailabilityCheck(point);
		}

		streetViewClient.getPanoramaByLocation(this.latLng,50,onAvailabilityCheck);

	}

	this.onAvailabilityCheck = function(panoramaData,status){

		if(status == google.maps.StreetViewStatus.OK || (panoramaData != null && panoramaData.location != null)){
			this.latLng = panoramaData.location.latLng;
			this.displayContent();
		}

	}

	this.displayContent = function(){

		if(this.latLng != null){
			this.createDOMElement("a","StreetViewButtonObject streetViewButton");
			this.setDOMAttribute("href","javascript:void(0);");
			this.setDOMAttribute("title",this.label);
			this.setHTML("<span>"+this.label+"</span>");

			if(this.onClickFunction != null){

				var latLng = this.latLng;
				var thisObj = this;

				this.domElement.onclick = function(){
					thisObj.onClickFunction(latLng);
				}
			}

			if(this.onDisplay != null){
				this.onDisplay(this);
			}
		}
	}


}

StreetViewButtonObject.inherits(DisplayObject);

function StreetViewObject(){

	DisplayObject.call(this);

	this.panoramaOptions = new Object();
	this.panoramaOptions.visible = true;

	this.panoramaObj = null;

	this.onDisplay = null;

	this.loadStreetView = function(location){

		var regex = /^-?[\d\.]+,-?[\d\.]+$/;

		if(String(typeof location).toLowerCase() == "object"){// assume GLatLng has been passed

			this.panoramaOptions.position = location;

			this.displayContent();

		}else if (regex.test(location)) {// we've been passed geocodes

			location = location.split(",");

			this.panoramaOptions.position = new google.maps.LatLng(location[0],location[1]);

			this.displayContent();

		}else{// assume we've been passed address - try for geocodes

			var geocoder = new google.maps.ClientGeocoder();

			var thisObj = this;
			var onGeocodeLookup = function(point){
				thisObj.onGeocodeLookup(point);
			}
			geocoder.getLatLng(location,onGeocodeLookup);
		}

	}

	this.onGeocodeLookup = function(point){

		if(point == null){
			alert("Sorry, the location can't be found.");
		}else{
			this.panoramaOptions.position = point;
			this.displayContent();
		}

	}

	this.displayContent = function(){

		this.createDOMElement("div","StreetViewObject");

		if(this.onDisplay != null){
			this.onDisplay();
		}

	}

	this.initPanorama = function(){

		this.panoramaObj = new google.maps.StreetViewPanorama(this.domElement,this.panoramaOptions);

		google.maps.event.trigger(this.panoramaObj, "resize");
	}

}

StreetViewObject.inherits(DisplayObject);
function StreetViewLauncherObject(){

	DisplayObject.call(this);


	this.overlay = null;

	this.streetViewObj = null;

	this.loadStreetView = function(location){

		this.streetViewObj = new StreetViewObject();
		var thisObj = this;
		this.streetViewObj.onDisplay = function(){
			thisObj.displayContent();
		}
		this.streetViewObj.loadStreetView(location);

	}

	this.displayContent = function(){

		this.createOverlay();

		this.createContainer();

		this.streetViewObj.appendToElement(this.domElement);

		this.positionContainer();

		this.streetViewObj.initPanorama();
	}

	this.noFlashHandler = function(errorCode) {
		if (errorCode == 603) {
		    alert("Error: Flash doesn't appear to be supported by your browser");
    		return;
  		}
	}

	this.remove = function(){

		this.removeOverlay();
		this.removeContainer();
	}

	this.createContainer = function(){
		this.removeContainer();

		this.createDOMElement("div","StreetViewLauncherObject");

		var bodyObj = document.getElementsByTagName("body").item(0);

		this.appendToElement(bodyObj);

		this.setStyle("z-index",1002);

		var closeButton = this.addElement("a");

		closeButton.className = "closeButton";
		closeButton.href = "javascript:void(0);";
		closeButton.title = "Close StreetView";

		var thisObj = this;
		closeButton.onclick = function(){
			thisObj.remove();
		}

		closeButton.innerHTML = "<span>Close</span>";

	}

	this.removeContainer = function(){

		if(this.domElement != null && this.domElement.parentNode != null){
			this.domElement.parentNode.removeChild(this.domElement);
		}

	}

	this.positionContainer = function(){


		this.setStyle("position","absolute");

		// get image width and height

		var pageSizes = this.getPageSizeObject();

		var w = Math.min(pageSizes.windowWidth-20,800);
		var h = Math.min(pageSizes.windowHeight-20,660);

		this.maxImageWidth = w-40;
		this.maxImageHeight = h-90;

		this.setStyle("width",w+"px");
		this.setStyle("height",h+"px");

		this.streetViewObj.setStyle("height",(h - 31) + "px");
		this.streetViewObj.setStyle("margin","5px");

		var yScroll = this.getYScroll();

		var top = Math.max(0,yScroll + ((pageSizes.windowHeight - h) / 2));

		this.setStyle("top",top+"px");
		this.setStyle("left", Math.max(0,(pageSizes.pageWidth - w) / 2) + "px");

	}

	this.createOverlay = function(){

		this.removeOverlay();

		this.overlay = new OverlayObject();

		var thisObj = this;

		this.overlay.onRemoveFunction = function(){
			thisObj.remove();
		}

		this.overlay.displayContent();

		this.overlay.setStyle("z-index",1000);

	}

	this.removeOverlay = function(){
		if(this.overlay != null){
			this.overlay.remove();
			this.overlay = null;
		}
	}

}

StreetViewLauncherObject.inherits(DisplayObject);

StreetViewLauncher = new StreetViewLauncherObject();
/**
 * @author diccon
 */
function JSONSocketObject(httpRoot){

	this.httpRoot = httpRoot;

	this.jsonObjects = new Object();
	this.callbacks = new Object();

	this.globalVariable = "JSONSocket";


	this.makeCall = function(name,action,data,callback){

		var url = this.httpRoot+directoryIndex+"?action="+action;

		if(data != null){
			//url += "&data="+urlEncode(this.serialize(data));
			var dataStr = this.serialize(data);

			

			dataStr = dataStr.replace( /\u2018/g, "'" );
			dataStr = dataStr.replace( /\u2019/g, "'" );
			dataStr = dataStr.replace( /\u201c/g, '\\\"' );
			dataStr = dataStr.replace( /\u201d/g, '\\\"' );
			dataStr = dataStr.replace( /\u2013/g, '-' );
			dataStr = dataStr.replace( /\u2014/g, '--' );
			dataStr = dataStr.replace( /\uFFFD/g, "'" );
			dataStr = dataStr.replace( /\u2026/g,"...");
			dataStr = dataStr.replace( /\\xA3/g,"GBPOUNDSIGN");

			dataStr = escape(dataStr);

			dataStr = dataStr.replace( /GBPOUNDSIGN/g,"%A3");

			var regex = /%0D%0A/g;
			dataStr = dataStr.replace(regex,"%5Cn");

			//alert(dataStr);	
			url += "&data="+dataStr;

			//alert(url);

		}


		if(callback != null){
			url += "&callback="+this.registerCallback(name,callback);
		}

		if(this.jsonObjects[name] != null){
			this.jsonObjects[name].removeScriptTag();
		}

		this.jsonObjects[name] = new JSONscriptRequest(url);
		// Build the dynamic script tag
		this.jsonObjects[name].buildScriptTag();
		// Add the script tag to the page
		//alert('aa3'+this.jsonObjects[name].scriptObj);
		
		this.jsonObjects[name].addScriptTag();
	}

	this.registerCallback = function(name,func){
		this.callbacks[name] = func;
		return this.globalVariable+".callbacks['"+name+"']";
	}

	// Javascript serialize - thanks http://blog.stchur.com/2007/04/06/serializing-objects-in-javascript/

	this.serialize = function(_obj){

		if(_obj == null){
			return null;
		}
	   // Let Gecko browsers do this the easy way
	   if (typeof _obj.toSource !== 'undefined' && typeof _obj.callee === 'undefined'){
	      return _obj.toSource();
	   }

	   // Other browsers must do it the hard way
	   switch (typeof _obj){
	      // numbers, booleans, and functions are trivial:
	      // just return the object itself since its default .toString()
	      // gives us exactly what we want
	      case 'number':
	      case 'boolean':
	      case 'function':
	         return _obj;
	         break;

	      // for JSON format, strings need to be wrapped in quotes
	      case 'string':
	         return '"' + _obj.replace(/"/g,'\\"') + '"';
	         break;

	      case 'object':
	         var str;
	         if (_obj.constructor === Array || typeof _obj.callee !== 'undefined'){
	            str = '[';
	            var i, len = _obj.length;
	            for (i = 0; i < len-1; i++) { str += this.serialize(_obj[i]) + ','; }
	            str += this.serialize(_obj[i]) + ']';
	         } else {
	            str = '{';
	            var key;
	            for (key in _obj) { str += key + ':' + this.serialize(_obj[key]) + ','; }
	            str = str.replace(/\,$/, '') + '}';
	         }
	         return str;
	         break;

	      default:
	         return 'UNKNOWN';
	         break;
	   }
	}

	this.post = function(url,data,callback,timeout){

		if(typeof(JSONRequest) == "undefined"){
			alert("JSONRequest object must be loaded before posting data.");
			return;
		}

		JSONRequest.post(url,data,callback,timeout);

	}

}

/*if(typeof(httpRoot) == "undefined" && typeof(DTDSiteRoot) != "undefined"){
	var httpRoot = DTDSiteRoot;
}*/


var JSONSocket = new JSONSocketObject(httpRoot);


function RPWPropertySlideShowObject(dataObject){

	DisplayObject.call(this);

	// create container

	// sub-elements
	this.dataObject = dataObject;
	this.optionButtonsElement = null;
	this.saveButton = null;
	this.statusElement = null;

	this.imageArray = new Array();// array to store image elements, dataobjects and type (ieg image, floorplan, epc).
	this.imagePointer = 0;
	this.maxImageHeight = 600;
	this.maxImageWidth = 800;
	this.currentImageObject = null;

	this.enableStreetView = false;
	this.isStandAlone = false;

	this.imageTotal = 0;
	this.floorplanTotal = 0;

	this.onRemoveFunction = null;

	//

	this.RPWPropertySlideShowObject = function(){

		// create array of images including floorplans and epc

		if(this.dataObject.images != null){
			for(var i in this.dataObject.images){
				this.imageArray[i] = this.dataObject.images[i];
				this.imageArray[i].type = "image";
			}

			this.imageTotal = this.dataObject.images.length;
		}

		var index;
		if(this.dataObject.floorplans != null){
			for(var i in this.dataObject.floorplans){
				index = this.imageArray.length;
				this.imageArray[index] = this.dataObject.floorplans[i];
				this.imageArray[index].type = "floorplan";
			}

			this.floorplanTotal = this.dataObject.floorplans.length;
		}

		if(this.dataObject.epc != null){
			index = this.imageArray.length;
			this.imageArray[index] = this.dataObject.epc;
			this.imageArray[index].type = "epc";
		}


		this.createDOMElement("div","RPWSlideShow");
		this.setStyle("background","#FFF");

		this.setPosition();

	}

	this.setPosition = function(){


		this.setStyle("position","absolute");

		// get image width and height

		var pageSizes = this.getPageSizeObject();

		var w = Math.min(pageSizes.windowWidth-20,800);
		var h = Math.min(pageSizes.windowHeight-20,660);

		this.maxImageWidth = w-40;
		this.maxImageHeight = h-90;

		this.setStyle("width",w+"px");
		this.setStyle("height",h+"px");

		var yScroll = this.getYScroll();

		var top = Math.max(0,yScroll + ((pageSizes.windowHeight - h) / 2));

		this.setStyle("top",top+"px");
		this.setStyle("left", Math.max(0,(pageSizes.pageWidth - w) / 2) + "px");


	}


	this.displayContent = function(type){

		this.clearContents();

		this.addCloseButton();

		this.optionButtonsElement = this.getOptionButtonsElement();

		if(this.optionButtonsElement != null){
			this.domElement.appendChild(this.optionButtonsElement);
		}

		//this.optionButtonsElement.style.position ="absolute";
		//this.optionButtonsElement.style.top = (this.maxImageHeight + 40)+"px";
		//this.optionButtonsElement.style.width = this.maxImageWidth+"px";
		//this.optionButtonsElement.style.left = "20px";
		//this.optionButtonsElement.style.textAlign = "center";

		this.addStatusElement();

		if(this.imageArray.length > 0 || type == "streetview"){

			if(type != null){

				if (type == "streetview") {
					this.loadStreetView();
				} else {

					for (var i in this.imageArray) {
						if (type == this.imageArray[i].type) {
							this.loadImage(i);
							break;
						}
					}
				}
			}else{
				this.loadImage(0);
			}

			// add navigation

			if(this.imageArray.length > 1){

				this.addNavigation();


			}


		}

	}

	this.remove = function(e){

		if(this.onRemoveFunction != null){
			this.onRemoveFunction(this);
		}

	}


	/// IMAGE METHODS

	this.loadImage = function(index){

		this.imagePointer = index;

		if(this.imageArray[index] != null){

			var newImage;

			switch(this.imageArray[index].type){

				case "floorplan":
					newImage = new RPWFloorplanViewerObject(this.imageArray[index]);
					if(this.floorplanTotal > 1){
						this.setStatus("Floorplan "+(index-this.imageTotal+1)+" of "+this.floorplanTotal);
					}else{
						this.setStatus("Floorplan");
					}
					break;

				case "epc":
					newImage = new RPWPropertyImageObject(this.imageArray[index]);
					this.setStatus("EPC");
					break;
				default:
					newImage = new RPWPropertyImageObject(this.imageArray[index]);
					this.setStatus("Image "+(index+1)+" of "+this.imageTotal);
			}

			//newImage.setStyle("position","absolute");
			//newImage.setStyle("left","20px");
			//newImage.setStyle("top","20px");
			newImage.setOpacity(0);
			newImage.displayContent(this.maxImageWidth, this.maxImageHeight, 0);

			newImage.appendToElement(this.domElement);

			newImage.changeOpacity(100);

			this.removeCurrentImage();
			this.hideStreetView();

			this.currentImageObject = newImage;

		}
	}

	this.removeCurrentImage = function(){

		if(this.currentImageObject != null){

			var thisObj = this;
			var func = function(displayObject){ thisObj.unloadImage(displayObject); };

			this.currentImageObject.transformationEndFunctions["opacity"] = func;

			this.currentImageObject.changeOpacity(0);
		}

	}

	this.unloadImage = function(imageObject){

		imageObject.removeFromElement(this.domElement);

	}

	this.loadFloorplan = function(){

		if(this.imageArray != null){
			for(var i in this.imageArray){
				if(this.imageArray[i].type == "floorplan"){
					this.loadImage(i);
					return true;
				}
			}
		}

		return false;
	}

	this.loadEPC = function(){

		if(this.imageArray != null){
			for(var i in this.imageArray){
				if(this.imageArray[i].type == "epc"){
					this.loadImage(i);
					return true;
				}
			}
		}

		return false;
	}

	this.loadStreetView = function(){

		this.streetViewObj = new StreetViewObject();
		var thisObj = this;

		var location = (this.dataObject.latitude != null && this.dataObject.longitude != null) ? new google.maps.LatLng(this.dataObject.latitude, this.dataObject.longitude) : this.dataObject.postcode;

		this.streetViewObj.onDisplay = function(){
			thisObj.showStreetView();
		}

		this.streetViewObj.loadStreetView(location);

	}

	this.showStreetView = function(){

		this.removeCurrentImage();

		this.streetViewObj.setStyle("width",this.maxImageWidth+"px");
		this.streetViewObj.setStyle("height",this.maxImageHeight+"px");
		this.streetViewObj.setStyle("left","20px");
		this.streetViewObj.setStyle("top","30px");
		this.streetViewObj.setStyle("position","absolute");
		this.streetViewObj.setOpacity(0);

		this.streetViewObj.appendToElement(this.domElement);
		this.streetViewObj.initPanorama();
		this.streetViewObj.changeOpacity(100);
		this.setStatus("StreetView");
	}

	this.hideStreetView = function(){

		if (this.streetViewObj != null) {
			var thisObj = this;
			this.streetViewObj.transformationEndFunctions["opacity"] = function(displayObject){
				thisObj.removeStreetView(displayObject);
			}
			this.streetViewObj.changeOpacity(0);
		}
	}

	this.removeStreetView = function(displayObject){
		displayObject.removeFromElement(this.domElement);
		this.streetViewObj = null;
	}


	// STATUS METHODS

	this.addStatusElement = function(){

		this.statusElement = this.addElement("p");
		this.statusElement.className = "status";
		//this.statusElement.style.position = "absolute";
		//this.statusElement.style.top = (this.maxImageHeight + 40)+"px";
		//this.statusElement.style.left = "20px";

	}

	this.setStatus = function(msg){
		this.statusElement.innerHTML = msg;
	}



	// NAVIGATION METHODS

	this.addNavigation = function(){

		var thisObj = this;

		var p = this.addElement("p");
		p.className = "RPWSlideShowNavigation";

		//p.style.position = "absolute";
		//p.style.top = (this.maxImageHeight + 40)+"px";
		//p.style.right = "20px";

		var button = document.createElement("a");
		button.setAttribute("href","javascript:void(0);");
		button.className = "previous";
		button.title = "Previous";
		button.innerHTML = "<span>Previous</span>";
		button.onclick = function(){ thisObj.gotoPrevious();this.blur();};

		p.appendChild(button);

		p.appendChild(document.createTextNode(" "));

		button = document.createElement("a");
		button.setAttribute("href","javascript:void(0);");
		button.className = "next";
		button.title = "Next";
		button.innerHTML = "<span>Next</span>";
		button.onclick = function(){ thisObj.gotoNext();this.blur();};

		p.appendChild(button);

		this.domElement.appendChild(p);
	}

	this.gotoPrevious = function(){

		this.imagePointer --;
		if(this.imagePointer < 0){
			this.imagePointer = this.imageArray.length -1;
		}

		this.loadImage(this.imagePointer);

	}

	this.gotoNext = function(){

		this.imagePointer++;
		if(this.imagePointer >= this.imageArray.length){
			this.imagePointer = 0;
		}

		this.loadImage(this.imagePointer);

	}


	this.addCloseButton = function(){

		button = document.createElement("a");
		button.setAttribute("href","javascript:void(0);");
		button.className = "closeButton";
		button.title = "Close";
		button.innerHTML = "<span>Close</span>";

		var thisObj = this;
		button.onclick = function(){ thisObj.remove();};
		//button.style.position = "absolute";
		//button.style.top = "5px";
		//button.style.right = "5px";

		this.domElement.appendChild(button);

	}


	this.getOptionButtonsElement = function(){

		if(this.isStandAlone){
			return null;
		}


		var element = document.createElement("p");
		element.className = "optionButtons";

		this.saveButton = this.getSaveButtonElement();


		if(this.saveButton != null){
			this.markAsSaved(this.dataObject,this.parentObj.propertyIsSaved(this.dataObject));
			element.appendChild(this.saveButton);
		}

		var button,func;
		var thisObj = this;

		// FLOORPLAN BUTTON

		if(this.dataObject.floorplans != null){

			element.appendChild(document.createTextNode(" "));

			button = document.createElement("a");
			button.setAttribute("href","javascript:void(0);");
			button.className = "pOptionButton floorplan";

			var title = (this.dataObject.floorplans.length > 1)  ? "Floorplans" : "Floorplan";
			button.innerHTML = "<span>"+title+"</span>";
			button.title = title;

			func = function(){thisObj.loadFloorplan();this.blur();}

			button.onclick = func;

			element.appendChild(button);
		}

		// EPC BUTTON

		if(this.dataObject.epc != null){

			element.appendChild(document.createTextNode(" "));

			button = document.createElement("a");
			button.setAttribute("href","javascript:void(0);");
			button.className = "pOptionButton epc";
			button.innerHTML = "<span>EPC</span>";
			button.title = "EPC";

			func = function(){thisObj.loadEPC();this.blur();}

			button.onclick = func;

			element.appendChild(button);
		}

		// MAP BUTTON


		if(this.dataObject.latitude != null && this.dataObject.longitude != null && this.dataObject.latitude != 0 && this.dataObject.longitude != 0){

			element.appendChild(document.createTextNode(" "));

			button = document.createElement("a");
			button.setAttribute("href","javascript:void(0);");

			var thisObj = this;

			button.onclick = function(){thisObj.showOnMap(); this.blur();};

			button.className = "pOptionButton map";

			var text = (this.getAttribute("RPWPropertyListObject.mapLabel")) ? this.getAttribute("RPWPropertyListObject.mapLabel") : "Show on map";

			button.innerHTML = "<span>"+text+"</span>";
			button.title = text;

			element.appendChild(button);

		}


		// STREET VIEW BUTTON


		if(this.enableStreetView && ((this.dataObject.latitude != null && this.dataObject.longitude != null) || this.dataObject.postcode.length > 6)){

			element.appendChild(document.createTextNode(" "));

			var location = (this.dataObject.latitude != null && this.dataObject.longitude != null) ? new google.maps.LatLng(this.dataObject.latitude, this.dataObject.longitude) : this.dataObject.postcode;
			var button = new StreetViewButtonObject();
			var thisObj = this;
			button.onClickFunction = function(){
				thisObj.loadStreetView();
			}
			button.onDisplay = function(button){
				thisObj.attachStreetviewButton(button);
			}
			button.load(location);

		}

		return element;

	}

	this.attachStreetviewButton = function(button){
		button.appendToElement(this.optionButtonsElement);
		button.setClass("pOptionButton streetview");
	}



	this.getSaveButtonElement = function(){

		if (this.showSaveButton) {
			var element = document.createElement("a");
			element.setAttribute("href", "javascript:void(0);");

			var thisObj = this;
			element.onclick = function(e){
				thisObj.toggleSaved(e);
				this.blur();
			};

			element.className = "pOptionButton saveToShortlist";
			element.innerHTML = "<span>Save to shortlist</span>";
			element.title = "Save to shortlist";


			return element;

		}

		return null;

	}

	this.toggleSaved = function(e){

		if(!this.parentObj.propertyIsSaved(this.dataObject)){

			this.parentObj.saveProperty(this.dataObject);

		}else{

			this.parentObj.removeSavedProperty(this.dataObject);

		}

	}

	this.markAsSaved = function(dataObject,saved){

		if(dataObject.db == this.dataObject.db && dataObject.pcode == this.dataObject.pcode){

			if(saved){
				this.saveButton.className = "pOptionButton removeFromShortlist";
				this.saveButton.title = "Remove from shortlist";
				this.saveButton.innerHTML = "<span>Remove from shortlist</span>";
			}else{
				this.saveButton.className = "pOptionButton saveToShortlist";
				this.saveButton.title = "Save to shortlist";
				this.saveButton.innerHTML = "<span>Save to shortlist</span>";
			}

		}
	}


	this.showOnMap = function(){
		this.parentObj.showPropertyOnMap(this.dataObject);
		this.remove();
	}



	// init constructor

	this.RPWPropertySlideShowObject();

}

RPWPropertySlideShowObject.inherits(DisplayObject);

function RPWPropertyImageObject(dataObject){

	DisplayObject.call(this);

	this.dataObject = dataObject;

	// Constructor

	this.RPWPropertyImageObject = function(){

		this.createDOMElement("div","RPWPropertyImageObject");

	}

	this.displayContent = function(maxWidth,maxHeight,crop){

		// add image

		//this.imageElement = this.addElement("img",null,"src",httpRoot+"index.php?action=getthumbnail&filepath="+this.dataObject.filepath+"&width="+maxWidth+"&height="+maxHeight+"&quality=85&crop="+crop);
		this.imageElement = this.addElement("img",null,"src",httpRoot+"index.php?action=getthumbnail&filepath="+this.dataObject.filepath+"&width=800&height=600&quality=85&crop="+crop);
		if(dataObject.caption != null){
			this.imageElement.title = dataObject.caption;
		}

		// get sizes
		var w,h;

		if(this.dataObject.width/this.dataObject.height > maxWidth/maxHeight){

			w = maxWidth;
			h = this.dataObject.height * maxWidth/this.dataObject.width;

		}else{

			h = maxHeight;
			w = this.dataObject.width * maxHeight/this.dataObject.height;
		}

		this.setStyle("width", w+"px");
		this.setStyle("height", h+"px");

		this.imageElement.setAttribute("width",w);
		this.imageElement.setAttribute("height",h);

		this.setStyle("left",(20+((maxWidth-w)/2))+"px");
		this.setStyle("top",(30+((maxHeight-h)/2))+"px");


		if(this.dataObject.description != null){


		}

	}

	this.RPWPropertyImageObject();

}

RPWPropertyImageObject.inherits(DisplayObject);

function RPWFloorplanViewerObject(dataObject){

	DisplayObject.call(this);

	// create container

	// sub-elements
	this.dataObject = dataObject;

	this.mouseX = null;
	this.mouseY = null;

	this.apertureWidth = null;
	this.apertureHeight = null;

	this.dragAreaObject = null;

	this.RPWFloorplanViewerObject = function(){

		this.createDOMElement("div","RPWFloorplanViewer");
		this.setStyle("overflow","hidden");
		this.setStyle("position","relative");

	}

	this.displayContent = function(w,h){

		this.apertureWidth = w;
		this.apertureHeight = h;

		// add image

		this.imageElement = new DisplayObject();
		this.imageElement.createDOMElement("img");

		//this.imageElement.setDOMAttribute("src",this.dataObject.httppath);
		this.imageElement.setDOMAttribute("src", httpRoot+"index.php?action=getthumbnail&filepath="+this.dataObject.filepath+"&width=1200&height=1200&quality=85&crop=0");

		this.imageElement.setStyle("position","absolute");

		var d = this.getWindowFitDimensions();
		this.imageElement.setStyle("left",d.x+"px");
		this.imageElement.setStyle("top",d.y+"px");
		this.imageElement.setStyle("width",d.width+"px");
		this.imageElement.setStyle("height",d.height+"px");

		this.imageElement.appendToElement(this.domElement);

		this.dragAreaObject = this.addElement("div");
		this.dragAreaObject.style.position = "absolute";
		this.dragAreaObject.style.width = w+"px";
		this.dragAreaObject.style.height = h+"px";
		this.dragAreaObject.style.cursor = "move";
		this.dragAreaObject.style.background = "#FFF";
		this.setOpacity(0,this.dragAreaObject);

		var controlElement = this.getControlElement();
		controlElement.style.position = "absolute";
		this.domElement.appendChild(controlElement);



		this.setStyle("width", w+"px");
		this.setStyle("height", h+"px");

		this.setStyle("left","20px");
		this.setStyle("top","30px");

		this.setStyle("border","1px solid #AAA");

		this.addMouseListener();

	}


	// CONTROLS

	this.getControlElement = function(){

		var element = document.createElement("p");
		element.className = "controlButtons";

		var thisObj = this;

		var zoomInButton = document.createElement("a");
		zoomInButton.href = "javascript:void(0);";
		zoomInButton.onclick = function(){thisObj.zoomIn();this.blur();};
		zoomInButton.className = "zoomIn";
		zoomInButton.title = "Zoom in";
		zoomInButton.innerHTML = "<span>Zoom in</span>";

		element.appendChild(zoomInButton);

		element.appendChild(document.createTextNode(" "));

		var zoomOutButton = document.createElement("a");
		zoomOutButton.href = "javascript:void(0);";
		zoomOutButton.className = "zoomOut";
		zoomOutButton.onclick = function(){thisObj.zoomOut();this.blur();};
		zoomOutButton.title = "Zoom out";
		zoomOutButton.innerHTML = "<span>Zoom out</span>";

		element.appendChild(zoomOutButton);

		element.appendChild(document.createTextNode(" "));

		var fitInWindowButton = document.createElement("a");
		fitInWindowButton.href = "javascript:void(0);";
		fitInWindowButton.className = "fitInWindow";
		fitInWindowButton.onclick = function(){thisObj.fitInWindow();this.blur();};
		fitInWindowButton.title = "Fit in window";
		fitInWindowButton.innerHTML = "<span>Fit in window</span>";

		element.appendChild(fitInWindowButton);

		element.appendChild(document.createTextNode(" "));

		var printButton = document.createElement("a");
		printButton.href = "javascript:void(0);";
		printButton.className = "print";
		printButton.onclick = function(){thisObj.print();this.blur();};
		printButton.title = "Print";
		printButton.innerHTML = "<span>Print</span>";

		element.appendChild(printButton);

		return element;

	}

	// LISTENERS

	this.addMouseListener = function(){

		var thisObj = this;

		this.dragAreaObject.onmousedown = function(e){ thisObj.addMouseMoveListener(e);return false;};

		this.dragAreaObject.onmouseup = function(e){ thisObj.removeMouseMoveListener(e);};

		this.dragAreaObject.onmouseout = function(e){ thisObj.removeMouseMoveListener(e);};
	}

	this.addMouseMoveListener = function(event){


		event = (!event) ? window.event : event;

		if(event.preventDefault){
			event.preventDefault();
		}

		this.mouseX = event.clientX;
		this.mouseY = event.clientY;

		var thisObj = this;
		this.dragAreaObject.onmousemove = function(e){ thisObj.positionPlan(e);}

		return false;

	}

	this.removeMouseMoveListener = function(event){

		this.dragAreaObject.onmousemove = null;

	}




	// CONTROL METHODS


	this.positionPlan = function(e){

		e = (!e) ? window.event : e;

		this.imageElement.setStyle("left", (parseInt(this.imageElement.getStyle("left")) + e.clientX-this.mouseX)+"px");
		this.imageElement.setStyle("top", (parseInt(this.imageElement.getStyle("top")) + e.clientY-this.mouseY)+"px");
		this.mouseX = e.clientX;
		this.mouseY = e.clientY;

	}

	this.zoomIn = function(){
		this.zoom(2);
	}

	this.zoomOut = function(){
		this.zoom(0.5);
	}

	this.zoom = function(ratio){

		// calculate current position;

		var steps = 10;

		var offsetX = parseInt(this.imageElement.getStyle("left"))-(this.apertureWidth/2);
		var offsetY = parseInt(this.imageElement.getStyle("top"))-(this.apertureHeight/2);

		var w = parseInt(this.imageElement.getStyle("width"));
		var h = parseInt(this.imageElement.getStyle("height"));

		w *= ratio;
		h *= ratio;

		offsetX *= ratio;
		offsetY *= ratio;

		offsetX += (this.apertureWidth/2);
		offsetY += (this.apertureHeight/2);


		this.imageElement.changeDimension("left",offsetX,steps);
		this.imageElement.changeDimension("top",offsetY,steps);

		this.imageElement.changeDimension("width",w,steps);
		this.imageElement.changeDimension("height",h,steps);

	}

	this.fitInWindow = function(){

		var d = this.getWindowFitDimensions();
		var steps = 10;

		this.imageElement.changeDimension("left",d.x,steps);
		this.imageElement.changeDimension("top",d.y,steps);

		this.imageElement.changeDimension("width",d.width,steps);
		this.imageElement.changeDimension("height",d.height,steps);

	}

	this.getWindowFitDimensions = function(){

		var newWidth, newHeight, newX, newY;

		if(this.dataObject.width/this.dataObject.height > this.apertureWidth/this.apertureHeight){

			newWidth = this.apertureWidth;
			newHeight = this.dataObject.height*this.apertureWidth/this.dataObject.width;

		}else{
			newHeight = this.apertureHeight;
			newWidth = this.dataObject.width*this.apertureHeight/this.dataObject.height;

		}

		newX = (this.apertureWidth-newWidth)/2;
		newY = (this.apertureHeight-newHeight)/2;

		return { x: newX, y: newY, width: newWidth, height: newHeight };

	}

	// PRINT METOHDS

	this.print = function(){
		// We break the closing script tag in half to prevent
		// the HTML parser from seeing it as a part of
		// the *main* page.

		var pageContent = "<html>\n" +
		"<head>\n" +
		"<title>Printing floorplan . . .</title>\n" +
		"<script>\n" +
		"function step1() {\n" +
		"  setTimeout('step2()', 10);\n" +
		"}\n" +
		"function step2() {\n" +
		"  window.print();\n" +
		"  window.close();\n" +
		"}\n" +
		"</scr" + "ipt>\n" +
		"</head>\n" +
		"<body onLoad='step1()'>\n" +
		"<img src='" + httpRoot+"index.php?action=getthumbnail&filepath="+this.dataObject.filepath+"&width=1200&height=1200&quality=85&crop=0'/>\n" +
		"</body>\n" +
		"</html>\n";

		var pw = window.open("about:blank", "_new");
		pw.document.open();
		pw.document.write(pageContent);
		pw.document.close();
	}


	// init constructor

	this.RPWFloorplanViewerObject();

}

RPWFloorplanViewerObject.inherits(DisplayObject);



/* Object to connect to RPW server, perform searches and store JSON data */

function RPWSearchSocketObject(httpRoot){

	JSONSocketObject.call(this,httpRoot);

	this.globalVariable = "RPWSearchSocket";

	this.searchSettings = new Object();// associative array object to hold search settings

	this.sessionName = "propertysearch";

	this.onResultLoadAction = null;// method to call on result load.

	this.onSearchSettingsLoadAction = null;

	this.onSearchStartAction = null;

	this.onSearchCompleteAction = null;

	this.onShortlistLoadAction = null;

	this.onSearchFormAttributesLoadAction = null;

	this.onUserPreferencesLoadAction = null;

	this.userPreferences = new Object();

	this.onSchoolsLoadAction = null;

	this.onStationsLoadAction = null;

	this.onOfficeLoadAction = null;

	this.onCachedTotalLoadAction = null;

	this.cachedTotalLoadCancelled = false;

	this.cachedTotalOptionArray = null;// array to hold JSON objects {setting: value}

	this.cachedTotalOptionIndex = 0;

	this.resultSet = null;// object to hold result data

	this.resultTotal = 0;

	this.googleMapData = null;

	this.propertyPExtras = null;

	this.settingsChanged = false;

	this.webUserData = null;

	// JSON objects

	this.searchJsonObj = null;
	this.resultsJsonObj = null;
	this.settingsJsonObj = null;
	this.shortlistJsonObj = null;
	this.searchFormAttributesJsonObj = null;
	this.schoolsJsonObj = null;
	this.officeJsonObj = null;
	this.stationsJsonObj = null;
	this.preferencesJsonObj = null;
	this.savePreferencesJsonObj = null;
	this.cachedTotalJsonObj = null;

	// URL hooks

	this.searchURL = "index.php?action=propertysearchjson";
	this.resultsURL = "index.php?action=searchresultsjson";
	this.schoolsURL = "index.php?action=getschoolsjson";
	this.stationsURL = "index.php?action=getstationsjson";
	this.officesURL = "index.php?action=getofficesjson";
	this.searchSettingsURL = "index.php?action=getsearchsettingsjson";
	this.searchFormAttributesURL = "index.php?action=getsearchformattributesjson";
	this.cachedTotalURL = "index.php?action=getcachedtotal";

	// Search Methods

	this.doSearch = function(callback){

		this.cancelCachedTotalLoad(true);

		if(this.onSearchStartAction != null){
			this.onSearchStartAction();
		}

		this.settingsChanged = false;// commit state

		if(callback != null){
			this.onSearchCompleteAction = callback;
		}

		this.resetData();

		var url = this.httpRoot+this.searchURL+"&sessionname="+this.sessionName;

		url += "&"+this.getSearchSettingsString();

		url += "&callback=RPWSearchSocket.onSearchComplete";

		//alert(url);

		if(this.searchJsonObj != null){
			this.searchJsonObj.removeScriptTag();
		}

		this.searchJsonObj = new JSONscriptRequest(url);
		// Build the dynamic script tag
		this.searchJsonObj.buildScriptTag();
		// Add the script tag to the page
		this.searchJsonObj.addScriptTag();

	}

	this.resetData = function(){

		this.resultSet = null;
		this.resultTotal = 0;
		this.googleMapData = null;

	}

	this.onSearchComplete = function(data){

		this.resultTotal = data.resultTotal;

		if(this.onSearchCompleteAction != null){
			this.onSearchCompleteAction(data);
		}

	}

	this.getResultSet = function(offset,displayCount,callback,offices,schools){

		this.cancelCachedTotalLoad();// cancel cached total load while we load results

		if(callback != null){
			this.onResultLoadAction = callback;
		}

		var url = this.httpRoot+this.resultsURL+"&sessionname="+this.sessionName+"&offset="+offset+"&displaycount="+displayCount+"&callback=RPWSearchSocket.onResultLoad";

		url += (offices) ? "&getoffices=true" : "";
		url += (schools) ? "&getschools=true" : "";

		if(this.resultsJsonObj != null){
			this.resultsJsonObj.removeScriptTag();
		}

		if(this.propertyPExtras != null){
			url+= "&extras="+urlEncode(this.propertyPExtras);
		}


		this.resultsJsonObj = new JSONscriptRequest(url);
		// Build the dynamic script tag
		this.resultsJsonObj.buildScriptTag();
		// Add the script tag to the page
		this.resultsJsonObj.addScriptTag();

	}

	this.onResultLoad = function(data){

		if(this.onResultLoadAction != null){
			this.onResultLoadAction(data);
		}

		this.resumeCachedTotalLoad();

	}

	this.getResultTotal = function(){

		return this.resultTotal;

	}

	this.setCachedPropertyOptions = function(settingsOptions, callback){

		if(callback != null){
			this.onCachedTotalLoadAction = callback;
		}

		if(settingsOptions != null && settingsOptions.length > 0){// we have settings - proceed

			this.cachedTotalOptionArray = settingsOptions;
			this.cachedTotalOptionIndex = 0;

		}

	}

	this.getCachedPropertyTotal = function(altSetting,altValue,callback){

		if(callback != null){
			this.onCachedTotalLoadAction = callback;
		}

		var url = this.httpRoot+this.cachedTotalURL+"&sessionname="+this.sessionName;

		var altValueSet = false;
		var altMaxPrice = false;
		var altMaxPriceSet = false;

		if(altSetting == "price" && /^\d+-(\d+|~)$/.test(altValue)) {
			var matches = /^(\d+)-(\d+|~)$/.exec(altValue);
			altSetting = "min_price";
			altValue = matches[1];
			altMaxPrice = matches[2];
		}


		for(var i in this.searchSettings){

			if (i == "max_price" && altMaxPrice) {
				url += "&max_price="+escape(altMaxPrice);
				altMaxPriceSet = true;
			}else if(altSetting == i){
				url += "&"+altSetting+"="+escape(altValue);
				altValueSet = true;
			}else if(this.searchSettings[i] != null){
				url += "&"+i+"="+escape(this.searchSettings[i]);
			}

		}

		if(altSetting != null && !altValueSet){
			url += "&"+altSetting+"="+escape(altValue);
		}

		if(altMaxPrice && !altMaxPriceSet){
			url += "&max_price="+escape(altMaxPrice);
		}

		url += "&callback=RPWSearchSocket.onCachedTotalLoad";

		if(this.cachedTotalJsonObj != null){
			this.cachedTotalJsonObj.removeScriptTag();
		}


		this.cachedTotalJsonObj = new JSONscriptRequest(url);
		// Build the dynamic script tag
		this.cachedTotalJsonObj.buildScriptTag();
		// Add the script tag to the page
		this.cachedTotalJsonObj.addScriptTag();
	}

	this.onCachedTotalLoad = function(data){

		if(this.onCachedTotalLoadAction != null){

			if(this.cachedTotalOptionArray != null && this.cachedTotalOptionArray.length > 0){
				data.setting = this.cachedTotalOptionArray[this.cachedTotalOptionIndex].setting;
				data.value = this.cachedTotalOptionArray[this.cachedTotalOptionIndex].value;
			}

			this.onCachedTotalLoadAction(data);
		}

		if(!this.cachedTotalLoadCancelled && this.cachedTotalOptionArray != null && this.cachedTotalOptionArray.length > 0){// process not cancelled

			this.cachedTotalOptionIndex++;

			if (this.cachedTotalOptionIndex < this.cachedTotalOptionArray.length) {// we still have more to get
				this.getCachedPropertyTotal(this.cachedTotalOptionArray[this.cachedTotalOptionIndex].setting, this.cachedTotalOptionArray[this.cachedTotalOptionIndex].value);
			}else{// reset index
				this.cachedTotalOptionIndex = 0;
			}
		}

	}

	this.cancelCachedTotalLoad = function(reset){
		if(reset){// start from beginning again
			this.cachedTotalOptionIndex = 0;
		}
		this.cachedTotalLoadCancelled = true;
	}

	this.resumeCachedTotalLoad = function(reset){

		this.cachedTotalLoadCancelled = false;

		if(reset){// start from beginning again
			this.cachedTotalOptionIndex = 0;
		}

		if (this.onCachedTotalLoadAction != null && this.cachedTotalOptionArray != null && this.cachedTotalOptionArray.length > 0) {// we have settings to query
			if (this.cachedTotalOptionIndex < this.cachedTotalOptionArray.length) {// we still have more to get
				this.getCachedPropertyTotal(this.cachedTotalOptionArray[this.cachedTotalOptionIndex].setting, this.cachedTotalOptionArray[this.cachedTotalOptionIndex].value);
			}
		}
	}

	// SCHOOLS METHODS


	this.getSchools = function(lat1,lat2,lng1,lng2,callback){

		if(callback != null){
			this.onSchoolsLoadAction = callback;
		}

		var url = this.httpRoot+this.schoolsURL+"&lat1="+lat1+"&lat2="+lat2+"&lng1="+lng1+"&lng2="+lng2+"&callback=RPWSearchSocket.onSchoolsLoad";

		if(this.schoolsJsonObj != null){
			this.schoolsJsonObj.removeScriptTag();
		}


		this.schoolsJsonObj = new JSONscriptRequest(url);
		// Build the dynamic script tag
		this.schoolsJsonObj.buildScriptTag();
		// Add the script tag to the page
		this.schoolsJsonObj.addScriptTag();

	}

	this.onSchoolsLoad = function(data){

		if(this.onSchoolsLoadAction != null){
			this.onSchoolsLoadAction(data);
		}

	}

	// STATIONS METHODS


	this.getStations = function(lat1,lat2,lng1,lng2,callback){

		if(callback != null){
			this.onStationsLoadAction = callback;
		}

		var url = this.httpRoot+this.stationsURL+"&lat1="+lat1+"&lat2="+lat2+"&lng1="+lng1+"&lng2="+lng2+"&callback=RPWSearchSocket.onStationsLoad";

		if(this.stationsJsonObj != null){
			this.stationsJsonObj.removeScriptTag();
		}

		this.stationsJsonObj = new JSONscriptRequest(url);
		// Build the dynamic script tag
		this.stationsJsonObj.buildScriptTag();
		// Add the script tag to the page
		this.stationsJsonObj.addScriptTag();

	}

	this.onStationsLoad = function(data){

		if(this.onStationsLoadAction != null){
			this.onStationsLoadAction(data);
		}

	}
	// OFFICES METHODS


	this.getOffices = function(lat1,lat2,lng1,lng2,callback){

		if(callback != null){
			this.onOfficesLoadAction = callback;
		}

		var url = this.httpRoot+this.officesURL+"&lat1="+lat1+"&lat2="+lat2+"&lng1="+lng1+"&lng2="+lng2+"&callback=RPWSearchSocket.onOfficesLoad";

		if(this.getSearchSetting("searchtype") == "sales" || this.getSearchSetting("searchtype") == "lettings"){
			url+= "&searchtype="+this.getSearchSetting("searchtype");
		}

		if(this.officesJsonObj != null){
			this.officesJsonObj.removeScriptTag();
		}


		this.officesJsonObj = new JSONscriptRequest(url);
		// Build the dynamic script tag
		this.officesJsonObj.buildScriptTag();
		// Add the script tag to the page
		this.officesJsonObj.addScriptTag();

	}

	this.onOfficesLoad = function(data){

		if(this.onOfficesLoadAction != null){
			this.onOfficesLoadAction(data);
		}

	}

	// Setting Methods

	this.inputSearchSetting = function(inputObj){// method to accept input from form elements (eg INPUT, SELECT etc)

		var value;

		switch(inputObj.nodeName.toLowerCase()){
			case "input":
				switch(inputObj.type){
					case "checkbox":
						if(inputObj.checked){
							value = inputObj.value;
						}else{
							value = null;
						}

						if(/dep_\d/.test(inputObj.name)){
							this.setMultiSelectSearchSetting(inputObj.name.substr(0,5),inputObj.value,value);
						}else{
							this.setSearchSetting(inputObj.name,value);
						}
						break;

					case "text":
						this.setSearchSetting(inputObj.name,inputObj.value);
					}

				break;

			case "select":
				var selectedArray = new Array();
				for (i=0; i<inputObj.options.length; i++) {
					if (inputObj.options[i].selected) {
						selectedArray.push(inputObj.options[i].value);
					}
				}

				selectedArray = (selectedArray.length > 0) ? selectedArray.join(",") : null;
				this.setSearchSetting(inputObj.name,selectedArray);
				break;
		}

	}

	this.getSearchSettings = function(){
		return this.searchSettings;
	}

	this.getSearchSettingsString = function(){

		var str = "";

		for(var i in this.searchSettings){

			if(this.searchSettings[i] != null){
				str += (str == "") ? "" : "&";
				str += i+"="+escape(this.searchSettings[i]);
			}

		}

		return str;

	}

	this.setMultiSelectSearchSetting = function(setting,value,selected){

		var regex = new RegExp("(^|,)"+value+"(,|$)", "g");
		if(this.searchSettings[setting] != null && !selected){// remove dep from stored list
			this.searchSettings[setting] = this.searchSettings[setting].replace(regex,",");
		}else{
			if(this.searchSettings[setting] == null){
				this.searchSettings[setting] = new String(value);
			}else if(!regex.test(this.searchSettings[setting])){// dep not already set, add it
				this.searchSettings[setting] += (this.searchSettings[setting] == "") ? "" : ",";
				this.searchSettings[setting] += value;
			}
		}
		this.searchSettings[setting] = this.searchSettings[setting].replace(/^,/,"").replace(/,$/,"").replace(/,,/,",");

		this.settingsChanged = true;

	}

	this.setSearchSetting = function(a,v){

		if(a == "price"){
			if (v == null) {
				this.setSearchSetting("min_price", null);
				this.setSearchSetting("max_price", null);
			} else if (/^\d+-(\d+|~)$/.test(v)) {
				var matches = /^(\d+)-(\d+|~)$/.exec(v);
				this.setSearchSetting("min_price", matches[1]);
				this.setSearchSetting("max_price", matches[2]);
			}
			return;
		}

		if(v == null && this.searchSettings[a] != null){
			delete this.searchSettings[a];
		}else{
			this.searchSettings[a] = v;
		}

		this.settingsChanged = true;
	}

	this.setSearchSettings = function(str){

		var settings = str.split("&");
		var pair;

		for(var i in settings){
			if(settings[i].indexOf("=") != -1){
				pair = settings[i].split("=");
				this.setSearchSetting(pair[0],pair[1]);
			}
		}

	}

	this.getSearchSetting = function(a){

		return this.searchSettings[a];

	}

	this.clearSearchSettings = function(){

		this.searchSettings = new Object();

	}

	this.clearAreas = function(){
		for(var i in this.searchSettings){
			if(i.substr(0,8) == "area_str"){
				delete this.searchSettings[i];
			}
		}
	}

	this.getSetOffices = function(){
		var officeArray = new Array();

		if(this.getSearchSetting("ocode")){
			officeArray.push(this.getSearchSetting("ocode"));
		}

		for(var i in this.searchSettings){
			if(i.substr(0,8) == "area_str" && this.searchSettings[i] != null && this.searchSettings[i].substr(0,5) == "ocode"){
				officeArray.push(this.searchSettings[i].substr(5));
			}
		}

		return (officeArray.length > 0) ? officeArray : null;
	}

	this.loadSettings = function(){

		var url = this.httpRoot+this.searchSettingsURL+"&sessionname="+this.sessionName+"&searchtype="+this.getSearchSetting("searchtype");

		if(this.settingsJsonObj != null){
			this.settingsJsonObj.removeScriptTag();
		}

		url += "&callback=RPWSearchSocket.onSettingsLoad";

		this.settingsJsonObj = new JSONscriptRequest(url);
		// Build the dynamic script tag
		this.settingsJsonObj.buildScriptTag();
		// Add the script tag to the page
		this.settingsJsonObj.addScriptTag();

	}

	this.onSettingsLoad = function(data){

		if (data.searchtype == this.getSearchSetting("searchtype")) {

			for (i in data) {

				if(i == "webuser"){
					this.setWebUserData(data[i]);
				}else{
					this.searchSettings[i] = data[i];
				}
			}

			if (data.resultTotal != null) {
				this.resultTotal = data.resultTotal;
			}

		}

		if(data.interestRate != null){
			this.searchSettings["interestRate"] = data.interestRate;
		}

		this.settingsChanged = false;

		if(this.onSearchSettingsLoadAction != null){
			this.onSearchSettingsLoadAction(data);
		}
	}

	this.setWebUserData = function(data){
		this.webUserData = data;
	}

	this.getWebUserData = function(){
		return this.webUserData;
	}

	this.loadSearchFormAttributes = function(qString){

		var url = this.httpRoot+this.searchFormAttributesURL;

		if(this.searchFormAttributesJsonObj != null){
			this.searchFormAttributesJsonObj.removeScriptTag();
		}

		if(qString != null){
			url += "&"+qString;
		}

		url += "&callback=RPWSearchSocket.onSearchFormAttributesLoad";

		this.searchFormAttributesJsonObj = new JSONscriptRequest(url);
		// Build the dynamic script tag
		this.searchFormAttributesJsonObj.buildScriptTag();
		// Add the script tag to the page
		this.searchFormAttributesJsonObj.addScriptTag();

	}

	this.onSearchFormAttributesLoad = function(data){
		if(this.onSearchFormAttributesLoadAction != null){
			this.onSearchFormAttributesLoadAction(data);
		}
	}

	this.loadUserPreferences = function(callback){

		if(callback != null){
			this.onUserPreferencesLoadAction = callback;
		}

		var url = this.httpRoot+"index.php?action=getuserpreferencesjson";

		if(this.preferencesJsonObj != null){
			this.preferencesJsonObj.removeScriptTag();
		}

		url += "&callback=RPWSearchSocket.onUserPreferencesLoad";

		this.preferencesJsonObj = new JSONscriptRequest(url);
		// Build the dynamic script tag
		this.preferencesJsonObj.buildScriptTag();
		// Add the script tag to the page
		this.preferencesJsonObj.addScriptTag();

	}

	this.onUserPreferencesLoad = function(data){

		if(data != null && data.preferences != null){

			var j;
			for(var i in data.preferences){
				for (j in data.preferences[i]) {
					//alert(j+"="+data.preferences[i][j]);
					this.userPreferences[j] = data.preferences[i][j];
				}
			}
		}


		if(this.onUserPreferencesLoadAction != null){
			this.onUserPreferencesLoadAction(data);
		}

	}

	this.setUserPreference = function(pref, val){

		//alert("save "+pref+" = "+val);

		this.userPreferences[pref] = val;

	}

	this.saveUserPreference = function(pref,val){

		//alert("save "+pref+" = "+val);

		this.userPreferences[pref] = val;

		var url = this.httpRoot+"index.php?action=saveuserpreferencejson";

		url += "&preference="+pref+"&value="+val;

		if(this.savePreferencesJsonObj != null){
			this.savePreferencesJsonObj.removeScriptTag();
		}

		url += "&callback=RPWSearchSocket.onUserPreferenceSave";

		this.savePreferencesJsonObj = new JSONscriptRequest(url);
		// Build the dynamic script tag
		this.savePreferencesJsonObj.buildScriptTag();
		// Add the script tag to the page
		this.savePreferencesJsonObj.addScriptTag();

	}

	this.getUserPreference = function(pref){
		if(this.userPreferences != null && this.userPreferences[pref] != null){
			return this.userPreferences[pref];
		}
		return null;
	}

	this.onUserPreferenceSave = function(data){

	}

	// WEBSTAT Methods

	this.saveWebStat = function(identifier,type){

		if (this.webStatURL != null) {

			type = (type == null) ? "d" : type;

			var url = this.httpRoot + this.webStatURL+"&property="+identifier+"&type="+type;

			url += "&callback=RPWSearchSocket.onWebStatSave";

			this.webStatJsonObj = new JSONscriptRequest(url);
			// Build the dynamic script tag
			this.webStatJsonObj.buildScriptTag();
			// Add the script tag to the page
			this.webStatJsonObj.addScriptTag();

		}
	}

	this.onWebStatSave = function(data){

	}

	// Shortlist methods

	this.saveShortlistToSession = function(shortlist,itemObject){

		var url = this.httpRoot+"index.php?action=savecartjson&cart="+shortlist+"&items=";

		for(var i in itemObject){

			url += (i > 0) ? "," : "";

			url += itemObject[i].db+"-"+itemObject[i].pcode;

		}


		url += "&callback=RPWSearchSocket.onShortlistSave";

		if(this.shortlistJsonObj != null){
			this.shortlistJsonObj.removeScriptTag();
		}

		this.shortlistJsonObj = new JSONscriptRequest(url);
		// Build the dynamic script tag
		this.shortlistJsonObj.buildScriptTag();
		// Add the script tag to the page
		this.shortlistJsonObj.addScriptTag();


	}

	this.onShortlistSave = function(dataObj){
		//alert("saved");
	}

	this.loadShortlist = function(shortlist,callback){

		if(callback != null){
			this.onShortlistLoadAction = callback;
		}

		var url = this.httpRoot+"index.php?action=getshortlistitemsjson&cart="+shortlist;

		url += "&callback=RPWSearchSocket.onShortlistLoad";

		if(this.shortlistJsonObj != null){
			this.shortlistJsonObj.removeScriptTag();
		}

		this.shortlistJsonObj = new JSONscriptRequest(url);
		// Build the dynamic script tag
		this.shortlistJsonObj.buildScriptTag();
		// Add the script tag to the page
		this.shortlistJsonObj.addScriptTag();


	}

	this.onShortlistLoad = function(dataObj){
		if(this.onShortlistLoadAction != null){
			this.onShortlistLoadAction(dataObj);
		}
	}


}

RPWSearchSocketObject.inherits(JSONSocketObject);

// create global instance of search socket object

var RPWSearchSocket = new RPWSearchSocketObject(httpRoot);


// Inheritance method
if(!Function.inherits){
	Function.prototype.inherits = function(superclass){
		var x = function(){
		};
		x.prototype = superclass.prototype;
		this.prototype = new x();
	}
}

function FormObject(name, action, method){

	this.name = name;
	this.action = action;
	this.method = method;

	this.inputArray = new Array();
	this.hiddenFieldArray = new Array();

	// Inherit Display object
	DisplayObject.call(this);

	//

	this.FormObject = function(){

		this.createDOMElement("form");

		if(this.name){
			this.setDOMAttribute("name", this.name);
		}

		if(this.action){
			this.setDOMAttribute("action", this.action);
		}

		if(this.method){
			this.setDOMAttribute("method", this.method);
		}

		this.setDOMAttribute("accept-charset","UTF-8");

	}

	this.addTitle = function(text, tag){

		tag = (tag == null) ? "h3" : tag;

		var element = document.createElement(tag);

		var textNode = document.createTextNode(text);

		element.appendChild(textNode);

		this.domElement.appendChild(element);

		return element;

	}

	this.addHiddenField = function(name, value){

		var element = document.createElement("input");
		element.setAttribute("type", "hidden");
		element.setAttribute("name", name);
		if (value != null) {
			element.setAttribute("value", value);
		}

		this.domElement.appendChild(element);

		this.hiddenFieldArray.push(element);

		return element;

	}

	this.addLine = function(label, className, required){

		var line = new FormLineObject(label, className, required);
		line.displayContent();
		line.appendToElement(this.domElement);

		return line;

	}

	this.addTextField = function(name, label, value, className, required){

		var line = this.addLine(label, className, required);
		var element = new FormFieldElement(name, label, value, required);
		element.displayContent();
		element.appendToElement(line.domElement);
		element.setParent(this);

		this.inputArray.push(element);

		return element;

	}

	this.addPasswordField = function(name, label, value, className, required){

		var line = this.addLine(label, className, required);
		var element = new PasswordFieldElement(name, label, value, required);
		element.displayContent();
		element.appendToElement(line.domElement);
		element.setParent(this);

		this.inputArray.push(element);

		return element;

	}

	this.addDateField = function(name, label, value, className, required){

		var line = this.addLine(label, className, required);
		var element = new FormFieldElement(name, label, value, required);
		element.displayContent();
		element.appendToElement(line.domElement);
		element.setParent(this);

		this.inputArray.push(element);

		if($.datepicker != null){
			$(element.domElement).datepicker({ dateFormat: 'dd/mm/yy' });
		}

		return element;

	}

	this.addMemoField = function(name, label, value, className, required){

		var line = this.addLine(label, className, required);
		var element = new MemoFieldElement(name, label, value, required);
		element.displayContent();
		element.appendToElement(line.domElement);
		element.setParent(this);

		this.inputArray.push(element);

		return element;

	}

	this.addHTMLEditor = function(name, label, value, className, required){

		var element = this.addMemoField(name, label, value, className, required);

		if(typeof(tinyMCE) != "undefined"){// TinyMCE loaded
			element.setClass("mceEditor");
		}

		return element;

	}


	this.addCheckBox = function(name, label, value, checkedValue, className, required){

		var line = this.addElement("p");//this.addLine(label, className, required);
		line.className = className;
		var element = new CheckBoxElement(name, label, value, checkedValue, required);
		element.displayContent();
		element.appendToElement(line);
		var label = document.createTextNode(label);
		line.appendChild(label);
		element.setParent(this);

		this.inputArray.push(element);

		return element;

	}

	this.addSelectField = function(name, label, value, values, labels, className, required){

		var line = this.addLine(label, className, required);
		var element = new SelectFieldElement(name, label, value, values, labels, required);
		element.displayContent();
		element.appendToElement(line.domElement);
		element.setParent(this);

		this.inputArray.push(element);

		return element;

	}

	this.addMultipleSelectField = function(name, label, value, values, labels, size, className){

		var line = this.addLine(label, className);
		var element = new MultipleSelectFieldElement(name, label, value, values, labels, size);
		element.displayContent();
		element.appendToElement(line.domElement);
		element.setParent(this);

		this.inputArray.push(element);

		return element;

	}

	this.addMultiSelectField = function(name, label, value, values, labels, fieldNamingConvention, className){

		var line = this.addLine(label, className);
		var element = new MultiSelectElement(name, label, value, values, labels, fieldNamingConvention);
		element.displayContent();
		element.appendToElement(line.domElement);
		element.setParent(this);

		this.inputArray.push(element);

		return element;

	}

	this.addUploadField = function(name, label, value, thumbnail, uploadFormURL, className){

		var line = this.addLine(label, className);
		var element = new UploadElement(name, label, value, thumbnail);
		element.displayContent();
		element.appendToElement(line.domElement);
		element.setParent(this);

		line.addUploader(uploadFormURL,element);

		this.inputArray.push(element);

		return element;

	}

	this.addMultiUploadField = function(name, label, existing, uploadFormURL, className){

		var line = this.addLine(label, className);
		var element = new UploadCollectionElement(name, label, existing);
		element.displayContent();
		element.appendToElement(line.domElement);
		element.setParent(this);

		line.addUploader(uploadFormURL,element);

		this.inputArray.push(element);

		return element;

	}

	this.addSubmitLine = function(label, onSubmitFunction, cancelFunction, cancelLabel){

		label = (label == null) ? "Submit" : label;

		cancelLabel = (cancelLabel == null) ? "Cancel" : cancelLabel;

		var element = new DisplayObject();
		element.createDOMElement("p", "formSubmit");

		if(cancelFunction != null){

			var cancelButton = document.createElement("input");
			cancelButton.setAttribute("type", "button");
			cancelButton.setAttribute("class", "button");
			cancelButton.setAttribute("className", "button");
			cancelButton.setAttribute("value", cancelLabel);
			cancelButton.onclick = cancelFunction;

			element.domElement.appendChild(cancelButton);
			element.domElement.appendChild(document.createTextNode(" "));

		}

		var submitButton = document.createElement("input");
		submitButton.setAttribute("type", "submit");
		submitButton.setAttribute("class", "button");
		submitButton.setAttribute("className", "button");
		submitButton.setAttribute("value", label);

		if(onSubmitFunction != null){
			var thisObj = this;
			submitButton.onclick = function(){
				onSubmitFunction(thisObj.getData());
			};
			this.domElement.onsubmit = function(){ return false;};
		}

		element.domElement.appendChild(submitButton);

		element.appendToElement(this.domElement);

		return element;

	}

	this.validate = function(){

		var errorStr = "";
		var article;
		var vowels = /^[aeiou]/i;

		for(i in this.inputArray){

			if((this.inputArray[i].labelString.toLowerCase == "email" || this.inputArray[i].labelString.toLowerCase() == "e-mail") && !validateEmail(this.inputArray[i].getValue())){
				errorStr += this.inputArray[i].labelString+"Please supply a valid e-mail address\n";
			}else if(this.inputArray[i].required && (this.inputArray[i].getValue() == null || this.inputArray[i].getValue() == "")){

				article = (this.inputArray[i].labelString.match(vowels)) ? "an" : "a";

				errorStr += "Please supply "+article+" "+this.inputArray[i].labelString.toLowerCase()+"\n";

			}
		}
		//alert("Bob"+errorStr);
		
		
		if(errorStr != ""){
			alert(errorStr);
			return false;
		}

		return true;

	}

	this.getData = function(){

		var dataObject = new Object();

		for(var i in this.hiddenFieldArray){
			dataObject[this.hiddenFieldArray[i].name] = this.hiddenFieldArray[i].value;
		}

		for(i in this.inputArray){
			dataObject[this.inputArray[i].fieldName] = this.inputArray[i].getValue();
			//alert(this.inputArray[i].fieldName+"="+this.inputArray[i].getValue());
		}

		//alert(dataObject.toSource());
		//alert(print_r(dataObject));
		return dataObject;

	}


	this.initHTMLEditors = function(){// must be called after form is attached to DOM.

		if(typeof(tinyMCE) != "undefined"){
			var mceOptions = {
				mode : "specific_textareas",
				editor_selector : "mceEditor",
				theme: "advanced",
				theme_advanced_buttons1: "bold,italic,underline,|,justifyleft,justifycenter,justifyright,justifyfull,|,formatselect,fontsizeselect,|,link,unlink",
				theme_advanced_buttons2: null,
				theme_advanced_buttons3: null,
				theme_advanced_buttons4: null,
				theme_advanced_toolbar_location: "top",
				theme_advanced_toolbar_align: "left"
			}

			tinyMCE.init(mceOptions);
		}

	}

	this.FormObject();

}

FormObject.inherits(DisplayObject);


/**
 * Concatenates the values of a variable into an easily readable string
 * by Matt Hackett [scriptnode.com]
 * @param {Object} x The variable to debug
 * @param {Number} max The maximum number of recursions allowed (keep low, around 5 for HTML elements to prevent errors) [default: 10]
 * @param {String} sep The separator to use between [default: a single space ' ']
 * @param {Number} l The current level deep (amount of recursion). Do not use this parameter: it's for the function's own use
 */
function print_r(x, max, sep, l) {

	l = l || 0;
	max = max || 10;
	sep = sep || ' ';

	if (l > max) {
		return "[WARNING: Too much recursion]\n";
	}

	var
		i,
		r = '',
		t = typeof x,
		tab = '';

	if (x === null) {
		r += "(null)\n";
	} else if (t == 'object') {

		l++;

		for (i = 0; i < l; i++) {
			tab += sep;
		}

		if (x && x.length) {
			t = 'array';
		}

		r += '(' + t + ") :\n";

		for (i in x) {
			try {
				r += tab + '[' + i + '] : ' + print_r(x[i], max, sep, (l + 1));
			} catch(e) {
				return "[ERROR: " + e + "]\n";
			}
		}

	} else {

		if (t == 'string') {
			if (x == '') {
				x = '(empty)';
			}
		}

		r += '(' + t + ') ' + x + "\n";

	}

	return r;

};
var_dump = print_r;


function FormLineObject(label,className, required){

	DisplayObject.call(this);

	this.labelString = label;
	this.required = required;

	this.formElementObject = null;

	className = (className == null) ? "formLine" : className;

	if(typeof(label) == "string"){
		className += " "+label.replace(/\W/g,"");
	}

	this.createDOMElement("p",className);

	// Label Methods

	this.appendLabel = function(){

		this.labelObject = this.getLabelElement();
		if(this.labelObject != null){
			this.domElement.appendChild(this.labelObject);
		}

	}

	this.removeLabel = function(){

		if(this.labelObject != null){

			this.domElement.removeChild(this.labelObject);
			this.labelObject = null;

		}

	}

	this.getLabelElement = function(){

		if (this.labelString != null) {

			var element = document.createElement("strong");
			element.innerHTML = this.labelString;

			if(this.required == true){
				element.innerHTML += "*";
			}

			return element;

		}

		return null;

	}

	this.addFormElementObject = function(element){
		this.formElementObject = element;
	}

	this.displayContent = function(){
		this.clearContents();
		this.appendLabel();
		if(this.formElementObject != null){
			this.formElementObject.displayContent();
			this.domElement.appendChild(this.formElementObject.domElement);
		}
	}

	this.clearContents = function(){
		this.removeLabel();
	}

	this.addUploader = function(uploadFormURL,targetObj){

		// register callback

		CallBackRegistry.registerFunction("FormField"+targetObj.fieldName,function(data){targetObj.onFileUpload(data)});

		var src = pathToRoot + unescape(uploadFormURL)+"&_setting="+targetObj.fieldName+"&_callback=parent.CallBackRegistry.call('FormField"+targetObj.fieldName+"')";

		var height;
		var className = "uploadFrame";

		if (String(uploadFormURL).indexOf("showsaveoptions") != -1) {
			height = "58";
			className += " options";
		}else{
			height = "34";
		}

		//alert(height);

		this.addElement("iframe",null,"class",className,"src",src,"width","475","height",height,"frameBorder","0","scrolling","no");

	}

}


FormLineObject.inherits(DisplayObject);

// Generic Text Box

function FormFieldElement(fieldName, label, storedValue, required){// generic form
	// element (text
	// input with label)

	this.fieldName = fieldName;
	this.labelString = label;
	this.required = (required == true) ? true : false;

	if(storedValue != null){
		this.storedValue = unescape(storedValue);
	}

	// Inherit Display object
	DisplayObject.call(this);

	// sub units

	this.labelObject = null;
	this.inputObject = null;

	this.onChangeListener = null;// container for onchange function

	this.getValue = function(){

		if(this.inputObject != null){

			return this.inputObject.value;

		}

		return null;

	}

	this.setValue = function(value){

		if(this.inputObject != null){

			if(value == null){
				value = "";
			}

			this.inputObject.value = value;

		}

		this.storeValue();

	}

	this.storeValue = function(){

		this.storedValue = this.getValue();

	}

	this.disable = function(col){

		if(this.inputObject != null){
			this.inputObject.disabled = "disabled";
		}

		if(this.domElement != null){
			this.domElement.className = "formLine disabled";
		}

	}

	this.enable = function(){

		if(this.inputObject != null){
			this.inputObject.disabled = null;
		}

		if(this.domElement != null){
			this.domElement.className = "formLine";
		}
	}

	// Default value

	this.getStoredValue = function(){// method to return default value

		/*
		 * var val;
		 *
		 * if(RPWSearchSocket != null){ val =
		 * RPWSearchSocket.getSearchSetting(this.fieldName); if(val != null){
		 * return val; } }
		 */

		return this.storedValue;

	}

	// Content Creation

	this.displayContent = function(){

		var oldElement = null;
		if(this.domElement != null && this.domElement.parentNode != null){
			var oldElement = this.domElement;
		}

		this.createInput();

		if(oldElement != null){
			oldElement.parentNode.insertBefore(this.domElement, oldElement);
			oldElement.parentNode.removeChild(oldElement);
		}

	}

	this.clearContents = function(){

		this.removeInput();

	}

	this.setInputWidth = function(w){

		if(this.inputObject != null){

			this.inputObject.style.width = w + "px";

		}

	}

	// Input methods

	this.createInput = function(){

		this.inputObject = this.getInputElement();
		if(this.inputObject != null){
			this.domElement = this.inputObject;
		}

	}

	this.removeInput = function(){

		if(this.inputObject != null){

			this.domElement.parentNode.removeChild(this.domElement);
			this.inputObject = null;

		}

	}

	this.getInputElement = function(){

		var element = document.createElement("input");
		element.setAttribute("name", this.fieldName);
		element.setAttribute("class", "textbox");
		element.setAttribute("className", "textbox");

		var val = this.getStoredValue();

		if(val != null){
			element.setAttribute("value", (val));
		}

		var thisObj = this;
		element.onchange = function(){ thisObj.onChange(this) };

		element.onkeypress = function(e){
			// look for window.event in case event isn't passed in
			if (window.event) { e = window.event; }
			if (e.keyCode == 13){
				thisObj.onChange(this);
				//this.blur();
			}
        }


		return element;

	}

	this.setOnChangeListener = function(f){

		this.onChangeListener = f;

	}

	this.onChange = function(element){

		this.storeValue();

		if(this.onChangeListener != null){

			this.onChangeListener(element,this);

		}

	}

	this.focus = function(){
		if(this.inputObject != null){
			this.inputObject.focus();
		}
	}

	this.reset = function(){
		if(this.inputObject != null){
			this.inputObject.value = "";
			this.storedValue = null;
		}
	}


}

FormFieldElement.inherits(DisplayObject);

// password field
function PasswordFieldElement(fieldName, label, storedValue, required){

	FormFieldElement.call(this, fieldName, label, storedValue, required);

	this.getInputElement = function(){

		var element = document.createElement("input");
		element.setAttribute("name", this.fieldName);
		element.setAttribute("class", "textbox");
		element.setAttribute("className", "textbox");
		element.setAttribute("type", "password");

		var val = this.getStoredValue();

		if(val != null){
			element.setAttribute("value", (val));
		}

		var thisObj = this;
		element.onchange = function(){ thisObj.onChange(this) };

		element.onkeypress = function(e){
			// look for window.event in case event isn't passed in
			if (window.event) { e = window.event; }
			if (e.keyCode == 13){
				thisObj.onChange(this);
				//this.blur();
			}
        }


		return element;

	}



}
// Memo box

function MemoFieldElement(fieldName, label, storedValue, required){

	FormFieldElement.call(this, fieldName, label, storedValue, required);

	this.getInputElement = function(){

		var element = document.createElement("textarea");
		element.setAttribute("name", this.fieldName);
		element.setAttribute("class", "textbox");

		var val = this.getStoredValue();

		if(val != null){
			element.value = (val);
		}

		var thisObj = this;
		element.onchange = function(){thisObj.onChange(this) };

		return element;

	}

	this.getValue = function(){

		if(this.inputObject != null){

			if(this.inputObject.className.indexOf("mceEditor") != -1 && typeof(tinyMCE) != "undefined"){

				var editor = tinymce.get(this.fieldName);

				if(editor != null){
					return editor.getContent();
				}

			}

			return this.inputObject.value;

		}

		return null;

	}



}

MemoFieldElement.inherits(FormFieldElement);

// Checkbox

function CheckBoxElement(fieldName, label, storedValue, fieldValue, required){

	FormFieldElement.call(this, fieldName, label, storedValue, required);

	this.fieldValue = (fieldValue == null) ? 1 : fieldValue;

	if(storedValue != null){
		this.storedValue = storedValue;// true or false
	}

	this.getInputElement = function(){

		var ieElement = "<input type=\"checkbox\" name=\"" + this.fieldName	+ "\" title=\"" + this.labelString + "\" value=\""+this.fieldValue+"\"";
		ieElement += (this.getStoredValue()) ? " checked=\"checked\"" : "";
		ieElement += " />";

		try{
			var element = document.createElement(ieElement);
		}catch (e){
			var element = document.createElement("input");
			element.setAttribute("name", this.fieldName);
			element.setAttribute("title", this.labelString);
			element.setAttribute("type", "checkbox");
			element.setAttribute("value", this.fieldValue);

			if(this.getStoredValue() == true){
				element.checked = true;
			}
		}

		var thisObj = this;
		element.onclick = function(){
			thisObj.onChange(this)
		};

		return element;

	}

	this.getValue = function(){

		if(this.inputObject != null){

			return (this.inputObject.checked) ? this.fieldValue : 0;

		}

		return null;

	}

	this.reset = function(){
		if (this.inputObject != null) {
			this.inputObject.checked = false;
		}
	}

}

CheckBoxElement.inherits(FormFieldElement);

// Select Drop-down List

function SelectFieldElement(fieldName, label, storedValue, options, optionLabels, required){// extends FormFieldElement to provide drop-down list

	FormFieldElement.call(this, fieldName, label, storedValue, required);

	if(options != null){
		if(typeof options == "string"){
			this.options = options.split(",");
		}else{
			this.options = options;
		}
	}

	if(optionLabels != null){
		if(typeof optionLabels == "string"){
			this.optionLabels = optionLabels.split(",");
		}else{
			this.optionLabels = optionLabels;
		}
	}

	this.setOptions = function(options, optionLabels){

		if(options != null){
			if(typeof options == "string"){
				this.options = options.split(",");
			}else{
				this.options = options;
			}
		}

		if(optionLabels != null){
			if(typeof optionLabels == "string"){
				this.optionLabels = optionLabels.split(",");
			}else{
				this.optionLabels = optionLabels;
			}
		}

	}

	this.getValue = function(){

		if(this.inputObject != null){

			return this.inputObject.options[this.inputObject.selectedIndex].value;

		}

		return null;

	}

	this.setValue = function(val){

		if(this.inputObject != null && val != null){

			for(var i=0;i<this.inputObject.options.length;i++){

				if(this.inputObject.options[i].value == val){
					this.inputObject.selectedIndex = i;
					return;
				}
			}

		}
		if (this.inputObject != null && val == null) {
			this.inputObject.selectedIndex = 0;
		}

	}

	this.getInputElement = function(){

		if(this.options != null){

			var element = document.createElement("select");
			element.setAttribute("name", this.fieldName);
			if(this.isMulti){
				element.setAttribute("multiple", "multiple");
				element.setAttribute("size", this.size);
			}

			var option;
			var label;

			for( var i in this.options){

				option = document.createElement("option");
				option.setAttribute("value", this.options[i]);

				if(this.valueIsSelected(this.options[i])){

					option.setAttribute("selected", "selected");

				}


				label = (this.optionLabels == null || this.optionLabels[i] == null) ? this.options[i] : this.optionLabels[i];

				option.setAttribute("title",label);

				option.innerHTML = label;

				element.appendChild(option);

			}

			var thisObj = this;
			element.onchange = function(){ thisObj.onChange(this) };

			return element;

		}

		return null;

	}

	this.valueIsSelected = function(value){
		return (value == this.getStoredValue());
	}

	this.reset = function(){
		if (this.inputObject != null) {
			this.inputObject.selectedIndex = 0;
		}
		this.storedValue = null;
	}

}

SelectFieldElement.inherits(FormFieldElement);

function MultipleSelectFieldElement(fieldName, label, storedValue, options, optionLabels, size){// extends FormFieldElement to provide multi-select list

	SelectFieldElement.call(this, fieldName, label, storedValue, options, optionLabels);

	this.size = (size == null) ? Math.min(6,this.options.length) : size;

	this.isMulti = true;

	this.valueIsSelected = function(value){
		var regex = new RegExp("(^|\b)"+value+"(\b|$)","g");
		return regex.test(String(this.getStoredValue()));
	}

	this.getValue = function(){

		if(this.inputObject != null){

			var arr = new Array();

			for(var i in this.inputObject.options){
				if(this.inputObject.options[i] != null && this.inputObject.options[i].selected){
					arr.push(this.inputObject.options[i].value);
				}
			}

			if(arr.length > 0){
				return arr.join(",");
			}

		}

		return null;

	}

	this.setValue = function(value){

		this.storedValue = value;

		if(this.inputObject != null){

			for(var i in this.inputObject.options){
				if(this.valueIsSelected(this.inputObject.options[i].value)){
					this.inputObject.options[i].selected = true;
				}
			}

			if(arr.length > 0){
				return arr.join(",");
			}

		}

		return null;

	}

	this.reset = function(){
		if(this.inputObject != null){
			for(var i in this.inputObject.options){
				this.inputObject.options[i].selected = false;
			}
		}
		this.storedValue = null;
	}

}

MultipleSelectFieldElement.inherits(SelectFieldElement);


// Multiple checkboxes

function MultiSelectElement(fieldName, label, storedValue, options, optionLabels, fieldNamingConvention){// extends FormFieldElement to provide mulitple check boxes

	FormFieldElement.call(this, fieldName, label, storedValue);

	this.checkboxArr = new Array();

	this.fieldNamingConvention = (fieldNamingConvention == null) ? "array" : fieldNamingConvention;

	if(options != null){
		if(typeof options == "string"){
			this.options = options.split(",");
		}else{
			this.options = options;
		}
	}

	if(optionLabels != null){
		if(typeof optionLabels == "string"){
			this.optionLabels = optionLabels.split(",");
		}else{
			this.optionLabels = optionLabels;
		}
	}

	this.getValue = function(){

		if(this.checkboxArr != null){

			var selected = "";

			for( var i in this.checkboxArr){

				if(this.checkboxArr[i].checked){

					selected += (selected == "") ? "" : ",";
					selected += this.checkboxArr[i].value;

				}

			}

			return selected;

		}

		return null;

	}

	this.getSelectedValues = function(){

		if(this.checkboxArr != null){

			var selectedArr = new Array();

			for( var i in this.checkboxArr){

				if(this.checkboxArr[i].checked){

					selectedArr.push(this.checkboxArr[i].value);

				}

			}

			return (selectedArr.length > 0) ? selectedArr : null;

		}

		return null;
	}

	this.setValue = function(value){

		if(this.inputObject != null){

			for(i in this.inputObject.options){

				if(this.inputObject.options[i].value == value){

					this.inputObject.selectedIndex = i;
					break;
				}
			}

		}

	}

	this.isStoredValue = function(value){

		var selected = this.getStoredValue();

		var regex = new RegExp("(^|,)" + value + "(,|$)", "i");
		return regex.test(selected);

	}

	this.getInputElement = function(){

		if(this.options != null){

			this.checkboxArr = new Array();

			var element = document.createElement("div");

			var span;
			var checkbox;
			var label;
			var labelStr;
			var ieElement;
			var br;
			var fieldSuffix;
			var fieldValue;

			var thisObj = this;


			for(var i in this.options){

				if(this.options.constructor.toString().indexOf("Array") != -1){
					fieldValue = this.options[i];
					labelStr = (this.optionLabels == null || this.optionLabels[i] == null) ? this.options[i]	: this.optionLabels[i];
				}else{
					fieldValue = i;
					labelStr = this.options[i];
				}

				fieldSuffix = (this.fieldNamingConvention == "ordinal") ? i : "[]";

				ieElement = "<input type=\"checkbox\" name=\"" + this.fieldName + fieldSuffix+"\" value=\"" + fieldValue + "\"";
				ieElement += (this.isStoredValue(this.options[i])) ? " checked=\"checked\""
						: "";
				ieElement += " />";

				try{
					checkbox = document.createElement(ieElement);
				}catch (e){
					checkbox = document.createElement("input");
					checkbox.setAttribute("name", this.fieldName + fieldSuffix);
					checkbox.setAttribute("type", "checkbox");
					checkbox.setAttribute("value", fieldValue);

					if(this.isStoredValue(fieldValue)){
						checkbox.checked = true;
					}
				}

				checkbox.onclick = function(){
					thisObj.onChange(this)
				};

				span = document.createElement("span");

				span.appendChild(checkbox);

				this.checkboxArr.push(checkbox);

				label = document.createTextNode(labelStr);

				span.appendChild(label);

				element.appendChild(span);

				br = document.createElement("br");

				element.appendChild(br);

			}

			return element;

		}

		return null;

	}

	this.reset = function(){
		for(var i in this.checkboxArr){
			this.checkboxArr[i].checked = false;
		}
		this.storedValue = null;
	}

}

MultiSelectElement.inherits(FormFieldElement);


//File Upload

function UploadElement(fieldName, label, value, thumbnail){// extends FormFieldElement to creat file uploader

	FormFieldElement.call(this, fieldName, label, value);

	this.hiddenInput = null;
	this.imageInput = null;
	this.thumbnail = urlDecode(thumbnail);

	// Content Creation

	this.displayContent = function(){

		this.clearContents();

		this.createInput();

	}

	this.getInputElement = function(){

		var inputGroup = document.createElement("div");

		inputGroup.setAttribute("class","fileCollection");

		var thisObj = this;

		// add existing image

		if(this.storedValue != null){

			var imageInput = document.createElement("input");
			imageInput.setAttribute("type", "image");
			imageInput.setAttribute("value", (this.storedValue));
			imageInput.setAttribute("title", (this.storedValue));
			imageInput.setAttribute("name", this.fieldName+"Image");
			imageInput.setAttribute("src", (this.thumbnail));
			//imageInput.setAttribute("src",pathToRoot+directoryIndex+"?action=getmodulefilethumbnail&"+this.moduleIdentifier+"&setting="+this.fieldName+"&file="+this.storedImage+"&width=50&height=50&quality=80&crop=1");

			imageInput.onmousedown = function(event){ thisObj.showContextMenu(event, this) };
			imageInput.onclick = function(event){ return false; };

			inputGroup.appendChild(imageInput);

			this.imageInput = imageInput;

		}

		this.hiddenInput = document.createElement("input");
		this.hiddenInput.setAttribute("type","hidden");
		this.hiddenInput.setAttribute("name",this.fieldName);
		this.hiddenInput.setAttribute("value",this.storedValue)

		inputGroup.appendChild(this.hiddenInput);

		return inputGroup;

	}

	this.showContextMenu = function(event, item){

		var thisObj = this;

		var deleteFunction = function(){ thisObj.deleteItem(item);ContextMenu.removeMenu(); };

		ContextMenu.createMenu(event, "Delete", deleteFunction);

	}

	this.deleteItem = function(item){

		this.hiddenInput.value = "";

		this.inputObject.removeChild(item);

		this.imageInput = null;
	}

	this.onFileUpload = function(data){

		if(data.files == null || data.moduleIdentifier == null){
			return null;
		}

		var files = data.files;

		var fileArray = files.split(",");


		var thisObj = this;

		if(this.inputObject != null){
			// see if we have any files left - add them if we do.
			if(fileArray.length > 0){
				if(this.imageInput == null){
					var input;
					input = document.createElement("input");
					input.setAttribute("type","image");
					input.setAttribute("name",this.fieldName+"Image");
					input.onmousedown = function(event){ thisObj.showContextMenu(event, this) };
					input.onclick = function(event){ return false; };
					this.inputObject.appendChild(input);
					this.imageInput = input
				}
				this.imageInput.setAttribute("value",fileArray[0]);
				this.imageInput.setAttribute("src",pathToRoot+directoryIndex+"?action=getmodulefilethumbnail&"+unescape(data.moduleIdentifier)+"&setting="+this.fieldName+"&file="+fileArray[0]+"&width=50&height=50&quality=80&crop=1");
				this.imageInput.setAttribute("title",fileArray[0]);

				this.hiddenInput.value = fileArray[0];
			}

		}
	}


}

UploadElement.inherits(FormFieldElement);

// File Collection

function UploadCollectionElement(fieldName, label, existing){// extends FormFieldElement to creat file uploader

	FormFieldElement.call(this, fieldName, label, null);

	if(existing != null){
		this.inputArray = existing;
	}else{
		this.inputArray = new Array();
	}
	this.deletedItems = new Array();

	this.hiddenInput = null;

	// Content Creation

	this.displayContent = function(){

		this.clearContents();

		this.createInput();

	}

	this.getInputElement = function(){

		var inputGroup = document.createElement("div");

		inputGroup.setAttribute("class","fileCollection");

		var thisObj = this;

		// add existing images

		var fileList = "";

		for( var i = 0; i < this.inputArray.length; i++){

			var imageInput = document.createElement("input");
			imageInput.setAttribute("type", "image");
			imageInput.setAttribute("value", urlDecode(this.inputArray[i].file));
			imageInput.setAttribute("title", urlDecode(this.inputArray[i].file));
			imageInput.setAttribute("name", this.fieldName + "[]");
			imageInput.setAttribute("src", urlDecode(this.inputArray[i].thumbnail));

			imageInput.onmousedown = function(event){ thisObj.showContextMenu(event, this) };
			imageInput.onclick = function(event){ return false; };

			this.inputArray[i].domElement = imageInput;

			inputGroup.appendChild(imageInput);

			fileList += (fileList == "") ? "" : ",";
			fileList += urlDecode(this.inputArray[i].file);

		}

		this.hiddenInput = document.createElement("input");
		this.hiddenInput.setAttribute("type","hidden");
		this.hiddenInput.setAttribute("name",this.fieldName);
		this.hiddenInput.setAttribute("value",fileList)

		inputGroup.appendChild(this.hiddenInput);

		return inputGroup;

	}


	this.showContextMenu = function(event, item){

		var thisObj = this;

		var deleteFunction = function(){ thisObj.deleteItem(item);ContextMenu.removeMenu(); };

		ContextMenu.createMenu(event, "Delete", deleteFunction);

	}

	this.deleteItem = function(item){

		this.deletedItems.push(item.value);

		var fileArray = this.hiddenInput.value.split(",");

		for(var i=0;i<fileArray.length;i++){

			if(fileArray[i] == item.value){
				fileArray.splice(i,1);
			}

		}

		var fileList = "";
		for(var i=0;i<fileArray.length;i++){

			fileList += (fileList == "") ? "" : ",";
			fileList += fileArray[i];

		}
		this.hiddenInput.value = fileList;


		this.inputObject.removeChild(item);
	}

	this.onFileUpload = function(data){

		//alert(data.toSource());

		if(data.files == null || data.moduleIdentifier == null){
			return null;
		}

		var files = data.files;

		var fileArray = files.split(",");

		// loop through files, removing entries for those we've deleted

		for(var i=0;i<fileArray.length;i++){
			if(isInArray(fileArray[i],this.deletedItems)){// item has been deleted
				fileArray.splice(i,1);
			}
		}

		var thisObj = this;
		if(this.inputObject != null){
			// loop through existing inputs to see if they're still wanted - if not, delete them
			var fileFound;
			var fileList = "";

			if(this.inputObject.hasChildNodes()){
				inputs = this.inputObject.childNodes;
				for(i=0; i<inputs.length;i++){
					if(typeof(inputs[i].nodeName) != "undefined" && inputs[i].nodeName.toLowerCase() == "input" && inputs[i] != this.hiddenInput){

						fileFound = false;

						for(var j=0;j<fileArray.length;j++){// loop through list of files,
							if(fileArray[j] == String(inputs[i].value)){
								fileFound = true;
								fileList += (fileList == "") ? "" : ",";
								fileList += fileArray[j];
								fileArray.splice(j,1);
								break;
							}
						}

						if(!fileFound){// delete input from display

							inputs[i].parentNode.removeChild(inputs[i]);

							i--;

						}
					}
					inputs = this.inputObject.childNodes;
				}
			}
			// see if we have any files left - add them if we do.
			if(fileArray.length > 0){
				var input;
				for(i in fileArray){
					input = document.createElement("input");
					input.setAttribute("type","image");
					input.setAttribute("name",this.fieldName+"[]");
					input.setAttribute("value",fileArray[i]);
					input.setAttribute("src",pathToRoot+directoryIndex+"?action=getmodulefilethumbnail&"+unescape(data.moduleIdentifier)+"&setting="+this.fieldName+"&file="+fileArray[i]+"&width=50&height=50&quality=80&crop=1");
					input.setAttribute("title",fileArray[i]);
					input.onmousedown = function(event){ thisObj.showContextMenu(event, this) };
					input.onclick = function(event){ return false; };
					this.inputObject.appendChild(input);
					fileList += (fileList == "") ? "" : ",";
					fileList += fileArray[i];
				}
			}

			this.hiddenInput.value = fileList;
		}

	}


}

function validateEmail(str){
	var filter=/^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i
	if (filter.test(str)){
		return true;
	}
	return false;
}

UploadCollectionElement.inherits(FormFieldElement);

function RPWEmailPropertyFormObject(propertyDataObject){

	DisplayObject.call(this);

	this.form = null;

	this.titleStr = "Send to a friend";
	this.message = null;
	this.formFields = "Name*,Email*,Message";
	this.action = null;

	this.propertyDataObject = propertyDataObject;

	this.introStr = null;
	this.showImage = false;
	this.imageWidth = 100;
	this.imageHeight = 100;
	this.cropImage = false;
	this.width = 360; 
	this.autoPosition = true; 

	this.RPWEmailPropertyFormObject = function(){

		this.createDOMElement("div", "RPWEmailPropertyForm");
		
		//this.setStyle("width", "360px");

	}


	this.displayContent = function(){
		if (this.autoPosition) {
			this.setStyle("width", this.width + "px");
		 } 
		
		
		this.clearContents();

		var parentObj = this.getParent();

		this.form = new FormObject("rpwEmailPropertyForm");
		this.form.domElement.onsubmit = function(){ return false; };

		//this.form.addElement("h3",this.titleStr);

		var image = this.getImageElement();

		if(image != null){
			this.form.appendChild(image);
		}

		if(this.propertyDataObject.address){
			//this.form.addElement("h4",this.propertyDataObject.address);
		}


		// HIDDEN FIELDS

		this.form.addHiddenField("_pcode",this.propertyDataObject.pcode);
		this.form.addHiddenField("_rps",this.propertyDataObject.db);
		this.form.addHiddenField("Property",this.propertyDataObject.address);

		// FIELDS

		var formFields = urlDecode(this.formFields).split(",");
		var field;
		var value;
		var required;
		var requiredRegex = /\*$/;

		for(var i in formFields){

			field = formFields[i].replace(/^\s\s*/, '').replace(/\s\s*$/, '');

			if(field.match(requiredRegex)){
				required = true;
				field = field.replace(requiredRegex,"");
			}else{
				required = false;
			}

			if(field.toLowerCase() == "address" || field.toLowerCase() == "message" || field.toLowerCase() == "notes" || field.toLowerCase() == "enquiry"){

				value = (field.toLowerCase() == "message" && this.message != null) ? this.message : null;

				this.form.addMemoField(field,field,value,null,required);
			}else{
				this.form.addTextField(field,field,null,null,required);
			}

		}

		// SUBMIT

		var thisObj = this;

		var cancelFunction = function(){
			thisObj.cancel();
		}

		var submitFunction = function(){
			thisObj.submit();
		}

		//this.form.addSubmitLine("Submit", submitFunction, cancelFunction, "Cancel");
		this.form.addSubmitLine("Submit", submitFunction, null, null);

		this.form.appendToElement(this.domElement);

		this.setPosition();

	}

	this.getImageElement = function(){
		if(this.showImage && this.propertyDataObject.images != null){

			var img  = document.createElement("img");

			if (this.cropImage) {
				img.setAttribute("width", this.imageWidth);
				img.setAttribute("height", this.imageHeight);
			}

			img.setAttribute("src",httpRoot+"index.php?action=getthumbnail&filepath="+this.propertyDataObject.images[0].filepath+"&width="+this.imageWidth+"&height="+this.imageHeight+"&quality=75&crop="+Number(this.cropImage));

			return img;

		}

		return null;
	}

	this.submit = function(){
		if(this.form.validate()){

			var data = this.form.getData();
			//alert(data);	
			if(RPWSearchSocket != null){

				var thisObj = this;
				var callbackFunc = function(data){
					thisObj.onRequestSend(data);
				}
				//alert("aa2"+data.error);	
				RPWSearchSocket.makeCall("emailProperty", this.action, data, callbackFunc);

			}

		}
	}

	this.onRequestSend = function(data){
		//alert("HERE"+data.error);
		if(data.error != null){
			alert(data.error);
			return;
		}

		this.clearContents();

		this.addElement("p",data.result);
		var closePara = this.addElement("p");
/*
		var a = document.createElement("a");
		a.setAttribute("href","#");

		var thisObj = this;

		a.onclick = function(){
			thisObj.cancel();
		}

		a.innerHTML = "Close";
		closePara.appendChild(a);
*/
		setTimeout("post_result_email_toggle()",2000);
	}

	this.cancel = function(){

		var parentObj = this.getParent();
		if (parentObj != null && typeof parentObj.removeViewingRequestForm != "undefined") {
			parentObj.removeViewingRequestForm();
		}else if(this.onRemoveFunction != null){
			this.onRemoveFunction();
		}else if(this.domElement.parent != null){
			this.domElement.parent.removeChild(this.domElement);
		}

	}

	this.setPosition = function(){
		if(this.autoPosition){ 
		//this.setStyle("position","absolute");

		// get image width and height

		var pageSizes = this.getPageSizeObject();

		var w = this.getWidth();
		var h = this.getHeight();

		var yScroll = this.getYScroll();

		var top = Math.max(0,yScroll + ((pageSizes.windowHeight - h) / 2));

		this.setStyle("top",top+"px");
		this.setStyle("left", Math.max(0,(pageSizes.pageWidth - w) / 2) + "px");
		}
	}



	this.RPWEmailPropertyFormObject();

}

RPWEmailPropertyFormObject.inherits(DisplayObject);
function RPWViewingRequestFormObject(propertyDataObject){

	DisplayObject.call(this);

	this.form = null;

	this.titleStr = "Book a Viewing";
	this.address = null;
	this.introStr = null;
	this.formFields = "Name*,Telephone*,Email*,Enquiry";
	this.recipient = null;
	this.pcode = null;
	this.rps = null;
	this.action = null;
	this.showImage = false;
	this.imageWidth = 100;
	this.imageHeight = 100;
	this.cropImage = false;
	this.width = 360;
	this.autoPosition = false; 

	this.propertyDataObject = propertyDataObject;

	this.introStr = null;


	this.RPWViewingRequestFormObject = function(){

		this.createDOMElement("div", "RPWViewingRequestForm");
		//this.setStyle("width", "360px");

	}


	this.displayContent = function(){
		if (this.autoPosition) {
			this.setStyle("width", this.width + "px");
			} 
		
		
		this.clearContents();

		var parentObj = this.getParent();

		this.form = new FormObject("rpwViewingRequestForm");
		this.form.domElement.onsubmit = function(){ return false; };

		this.form.addElement("h3",this.titleStr);

		var image = this.getImageElement();

		if(image != null){
			this.form.appendChild(image);
		}

		if(this.propertyDataObject.address){
		//	this.form.addElement("h4",this.propertyDataObject.address);
		}

		// INTRO

		if (this.introStr != null) {
			var intro = this.form.addElement("p");
			intro.className = "intro";
			intro.innerHTML = urlDecode(this.introStr);
		}

		// HIDDEN FIELDS

		this.form.addHiddenField("_pcode",this.propertyDataObject.pcode);
		this.form.addHiddenField("_rps",this.propertyDataObject.db);
		this.form.addHiddenField("Property",this.propertyDataObject.address);

		// FIELDS

		var formFields = urlDecode(this.formFields).split(",");
		var field;
		var required;
		var requiredRegex = /\*$/;
		var varName;

		for(var i in formFields){

			field = formFields[i].replace(/^\s\s*/, '').replace(/\s\s*$/, '');

			if(field.match(requiredRegex)){
				required = true;
				field = field.replace(requiredRegex,"");
			}else{
				required = false;
			}

			varName = field.replace(/\W/,"");

			if(field.toLowerCase() == "address" || field.toLowerCase() == "message" || field.toLowerCase() == "notes" || field.toLowerCase() == "enquiry"){
				this.form.addMemoField(varName,field,null,null,required);
			}else{
				this.form.addTextField(varName,field,null,null,required);
			}

		}

		// SUBMIT

		var thisObj = this;

		var cancelFunction = function(){
			thisObj.cancel();
		}

		var submitFunction = function(){
			thisObj.submit();
		}

		//this.form.addSubmitLine("Submit", submitFunction, cancelFunction, "Cancel");
		this.form.addSubmitLine("Submit", submitFunction, null, "Cancel");

		this.form.appendToElement(this.domElement);

		this.setPosition();

	}

	this.getImageElement = function(){
		if(this.showImage && this.propertyDataObject.images != null){

			var img  = document.createElement("img");

			if (this.cropImage) {
				img.setAttribute("width", this.imageWidth);
				img.setAttribute("height", this.imageHeight);
			}

			img.setAttribute("src",httpRoot+"index.php?action=getthumbnail&filepath="+this.propertyDataObject.images[0].filepath+"&width="+this.imageWidth+"&height="+this.imageHeight+"&quality=75&crop="+Number(this.cropImage));

			return img;

		}

		return null;
	}

	this.submit = function(){
		//alert('Submit clicked');
		if(this.form.validate()){

			var data = this.form.getData();

			//alert(data.Email);

			if(RPWSearchSocket != null){

				var thisObj = this;
				var callbackFunc = function(data){
					thisObj.onRequestSend(data);
				}

				RPWSearchSocket.makeCall("bookViewing", this.action, data, callbackFunc);

			}

		}
	}

	this.onRequestSend = function(data){

		this.clearContents();

		this.addElement("p",data.result);
		var closePara = this.addElement("p");
		/*
		var a = document.createElement("a");
		a.setAttribute("href","javascript:void(0);");

		var thisObj = this;

		a.onclick = function(){
			thisObj.cancel();
		}

		a.innerHTML = "Close";
		closePara.appendChild(a);
*/
		
		//setTimeout("post_result_email_toggle()",2000);
		
		
	}
	
	
	

	this.cancel = function(){

		var parentObj = this.getParent();
		if (parentObj != null && typeof parentObj.removeViewingRequestForm != "undefined") {
			parentObj.removeViewingRequestForm();
		}else if(this.onRemoveFunction != null){
			this.onRemoveFunction();
		}else if(this.domElement.parent != null){
			this.domElement.parent.removeChild(this.domElement);
		}

	}

	this.setPosition = function(){
		if(this.autoPosition){ 	
		this.setStyle("position","absolute");

		// get image width and height

		var pageSizes = this.getPageSizeObject();

		var w = this.getWidth();
		var h = this.getHeight();

		var yScroll = this.getYScroll();

		var top = Math.max(0,yScroll + ((pageSizes.windowHeight - h) / 2));

		this.setStyle("top",top+"px");
		this.setStyle("left", Math.max(0,(pageSizes.pageWidth - w) / 2) + "px");
		}
	}



	this.RPWViewingRequestFormObject();

}

function initJavascriptObjectsindex_php_RPW_property_details_obj(){

	if(typeof(initStreetViewButtonindex_php_RPW_property_details_obj) != 'undefined'){
		initStreetViewButtonindex_php_RPW_property_details_obj();
	}

}




RPWViewingRequestFormObject.inherits(DisplayObject);
initJavascriptObjectsindex_php_RPW_property_details_obj();
		

