﻿/**
 *
 * Redistribution and use of this software and associated documentation
 * ("Software"), with or without modification, are prohibited 
 *
 * THIS SOFTWARE IS PROVIDED BY SMARTFOCAL AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
 * OPENCS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Copyright 2008 (C) smartFocal. All Rights Reserved.
 *
 */
var SmartFocal = {
  Version: '0.0.0.2',
  Mime: {
    SVG:  'image/svg+xml',
    VML:  'text/vml',
    FLASH: 'application/x-shockwave-flash',
    PNG: 'image/png',
    JPEG: 'image/jpeg'
  },
  MapType: {
    GRAPH:  'graph',
    TREE:   'tree'
  },
  MapTipId: 'smartfocalTip',
  getNodeType: function(element) {
	if( element.tagName!='g' && element.tagName!='v:group' && element.tagName!='group') 
		return SmartFocalItem.Type.NONE;
	var className = element.className.baseVal || element.className;
	switch( className) {
		case 'map-layers':
			return SmartFocalItem.Type.MAP;
		case 'node-layers':
			return SmartFocalItem.Type.OBJECT;
		case 'node-property-layers':
			return SmartFocalItem.Type.PROPERTY;
		case 'group-layers':
			return SmartFocalItem.Type.GROUP;
		case 'link-layers':
			return SmartFocalItem.Type.LINK;
	}
	return SmartFocalItem.Type.NONE;
  }
}

var SmartFocalMap = Class.create();
SmartFocalMap.prototype = {
initialize: function( uuid, mapDiv, callback) {
	this.url = "/smartfocal";
	this.uuid = uuid;
	this.callback = false;
	this.callback = callback; 
	this.SMFparameters = new Hash();
	this.MyParameters = new Hash();
	this.domMap = false;
	this.map = false;
	this.mapDiv = $(mapDiv);
	this.mapDiv.smartFocal = this;
	this.inline = false;
	this.currentTip = false;
	this.mousing = false;
},
setSMFParameter: function( name, value) {
	this.SMFparameters.set( name, value);	
},
getSMFParameter: function( name) {
	return this.SMFparameters.get( name);	
},
setMyParameter: function( name, value) {
	this.MyParameters.set( name, value);	
},
getMyParameter: function( name) {
	return this.MyParameters.get( name);	
},
prepareParameters: function() {
	this.SMFparameters.set( 'smf-url', this.url);
	this.SMFparameters.set( 'map', this.uuid);
	this.SMFparameters.set( 'div', this.mapDiv.id);
	this.SMFparameters.set( 'width', this.mapDiv.getWidth());
	this.SMFparameters.set( 'height', this.mapDiv.getHeight());
	if( document['characterSet'])
		this.SMFparameters.set( 'encoding', document[ 'characterSet']);
	this.SMFparameters.set( 'myParameters', Object.toQueryString( this.MyParameters));
	if( Prototype.Browser.IE) {
		this.SMFparameters.set( 'format', SmartFocal.Mime.VML);
		this.SMFparameters.set( 'encapsulate', 'frame');
	}
	else if (navigator.mimeTypes && navigator.mimeTypes.length > 0 && navigator.mimeTypes[SmartFocal.Mime.SVG])
		this.SMFparameters.set( 'format', SmartFocal.Mime.SVG);
	else if (navigator.userAgent.indexOf('Firefox') > -1)
		this.SMFparameters.set( 'format', SmartFocal.Mime.SVG);
	else 
		this.SMFparameters.set( 'format', SmartFocal.Mime.PNG);
},
generate: function() {
	this.mousing = false;
	if( this.currentTip) {
		this.currentTip = false;
		$(SmartFocal.MapTipId).style.visibility = 'hidden';
	}
	this.prepareParameters();
	if( this.callback)
		this.callback( this, null, { type : 'pre-generate'});
	var url = this.url + '/engine';
	
	var frameCall = false; 
	if( this.SMFparameters.get( 'encapsulate') == 'frame') {
		frameCall = '<iframe resizable="no" style="margin:0;padding:0;border-width:0;border-style:none;scrolling:none" src=' + url + '?' + Object.toQueryString( this.SMFparameters) + ' width="100%" height="100%" ></iframe>'; 
	}
	if( this.SMFparameters.get( 'format') == SmartFocal.Mime.VML){
		if( frameCall) {
			this.mapDiv.update( frameCall);
		}
		else {
			var mapDiv = this.mapDiv;
			new Ajax.Request(url, {
				method: 'post',
				parameters: Object.toQueryString( this.SMFparameters),
				onSuccess: function(transport) {
					mapDiv.update( transport.responseText);
				},
				onFailure: function(transport) {
				  	alert( "erreur");
				}
			});
			this.inline = true;
		}
		if( !$(SmartFocal.MapTipId)) {
			var divTip = document.createElement("div");
			with( divTip) {
				id = SmartFocal.MapTipId;
				style.position = 'absolute';
				style.visibility = 'hidden';
				//style.z-index = '1';
			}
			document.body.appendChild(divTip);
			//new Insertion.After( this.mapDiv, '<div id="'+SmartFocal.MapTipId+'" style="position:absolute;visibility:hidden;left:0;top:0;width:0;height:0;z-index:1"></div>');
		}
	}
	else if( this.SMFparameters.get( 'format') == SmartFocal.Mime.SVG) { 
		if( frameCall) {
			this.mapDiv.update( frameCall);
		}
		else {
			this.mapDiv.update( '<object type="image/svg+xml" data=' + url + '?' + Object.toQueryString( this.SMFparameters) + ' width="' + this.SMFparameters.get( 'width') + '" height="' + this.SMFparameters.get( 'height') + '" />');
		}
		if( !$(SmartFocal.MapTipId)) {
			var divTip = document.createElement("div");
			with( divTip) {
				id = SmartFocal.MapTipId;
				style.position = 'absolute';
				style.visibility = 'hidden';
				//style.z-index = '1';
			}
			document.body.appendChild(divTip);
		}
	}
	else if( this.SMFparameters.get( 'format') == SmartFocal.Mime.JPEG) { 
		this.mapDiv.update( '<img src=' + url + '?' + Object.toQueryString( this.SMFparameters) + ' width="100%" height="100%" />');
		if( this.callback) this.callback( this, null, { type : 'post-generate'});
	}
	else if( this.SMFparameters.get( 'format') == SmartFocal.Mime.PNG) { 
		this.mapDiv.update( '<img src=' + url + '?' + Object.toQueryString( this.SMFparameters) + ' width="100%" height="100%" />');
		if( this.callback) this.callback( this, null, { type : 'post-generate'});

		var mapDiv = this.mapDiv; 
		var params = new Hash();
		params.set( 'type', 'unsupported');
		params.set( 'navigator.appName', navigator.appName);
		params.set( 'navigator.appCodeName', navigator.appCodeName);
		params.set( 'navigator.appVersion', navigator.appVersion);
		params.set( 'navigator.platform', navigator.platform);
		params.set( 'navigator.plugins', navigator.plugins);
		params.set( 'navigator.userAgent', navigator.userAgent);
		$H(SmartFocal.Mime).each( function(mime) {
			params.set( 'navigator.mimeTypes['+mime[1]+']', navigator.mimeTypes && navigator.mimeTypes[mime[1]] ? navigator.mimeTypes[mime[1]].type  : 'none');
		});
		var url = this.url + "/error";
		new Ajax.Request(url, {
			method: 'post',
			parameters: params
		});
	}
},
_initialize: function( domMap, jsonMap) {
	//Element.extend( map);
	this.domMap = domMap; 
	this.map = this.fetch( jsonMap.evalJSON(), domMap); 
	if( this.callback)
		this.callback( this, null, { type : 'post-generate'});
},
_error: function( error) {
	alert( error);
},
onMapEvent: function(event) {
	var node = this.getSmartFocalNode(Event.element(event));//event.target);
	if( !node) return;
	switch( event.type) {
    case 'mouseover':
    	//console.log( "Mouseover " + node.id);
      //this.mousing += "Mouseover " + node.id + " / ";
			this.toggle(node,SmartFocalItem.State.ACTIVE,SmartFocalItem.State.AWAKE);
			node.showTip(this,event.clientX,event.clientY);
      if( this.callback)
				this.callback( this, node, event);
		break;
    case 'mousemove':
			node.showTip(this,event.clientX,event.clientY);
			break;
    case 'mouseout': 
    	//console.log( "Mouseout " + node.id);
      //this.mousing += "Mouseout " + node.id + " / ";
    	node.hideTip(this); 
			this.toggle(node,SmartFocalItem.State.ASLEEP,SmartFocalItem.State.ASLEEP);
      if( this.callback)
				this.callback( this, node, event);
			break;
    case 'click':
     	//alert( this.mousing);
      if( this.callback)
				this.callback( this, node, event);
			break;
    }
 	//Event.stop(event);
},
getSmartFocalNode: function(item) {
	while(item && (item.tagName!='svg' || item.tagName!='div')) {
		//console.log( 'item ' + item.tagName);
	  	switch( SmartFocal.getNodeType( item)) {
	  	case SmartFocalItem.Type.MAP:
			return this.map;
	  	case SmartFocalItem.Type.GROUP:
			return this.map.groups.get( item.id);
		case SmartFocalItem.Type.OBJECT:
			return this.map.objects.get( item.id);
		case SmartFocalItem.Type.LINK:
			return this.map.links.get( item.id);
		case SmartFocalItem.Type.PROPERTY:
		    var owner = this.getSmartFocalNode(item.parentNode);
		    return owner.properties.get( item.id);
		default:
			item = item.parentNode;
		}
	}
	return false;
},
getToggleSet: function(node) {
	if( SmartFocalItem.Type.PROPERTY == node.smftype) {
		return this.getToggleSet(node.owner);
	}
	else if( SmartFocalItem.Type.GROUP == node.smftype) {
		return node;
	}
	else if( SmartFocalItem.Type.OBJECT == node.smftype) {
		if( SmartFocal.MapType.GRAPH == this.map.format)
			return node.group;
		return node;
	}
	else if( SmartFocalItem.Type.LINK == node.smftype) {
		return node;
	}
	return node;
},
toggle: function(node, center, neighbor) {
	var tset = this.getToggleSet( node);
	tset.toggle(neighbor);
	node.toggleItem(center);
},
fetch: function(map, domMap) {
	if( SmartFocal.MapType.TREE == map.format)
		return this.fetchTree(map, domMap, this.onMapEvent.bind(this));
	if( SmartFocal.MapType.GRAPH == map.format)
		return this.fetchGraph(map, domMap, this.onMapEvent.bind(this));
},
fetchTree: function(sfmap, domMap, eventhandler) {
	var smartfocal = this;
	var objects = new Hash();
	sfmap.objects.each( function(object) {
      object.smftype = SmartFocalItem.Type.OBJECT;
      object.element = domMap.getElementById(object.id);
      object.smartfocal = smartfocal;
      Object.extend(object,SmartFocalItem);
      Object.extend(object,SmartFocalObject);
      object.fetchProperties();
      object._initEvents( eventhandler);
      objects.set( object.id, object);
	});	
	var links = new Hash();
	sfmap.links.each( function(link) {
	  link.smftype = SmartFocalItem.Type.LINK;
      link.element = domMap.getElementById(link.id);
      link.smartfocal = smartfocal;
      Object.extend(link,SmartFocalItem);
      Object.extend(link,SmartFocalLink);
      link._initEvents( eventhandler);
	  links.set( link.id, link);
	});	
    sfmap.objects = objects;
	sfmap.links = links;
	
	sfmap.smftype = SmartFocalItem.Type.MAP;
	sfmap.element = domMap.getElementById(sfmap.id);
	sfmap.smartfocal = smartfocal;
	Object.extend(sfmap,SmartFocalItem);
	Object.extend(sfmap,SmartFocalMapContainer);
	sfmap._initEvents( eventhandler);
	return sfmap;
},
fetchGraph: function(sfmap, domMap, eventhandler) {
	var smartfocal = this;
	var groups = new Hash();
	sfmap.groups.each( function(group) {
	  group.smftype = SmartFocalItem.Type.GROUP;
      group.element = domMap.getElementById(group.id);
      group.smartfocal = smartfocal;
      Object.extend(group,SmartFocalItem);
      Object.extend(group,SmartFocalGroup);
      group._initEvents( eventhandler);
	  groups.set( group.id, group);
	});	
	var links = new Hash();
	sfmap.links.each( function(link) {
	  link.smftype = SmartFocalItem.Type.LINK;
      link.element = domMap.getElementById(link.id);
      link.smartfocal = smartfocal;
      Object.extend(link,SmartFocalItem);
      Object.extend(link,SmartFocalLink);
      link._initEvents( eventhandler);
	  links.set( link.id, link);
	});	
	var objects = new Hash();
	sfmap.objects.each( function(object) {
	  object.smftype = SmartFocalItem.Type.OBJECT;
      object.element = domMap.getElementById(object.id);
      object.smartfocal = smartfocal;
      Object.extend(object,SmartFocalItem);
      Object.extend(object,SmartFocalObject);
      object.fetchProperties();
      object._initEvents( eventhandler);
	  objects.set( object.id, object);
	});	
	var attributes = new Hash();
	sfmap.attributes.each( function(attribute) {
	  attribute.smftype = SmartFocalItem.Type.ATTRIBUTE;
      attribute.smartfocal = smartfocal;
      Object.extend(attribute,SmartFocalItem);
      Object.extend(attribute,SmartFocalAttribute);
      attribute._initEvents( eventhandler);
	  attributes.set( attribute.id, attribute);
	});	
	groups.each(function(pair) {
 		pair.value.links.each( function(link) {
		  link = links.get( link);
		});	
	});
	links.each(function(pair) {
 		pair.value.from = groups.get( pair.value.from);
 		pair.value.to = groups.get( pair.value.to);
	});
	objects.each(function(pair) {
 		pair.value.group = groups.get( pair.value.group);
	});
	attributes.each(function(pair) {
 		pair.value.objects.each( function(object) {
		  object = objects.get( object);
		});	
 		pair.value.links.each( function(link) {
		  link = links.get( link);
		});	
	});

	sfmap.groups = groups;
	sfmap.links = links;
	sfmap.objects = objects;
	sfmap.attributes = attributes;
	
	sfmap.groups.each( function(group) {
	  var o = new Hash();
	  group.value.objects.each( function(id) {
		o.set( id, sfmap.objects.get( id));
	  });
	  group.value.objects = o;
	  o = new Hash();
	  group.value.attributes.each( function(id) {
		o.set( id, sfmap.attributes.get( id));
	  });
	  group.value.attributes = o;
	});	

	sfmap.objects.each( function(object) {
	  o = new Hash();
	  object.value.attributes.each( function(id) {
		o.set( id, sfmap.attributes.get( id));
	  });
	  object.value.attributes = o;
	});	

	sfmap.links.each( function(link) {
	  o = new Hash();
	  link.value.attributes.each( function(id) {
		o.set( id, sfmap.attributes.get( id));
	  });
	  link.value.attributes = o;
	});	
	
	sfmap.smftype = SmartFocalItem.Type.MAP;
	sfmap.element = domMap.getElementById(sfmap.id);
    sfmap.smartfocal = this;
	Object.extend(sfmap,SmartFocalItem);
	Object.extend(sfmap,SmartFocalMapContainer);
    sfmap._initEvents( eventhandler);
	return sfmap;
  }
}

var SmartFocalProperty = {
  toggle: function(show) {
  	this.toggleItem(show);
  },
  nodeName: function() {
  	return "node-property-layers";
  }
}

var SmartFocalGroup = {
  toggle: function(show) {
	this.objects.each(function( obj) {
		obj.value.toggle(show);
	});
  	this.toggleItem(show);
  },
  nodeName: function() {
  	return "group-layers";
  }
}

var SmartFocalObject = {
  toggle: function(show) {
	this.properties.each(function(prop) {
		prop.value.toggle(show);
	});
  	this.toggleItem(show);
  },
  nodeName: function() {
  	return "node-layers";
  }
}

var SmartFocalAttribute = {
  toggle: function(show) {
  	this.toggleItem(show);
  },
  nodeName: function() {
  	return "attribute-layers";
  }
}

var SmartFocalLink = {
  toggle: function(show) {
  	this.toggleItem(show);
  },
  nodeName: function() {
  	return "link-layers";
  }
}

var SmartFocalMapContainer = {
  toggle: function(show) {
  	this.toggleItem(show);
  },
  nodeName: function() {
  	return "map-layers";
  }
}

var SmartFocalItem = {
  Type: {
    MAP: 'map',
    GROUP: 'group',
    OBJECT: 'object',
    ATTRIBUTE: 'attribute',
    LINK: 'link',
    PROPERTY: 'property',
    NONE: false
  },
  State: {
    ASLEEP: '.asl',
    AWAKE: '.awk',
    ACTIVE: '.act',
    FLAG: '.flg',
    TIP: '.tip'
  },
  _initEvents: function( eventHandler) {
  	if( !this.element) return;
		Event.observe(this.element, 'click', eventHandler);
		Event.observe(this.element, 'mouseover', eventHandler);
		Event.observe(this.element, 'mouseout', eventHandler);
		Event.observe(this.element, 'mousemove', eventHandler);
  },
  fetchProperties: function() {
    this.properties = new Hash();
    var element = this.element.firstChild;
    while (element) {
      if(SmartFocal.getNodeType(element)==SmartFocalItem.Type.PROPERTY){
				var property = new Object();
				Object.extend(property,SmartFocalItem);
				Object.extend(property,SmartFocalProperty);
		  	property.id = element.id;
		  	property.smftype = SmartFocalItem.Type.PROPERTY;
				property.element = element;
				property.owner = this;
			  this.properties.set( element.id, property);
      }
      element = element.nextSibling;
    }
  },
  getChildsByMode: function() {
  	if( this.childByMode) return this.childByMode;
  	var id = this.id;
    var result = new Hash();
    var element = this.element.firstChild;
    while (element && result.size()<4) {
      if( 1 == element.nodeType) {
      	if(id+SmartFocalItem.State.ASLEEP == element.id)
	        result.set( SmartFocalItem.State.ASLEEP, element);
      	else if(id+SmartFocalItem.State.AWAKE == element.id)
	        result.set( SmartFocalItem.State.AWAKE, element);
      	else if(id+SmartFocalItem.State.ACTIVE == element.id)
	        result.set( SmartFocalItem.State.ACTIVE, element);
      	else if(id+SmartFocalItem.State.FLAG == element.id)
	        result.set( SmartFocalItem.State.FLAG, element);
//      	else if(id+SmartFocalItem.State.TIP == element.id)
//	        result.set( SmartFocalItem.State.TIP, element);
	    }
      element = element.nextSibling;
    }
    if( this.smartfocal) {
	    element = this.smartfocal.domMap.getElementById( id+SmartFocalItem.State.TIP);
	    if( element)
		  	result.set( SmartFocalItem.State.TIP, element);
		}
    this.childByMode = result;
    return result;
  },
  toggleItem: function(show) {
  	var childs = this.getChildsByMode();
  	if( childs.get( show) && !this.visible( childs.get( show))) {
  		var item = this;
  		item.show( childs.get( show), true);
      childs.each(function(node){
  		  if(node.key!=show && node.key!=SmartFocalItem.State.TIP) 
  		  	item.show(node.value,false);
  		})
	}
  },
  flag: function() {
  	this.toggleItem( SmartFocalItem.State.FLAG);
  },
  flash: function() {
  	var childs = this.getChildsByMode();
  	childs.remove( SmartFocalItem.State.FLAG);
  	var keys = childs.keys();
	new PeriodicalExecuter(function(pe) {
	  	for (var i=0; i < keys.length; ++i) {
		  	if( this.visible( childs.get( keys[i])))
		  		this.toggleItem( childs.get( keys[(i+1 == keys.length ? 0 : i+1)]));
	  	}
		node.
		pe.stop();
	}, 1);
  },
  visible: function(element) {
  	if( !element) return;
  	return element.style.visibility != 'hidden';
  },
  show: function(element,display) {
  	if( !element) return;
  	if( display && !this.visible(element))
  		element.style.visibility = 'visible';
  	else if( !display && this.visible(element))
  		element.style.visibility = 'hidden';
  },
  setOnTopLevel: function( smfMap, elem) {
  	var level = new Hash();
  	if( smfMap.SMFparameters.get( 'format') == SmartFocal.Mime.SVG) {
	  	level.set( 'parent', elem.parentNode);
	  	level.set( 'next', elem.nextSibling);
			//smfMap.domMap.getElementsByTagName('svg')[0].appendChild( elem);
  		return level;
	  }
  	else if( smfMap.SMFparameters.get( 'format') == SmartFocal.Mime.VML) {
 			level.set( 'z-index', elem.style.zindex ? elem.style.zindex : 0);
 			elem.style.zindex = '1';
	  	return level;
  	}
  	return false;
  },
  restoreLevel: function( smfMap, elem, level) {
  	if( !level) return;
  	if( smfMap.SMFparameters.get( 'format') == SmartFocal.Mime.SVG) {
  		if( level.get( 'parent') && level.get( 'next')) {
				//level.get( 'parent').insertBefore( elem, level.get( 'next'));	
			}
	  }
  	else if( smfMap.SMFparameters.get( 'format') == SmartFocal.Mime.VML) {
  		if( level.get( 'z-index'))
 				elem.style.zindex = level.get( 'z-index');
  	}
  },
  showTip: function( smfMap, x, y) {
		var mousedeltax = 10, mousedeltay = 10, securex = 0, securey = 0;
		var tipScale = 1;
		var tipcontent = $(SmartFocal.MapTipId);
		var xPos = x;// + (10 * tipScale);
		var yPos = y;// + (10 * tipScale);
		if( !smfMap.currentTip || smfMap.currentTip.get('elem').id!=this.id){
			this.hideTip( smfMap);
	  	var tip = this.getChildsByMode().get( SmartFocalItem.State.TIP);
	  	if( !tip) return;
  		smfMap.currentTip = new Hash();
    	smfMap.currentTip.set( 'elem', this);
    	smfMap.currentTip.set( 'frame', tip);
    	var c = tip.firstChild;
	    while (c) {
	      if( 1 == c.nodeType) {
      		smfMap.currentTip.set( 'box', c);
      		break;
      	}
      	c = c.nextSibling;
	    }
    
  		var text = false;
  		if( smfMap.callback) text = smfMap.callback( smfMap, this, { type : 'tiptext'});
			if( !text) {
				smfMap.currentTip = false;
				return;
			}
			tipcontent.update( text);
		
			var deltax = xPos + tipcontent.offsetWidth + securex < this.smartfocal.mapDiv.offsetWidth ? mousedeltax : -tipcontent.offsetWidth-mousedeltax;
			var deltay = yPos + tipcontent.offsetHeight + securey < this.smartfocal.mapDiv.offsetHeight ? mousedeltay : -tipcontent.offsetHeight-mousedeltay;
			if( smfMap.SMFparameters.get( 'format') == SmartFocal.Mime.SVG) {
				var mapPos = this.smartfocal.mapDiv.cumulativeOffset();
				tipcontent.style.left=xPos+deltax+mapPos[0]+"px";
				tipcontent.style.top=yPos+deltay+mapPos[1]+"px";
				with( smfMap.currentTip.get( 'box')) {
					setAttribute( 'width', tipcontent.offsetWidth);
					setAttribute( 'height', tipcontent.offsetHeight);
					setAttribute( 'x', xPos+deltax);//+mapPos[0]);
					setAttribute( 'y', yPos+deltay);//+mapPos[1]);
				}
			}
			else if( smfMap.SMFparameters.get( 'format') == SmartFocal.Mime.VML) {
				var mapPos = smfMap.inline ? this.smartfocal.mapDiv.cumulativeScrollOffset() : this.smartfocal.mapDiv.cumulativeOffset();
				var mapPos2 = smfMap.inline ? this.smartfocal.mapDiv.cumulativeOffset() : this.smartfocal.mapDiv.cumulativeOffset();
				tipcontent.style.left=xPos+deltax+mapPos[0]+"px";
				tipcontent.style.top=yPos+deltay+mapPos[1]+"px";
				with( smfMap.currentTip.get( 'box').style) {
					width = tipcontent.offsetWidth+"px";
					height = tipcontent.offsetHeight+"px";
					left = xPos+deltax+mapPos[0]-mapPos2[0]+"px";
					top = yPos+deltay+mapPos[1]-mapPos2[1]+"px";
				}
			}
			this.show(smfMap.currentTip.get( 'frame'),true);
			this.show(tipcontent,true);
		}
		else {
			var deltax = xPos + tipcontent.offsetWidth + securex < this.smartfocal.mapDiv.offsetWidth ? mousedeltax : -tipcontent.offsetWidth-mousedeltax;
			var deltay = yPos + tipcontent.offsetHeight + securey < this.smartfocal.mapDiv.offsetHeight ? mousedeltay : -tipcontent.offsetHeight-mousedeltay;
			if( smfMap.SMFparameters.get( 'format') == SmartFocal.Mime.SVG) {
				var mapPos = this.smartfocal.mapDiv.cumulativeOffset();
				tipcontent.style.left=xPos+deltax+mapPos[0]+"px";
				tipcontent.style.top=yPos+deltay+mapPos[1]+"px";
				with( smfMap.currentTip.get( 'box')) {
					setAttribute( 'x', xPos+deltax);
					setAttribute( 'y', yPos+deltay);
				}
			}
			else if( smfMap.SMFparameters.get( 'format', SmartFocal.Mime.VML)) {
				var mapPos = smfMap.inline ? this.smartfocal.mapDiv.cumulativeScrollOffset() : this.smartfocal.mapDiv.cumulativeOffset();
				var mapPos2 = smfMap.inline ? this.smartfocal.mapDiv.cumulativeOffset() : this.smartfocal.mapDiv.cumulativeOffset();
				tipcontent.style.left=xPos+deltax+mapPos[0]+"px";
				tipcontent.style.top=yPos+deltay+mapPos[1]+"px";
				with( smfMap.currentTip.get( 'box').style) {
					left = xPos+deltax+mapPos[0]-mapPos2[0]+"px";
					top = yPos+deltay+mapPos[1]-mapPos2[1]+"px";
				}
			}
		}
  },
  hideTip: function( smfMap) {
		if( smfMap.currentTip) {
			var tipcontent = $(SmartFocal.MapTipId);
			this.show(tipcontent,false);
			this.show(smfMap.currentTip.get( 'frame'),false);
			//tipcontent.update( '');
			smfMap.currentTip = false;
		}
  }
}

var SmartFocalPopupMenu = Class.create();
SmartFocalPopupMenu.prototype = {
  SEPARATOR: 'SmartFocalPopupMenu.SEPARATOR',
  current: null,
  initialize: function( smfmap, style) {
	this.smfmap = smfmap;
	this.items  = [];
	this.width  = 0;
	this.height = 0;
	this.smfstyle = style;
},
setSize: function(width, height) {
    this.width  = width;
    this.height = height;
    if (this.element) {
        var self = this;
        with (this.element.style) {
            if (self.width)  width  = self.width  + 'px';
            if (self.height) height = self.height + 'px';
        }
    }
},
add: function(text, callback, style, over, out) {
    this.items.push({text: text, callback: callback, style: style, over: over, out: out});
},
addSeparator: function(style) {
    this.items.push({text: SmartFocalPopupMenu.SEPARATOR, style: style});
},
onMapEvent: function(event) {
	switch( event.type) {
      case 'click':
    	if (SmartFocalPopupMenu.current && SmartFocalPopupMenu.current == this) {
	  		this.hide();
    	}
		break;
	}
},
show: function(e) {
    if (SmartFocalPopupMenu.current && SmartFocalPopupMenu.current != this) return;
    SmartFocalPopupMenu.current = this;
    var newelem = !this.element;
    if( newelem)
        this.element = this.createMenu(this.items);
	    var deltax = 0;
	    var deltay = 0;
		if( this.smfmap.SMFparameters.get( 'format') == SmartFocal.Mime.SVG) {
		    deltax = this.smfmap.inline ? 0 : this.smfmap.mapDiv.offsetLeft;
		    deltay = this.smfmap.inline ? 0 : this.smfmap.mapDiv.offsetTop;
		}
		else if( this.smfmap.SMFparameters.get( 'format', SmartFocal.Mime.VML)) {
			var mapPos = this.smfmap.mapDiv.cumulativeOffset();
		    deltax = this.smfmap.inline ? 0 : mapPos[0];
		    deltay = this.smfmap.inline ? 0 : mapPos[1]; 
		}
    this.element.style.top  = (e.clientY+deltay) + 'px';
    this.element.style.left = (e.clientX+deltax) + 'px';
	if( newelem)
        document.body.appendChild(this.element);
    else 
        this.element.style.display = '';
    Event.stop(e);
	Event.observe(this.smfmap.domMap, 'click', this.onMapEvent.bind(this));
},
hide: function() {
    SmartFocalPopupMenu.current = null;
    if (this.element) this.element.style.display = 'none';
	Event.stopObserving(this.smfmap.domMap, 'click', this.onMapEvent.bind(this));
	Element.remove(this.element);
},
createMenu: function(items) {
    var self = this;
    var menu = document.createElement('div');
    Element.setStyle( menu, this.smfstyle);
    Element.setStyle( menu, {position:'absolute',display:'block'});
    for (var i = 0; i < items.length; i++) {
        var item;
        if (items[i].text == SmartFocalPopupMenu.SEPARATOR) {
            item = this.createSeparator(item.style);
        } else {
            item = this.createItem(items[i]);
        }
        menu.appendChild(item);
    }
    return menu;
},
createItem: function(item) {
	var self = this;
    var elem = document.createElement('div');
    Element.setStyle( elem, item.style);
    Element.setStyle( elem, item.out);
    var callback = item.callback;
	Event.observe(elem, 'click', function(_callback) {
        return function() {
            self.hide();
            _callback(self.smfmap);
        };
    }(callback), true);
    Event.observe(elem, 'mouseover', function(e) {
    	Element.setStyle( elem, item.over);
    }, true);
    Event.observe(elem, 'mouseout', function(e) {
    	Element.setStyle( elem, item.out);
    }, true);
    elem.appendChild(document.createTextNode(item.text));
    return elem;
},
createSeparator: function(style) {
    var sep = document.createElement('div');
    if( !style) style = {borderTop:'1px dotted #000000', fontSize:'0px', height:'0px'};
   	Element.setStyle( sep, style);
    return sep;
}
}

