(Cookie = {
  hash : [], // hash of cookies
  init : function() {
    if (""!=document.cookie) {
      var p = document.cookie.split(/\s*;\s*/);
      for (i=0;i<p.length;i++) {
        var parts = p[i].split(/\s*=\s*/);
        Cookie.hash[parts[0]] = parts[1]?unescape(parts[1]):"";
      }
    }
  },
  isEnabled : function() {
	var result = false
	if (typeof(document.cookie) == 'string'){
		if (document.cookie.length == 0) {
			document.cookie = "test";
			result = (document.cookie == 'test');
			document.cookie = '';
		} else {
			result = true;
		}
	}
	return result;
  },
  get : function(name) {
    return Cookie.hash[name]?Cookie.hash[name]:null;
  },
  set : function(name, value, expire, path, domain, secure) {
    if (""!=name) {
      document.cookie = name + "=" + escape(value) +
      ((path == null) ? "" : ";path=" + path) +
      ((expire == null) ? "" : ";NoExp=" + ((typeof(expire)=='object')?expire.toGMTString():new Date(new Date().getTime()+expire*1000).toGMTString())) +
      ((domain == null) ? "" : ";domain=" + domain) +
      ((secure == null) ? "" : ";secure");
      Cookie.hash[name] = escape(value);
      return true;
    }
    return false;
  },
  isSet : function(name) {
    return Cookie.hash[name]?true:false;
  },
  del : function(name,path,domain) {
    if (Cookie.isSet(name)) {
      document.cookie = name + "=" +
      ((path == null) ? "" : "; path=" + path) +
      ((domain == null) ? "" : "; domain=" + domain) +
      "; NoExp=Thu, 01-Jan-70 00:00:01 GMT";
      delete Cookie.hash[name];
      return true;
    }
    return false;
  },
  delAll : function() {
    var i;
    for (i in Cookie.hash) {
      Cookie.del(i);
    }
    return true;
  }
}).init();



if (navigator.userAgent.match(/Gecko/)){
	HTMLElement.prototype.__defineGetter__("outerHTML", function () {
	   var attrs = this.attributes;
	   var str = "<" + this.tagName;
	   for (var i = 0; i < attrs.length; i++)
		  str += " " + attrs[i].name + "=\"" + attrs[i].value + "\"";
	
	   if ({
		   "IMG":   true,
		   "BR":    true,
		   "INPUT": true,
		   "META":  true,
		   "LINK":  true,
		   "PARAM": true,
		   "HR":    true
		}[this.tagName]) return str + ">";
	
	   return str + ">" + this.innerHTML + "</" + this.tagName + ">";
	});
}

// remove css image flicker
if ( navigator.appVersion.match(/\bMSIE\b/) && !navigator.appVersion.match(/\bMSIE 7\b/) ){
	try{
		document.execCommand("BackgroundImageCache", false, true);
	}catch(e){}
}

/* image preloading */
loadingImage = new Image(); 
loadingImage.src = "dev/views/images/public/loading.gif";
shadowSimple = new Image();
shadowSimple.src = "dev/views/images/stickywindow/shadow-simple.png";

function redirect(url) {
	document.location.href = url;
	return false;
}

// Best effort to get a number out of a text field 
function convertNumber(n) {
	var regex = /^\$*([0-9,.]+)\s*(k|m)*$/i;
	if(!regex.test(n)) return 0;
	
	var unit = RegExp.$2.toLowerCase(), 
		multiplier = 1;
	if (unit == 'm') multiplier = 1000000;
	else if (unit == 'k') multiplier = 1000;
	return Math.round(parseFloat((new String(RegExp.$1)).replace(/,/g,'')) * multiplier);
} 

// Returns a pretty number
function humanFriendlyNumber(n, stripEmptyFloat) {
	stripEmptyFloat = stripEmptyFloat !== false ? true : false;
	if (parseFloat(n) < 1000) return n;
	n = n + "";
	var dot = (n).lastIndexOf('.'),
		s = '',
		start = n.length - 1;
		
	if (dot >= 0) {
		start = dot - 1;
		s = n.substr(dot);
	}
	if (stripEmptyFloat && s == ",00"){
		s = '';
	}
	var ct = 0;
	for (var i = start; i >= 0; --i) {
		s = n.charAt(i) + s;
		++ct;
		if (ct == 3 && i != 0){
			s = '.' + s;
			ct = 0;
		}
	}
	return s;
}

Undwo.UrlManagerClass = function()
{
	var url = HERE_URL.replace(/\/(.[^\/]+\.htm)$/g, '').split('/'),
		urlParts = [],
		urlParams = [],
		filterOptions = ['selling', 'type', 'sort', 'price', 'size', 'rooms', 'bedrooms', 'bathrooms'];
	
	for(var i = 0, len = url.length; i < len; i++){
		if (!url[i]) continue;
		
		var regex = new RegExp("^("+ filterOptions.join('|') +")=(.+)?$", "i"),
			matches = regex.exec(url[i]);
		if (matches){
			if (matches[2]){
				urlParams[matches[1]] = matches[2];
			}
		} else {
			urlParts.push(url[i]);
		}
	}
	
	function validateParams(){
		if (urlParams && urlParams['sort'] && urlParams['sort'] == 'recent'){
			urlParams['sort'] = null;	
		}
	}
	
	var public = {
		getFullUrl : function(){
			return FULL_APP_URL + this.getUrlParts() + "/" + this.getParams();
		},
		getUrlParts : function(){
			return urlParts.join("/");
		},
		getParams : function(){
			validateParams();
			var result = "";
			for(var i in urlParams){
				if (typeof(urlParams[i]) != "string" || !urlParams[i]) continue;
				result += i + "=" + urlParams[i] + "/";
			}
			return result;
		},
		insertParam : function(name, value){
			urlParams[name] = value;
		},
		insertUrlPart : function(name, value){
			urlParts[name] = value;
		},
		changeLocation : function(clearParams){
			if (clearParams) urlParams = null;
			window.document.location.href = this.getFullUrl();
		}
	};

	return public;
}
Undwo.UrlManager = new Undwo.UrlManagerClass();

Undwo.ErrorMessagesManagerClass = function(){
	var errors = [];
	
	var public = {
		add : function(id, value){
			return errors[id] = value;
		},
		get : function(id){
			var res = "";
			$A(arguments).each(function(id){
				if (typeof errors[id] != "undefined"){
					res = errors[id];
					throw $break;
				}
			})
			return res;
		},
		exist : function(){
			var res = false;
			$A(arguments).each(function(id){
				if (typeof errors[id] != "undefined"){
					res = true;
					throw $break;
				}
			})
			return res;
		}
	};
	return public;
}
Undwo.ErrorMessagesManager = new Undwo.ErrorMessagesManagerClass();

function SearchSwitcher(container, items, formElement){
	var container = $(container),
		items = items,
		itemsCont = [],
		formElement = $(formElement);
	
	for(var i=0, len=items.length; i < len; i++){
		(function(){
			var citem = items[i],
				li = $(document.createElement('LI')),
				a = $(document.createElement('A'));
			a = Object.extend($(a), citem);
			a.innerHTML = citem.title;
			itemsCont[i] = li;
			if (citem.active){ 
				li.addClassName('active'); 
				formElement.value = citem.value;
			}
			li.observe('click', function(){
				activate(li);
			});
			li.observe('mouseover', function(){
				a.addClassName('over');
			});
			li.observe('mouseout', function(){
				a.removeClassName('over');
			});
			li.appendChild(a);
			container.appendChild(li);
		})();
	}
	
	function activate(li){
		for(var i=0, len=itemsCont.length; i < len; i++){
			itemsCont[i].className = '';
		}
		formElement.value = li.value;
		li.addClassName('active');
	}
}

function TogglePullDown(obj, params){
	var obj = $(obj);
	obj.removeClassName('pdm-trigger'); 
	obj.addClassName('pdm-trigger-active');
	//var title = Element.down(obj, 'span.underline');
	StickyWindowsFactory.hideAllInstances(obj.id || 'PullDown');
	var w = StickyWindowsFactory.getInstance(obj.id || 'PullDown');
	params = Object.extend({x:-30, y:20, bWidth:10, bHeight:10, draggable:false, onClose:function(){
		obj.removeClassName('pdm-trigger-active'); 
		obj.addClassName('pdm-trigger');
		obj.onclick = obj.prevOnclick;
		obj.pulledDown = false;
	}}, params);
	w.showAtElementPosition(obj,'<table'+ (params.id ? (' id="'+ params.id +'"') : '') +' width="'+ (params.width ? params.width : 160) +'" height="'+ (params.height ? params.height : 50) +'"><tr><td valign="top" style="padding:'+ (params.padding ? params.padding : '5px 7px') +'">'+ (params.html ? params.html : RenderList(params.items, params.additional)) +'</td></tr></table>', params);
	if (!obj.pulledDown){
		obj.prevOnclick = obj.onclick;
		obj.onclick = function(){
			w.hide();
			this.removeClassName('pdm-trigger-active'); 
			this.addClassName('pdm-trigger'); 
			this.onclick = this.prevOnclick;
			this.pulledDown = false;
			return false;
		}
		obj.pulledDown = true;
	}
}

function ShowWindowBlock(id, params){
	if (!id) return;
	
	var w = StickyWindowsFactory.getInstance(id);
	switch (id){
		case 'my_undwo': 
			w.showAtElementPosition('myundwo_link','<table width="300" height="200"><tr><td>test</td></tr></table>', {x:-250, y:30, bWidth:20, bHeight:20, draggable:false});
			break;
		case 'about_noaddress':
			w.showAtElementPosition(params.that,'<div class="small detailsWindow" style="height:auto;width:250px"><div class="title"><B>Adresse anfragen</b></div><div class="content">F&uuml;r diese Immobilie wurde vom Anbieter keine genaue Adresse ausser PLZ hinterlassen. Bitte kontaktieren Sie den Anbieter dieses Immobilienobjektes, um von ihm eine genaue Adresse zu bekommen.</div></div>', {x:-200, y:-80, bWidth:15, bHeight:15, draggable:true});
			break;
		case 'login': 
			w.showAtElementPosition('login_link','<table width="300" height="200"><tr><td>test</td></tr></table>', {x:-250, y:30, bWidth:20, bHeight:20, draggable:true});
			break;
		case 'signup': 
			w.showAtElementPosition('signup_link','<table width="300" height="200"><tr><td>test</td></tr></table>', {x:-260, y:30, bWidth:20, bHeight:20, draggable:true});
			break;
	}
}

function Logout(){
}

function ToggleNeighborhoods(forceOpen){
	var nearbyTownshipsTable = $('nearbyTownshipsTable'),
		nearbyDistrictsTable = $('nearbyDistrictsTable');
	if (nearbyTownshipsTable.visible() || forceOpen == true){
		nearbyTownshipsTable.hide();
		nearbyDistrictsTable.show();
	}
	else {
		nearbyDistrictsTable.hide();
		nearbyTownshipsTable.show();
	} 	
}

function RenderList(items, additional, css){
	if (!items){
		return "";	
	}
	var UL = document.createElement('UL');
	UL.className = css || 'list';
	for(var i = 0, len = items.length; i < len; i++){
		var item = items[i],
			LI = document.createElement('LI'),
			SPAN = document.createElement('SPAN'), 
			SPANStyle = SPAN.style,
			A = document.createElement('A'); 
		SPANStyle.width = '100%';
		SPANStyle.display = 'block';
		SPAN.onclick = function(){ document.location.href = item.href; }
		A = Object.extend(A, item);
		SPAN.innerHTML = A.outerHTML + (typeof(item.count) != 'undefined' ? ('&nbsp;<span class="small">(' + item.count + ')</span>') : '');
		LI.appendChild(SPAN);
		UL.appendChild(LI);
		if (i == len-1 && additional){
			var ADD = document.createElement('LI');
			ADD.innerHTML = additional;
			UL.appendChild(ADD);
		}
	}
	return UL.outerHTML;
}

function ShowFederalLandHierarchy(id, name, path, secId){
	StickyWindowsFactory.hideAllInstances();
	
	if (Undwo.Cache.hierarchy && typeof(Undwo.Cache.hierarchy[id])!="undefined"){
		var w = StickyWindowsFactory.getInstance('hierarchy_'+id);
		w.showAtElementPosition('FederalLandLink_' + id, Undwo.Cache.hierarchy[id], {x:0, y:20, bWidth:15, bHeight:20, draggable:false});
		return false;
	}

	var pattern = '<table width="250"><tr><td valign="top" style="padding:0px"><div style="padding:5px 7px"><a href="'+ APP_URLS['immobilien'] + 'immobilien/' + secId + '/' + path + '/' + Undwo.UrlManager.getParams() +'"><b>Alle anzeigen in '+ name +'</b></a></div><div style="padding:5px 7px; width:236px; height:190px;overflow:auto;overflow-x:hidden">%%CONTENT%%</div></td></tr></table>';
	var w = StickyWindowsFactory.getInstance('hierarchy_'+id);
	w.showAtElementPosition('FederalLandLink_' + id, pattern.replace('%%CONTENT%%', "Laden..."), {x:0, y:20, bWidth:15, bHeight:20, draggable:false});

	getHierarchy(id, function(items){
		var list = [];
		for(var i = 0, len = items.length; i < len; i++)
		{
			var item = items[i],
				count = item.getAttribute('roCount');
			if (count > 0) {
				list.push({
					innerHTML : item.getAttribute('name'),
					count : item.getAttribute('roCount'),
					href : APP_URLS['immobilien'] + 'immobilien/' +  item.getAttribute('secId') + '/' +  item.getAttribute('path') + '/' + Undwo.UrlManager.getParams()
				});
			}
		}
		
		if (!Undwo.Cache.hierarchy) {
			Undwo.Cache.hierarchy = [];
		}
		Undwo.Cache.hierarchy[id] = "";

		if (list.length){
			Undwo.Cache.hierarchy[id] = pattern.replace('%%CONTENT%%', RenderList(list));
		} else {
			Undwo.Cache.hierarchy[id] = pattern.replace('%%CONTENT%%', '<b style="color:red">No districts with properties were found!</b>');
		}
		w.changeContent(Undwo.Cache.hierarchy[id]);
	});
	
	return false;
}

function ShowDistrictHierarchy(id, path, secId){
	var pattern = '<div style="padding:5px 7px"><a href="' + APP_URLS['immobilien'] + 'immobilien/' + secId + '/' + Undwo.Location.District.Path + '/' + Undwo.UrlManager.getParams() +'"><b>Alle anzeigen in '+ Undwo.Location.District.Name +'</b></a></div><div style="width:200px;height:190px;overflow:auto;overflow-x:hidden;padding:5px 7px" id="DistrictContent_'+ id +'">%%CONTENT%%</div>';
	
	if (Undwo.Cache.hierarchy && typeof(Undwo.Cache.hierarchy[id]) != "undefined"){
		TogglePullDown('DistrictLink_' + id, {
			x : 0, y : 20,
			bWidth:15, bHeight:20,
			width : 200,
			height : 150,
			padding : '0px',
			html : pattern.replace('%%CONTENT%%', Undwo.Cache.hierarchy[id])
		})
		return;
	}
	
	TogglePullDown('DistrictLink_' + id, {
		x : 0, y : 20,
		bWidth:15, bHeight:20,
		width : 200,
		height : 150,
		padding : '0px',
		html : pattern.replace('%%CONTENT%%', "Laden...")
	})
	
	getHierarchy(id, function(items){
		var list = [];
		for(var i = 0, len = items.length; i < len; i++)
		{
			var item = items[i],
				count = item.getAttribute('roCount');
			if (count > 0) {
				list.push({
					innerHTML : item.getAttribute('name'),
					count : item.getAttribute('roCount'),
					href : APP_URLS['immobilien'] + 'immobilien/' + item.getAttribute('secId') + '/' + item.getAttribute('path') + '/' + Undwo.UrlManager.getParams()
				});
			}
		}
		
		if (!Undwo.Cache.hierarchy) {
			Undwo.Cache.hierarchy = [];
		}
		
		if (list.length){
			Undwo.Cache.hierarchy[id] = RenderList(list);
		} else {
			Undwo.Cache.hierarchy[id] = '<b style="color:red">No townships with properties were found!</b>';
		}
		
		$('DistrictContent_' + id).innerHTML = Undwo.Cache.hierarchy[id];
		
	});
}


function getHierarchy(id, callback){
	new Ajax.Request(FULL_APP_URL + 'services/geo/' + Undwo.UrlManager.getParams() + 'hierarchy.xml', {
		method : 'get',
		asynchronous : true, 
		evalScripts : false,
		parameters : "LocationId=" + id,

		onLoading : function(r){
			
		}, 
		onComplete : function(r){
			var xml = r.responseXML;
			if (xml && xml.documentElement)
			{
				callback(xml.documentElement.getElementsByTagName('item'));
			} 
			else {
				//ERROR;
			}
			
		}, 
		onFailed : function(r){
			
		}
	});
}

function addCustomPrice(){
	var priceSelect = $('filter_price'),
		from = parseInt(convertNumber($('CustomPrice_FROM').value)),
		to = parseInt(convertNumber($('CustomPrice_TO').value)),
		value = "", title = "";
	
	if (!from){
		value += "0";
		title += "< ";
	} else {
		/*
		var size = from;
		for(var si = 0; size >= 1000; size /= 1000, si++);
		var sizeParts = size.toString().split('.');
		title += sizeParts[0] + (sizeParts[1] ? ('.' + sizeParts[1].substr(0, 2)) : '') + ' KM'.substr(si, 1)
		*/
		value += from;
		title += humanFriendlyNumber(from) + CURRENCY;
	}
	if (!to){
		if (from) title += '+';
	} else {
		if (from) title += ' - ';
		/*
		var size = to;
		for(var si = 0; size >= 1000; size /= 1000, si++);
		var sizeParts = size.toString().split('.');
		title += CURRENCY + sizeParts[0] + (sizeParts[1] ? ('.' + sizeParts[1].substr(0, 2)) : '') + ' KM'.substr(si, 1)
		*/
		value += "-" + to;
		title += humanFriendlyNumber(to) + CURRENCY;
	}
	if (value){
		var len = priceSelect.options.length;
		priceSelect.options[len] = new Option(title/*.replace(/(\.)/g,',')*/, value);
		priceSelect.options[len].innerHTML = title;
		priceSelect.value = value;
	}
	Undwo.UrlManager.insertParam('price', value);
	$('CustomPrice').hide();
}
function addCustomSize(){
	var sizeSelect = $('filter_size'),
		from = parseInt($('CustomSize_FROM').value),
		to = parseInt($('CustomSize_TO').value),
		value = "", title = "";
	
	if (!from){
		value += "0";
		title += "< ";
	} else {
		value += from;
		title += humanFriendlyNumber(from) + "m&sup2;";
	}
	if (!to){
		if (from) title += "+";
	} else {
		if (from) title += " - ";
		value += "-" + to;
		title += humanFriendlyNumber(to) + "m&sup2;";
	}
	if (value){
		var len = sizeSelect.options.length;
		sizeSelect.options[len] = new Option(title.replace(/(\.)/g, ","), value);
		sizeSelect.options[len].innerHTML = title;
		sizeSelect.value = value;
	}
	Undwo.UrlManager.insertParam('size', value);	
	$('CustomSize').hide();
}

function field_OnFocus(obj){
	if (!obj.changed){
		obj.value = "";
	};
	obj.style.color = "black";
}
function field_OnBlur(obj, text){
	text = text || '';
	if(!obj.value){
		obj.value = text;
		obj.changed = false;
		obj.style.color = "#999999";
	}
	else if (obj.value != text) {
		obj.changed = true;
	}
}

/* !TODO : Move to search.js */

function searchForm_OnSubmit(form, text){
	text = text || '';
	var el = form.elements;
	if (el['Keyword'].value!='' && el['Keyword'].value != text){
		form.submit();
	}
	else {
		alert('Please  enter a city, state, ZIP code, or address.');
	}
	return false;
}

function IsDefaultFilterValues() {
	var result = true;
	if ($("filter_minprice").value != 'min'){ result = false; }
	if ($("filter_maxprice").value != 'max'){ result = false; }

	if ($("filter_size") && $("filter_size").selectedIndex != 0){ result = false; }
	if ($("filter_rooms") && $("filter_rooms").selectedIndex != 0){ result = false; }
	if ($("filter_bedrooms") && $("filter_bedrooms").selectedIndex != 0){ result = false; }
	if ($("filter_bathsroom") && $("filter_bathsroom").selectedIndex != 0){ result = false; }
	if ($("filter_type") && $("filter_type").selectedIndex != 0){ result = false; }

	return result;
}
function ManageFilters(){
	if (IsDefaultFilterValues()){
		$('filtersResetLink').hide();
	}
	else {
		$('filtersResetLink').show();
	}
}
function ResetFilterValues() {
	$("filter_minprice").value = 'min';
	$("filter_minprice").style.color='#999999';
	$("filter_maxprice").value = 'max';
	$("filter_maxprice").style.color='#999999';
	if ($("filter_size")){ $("filter_size").selectedIndex = 0; }
	if ($("filter_bedrooms")){ $("filter_bedrooms").selectedIndex = 0; }
	if ($("filter_rooms")){ $("filter_rooms").selectedIndex = 0; }
	if ($("filter_bathsroom")){ $("filter_bathsroom").selectedIndex = 0; }
	if ($("filter_type")){ $("filter_type").selectedIndex = 0; }
	Cookie.del('srchOpt');
	$('filtersResetLink').hide();
}

//return child DOM node by it ID
function getChildNodeById(parent, childId) {
	//Firefox use second way
	var collection = (parent.all || parent.getElementsByTagName('*'));
	
	for (var i = 0; i < collection.length; i++){
		var child = collection[i];
		
		if (child.id == childId)
			return child;
	}
}									

function searchPrepositionClickedSubscribe(li) {
  var id =  getChildNodeById(li, 'OptId').innerHTML;
  var name =  getChildNodeById(li, 'OptName').innerHTML;
  addRowElement(name, id);
  }

function searchPrepositionClicked(li) {
	var url = getChildNodeById(li, 'fullURL').innerHTML;

	var filter_minprice  = $("filter_minprice") ? $("filter_minprice").value : 'min';
	var filter_maxprice  = $("filter_maxprice") ? $("filter_maxprice").value : 'max';
	var filter_size      = $("filter_size") ? $("filter_size").selectedIndex : 0;
	var filter_rooms     = $("filter_rooms") ? $("filter_rooms").selectedIndex : 0;
	var filter_type      = $("filter_type") ? $("filter_type").selectedIndex : 0;
	
	if (filter_minprice != '' && filter_minprice != 'min' ||
		filter_maxprice != '' && filter_maxprice != 'max')
		url += 'price=';
    	
	if (filter_minprice != '' && filter_minprice != 'min')
		url += filter_minprice;
	if (filter_maxprice != '' && filter_maxprice != 'max')
		url += '-' + filter_maxprice;
		
	if (filter_minprice != '' && filter_minprice != 'min' ||
		filter_maxprice != '' && filter_maxprice != 'max')
		url += '/';
		
	if (filter_rooms != 0)
		url += 'rooms=' + filter_rooms + '/';
		
	if (filter_size != 0)
		url += 'size=' + filter_size + '/';
		
	if (filter_type != 0)
		url += 'type=' + filter_type + '/';
	 
	redirect(url);
}


var Drag = {

	obj : null,

	init : function(o, oRoot, minX, maxX, minY, maxY, bSwapHorzRef, bSwapVertRef, fXMapper, fYMapper)
	{
		o.onmousedown	= Drag.start;

		o.hmode			= bSwapHorzRef ? false : true ;
		o.vmode			= bSwapVertRef ? false : true ;

		o.root = oRoot && oRoot != null ? oRoot : o ;

		if (o.hmode  && isNaN(parseInt(o.root.style.left  ))) o.root.style.left   = "0px";
		if (o.vmode  && isNaN(parseInt(o.root.style.top   ))) o.root.style.top    = "0px";
		if (!o.hmode && isNaN(parseInt(o.root.style.right ))) o.root.style.right  = "0px";
		if (!o.vmode && isNaN(parseInt(o.root.style.bottom))) o.root.style.bottom = "0px";

		o.minX	= typeof minX != 'undefined' ? minX : null;
		o.minY	= typeof minY != 'undefined' ? minY : null;
		o.maxX	= typeof maxX != 'undefined' ? maxX : null;
		o.maxY	= typeof maxY != 'undefined' ? maxY : null;

		o.xMapper = fXMapper ? fXMapper : null;
		o.yMapper = fYMapper ? fYMapper : null;

		o.root.onDragStart	= new Function();
		o.root.onDragEnd	= new Function();
		o.root.onDrag		= new Function();
	},

	start : function(e)
	{
		var o = Drag.obj = this;
		e = Drag.fixE(e);
		var y = parseInt(o.vmode ? o.root.style.top  : o.root.style.bottom);
		var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right );
		o.root.onDragStart(x, y);

		o.lastMouseX	= e.clientX;
		o.lastMouseY	= e.clientY;

		if (o.hmode) {
			if (o.minX != null)	o.minMouseX	= e.clientX - x + o.minX;
			if (o.maxX != null)	o.maxMouseX	= o.minMouseX + o.maxX - o.minX;
		} else {
			if (o.minX != null) o.maxMouseX = -o.minX + e.clientX + x;
			if (o.maxX != null) o.minMouseX = -o.maxX + e.clientX + x;
		}

		if (o.vmode) {
			if (o.minY != null)	o.minMouseY	= e.clientY - y + o.minY;
			if (o.maxY != null)	o.maxMouseY	= o.minMouseY + o.maxY - o.minY;
		} else {
			if (o.minY != null) o.maxMouseY = -o.minY + e.clientY + y;
			if (o.maxY != null) o.minMouseY = -o.maxY + e.clientY + y;
		}

		document.onmousemove	= Drag.drag;
		document.onmouseup		= Drag.end;

		return false;
	},

	drag : function(e)
	{
		e = Drag.fixE(e);
		var o = Drag.obj;

		var ey	= e.clientY;
		var ex	= e.clientX;
		var y = parseInt(o.vmode ? o.root.style.top  : o.root.style.bottom);
		var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right );
		var nx, ny;

		if (o.minX != null) ex = o.hmode ? Math.max(ex, o.minMouseX) : Math.min(ex, o.maxMouseX);
		if (o.maxX != null) ex = o.hmode ? Math.min(ex, o.maxMouseX) : Math.max(ex, o.minMouseX);
		if (o.minY != null) ey = o.vmode ? Math.max(ey, o.minMouseY) : Math.min(ey, o.maxMouseY);
		if (o.maxY != null) ey = o.vmode ? Math.min(ey, o.maxMouseY) : Math.max(ey, o.minMouseY);

		nx = x + ((ex - o.lastMouseX) * (o.hmode ? 1 : -1));
		ny = y + ((ey - o.lastMouseY) * (o.vmode ? 1 : -1));

		if (o.xMapper)		nx = o.xMapper(y)
		else if (o.yMapper)	ny = o.yMapper(x)

		Drag.obj.root.style[o.hmode ? "left" : "right"] = nx + "px";
		Drag.obj.root.style[o.vmode ? "top" : "bottom"] = ny + "px";
		Drag.obj.lastMouseX	= ex;
		Drag.obj.lastMouseY	= ey;

		Drag.obj.root.onDrag(nx, ny);
		return false;
	},

	end : function()
	{
		document.onmousemove = null;
		document.onmouseup   = null;
		Drag.obj.root.onDragEnd(	parseInt(Drag.obj.root.style[Drag.obj.hmode ? "left" : "right"]), 
									parseInt(Drag.obj.root.style[Drag.obj.vmode ? "top" : "bottom"]));
		Drag.obj = null;
	},

	fixE : function(e)
	{
		if (typeof e == 'undefined') e = window.event;
		if (typeof e.layerX == 'undefined') e.layerX = e.offsetX;
		if (typeof e.layerY == 'undefined') e.layerY = e.offsetY;
		return e;
	}
};

var StickyWindowsFactory = {
	DWINDOW_INSTANCES_IDS : [],
	DWINDOW_INSTANCES : [],
	imgPath : IMG_PATH || '/dev/views/images/public/',
	
	isCreated : function(id)
	{
		return (typeof(this.DWINDOW_INSTANCES[id]) == 'object');
	},
	
	getInstance : function(id){
		if (typeof(this.DWINDOW_INSTANCES[id]) != 'object'){
			this.DWINDOW_INSTANCES_IDS.push(id);
			this.DWINDOW_INSTANCES[id] = new StickyWindow(id, this.imgPath);
		}
		return this.DWINDOW_INSTANCES[id];
	},
	getAllInstances : function(){
		return this.DWINDOW_INSTANCES;
	},
	hideAllInstances : function(except){
		for(var i in this.DWINDOW_INSTANCES){
			if (this.DWINDOW_INSTANCES_IDS.include(i)){
				if (except && except == i) {
					continue;
				}
				this.DWINDOW_INSTANCES[i].hide();
			}
		}
	},
	setImagePath : function(ip){
		this.imgPath = ip || IMG_PATH || this.imgPath;
	}
};

function StickyWindow(id, ip){
	var element = null, elementStyle = null,
		frame 	= null, frameStyle = null,
		shadow 	= null, shadowStyle = null,
		content = null, contentStyle = null,
		exit 	= null, exitStyle = null,
		id 		= id || 0,
		x 		= 0,
		y 		= 0,
		opened 	= false,
		created = false,
		imgPath = '/dev/views/images/public/',
		settings = {
			zIndexActive : 9999,
			zIndexInactive : 8999,
			bWidth : 20,
			bHeight : 20,
			unifyPosition : false,
			draggable : true,
			container : document.body
		};
	
	setImagePath(ip);
	
	function create(params){
		if (created) {
			return;
		}
		
		params = params ? Object.extend(settings, params) : settings;
		
		element = document.createElement("DIV");
		elementStyle = element.style;
		elementStyle.position = 'absolute';	
		elementStyle.left = '-9999px';
		elementStyle.top = '-9999px';
		
		// if under layer will be SELECT or other Windwos control element we put IFRAME to cover this elements
		if (navigator.appVersion.match(/\bMSIE\b/)){
			frame = document.createElement('IFRAME');
			frame.frameBorder = '0';
			frame.scrolling = 'no';
			frameStyle = frame.style;
			frameStyle.top = "0px";
			frameStyle.left = "0px";			
			frameStyle.position = 'absolute';	
			element.appendChild( frame );
		}
		
		// create window content
		content = document.createElement("DIV");
		content.className = 'StickyWindow-Content'
		contentStyle = content.style;
		contentStyle.position = 'absolute';
		content.onmousedown = function(){ bringOnTop(true); }
		
		// create window shadow
		shadow = new Image();
		shadowStyle = shadow.style; 
		shadowStyle.position = 'absolute';
		shadow.src = imgPath + 'stickywindow/shadow-simple.png';
		if (navigator.appVersion.match(/\bMSIE\b/)){
			shadow.runtimeStyle.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src='+ shadow.src +', sizingMethod=scale)'; 
			shadow.src = imgPath + 't.gif';
		}
		
		//create window close button
		exit = new Image();
		exitStyle = exit.style;
		exitStyle.position = 'absolute';
		exitStyle.right = '4px';
		exitStyle.top =  '4px';
		exitStyle.cursor = 'pointer';
		exit.src = imgPath + 'stickywindow/close.gif';
		exit.onmouseover = function(){ this.src = imgPath + 'stickywindow/close-h.gif'; }
		exit.onmouseout = function(){ this.src = imgPath + 'stickywindow/close.gif'; }
		exit.onclick = function(){ hide(); }

		//append childs to window object
		element.appendChild( shadow );
		content.appendChild( exit );
		element.appendChild( content );
		
		//append window to docuemnt
//		$('not-member-panel').appendChild(element); 
		
		params.container.appendChild(element); 
		created = true;

		draggable(params && params.draggable);
	}
	
	function render(params){
		params = params ? Object.extend(settings, params) : settings;
		
		var bodyWidth = document.body.clientWidth,
			bodyHeight = document.body.clientHeight,
			bodyScrlLeft = document.body.scrollLeft,
			bodyScrlTop = document.body.scrollTop,
			clWidth = content.clientWidth,
			clHeight = content.clientHeight,
			bWidth = params.bWidth, bHeight = params.bHeight;
		
		x = params.x || Math.round( (bodyWidth - clWidth) / 2  +  bodyScrlLeft);
		y = params.y || Math.round( (bodyHeight - clHeight) / 2 +  bodyScrlTop);
		
		// Prevent body overflow
		if (x + clWidth + bWidth > bodyWidth){
			x = x - (x + clWidth + bWidth - bodyWidth);	
		}

		var dirX = -1, dirY = -1, attemptsCount = 0;
		while (params.unifyPosition && !checkUniquePosition(x, y) && attemptsCount < 10){
			attemptsCount ++;
			x = x + (dirX * 20); y = y + (dirY * 20);	
			if (x < 0){ x = 0; dirX = 1; }
			if (y < 0){ y = 0; dirY = 1; }
			if (x - (clWidth + bWidth) > bodyWidth){ x = bodyWidth - (clWidth + bWidth); dirX = -1; }
			if (y - (clHeight + bHeight) > bodyHeight){ y = bodyHeight - (clHeight + bHeight); dirY = -1; }
		}
		
		// Change Shadow width and height because content height and width can be biger
		shadowStyle.width = (clWidth + bWidth) + 'px'; 
		shadowStyle.height = (clHeight + bHeight) + 'px';
		shadowStyle.left = (-1) *  Math.round(bWidth / 2.5) + 'px';
		shadowStyle.top =  (-1) * Math.round(bHeight / 2.5) + 'px';

		if (navigator.appVersion.match(/\bMSIE\b/)){
			frameStyle.width = clWidth + "px";
			frameStyle.height = clHeight + "px";	
		}
		
		elementStyle.left = x + 'px';
		elementStyle.top =  y + 'px';
	}
	
	function show(params){
		if (opened) { return; }
		opened = true;
		create(params);
		render(params);
		bringOnTop(true);
	}
	
	function hide(){
		if (!opened) { return; }
		elementStyle.left = '-9999px';
		elementStyle.top =  '-9999px';
		if (settings && typeof(settings.onClose) == 'function') {
			settings.onClose();
		}
		opened = false;
	}
	
	function draggable(state){
		create();
		if (typeof(Drag) == 'object'){
			if (state) {
				Drag.init(element);
			} else {
				element.onmousedown = null;
			}
		}	
	}
	
	function bringOnTop(state){
		if (state) {
			setzIndex(settings.zIndexActive);
			
			var instances = StickyWindowsFactory.getAllInstances();
			for (var key in instances){
				var instance = instances[key];
				if (typeof(instance) != 'object' || (typeof(instance.getId) == 'function' && instance.getId() == id)){
					continue;	
				}
				if (typeof(instance.bringOnTop) == 'function'){
					instance.bringOnTop(false);
				}
			}
		}
		else {
			setzIndex(settings.zIndexInactive);
		}
	}
	
	function setzIndex(index){
		exitStyle.zIndex 	= index;
		elementStyle.zIndex = index - 1;	
		contentStyle.zIndex = index - 2;
		if (navigator.appVersion.match(/\bMSIE\b/)){
			frameStyle.zIndex 	 = index - 3;
		}
		shadowStyle.zIndex  = index - 4;
	}
	
	function checkUniquePosition(x, y){
		var instances = StickyWindowsFactory.getAllInstances();
		for (var key in instances){
			var instance = instances[key];
			if (typeof(instance) != 'object' || (typeof(instance.getId) == 'function' && instance.getId() == id)){
				continue;	
			}
			if (typeof(instance.getPosition) == 'function'){
				var position = instance.getPosition();
				if (position.x == x && position.y == y){
					return false;
				}
			}
		}
		return true;
	}
	
	function setImagePath(ip){
		imgPath = ip || IMG_PATH || imgPath;
	}

	return {
		getId : function(){
			return id;
		},
		getPosition : function(){
			return {
				'x' : parseInt(elementStyle.left), 
				'y' : parseInt(elementStyle.top)
			};
		},
		changeContent : function(html, params){
			if (typeof(html) == 'string'){
				create(params);
				content.innerHTML = html;
				content.appendChild(exit);
			}
		},
		setOnClose : function(func){
			if (typeof(func) == 'function'){
				settings.onClose = func;
			}
		},
		draggable : function(state){
			draggable(state);
		},
		bringOnTop : function(state){
			bringOnTop(state);
		},
		show : function(html, params){
			if (typeof(html) == 'string'){
				this.changeContent(html);
			}
			show(params);	
		},
		showAtPosition : function(html, params){
			if (typeof(html) == 'string'){
				this.changeContent(html, params);
			}
			show(params);
		},
		showAtElementPosition : function(element, html, params){
			element = $(element);
			var pos = Position.positionedOffset(element);
			if (typeof(html) == 'string'){
				this.changeContent(html, params);
			}
			params = params || settings;
			params.x = (params.x || 0) + pos[0];
			params.y = (params.y || 0) + pos[1];
			show(params);
		},
		hide : function(){
			hide();	
		}
	}
}


