function runtime_controller()
{
	this.sheetMetadataId = null;
	this.activityDefinitionId = null;
	this.applicationId = null
	this.metadatatype = null
	this.editorGridViewId = null
    this.showValidation = false;
    this.selectedAttachment=null;
    this.cachedData = null;
    this.validationElements = null;
    this.lastExcludeConDictStr = null

   	this.locateLayoutTemplate = function(){return "layout";}

	this.locateViewTemplates = function(){return {content:"content",parameter:"parameter"};}

	this.preinit = function()
	{
		this.showValidation = false;
		this.validationElements=null;
		this.lastExcludeConDictStr = null;
		if(this.meta.validate)
			this.showValidation = true
		var urlWithQsList = this.url.split("?")
		if(urlWithQsList.length > 1)
			this.editorGridViewId = getQueryStringValue(urlWithQsList[1], 'editorGridViewId')
		var urlList = urlWithQsList[0].split('/')
		this.sheetMetadataId = urlList[3];
		this.activityDefinitionId = urlList[4];
		if (this.activityDefinitionId == "report")
			this.activityDefinitionId += '/'+ urlList[5]
		this.applicationId = urlList[1];
		this.metadatatype = urlList[2];
		this.cachedData = $(window).data(this.id)
	}

	this.getDatePickerFormatStr = function(datefmtStr){
		//http://docs.jquery.com/UI/Datepicker/formatDate
		return datefmtStr.replace("MMM", "M").replace("MM", "mm").replace("yy", "y").replace("yy", "y")
	}

	this.getDateTimePickerFormatStr = function(dateTimefmtStr){
		//need to revisit,since there is no proper timepicker plugin for Jquery UI datepicker
		//http://jsfiddle.net/hLTcB/8/
		return this.getDatePickerFormatStr(dateTimefmtStr).replace(" hh:mm a", "").replace(" HH:mm", "")
	}

	this.callback=function()
	{
		var controller = this;

		/*
		$(window).bind('beforeunload', function() {
			controller.send($(controller.graph));
			return ;
		});
		*/

		$('input[data-type=date]').datepicker({
			showOn: 'click',   // showOn: 'click' - is a new functionality added as a part of the jquery-ui.min.js (line no : 362)
            changeYear: true,
         	changeMonth: true,
            yearRange: '-90:+20',
            buttons: {
			    'Clear': function (sel) {
			        $.datepicker._clearDate(sel);
			    }
			},
            beforeShow: function(input, inst){
            	var currentWidget = $(input)
            	var datefmtStr = currentWidget.attr('data-format')
            	inst.settings["dateFormat"] = controller.getDatePickerFormatStr(datefmtStr)
            },
			onSelect: function(dateText, inst) {
				var currentWidget = $(this)
				var selectedDate = currentWidget.datepicker('getDate')
				var dateval = ""
				if(selectedDate){
		   			dateval = getExcelDateValue(selectedDate.getTime())
		   			//Math.ceil is specific to UB, getting 40806.958333333333 instead of 40807
		   			dateval=Math.ceil(dateval)
	   			}
			   	var args = new Array()
			   	args[currentWidget.attr('name')] = dateval
			   	currentWidget.focus();
			   	controller.update(this, args)
			}
		});

       	$('input[data-type=datetime]').datetimepicker({
       		showOn: 'click', // showOn: 'click' - is a new functionality added as a part of the jquery-ui.min.js (line no : 362)
     		changeYear: true,
         	changeMonth: true,
            yearRange: '-90:+20',
			buttons: {
			    'Clear': function (sel) {
			        $.datepicker._clearDate(sel);
			    }
			},
            beforeShow: function(input, inst){
            	var currentWidget = $(input)
            	var datefmtStr = currentWidget.attr('data-format')
            	inst.settings["dateFormat"] = controller.getDateTimePickerFormatStr(datefmtStr)
            	if(datefmtStr.indexOf('a') == -1)
            		inst.settings["clockType"] = 24
            },
         	onSelect: function( dateText, inst ) {
				var currentWidget = $(this)
				var selectedDate = currentWidget.datetimepicker('getDate')
				var dateval = ""
				if(selectedDate){
					dateval = getExcelDateValue(selectedDate.getTime())
		   		}
			   	var args = new Array()
			   	args[currentWidget.attr('name')] = dateval
			   	currentWidget.focus()
			   	controller.update(this, args)
			}
       	});

       	$('input[data-staticlist]').each(function(){
       		var individualElement = $(this)
       		var individualList = eval(individualElement.attr('data-staticlist'))
       		individualElement.autocomplete({
       			source:individualList,
       			minLength:0,
       			select:function(event, ui){
       				var currentElem = $(event.target)
       				var args = new Array()
       				args[currentElem.attr('name')] = ui.item.idval
			   		controller.update(this, args)
       			}
       		})
       	});

       	$('input[data-depandancylist]').each(function(){
       		var individualElement = $(this)
       		var individualList = controller.getDepandancyListValue(individualElement.attr('name'))
       		individualElement.autocomplete({
       			source:individualList,
       			minLength:0,
       			select:function(event, ui){
       				var currentElem = $(event.target)
       				var args = new Array()
       				var valueArray = {};
	       			valueArray[ui.item.idval] = ui.item.label
	       			args[currentElem.attr('name')] = valueArray
			   		controller.update(this, args)
       			}
       		})
       	});

        this.validationElements = $('*[data-error],*[pattern],*[data-info],*[data-warning]');
        this.validationElements.validator({
                position: 'bottom left',
                errorClass:"invalidentry-error",
                messageClass:"error",
            	message:"<div><img style='margin:2px' src='/static/images/error.png'/></div>"
        });

	    $.tools.validator.fn('*', "$1~$2" ,function(input, value) {
		    var error = input.attr("data-error");
		    var message = null;
		    if(error){
		        var funcList = eval(error)
		        for (i in funcList){
		        	message = funcList[i](input, value, controller)
		        	if (message != null && message.length > 0){
		            	return ["error", message]
		        	}
		        }
		    }

		    var pattern = input.attr("pattern");
		    if(pattern && value){
		        var regObj = new RegExp(pattern)
		        var result = regObj.exec(value)
		        if (result == null)
		            return ["error","Value doesnt match the expected format"]
		    }

		    var warning = input.attr("data-warning");
		    if(warning){
		        var funcList = eval(warning)
		        for (i in funcList){
		            message = funcList[i](input, value, controller)
			        if (message != null && message.length > 0){
			        	return ["warning", message]
		        	}
		        }
		    }

		    var info = input.attr("data-info");
		    if(info){
		        var funcList = eval(info)
		        for (i in funcList){
		            message = funcList[i](input, value, controller)
			        if (message != null && message.length > 0){
			        	return ["info", message]
		        	}
		        }
		    }
	    	return true;
	});

		//to trigger the validation again for newly rendered widgets
		if(this.showValidation)
		{
			this.resolveValidation(this.lastExcludeConDictStr);
		}
	}

	this.registerKeys=function(){}

	this.setTitle=function(){}

	this.render = function()
	{
		/*  Destroying the existing  validation elements*/
		this.destroyValidation();
		//update the currently typing value part of changesummary
		var currentWidget = $("*:focus");
		var currentElementId = currentWidget.attr("id")
		var currentInstanceId = currentWidget.attr('data-id')
		//UpdateGraph is keeped for selectbox and datepicker
		if(currentWidget.attr("autocomplete") == null && currentWidget.attr("data-type") != "datetime" && currentWidget.attr("data-type") != "date" && (currentWidget.attr("type") == "text" || currentWidget.attr("type") == "textarea")){
			this.updateGraph(currentWidget);
		}

		for(var name in this.views)
		{
			this.views[name].render();
		}

		//set back the focus on currently typing value
		if(currentElementId){
			var currentElement = $("*[id='"+currentElementId+"'][data-id='"+currentInstanceId+"']")
			//to make in work in IE 8.0.6001.18702IC it needs a small delay
			//currentElement.focus();
			setTimeout(function(){currentElement.focus();}, 0);
		}
		this.callback()
	}

	this.getRoot = function()
	{
		return this.graph;
	};

	//****************************************************** need to remove the below method *****************************************

	this.getCurrentInboxUrl=function()
	{
		return this.getApplicationUrl()+'/'+this.sheetMetadataId+'/'+this.activityDefinitionId
	}

	this.getApplicationUrl = function()
	{
		return '/'+this.applicationId+'/'+this.metadatatype
	}

	this.getCurrentUrl = function()
	{
		return this.url.split('?')[0]
	}

	//*********************************************************************************************************************************
	this.getPageSize = function(){
		var baseUrlList = this.cachedData.baseUrlList
		return parseInt(baseUrlList[baseUrlList.length - 1]);
	}

	this.getPageNumber = function () {
		var baseUrlList = this.cachedData.baseUrlList
		return parseInt(baseUrlList[baseUrlList.length - 2].split("p").pop());
	}

	this.getTotalPages = function() {
		var pageSize = this.getPageSize()
		var totalCount = this.getRoot().getValue('TotalCount');
		return Math.ceil(totalCount/pageSize);
	}

	this.getNextFilterValue = function()
	{
		var pageNumber = this.getPageNumber() + 1;
		var pageSize = this.getPageSize()
		var totalPageCount = this.getTotalPages();
		if(pageNumber > totalPageCount) {
			alert("The number exceeds the total pages");
			return;
		}
		this.list(pageNumber, pageSize)
	}

	this.getLastFilterValue = function()
	{
		var pageNumber = this.getPageNumber()
		var pageSize = this.getPageSize()
		var totalPageCount = this.getTotalPages();
		if (totalPageCount > 1 && pageNumber != totalPageCount)
			this.list(totalPageCount, pageSize)
	}

	this.getFilterValue = function(event) {
		if(event.keyCode == 13) {
			var pageSize = this.getPageSize()
			var totalPageCount = this.getTotalPages();
			var inputPageNo = $('#inputPage').val();
			if(inputPageNo > totalPageCount || inputPageNo <= 0 || isNaN(inputPageNo)) {
				alert("Pagenumber '" +inputPageNo+"' does not exist." );
				return;
			}
			this.list(inputPageNo, pageSize)
		}
	}

	this.getFirstFilterValue = function()
	{
		var pageNumber = this.getPageNumber()
		var pageSize = this.getPageSize()
		if(pageNumber > 1)
			this.list(1, pageSize)
	}

	this.getPreviousFilterValue = function() {
		var pageNumber = this.getPageNumber() - 1;
		var pageSize = this.getPageSize()
		if(pageNumber >= 1){
			this.list(pageNumber, pageSize)
		}
	}

	this.getInboxSerialNo = function(index){
		var pageNumber = this.getPageNumber();
		var pageSize = this.getPageSize()
	  	return ((pageNumber-1) * pageSize) + (parseInt(index) + 1)
	}

	this.getDataObject = function(currentElem)
	{
		var currentInstance = currentElem.attr("data-id")
		if(currentInstance && currentInstance.length > 0)
			return $(new DataObject(this.id, currentInstance))
		else
			return $(this.graph)
	}

	this.destroyValidation=function(){
		if(this.validationElements && this.validationElements.length > 0)
			this.validationElements.data("validator").destroy();
	}

	function getParamters(paramList){
	    var jqObj = $();
	    $(paramList).each(function(i, ele){
	        jqObj = jqObj.add($('#'+ele));
	    });
	    return jqObj;
	}

	this.serialiseInclude=function(inJson,exJqryObj){
	    for(Key in inJson){
	        var tmpJqryObj = $('#'+Key).find('*[data-error],*[pattern],*[data-info],*[data-warning]');
	        if(inJson[Key]['exclude-parameter'])
	            tmpJqryObj=tmpJqryObj.not(getParamters(inJson[Key]['exclude-paramter']))
	        else if(inJson[Key]['exclude-block'])
	            tmpJqryObj=tmpJqryObj.not(serialiseExclude(inJson[Key],$()))
	        exJqryObj = exJqryObj.not(tmpJqryObj)
	    }
	    return exJqryObj
	}

	this.serialiseExclude=function(exJson,exJqryObj){
	    for(key in exJson){
	        if(key == 'exclude-block'){
	            for(_key in exJson[key]){
	                exJqryObj = exJqryObj.add($('#'+_key).find('*[data-error],*[pattern],*[data-info],*[data-warning]'))
	                if(exJson[key][_key]['include-parameter'])
	                    exJqryObj=exJqryObj.not(getParamters(exJson[key][_key]['include-parameter']))
	                else if(exJson[key][_key]['include-block'])
	                    exJqryObj=this.serialiseInclude(exJson[key][_key]['include-block'],exJqryObj)
	            }
	        }
	        else if (key == 'exclude-parameter')
	            exJqryObj=exJqryObj.add(getParamters(exJson[key]))
	    }
	    return exJqryObj;
	}

	this.resolveValidation=function(excludeConDictStr){
		if(excludeConDictStr){
			this.lastExcludeConDictStr = excludeConDictStr
			var excludeDict = JSON.parse(excludeConDictStr);
			var resetfor = this.serialiseExclude(excludeDict,$());
		}

		if(this.validationElements && this.validationElements.length > 0){
			this.validationElements.data("validator").checkValidity();
		}

        if(resetfor){
			this.validationElements.data("validator").reset(resetfor);
		}
	}

	this.validateErrorMessage=function(validate, excludeConDictStr){
		if (validate == 'true' || validate == true){
			var errorStr="";
			var warningStr="";
			this.resolveValidation(excludeConDictStr);

			$('div.error[style*=visible]').each(function(i){
				errorStr +=  (i+1)+". "+$(this).text()+"\n"
			});
			if(errorStr.length > 0){
				alert("Please fill the fields before proceeding.\n" + errorStr)
				return false;
			}

			$('div.warning[style*=visible]').each(function(i){
				warningStr +=  (i+1)+". "+$(this).text()+"\n"
			});
			if(warningStr.length > 0){
				return confirm("Please fill the fields before proceeding.continue?\n" + warningStr)
			}
		}
		return true;
	}

	//--------------------------------------------------  Communicate Method ----------------------------------------------------------

	this.list = function(pageNumber, pageSize){
		var controller = this;
		var options = new Array();
		options["success"] =  function(list, dataObject){controller.render()}
		options["pageNumber"] =  pageNumber
		options["pageSize"] =  pageSize
		$(this.graph).osInvoke(this.id, 'move', options);
	}

	this.changeLocationHref = function(urlPath){
		//this method is introduced because of studio preview
		location.href = urlPath
	}

	this.send = function(dataObject, currentElem)
	{
		var controller = this;
		var target = null,message=null;
		if(currentElem){
			target = currentElem.attr("data-target");
			message = currentElem.attr("data-status");
		}
		var options = {
							beforeSend:function()
							{
								$.blockUI.defaults.css = {};
								if(target)
					            {
					                $.blockUI({ message: "Processing the record. Please wait" });
					            }
					            else
					            {
					                $.blockUI({
					                    message: 'Processing...',
					                    fadeIn: 700,
					                    fadeOut: 700,
					                    showOverlay: false,
					                    centerY: false
					                });
					             }
							},
							success: function(result, dataObject){
									var currentElementId = null, currentInstanceId = null
									if(currentElem){
										currentElementId =  currentElem.attr("id")
										currentInstanceId =  currentElem.attr('data-id')
									}
									controller.render()
									if(currentElementId  && currentInstanceId){
										var currentElemAfterRender = $("*[id='"+currentElementId+"'][data-id='"+currentInstanceId+"']")
										if(currentElemAfterRender && currentElemAfterRender.length>0){
											target = currentElemAfterRender.attr("data-target");
											message = currentElemAfterRender.attr("data-status");
										}
									}

									var pageUrlPath;
									if (target == "Inbox"){
										pageUrlPath = controller.getCurrentInboxUrl()+"?mimetype=text/html"
									}else if(target == "Worktop"){
										pageUrlPath = controller.getApplicationUrl()+"/home"
									}else if(target && target.length > 0){
										pageUrlPath = target
									}
									if(message){
							            jAlert(message,'Success',function(){
							                                        if(pageUrlPath)
							                                            controller.changeLocationHref(pageUrlPath)
							                                        },null);
							        }
							        else if (pageUrlPath){
							            controller.changeLocationHref(pageUrlPath)
							        }
							        if(target == null)
							        	$.unblockUI();
							},
							error: function(XMLHttpRequest, textStatus, errorThrown){
								errorCallback(XMLHttpRequest, textStatus, errorThrown)
				           		$.unblockUI();
				        	}
						}
		dataObject.osInvoke(this.id, 'send', options);

	}

	this.save = function(elem){
		var currentElem = $(elem)
		var validate = currentElem.attr('data-validate')
		var excludeConDictStr = currentElem.attr('data-exclude')
		var dataObject = this.getDataObject(currentElem)
		this.saveOnUnload(dataObject, validate, {async : false})
		if(this.validateErrorMessage(validate, excludeConDictStr)){
			this.send(dataObject, currentElem)
		}else{
 			this.showValidation = true;
		 }
	}

	//common for focus update before render and normal update
	this.updateGraph = function(currentElem, args)
	{
		var dataObject = this.getDataObject(currentElem)
		var options = new Array()
		if (args != null)
			options = args
		else{
			var format = currentElem.attr("data-format")
			var value = currentElem.attr("value")
			if(format)
				value = parseValue(value, format)
			options[currentElem.attr("name")] = value
		}
		return dataObject.osInvoke(this.id, 'update', options);
	}

	this.update = function(elem, args)
	{
		var currentElem = $(elem)
		var format = currentElem.attr('data-format')
		var widgetVal = currentElem.attr("value")
		//for datepicker,datetimepicket(it handled in datapicker onSelect) and time(they will enter in proper format)so we should not do formatdata
		if(format && format.indexOf('dd')<0 && format.indexOf('hh:')<0 && format.indexOf('m:')<0){
			var dispVal = formatdata(widgetVal, format)
			currentElem.val(dispVal)
		}
		var dataObject = this.updateGraph(currentElem, args)
		if(currentElem.attr("data-send") == "true" || currentElem.attr("data-send") == true )
		 	this.send(dataObject)
		else if(currentElem.attr("data-format") != "Text" || currentElem.attr("class").indexOf("combobox") > -1 ){
			//temp fix for focus problem, while doing render without sending it to server
			if(currentElem.attr("data-format") &&  currentElem.attr("data-format").indexOf("#") > -1){
				var inputWidgets = $(':input')
				var currentIndex = inputWidgets.index(currentElem)
				if(inputWidgets.length > currentIndex+1)
					$(inputWidgets[currentIndex+1]).focus()
			}
		 	this.render()
		}
	}

	this.create = function(elem, args)
	{
		var currentElem = $(elem)
		var dataObject = this.getDataObject(currentElem)
		var path = currentElem.attr("data-path")
		var pathList = path.split("/")
		var options = new Array()
		if(pathList.length > 2)
			options["childModelName"] =  pathList.pop()
		options["referenceCellName"] = pathList.pop()
		if(args != null)
			options["data"] = args
		dataObject.osInvoke(this.id, 'create', options);
		if(currentElem.attr("data-send") == true || currentElem.attr("data-send") == "true")
		 	this.send(dataObject)
 		else
 			this.render();
	}

	this.remove = function(elem)
	{
		var currentElem = $(elem)
		var dataObject;
		var path = currentElem.attr("data-path")
		var pathList = path.split("/")
		var options = new Array()
		options["instanceId"] =  pathList.pop()
		options["childModelName"] =  pathList.pop()
		options["referenceCellName"] = pathList.pop()
		if (pathList.length > 1)
			dataObject = $(new DataObject(this.id, pathList.pop()))
		else
			dataObject = $(this.graph)

		if(dataObject.get(0).getValue(options["referenceCellName"]) == options["instanceId"])
			delete options["childModelName"]
		dataObject.osInvoke(this.id, 'delete', options);
		if(currentElem.attr("data-send") == true || currentElem.attr("data-send") == "true")
		 	this.send(dataObject)
 		else
 			this.render();
	}

	this.invoke = function(elem, args)
	{
		var currentElem = $(elem)
		var validate = currentElem.attr('data-validate')
		var excludeConDictStr = currentElem.attr('data-exclude')
		var dataObject = this.getDataObject(currentElem)
		this.saveOnUnload(dataObject, validate, {async : false})
		if(this.validateErrorMessage(validate, excludeConDictStr)){
			var options = new Array()
			options["actionName"] = currentElem.attr("name")
			if (currentElem.attr("data-value"))
				options["caption"] = currentElem.attr("data-value")
			else
				options["caption"] = currentElem.attr("value")
			if(args != null)
				options["data"] = args
			dataObject.osInvoke(this.id, 'invoke', options);
			if(currentElem.attr("data-send") == true || currentElem.attr("data-send") == "true")
			 	this.send(dataObject, currentElem)
		 }else{
 			this.showValidation = true;
		 }
	}

	this.saveOnUnload = function(dataObject, validate, options){
		if (validate == 'true' || validate == true){
			var cachedData = getCachedData(this.id)
			if(cachedData.changeSummary.update && hasElement(cachedData.changeSummary.update)){
				var controller = this
				var defaultOptions = {
					success: function(result, dataObject){
							controller.render()
					},
					error: function(XMLHttpRequest, textStatus, errorThrown){
						errorCallback(XMLHttpRequest, textStatus, errorThrown)
		        	}
				}
				$.extend(defaultOptions, options );
				dataObject.osInvoke(this.id, 'send', defaultOptions);
			}
		}
	}

	this.updateAttach = function(elem)
	{
		var controller = this;
		var currentElem = $(elem)
		var dataObject = this.getDataObject(currentElem)
		var options = new Array()
		options["fileId"] = currentElem.attr("id")
		options["success"] = function(result, dataObject){
								controller.render()
							}
		dataObject.osInvoke(this.id, 'updateAttach', options);
	}

	this.removeAttach = function(elem)
	{
		var controller = this;
		var currentElem = $(elem)
		var dataObject = this.getDataObject(currentElem)
		var options = new Array()
		options["success"] = function(result, dataObject){
								controller.render()
							}
		dataObject.osInvoke(this.id, 'deleteAttach', options);
	}

	this.csvimport = function(elem)
	{
		var controller = this;
		var currentElem = $(elem)
		var dataObject = this.getDataObject(currentElem)
		var path = currentElem.attr("data-path")
		var pathList = path.split("/")
		var options = new Array()
		options["childModelId"] =  pathList.pop()
		options["referenceCellName"] = pathList.pop()
		options["mappingId"] = currentElem.attr("id")
		options["fileId"] = currentElem.attr("id")
		options["success"] = function(result, dataObject){
								controller.render()
							}
		dataObject.osInvoke(this.id, 'csvimport', options);
	}

	this.getCreateUrl = function(refUrl,updateDict)
	{
		return this.getCurrentUrl()+refUrl
	}

	this.ref_import = function(gridCellId, srcImg, refUrl)
	{
		this.update_onUnload()
		options = {'methodType':"POST"}
		options['url'] = this.getCreateUrl(refUrl)+"/import?gridCellId="+gridCellId
		options['data']={}
		this.communicate(options)
	}

	this.updateCheckboxParamCopy=function(elem, cellName, finalValue)
	{
		var currentElem = $(elem)
		var args = new Array()
		if (elem.checked)
			args[cellName]=finalValue
		else
			args[cellName]=''
		 this.update(elem, args)
	}

	this.showList = function(elem)
	{
		var currentElem = $(elem)
	    currentElem.autocomplete("search", "")
		currentElem.focus()
	}

	this.getDepandancyListValue=function(cellName)
	{
		var mapList = []
		mapList.push({"label":"None","idval":""})
		var value = this.getRoot().getActualJson()[cellName];
	 	for (var key in value){
	   		if(key != 'selected')
	     		mapList.push({"label":value[key],"idval":key})
	    }
		return mapList
	}

	this.dynamicSearch = function(elem){
		var currentElem = $(elem)
		var cellName = currentElem.attr('name')
		var controller = this
		var options = {cellName: cellName}
		options["error"] = errorCallback
		options["success"] = function(jDataObject, dataObect, data){
			var searchData = data[data['root']]
			var mapList = []
			mapList.push({"label":"None","idval":""})
			for(key in searchData)
			{
				if(key.indexOf('ModifiedBy.') > -1)
				{
					for(var item in searchData[key])
					{
						mapList.push({"label":searchData[key][item], "idval": item})
					}
					break;
				}
			}
			// To fix the issue (autocomplete list showing on top of the page) in jquery.ui-Autocomplete we added a fix in jquery-ui.min.js (line no : 298,299).
			// Issue : In some case autocomplete comes in top of the page. Because the element is not in visible mode some time.
			// Fix : We get the id of the invisible element then query it and then we will set it to element.
			currentElem.autocomplete({
				source:mapList,
				minLength:0,
				select:function(event, ui){
	       				var currentElem = $(event.target)
	       				var args = new Array()
	       				var valueArray = {};
	       				valueArray[ui.item.idval] = ui.item.label
	       				args[currentElem.attr('name')] = valueArray
				   		controller.update(event.target, args)
	       			}
			})
			currentElem.autocomplete("search","")
			currentElem.focus()
		}
		var dataObject = this.getDataObject(currentElem)
		dataObject.osInvoke(this.id, "search", options)


	}

// ****************************************************** helper methods *********************************************************************
	this.getGotoLinkUrl = function(instance,statusCellName,formName)
	{
		var sheetMetadataId = instance.getValue('SheetMetadataId')
		var linkUrl = this.getApplicationUrl()+"/"+sheetMetadataId+"/"+instance.getValue(statusCellName)+"/"+sheetMetadataId+"/"+instance.getValue('SheetId')
		if (formName)
		  linkUrl=linkUrl+"?mimetype=text/html&form="+formName
		return linkUrl
	}

	this.getAdvanceSearchUrl = function(cellName, relationUrl)
	{
		if(!relationUrl)
			searchUrl = this.getCurrentUrl()+"/"+cellName+"/search"
		else
			searchUrl = this.getCurrentUrl()+relationUrl+"/"+cellName+"/search"

		return searchUrl
	}

	this.getInbox_EditorURL=function(instanceId)
    {
		activityUrl=this.getApplicationUrl()+'/'+this.sheetMetadataId +'/'+this.activityDefinitionId+'/'+this.sheetMetadataId+'/'+instanceId
		return activityUrl
    }

    this.getAttachmentUrl = function(instance)
    {
    	return this.getCurrentUrl()+"/"+instance.getValue("SheetMetadataId")+"/"+instance.getValue("SheetId")
    }

	this.setSelectedAttachment = function(attachID){
		this.selectedAttachment=attachID;
		this.render();
	}

//*************************************************** for studio release ***********************************************************

	this.tagCommunicate = function(methodType,url)
	{
		var controller = this
		jQuery.ajax({
		   type: methodType,
		   url: url,
		   success: function(data){
		   },
		   error: function(XMLHttpRequest, textStatus, errorThrown){
		   	    exceptionMsg = XMLHttpRequest.getResponseHeader('ErrorMessage')
				exceptionTrace = XMLHttpRequest.responseText
		   	    if(textStatus=='error'){
			   	    if(textStatus=='error' || exceptionMsg.match("DeadlineExceededError")){
						controller.tagCommunicate(methodType, url)
					}
					jAlert('Error '+exceptionMsg,'Error',null,exceptionTrace);
				}
		   },
		   complete:function(XMLHttpRequest,textStatus){
		   }
		 });
	}

	this.tagApplication=function(elem)
	{
		var currentElem = $(elem);
		var url = currentElem.attr("data-path");
		var releaseId = currentElem.attr("data-id");
		var urlList = url.split('/')
		var appId = urlList[3];
		var dataObject = this.getDataObject(currentElem);
		var options = new Array();
		options["Application"] = appId;
		urlList.pop()
		urlList.pop()
		urlList.pop()
		/******* Temp Code for Id need to be Removed/changed (hardcoded Cell/Sheetmetadataif for Application)***************/
		appUrlString =this.getCurrentUrl()+"/CellMetadata_395/Sheet008/"+appId;
		var controller = this;
		dataObject.osInvoke(this.id, 'update', options).osInvoke(this.id,'send',{async:false,
			success:function(result)
			{
				applicationDataObject = new DataObject(controller.id, appId);
				$(applicationDataObject).osInvoke(controller.id, 'update', {NewRelease:''}).osInvoke(controller.id,'send',
				{
					success:function(result)
                    {
						releaseUrl = appUrlString +"/Cell_016_002_006/Sheet016/"+releaseId
						releaseUrlString = releaseUrl + '?action=invoke&invoke=orangescape.studio.sync.Tagging.releaseApplication'
						controller.tagCommunicate('POST', releaseUrlString)

						sheetList = applicationDataObject.getList('Application','SheetMetadata')
						for (i in sheetList){
							sheetId = sheetList[i].getValue('SheetId');
							modelUrlString = releaseUrl + '/Cell_017_006_002/Sheet017' + '?action=invoke&invoke=orangescape.studio.sync.Tagging.releaseModel&modelid='+sheetId
							controller.tagCommunicate('POST', modelUrlString)
						}
                    }
                });
            }});
	}

}

function sortByCreatedAt(a,b)
{
	var x = a.getValue('CreatedAt')
	var y = b.getValue('CreatedAt')
	return (x < y) ? -1 : ((x > y) ? 1 : 0);
}

function getOneToManySheetList(parentSheet, oneToManyCellName, orderByCellName, isDesc)
{
	var oneToManyCellNameSplit = oneToManyCellName.split(".")
	return parentSheet.getList(oneToManyCellNameSplit[0], oneToManyCellNameSplit[1], orderByCellName, isDesc)
}

function getTextareaValue(obj,length)
{
	value=obj.value
	if (value.length>=length){
        alert("The entered text is greater than "+length+" characters.Please check the content before submitting");
        $(obj).val(value.substring(0,length))
    }
}

runtime_controller.prototype = new controller;
