/*+********************************************************************************
 * The contents of this file are subject to the vtiger CRM Public License Version 1.0
 * ("License"); You may not use this file except in compliance with the License
 * The Original Code is:  vtiger CRM Open Source
 * The Initial Developer of the Original Code is vtiger.
 * Portions created by vtiger are Copyright (C) vtiger.
 * All Rights Reserved.
 ********************************************************************************/

function VTEmailTask($){
	var vtinst = new VtigerWebservices("webservice.php");
	var desc = null;
	var accessibleModulesInfo = null;

	var map = fn.map;
	var dict = fn.dict;
	var filter = fn.filter;
	var reduceR = fn.reduceR;
	var parallelExecuter = fn.parallelExecuter;
	var contains = fn.contains;
	var concat = fn.concat;
	
	function diff(reflist, list) {
		var out = [];
		$.each(list, function(i, v) {
			if(contains(reflist, v)) {
				out.push(v);
			}
		});
		return out;
	}
	
	//Display an error message.
	function errorDialog(message){
		alert(message);
	}

	//This is a wrapper to handle webservice errors.
	function handleError(fn){
		return function(status, result){
			if(status){
				fn(result);
			}else{
				errorDialog('Failure:'+result);
			}
		};
	}

	//Insert text at the cursor
	function insertAtCursor(element, value){
		//http://alexking.org/blog/2003/06/02/inserting-at-the-cursor-using-javascript
		if (document.selection) {
			element.focus();
			var sel = document.selection.createRange();
			sel.text = value;
			element.focus();
		}else if (element.selectionStart || element.selectionStart == '0') {
			var startPos = element.selectionStart;
			var endPos = element.selectionEnd;
			var scrollTop = element.scrollTop;
			element.value = element.value.substring(0, startPos)
				+ value
				+ element.value.substring(endPos,
				element.value.length);
			element.focus();
			element.selectionStart = startPos + value.length;
			element.selectionEnd = startPos + value.length;
			element.scrollTop = scrollTop;
		}	else {
			element.value += value;
			element.focus();
		}
	}

	//Convert user type into reference for consistency in describe objects
	//This is done inplace
	function referencify(desc){
		var fields = desc['fields'];
		for(var i=0; i<fields.length; i++){
			var field = fields[i];
			var type = field['type'];
			if(type['name']=='owner'){
				type['name']='reference';
				type['refersTo']=['Users'];
			}
		}
		return desc;
	}

	//Get an array containing the the description of a module and all modules
	//refered to by it. This is passed to callback.
	function getDescribeObjects(accessibleModules, moduleName, callback){
		vtinst.describeObject(moduleName, handleError(function(result){
			var parent = referencify(result);
			var fields = parent['fields'];
			var referenceFields = filter(function(e){
				return e['type']['name']=='reference';},
			  fields);
			var referenceFieldModules =
				map(
					function(e){
						return e['type']['refersTo'];
					},
					referenceFields
				);
			function union(a, b){
			  var newfields = filter(function(e){return !contains(a, e);}, b);
			  return a.concat(newfields);
			}
			var relatedModules = reduceR(union, referenceFieldModules, [parent['name']]);
			
			// Remove modules that is no longer accessible
			relatedModules = diff(accessibleModules, relatedModules);

			function executer(parameters){
				var failures = filter(function(e){return e[0]==false;}, parameters);
				if(failures.length!=0){
					var firstFailure = failures[0];
					callback(false, firstFailure[1]);
				}else{
					var moduleDescriptions = map(function(e){
						return referencify(e[1]);},
					  parameters);
					var modules = dict(map(function(e){
						  return [e['name'], e];},
						moduleDescriptions));
					callback(true, modules);
				}
			}
			var p = parallelExecuter(executer, relatedModules.length);
			$.each(relatedModules, function(i, v){
				p(function(callback){vtinst.describeObject(v, callback);});
			});
		}));
	}

	function fillSelectBox(id, modules, parentModule, filterPred){
		if(filterPred==null){
			filterPred = function(){
				return true;
			};
		}
		var parent = modules[parentModule];
		var fields = parent['fields'];

		function filteredFields(fields){
			return filter(
				function(e){
					var fieldCheck = !contains(['autogenerated', 'reference', 'owner', 'multipicklist', 'password'], e.type.name);
					var predCheck = filterPred(e);
					return fieldCheck && predCheck;
				},
				fields
			);
		}
		var parentFields = map(function(e){return[e['name'],e['label']];}, filteredFields(parent['fields']));

		var referenceFieldTypes = filter(function(e){
				return (e['type']['name']=='reference');
			},parent['fields']
		);
			
		var moduleFieldTypes = {};
		$.each(modules, function(k, v){
				moduleFieldTypes[k] = dict(map(function(e){return [e['name'], e['type']];},filteredFields(v['fields'])));
			}
		);

		function getFieldType(fullFieldName){
			var group = fullFieldName.match(/(\w+) : \((\w+)\) (\w+)/);
			if(group==null){
				var fieldModule = moduleName;
				var fieldName = fullFieldName;
				}else{
					var fieldModule = group[2];
				var fieldName = group[3];
			}
			return moduleFieldTypes[fieldModule][fieldName];
		}

		function fieldReferenceNames(referenceField){
			var name = referenceField['name'];
			var label = referenceField['label'];
			function forModule(moduleName){
				// If module is not accessible return no field information
				if(!contains(accessibleModulesInfo, moduleName)) return [];
				
				return map(function(field){					
					return ['('+name+' : '+'('+moduleName+') '+field['name']+')',label+' : '+'('+modules[moduleName]['label']+') '+field['label']];
					},
					filteredFields(modules[moduleName]['fields']));
			}
			return reduceR(concat,map(forModule,referenceField['type']['refersTo']),[]);
		}

		var referenceFields = reduceR(concat,map(fieldReferenceNames,referenceFieldTypes), []);
		var fieldLabels = dict(parentFields.concat(referenceFields));
		var select = $('#'+id);
		var optionClass = id+'_option';
		$.each(fieldLabels, function(k, v){
			select.append('<option class="'+optionClass+'" '+ 'value="'+k+'">' + v + '</option>');
		});

	}

	$(document).ready(function(){
		vtinst.extendSession(handleError(function(result){			
			vtinst.listTypes(handleError(function(accessibleModules) {
				accessibleModulesInfo = accessibleModules;
				
				getDescribeObjects(accessibleModules, moduleName, handleError(function(modules){
					fillSelectBox('task-fieldnames', modules, moduleName);
					$('#task-fieldnames-busyicon').hide();
					$('#task-fieldnames').show();
					$('#task-fieldnames').change(function(){
					var textarea = CKEDITOR.instances.save_content;
					var value = '$'+jQuery(this).attr('value');
					textarea.insertHtml(value);
					});

					fillSelectBox('task-subjectfields', modules, moduleName,
										 function(e){return (e['type']['name']!='file' && e['type']['name']!='text' );});
					$('#task-subjectfields-busyicon').hide();
					$('#task-subjectfields').show();
					$('#task-subjectfields').change(function(){
						var input = $($('#save_subject').get());
						var value = '$'+$(this).attr('value');
						input.attr("value", input.attr("value")+' '+value);
					});

					fillSelectBox('task-emailfields', modules, moduleName,
										 function(e){return e['type']['name']=='email';});
					$('#task-emailfields-busyicon').hide();
					$('#task-emailfields').show();
					$('#task-emailfields').change(function(){
						var input = $($('#save_recepient').get());
						var value = '$'+$(this).attr('value');
						input.attr("value", input.attr("value")+','+value);
					});
					var selptype = document.getElementById('task-emailfields');
			        var selecc = document.getElementById('task-emailfieldscc');
			        for (ops=0;ops<selptype.length;ops++) {
			          selecc.options[ops] = new Option(selptype.options[ops].text, selptype.options[ops].value);
			        }
			        $('#task-emailfieldscc-busyicon').hide();
					$('#task-emailfieldscc').show();
					$('#task-emailfieldscc').change(function(){
						var input = $($('#save_emailcc').get());
						var value = '$'+$(this).attr('value');
						input.attr("value", input.attr("value")+','+value);
					});
			        var selebcc = document.getElementById('task-emailfieldsbcc');
			        for (ops=0;ops<selptype.length;ops++) {
			          selebcc.options[ops] = new Option(selptype.options[ops].text, selptype.options[ops].value);
			        }
					$('#task-emailfieldsbcc-busyicon').hide();
					$('#task-emailfieldsbcc').show();
					$('#task-emailfieldsbcc').change(function(){
						var input = $($('#save_emailbcc').get());
						var value = '$'+$(this).attr('value');
						input.attr("value", input.attr("value")+','+value);
					});
					
					//time_changes
					$('#task_timefields').change(function(){
						var textarea = CKEDITOR.instances.save_content;
						var value = '$'+$(this).attr('value');
						textarea.insertHtml(value);
					});
				
					//changes
					fillSelectBox('task-group_usersnames', modules, moduleName);
					$('#task-fieldnames-busyicon').hide();
					$('#task-group_usersnames').show();
					$('#task-group_usersnames').change(function(){
						var textarea = $('#save_receipent').get(0);
						var value = '$'+$(this).attr('value');
						insertAtCursor(textarea, value);
					});
				}));
				
			}));

		}));
		//Setup the validator
		validator.mandatoryFields.push('recepient');
		validator.mandatoryFields.push('subject');
	});
}
vtEmailTask = VTEmailTask(jQuery);
