var JsonServiceClient = function() {};

/**
	Creates an HTTP request object for retreiving files.
	@return HTTP request object.
**/
JsonServiceClient.prototype.getHTTPRequestObject = function() 
{
        var obj;
        try{ //to get the mozilla httprequest object
            obj = new XMLHttpRequest();
        }catch(e){
            try{ //to get MS HTTP request object
                obj=new ActiveXObject("Msxml2.XMLHTTP.4.0");
            }catch(e){
                try{ //to get MS HTTP request object
                    obj=new ActiveXObject("Msxml2.XMLHTTP");
                }catch(e){
                    try{// to get the old MS HTTP request object
                        obj = new ActiveXObject("microsoft.XMLHTTP");
                    }catch(e){
                        throw new Exception("Unable to get an HTTP request object.");
                    }
                }
            }
        }
        return obj;
    };

JsonServiceClient.prototype.loadURI = function(uri, cb, sync)
{
	var async = sync == null || sync == false;
           var errorNotHandled=true;
           try{
               var xmlhttp = this.getHTTPRequestObject();
           }catch(e){
               cb(null, 'fail');
               return;
           }
          
           xmlhttp.onreadystatechange=function(){
               if (xmlhttp.readyState==4) {
                   //todo: the status checking needs testing
                   if(xmlhttp.status == 200 || xmlhttp.status == 0 || xmlhttp.status == null || xmlhttp.status == 304){
                       var s= xmlhttp.responseText;
                       xmlhttp = null;
                       cb(s);
                   }else{
                       if(errorNotHandled){
                           errorNotHandled=false;
                           cb(null, 'server error ' + xmlhttp.status);
                       }
                   }
                   xmlhttp=null;
               }else if (xmlhttp.readyState==2){
                   //status property should be available (MS IXMLHTTPRequest documentation)
                   //in Mozilla it is not if the request failed(server not reachable)
                   //in IE it is not available at all ?!
                   try{//see if it is mozilla otherwise don't care.
                       var isNetscape = netscape;
                       try{//if status is not available the request failed.
                           var s=xmlhttp.status;
                       }catch(e){//call the callback because Mozilla will not get to readystate 4
                           if(errorNotHandled){
                               xmlhttp = null;
                               errorNotHandled=false;
                               cb(null, 'url request failed');
                           }
                       }
                   }catch(e){
                   }
               }
           }
      
           try{
               xmlhttp.open("GET", uri, async);
               xmlhttp.send("");
           }catch(e){
               if(errorNotHandled){
                   errorNotHandled=false;
                   xmlhttp=null;
                   cb (null, 'failed');
               }
           }
   };

var JsonSuggester = function()
{
	this.baseUrl = '';
};

JsonSuggester.prototype.applySuggestion = function(fieldId, val)
{
	var elem = document.getElementById(fieldId);
	elem.value = val;
	if (this._popUp)
	{
		this._popUp.style.display = 'none';
	}
};

JsonSuggester.prototype.suggest = function(field, className, fieldName)
{
	var cb = function(src)
	{
		var data = eval('('+src+')');
		if (data.suggestions.length == 0 || data.suggestions[0] == field.value)
		{
			if (this._popUp)
			{
				this._popUp.style.display = 'none';
			}
			return;
		}
			
		var list = '<ul>';
		for (var i=0; i<data.suggestions.length; i++)
		{
			list += '<li onclick="suggester.applySuggestion(\''+field.id+'\',\''+data.suggestions[i]+'\')">' + data.suggestions[i] + '</li>';
		}
		list += '</ul>';
		var elem = document.createElement('div');
		elem.style.position = 'absolute';
		elem.className = 'SuggestionSelectPopUp';
		elem.innerHTML = list;
		elem.style.visibility = 'hidden';
		document.body.appendChild(elem);
		Position.clone(field, elem, {setLeft:true,setTop:true,setWidth:true,setHeight:false,offsetTop:24});
		elem.style.visibility = '';
		if (this._popUp)
		{
			this._popUp.style.display = 'none';
		}
		this._popUp = elem;
	};
	var curValue = field.value;

	var serv = new JsonServiceClient();
	serv.loadURI(this.baseUrl + 'json_service/suggest/'+className + '/' + fieldName + '/?q=' + encodeURIComponent(curValue), cb);
};

JsonSuggester.prototype.attach = function(field, className, fieldName)
{
	if (this._popUp)
	{
		this._popUp.style.display = 'none';
	}
	var thisObj = this;
	var updateTimeout = null;
	var update = function (evt) {
		window.clearTimeout(updateTimeout);
		updateTimeout = window.setTimeout(function (){thisObj.suggest(field, className, fieldName);}, 100);
	};
	field.onkeyup = update;
};

var suggester = new JsonSuggester();


var JsonAssociationManager = function()
{
	this.baseUrl = '';
	this.onShowPopUp = null;
	this.onHidePopUp = null;
};
JsonAssociationManager.prototype._applySelectedAssociation = function(link, fieldId, objId, objDisplayName)
{
	var f = document.getElementById(fieldId);
	f.value = (f.value  ? f.value + ',' : '') + objId;
	if (this._popUp)
	{
		if (this.onHidePopUp)
			this.onHidePopUp();
		this._popUp.style.display = 'none';
	}
	if (link)
	{
		var par = link;
		while (par)
		{
			if (par.nodeName == 'DIV')
			{
				for (var i=0; i<par.childNodes.length;i++)
				{
					var child = par.childNodes[i];
					if (child.nodeName == 'UL')
					{
						var newItem = document.createElement('li');
						newItem.innerHTML = objDisplayName;
						child.appendChild(newItem);
					}
				}
				break;
			}
			par = par.parentNode;
		}
	}
};

JsonAssociationManager.prototype.unlinkAssociation = function(link, fieldId, objId)
{
	var par = link;
	while (par)
	{
		if (par.nodeName == 'LI')
		{
			par.style.display = 'none';
			break;
		}
		par = par.parentNode;
	}
	this._applySelectedAssociation(null, fieldId, objId);
};

JsonAssociationManager.prototype.addAssociation = function(link,fieldId, className)
{
	var serv = new JsonServiceClient();
	var fieldId2 = fieldId;
	var link2 = link;
	var thisObj = this;
	var cb = function(src, err){
		if (err) alert(err);
		var data = eval('(' + src + ')');
		thisObj._showAssociationSelectionPopUp(link2, fieldId2, data);
	}
	serv.loadURI(this.baseUrl + 'json_service/find/'+className+'/', cb);
};

JsonAssociationManager.prototype.addBranch = function(link,fieldId, className)
{
	if (this._popUp)
	{
		if (this.onHidePopUp)
			this.onHidePopUp();
		this._popUp.style.display = 'none';
	}
	var serv = new JsonServiceClient();
	var fieldId2 = fieldId;
	var link2 = link;
	var thisObj = this;
	var bs = document.getElementById('BranchSearch');
	var cb = function(src, err){
		if (err) alert(err);
		var data = eval('(' + src + ')');
		thisObj._showAssociationSelectionPopUp(bs, fieldId2, data);
	}
	serv.loadURI(this.baseUrl + 'json_service/find/'+className+'/?q='+encodeURIComponent(bs.value), cb);
};

JsonAssociationManager.prototype._showAssociationSelectionPopUp = function(link, fieldId, data)
{
	var f = document.getElementById(fieldId);
	var elem = document.createElement('div');
	elem.className = 'AssociationSelectPopUp';
	elem.style.position = 'absolute';
	var list = document.createElement('ul');
	for (var i=0; i<data.objects.length; i++)
	{
		var li = document.createElement('li');
		li._fieldId = fieldId;
		li._objectId = data.objects[i].id;
		li._displayName =  data.objects[i].displayName;
		li._assocMgr = this;
		li.onclick = function () {this._assocMgr._applySelectedAssociation(link, this._fieldId, this._objectId, this._displayName);};
		li.innerHTML = li._displayName;
		list.appendChild(li);
	}
	elem.appendChild(list);
	elem.style.visibility = 'hidden';
	document.body.appendChild(elem);
	Position.clone(link, elem, {setLeft:true,setTop:true,setWidth:false,setHeight:false,offsetTop:24});
	if (this.onShowPopUp)
		this.onShowPopUp();
	elem.style.visibility = '';
	this._popUp = elem;
};

JsonAssociationManager.prototype.findObject = function(fieldId, className)
{
	var serv = new JsonServiceClient();
	var thisObj = this;
	var field2 = fieldId;
	var cb = function(src, err){
		var f = document.getElementById(field2);
		var fd = document.getElementById(field2+'_displayName');
		if (err) alert(err);
		var data = eval('(' + src + ')');
		thisObj._showObjectSelectionPopUp(field2, data);
	}
	serv.loadURI(this.baseUrl + 'json_service/find/' + className + '/', cb);
};

JsonAssociationManager.prototype._selectObjectForField = function(fieldId, objId, objDisplayName)
{
	var f = document.getElementById(fieldId);
	var fd = document.getElementById(fieldId+'_displayName');
	f.value = objId;
	fd.value = objDisplayName;
	if (this._popUp)
	{
		if (this.onHidePopUp)
			this.onHidePopUp();
		this._popUp.style.display = 'none';
	}
};
JsonAssociationManager.prototype._showObjectSelectionPopUp = function(fieldId, data)
{
	if (this._popUp)
	{
		this._popUp.style.display = 'none';
	}
	var fd = document.getElementById(fieldId+'_displayName');
	var elem = document.createElement('div');
	elem.className = 'ObjectSelectPopUp';
	elem.style.position = 'absolute';
	var list = document.createElement('ul');
	for (var i=0; i<data.objects.length; i++)
	{
		var li = document.createElement('li');
		li._fieldId = fieldId;
		li._objectId = data.objects[i].id;
		li._displayName =  data.objects[i].displayName;
		li._assocMgr = this;
		li.onclick = function () {this._assocMgr._selectObjectForField(this._fieldId, this._objectId, this._displayName);};
		li.innerHTML = li._displayName;
		list.appendChild(li);
	}
	elem.appendChild(list);
	elem.style.visibility = 'hidden';
	document.body.appendChild(elem);
	Position.clone(fd, elem, {setTop:true,setLeft:true,setWidth:true,setHeight:false,offsetTop:24});
	if (this.onShowPopUp)
		this.onShowPopUp();
	elem.style.visibility = '';
	this._popUp = elem;
};

var assocMgr = new JsonAssociationManager();

