function getScope(selector) {
	return angular.element($(selector)).scope();
}

function addCommonDirectives(module) {
	module.directive('compileTemplate', function($compile, $parse){
	    return {
	            link: function(scope, element, attr){
	                    var parsed = $parse(attr.ngBindHtml);
	        
	                    function getStringValue() { return (parsed(scope) || '').toString(); }

	                    //Recompile if the template changes
	                    scope.$watch(getStringValue, function() {
	            $compile(element, null, -9999)(scope);  //The -9999 makes it skip directives so that we do not recompile ourselves
	                    });
	            }         
	    }
	});

	module.directive('tooltip', function() {
		return {
			restrict : 'A',
			link : function(scope, element, attrs) {
				$(element).tooltip();
			}
		}
	});
	
	module.filter('sprintf', function() {
		function parse(str) {
			var args = [].slice.call(arguments, 1),
			i = 0;
			return str.replace(/%s/g, function() {
				return args[i++];
			});
		}
		 
		return function(str) {
			return parse(str, arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]);
		};
	});
}

function commonInitialize($scope, $http, $sce) {

	$scope.currentProc = {};
	$scope.currentProcNode = {};
	$scope.currentValue = {};
	$scope.currentNode = null;

	$scope.currentLog = [];
	$scope.currentSimpleLog = [];
	$scope.currentAdvancedLog = [];
	$scope.currentStartWf = '-';
	$scope.currentEndWf = '-';
	
	$scope.gridCurrentLogDetails = {
		data : 'currentLog',
		enableCellSelection : false,
		enableRowSelection : false,
		enableColumnResize : true,
		enableCellEditOnFocus : false,
		enablePaging : false,
		enableHighlighting: true,
		sortInfo : { fields : [ 'name' ], directions : [ 'asc' ] },
		columnDefs : [ 
		              {	field : 'name', displayName : 'Key', width : '25%', cellTemplate : '<div class="ngCellText" ng-class="col.colIndex()"><span ng-cell-text><a href="javascript:void(0)" ng-click="setCurrentValue(row.entity)">{{row.getProperty(col.field).replace(\"mainlog:\", \"\")}}</a></span></div>' },
		              {	field : 'value', displayName : 'Value' } 
		             ],        
		filterOptions: {filterText: '', useExternalFilter: false},
		showFilter: true
	};
	
	$scope.gridCurrentProcNodeEnvParams = {
			data : 'currentProcNode.params',
			enableCellSelection : false,
			enableRowSelection : false,
			enableCellEditOnFocus : false,
			enablePaging : false,
			enableHighlighting: true,
			sortInfo : { fields : [ 'name' ], directions : [ 'asc' ] },
			columnDefs : [ 
			              {	field : 'name', displayName : 'Env Parameter Name', width : '25%', cellTemplate : '<div class="ngCellText" ng-class="col.colIndex()"><span ng-cell-text><a href="javascript:void(0)" ng-click="setCurrentValue(row.entity)">{{row.getProperty(col.field)}}</a></span></div>' },
			              {	field : 'value', displayName : 'Env Parameter Value' } 
			             ],        
			filterOptions: {filterText: '', useExternalFilter: false},
			showFilter: true
		};
	
	$scope.to_trusted = function(html_code) {
		return $sce.trustAsHtml(html_code);
	}

	$scope.showError = function(error) {
		show_notification("error", error);
	}

	$scope.showNotification = function(message) {
		show_notification("info", message);
	}

	$scope.showSpinner = function() {
		showSpinner();
	}

	$scope.hideSpinner = function() {
		hideSpinner();
	}

	initSpinner();

	$scope.getNodeDetails = function(wf, node) {
		$scope.currentNode = null;
		$scope.showSpinner();
		$http
				.get('wf_workflow_node.json?wf=' + wf + '&node=' + node)
				.success(function(data) {
					$scope.currentNode = data;
					$scope.hideSpinner();
					$('#nodeEditModal').modal('show');
				})
				.error(
						function() {
							$scope.showError('Something really bad must have happened to our fellow hamster..');
							$scope.hideSpinner();
						});
	}

	$scope.setCurrentValue  = function(row) {
		$scope.currentValue = row;
	}
	
	$scope.showProcess = function(id) {
		$('#journalWfModal').modal('hide');
		$('#monitorWfModal').modal('hide');

		$scope.showSpinner();
		
		if (!$('#monitorProcWfModal').hasClass('in')) {
			$scope.currentStartWf = 0;
			$scope.currentEndWf = 0;
			$scope.currentValue = {};
			
			$scope.currentLog = null;
			$scope.currentAdvancedLog = null;
			$scope.currentSimpleLog = null;
			$scope.currentProc = null;
		}
		
		$http.get('wf_journal.get?id=' + id).success(function(data) {
			if (data.graph) {
				$scope.currentProc = data.graph;
			}

			if (!$('#monitorProcWfModal').hasClass('in')) {
				if (data.journal) {
					$scope.currentAdvancedLog = data.journal;
					$scope.currentSimpleLog = [];
	
					angular.forEach($scope.currentAdvancedLog, function(value, key){
						if ((/^dataprovider\:/).test(value.name) || (/^mainlog\:/).test(value.name) || ((/error/).test(value.name) && (value.value))) {
							$scope.currentSimpleLog.push(value);
						} else if (value.name == 'system:startDate') {
							$scope.currentStartWf = value.value;
						} else if (value.name == 'system:endDate') {
							$scope.currentEndWf = value.value;
						}
					});
				
					$scope.currentLog = $scope.currentSimpleLog;
					$scope.hideSpinner();
					
					$('#currentLogDetailsModal').modal('show');
					
				} else if ($scope.currentProc) {
					$('#monitorProcWfModal').modal('show');
				}
			}

			$scope.hideSpinner();

		}).error(function() {
			$scope.showError('Something really bad must have happened to our fellow hamster..');
			$scope.hideSpinner();
		});
	}
	
	
	$scope.calculateDateDiff = function(start, end) {
		if (start <= 0 || end <= 0) {
			return '-';
		}
		var seconds = 0;
		var minutes = 0;
		var hours = 0;
		var days = 0;

		if (end > start) {
			seconds = Math.round((end - start) / 1000);
			
			if (seconds > 60) {
				minutes = Math.floor(seconds / 60);
				seconds = seconds % 60;
				if (minutes > 60) {
					hours = Math.floor(minutes / 60);
					minutes = minutes % 60;
					if (hours > 24) {
						days = Math.floor(hours / 24);
						hours = hours % 24;
					}
				}
			}
		}
		
		var res = '';
		if (days > 0) {
			if (res) {	res += ', '; } 
			res += days + " day(s)"
		}
		if (hours > 0) {
			if (res) {	res += ', '; } 
			res += hours + " hour(s)"
		}
		if (minutes > 0) {
			if (res) {	res += ', '; } 
			res += minutes + " minute(s)"
		}
		if (seconds > 0) {
			if (res) {	res += ', '; } 
			res += seconds + " second(s)"
		}

		if (!res) {
			res = '0 seconds';
		} 
		
		return res;
	} 

	$scope.getProcessNodeDetails = function(procId, nodeId) {
		$('#monitorProcWfModal').modal('hide');
		$scope.showSpinner();
		$http
				.get('wf_proc_node.json?id=' + procId + "&node=" + nodeId)
				.success(function(data) {
					$scope.currentProcNode = data;
					$scope.hideSpinner();
					$('#monitorProcNodeModal').modal('show');
				})
				.error(
						function() {
							$scope
									.showError('Something really bad must have happened to our fellow hamster..');
							$scope.hideSpinner();
						});
	}

	$scope.killProcess = function(procId) {
		if (confirm("Are you sure ?")) {
			$scope.showSpinner();
			$http.get('wf_proc.kill?id=' + procId).success(function(data) {
				$scope.currentProc = {};
				$scope.hideSpinner();
				$('#monitorProcWfModal').modal('hide');
				$scope.showNotification('Workflow killed !');
			}).error(function() {
				$scope.showError('Something really bad must have happened to our fellow hamster..');
				$scope.hideSpinner();
			});
		}
	}

	$scope.showSpinner();
}

function wf_init($scope, $http, $sce) {
	
	$scope.currentWorkflow = {};
	$scope.currentUserParams = {};
	$scope.currentMetaWorkflow = {};
	$scope.metaworkflows = [];
	$scope.validParamValuesCache = {};
	$scope.currentHistory = [];
	$scope.filterMetaWfHistory = { filterText : '' };
		
	$scope.gridHistory = {
		data : 'currentHistory',
		enableCellEditOnFocus : false,
		enablePaging : false,
		enableHighlighting : true,
		sortInfo : { fields : [ 'date' ], directions : [ 'desc' ] },
		filterOptions : $scope.filterMetaWfHistory,
		columnDefs : [
			{ field : 'procId', displayName : 'Process ID', width : '15%', cellTemplate : '<div class="ngCellText"><a href="javascript:void(0)" ng-click="showProcess(row.getProperty(col.field))">{{row.getProperty(col.field)}}</a></div>' },
			{ field : 'name', displayName : 'Workflow name', width : '40%' },
			{ field : 'family', displayName : 'Workflow Family', width : '15%' },
			{ field : 'status', displayName : 'Status', width : '10%', cellTemplate : '<div class="ngCellText"><span class="label label-default" ng-class="{ \'label-success\': row.getProperty(col.field) == \'SUCCESS\', \'label-danger\': row.getProperty(col.field) == \'FAILURE\', \'label-info\': row.getProperty(col.field) == \'EXECUTING\'}">{{row.getProperty(col.field)}}</span></div>' },
			{ field : 'date', displayName : 'Last activity', cellTemplate : '<div class="ngCellText">{{ (row.getProperty("date") > 0 && row.getProperty("date") < 9999999999999) ? (row.getProperty("date") | date:"yyyy-MM-dd HH:mm:ss") : "not yet started" }}</div>' }
		]
	};
	
	$scope.verifyType = function(val, type) {
		if (type == 'string') {
			return val.length > 0;
		} else if (type == 'boolean') {
			return (val == 'true') || (val == 'false');
		} else if (type == 'int') {
			return val.test(/^\s*-?\d+\s*$/);
		} else if (type == 'float') {
			return val.test(/^\s*-?\d*(\.\d+)?\s*$/);
		} else if (type == 'date') {
			return val.test(/^(0[1-9]|[12][0-9]|3[01])[- \/.](0[1-9]|1[012])[- \/.](19|20)\d\d$/);
		} else if (type == 'datetime') {
			return true;
		} else if (type == 'property') {
			return true;
		} else {
			return false;
		}

	}
	
	$scope.getMetaWorkflow = function(id) {
		if (id) {
			$scope.showSpinner();
			$http.get('wf_metaworkflow.json?id=' + id).success(function(data) {
				$scope.currentMetaWorkflow = data;
				$scope.hideSpinner();
			}).error(function(err) {
				$scope.showError(err.message);
				$scope.hideSpinner();
			});
		}
	}
	
	$scope.getAtomicWorkflow = function(id) {
		$scope.currentWorkflow = null;
		$scope.currentNode = null;
		
		$scope.showSpinner();
		$http.get('wf_atomic_workflow.json?id=' + id).success(function(data) {
			$scope.currentWorkflow = data;
			$scope.hideSpinner();
			$('#atomWfModal').modal('show')
		}).error(function(err) {
			$scope.showError(err.message);
			$scope.hideSpinner();
		});
	}
	
	$scope.getAtomicWorkflowAndMetaWf = function(metaWfId, wfId) {
		$scope.showSpinner();
		$http.get('wf_metaworkflow.json?id=' + metaWfId).success(function(data) {
			$scope.currentMetaWorkflow = data;
			$scope.getAtomicWorkflow(wfId);
		}).error(function(err) {
			$scope.showError(err.message);
			$scope.hideSpinner();
		});
	}

	$scope.getWorkflows = function(loadFirstElement, params) {
		$scope.showSpinner();

		$http.get('list_metaworkflows.json?' + params).success(function(data) {
			$scope.metaworkflows = data;
			$scope.hideSpinner();

			if (loadFirstElement) {
				if ($scope.initialWf && $scope.initialMetaWf) {
					angular.forEach($scope.metaworkflows, function(mw, key) {
						if (mw.wfId == $scope.initialMetaWf) {
							$scope.getAtomicWorkflowAndMetaWf($scope.initialMetaWf, $scope.initialWf);
							return;
						}
					});
				} else if ($scope.initialMetaWf) {
					angular.forEach($scope.metaworkflows, function(mw, key) {
						if (mw.wfId == $scope.initialMetaWf) {
							$scope.getMetaWorkflow(mw.wfId);
							return;
						}
					});
				} else if ($scope.metaworkflows.length > 0) {
					var id = $scope.metaworkflows[0].wfId;
					$scope.getMetaWorkflow(id);
				}
			} else {
				angular.forEach($scope.metaworkflows, function(value, key){
					if (value.wfId == $scope.currentMetaWorkflow.wfId) {
						$scope.currentMetaWorkflow = value;
					}
				});
			}
		}).error(function(err) {
			$scope.showError(err.message);
			$scope.hideSpinner();
		});	
	}
	
	$scope.executeWf = function(wfId) {
		$http.get('wf.start?id=' + wfId).success(function(data) {
			$scope.updateMetaWorkflowHistory();
			$('#monitorWfModal').modal('show');
		}).error(function(err) {
			$scope.showError(err.message);
		});
	};

	$scope.executeMetaWf = function() {
		$http.get('metawf.start?id=' + $scope.currentMetaWorkflow.wfId).success(function(data) {
			$scope.updateMetaWorkflowHistory();
			$('#monitorWfModal').modal('show');
		}).error(function(err) {
			$scope.showError(err.message);
		});
	};
	
	$scope.prepareMetaWfEdit = function() {
		$scope.tempMetaWorkflow = angular.copy($scope.currentMetaWorkflow);
	};
	
	$scope.saveCurrentMetaWf = function() {
		$scope.showSpinner();
		$http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded; charset=UTF-8";
		$http.post('wf_metaworkflow.edit', $.param({
			'json' : JSON.stringify($scope.tempMetaWorkflow)
		})).success(function(data) {
			$scope.hideSpinner();

			angular.forEach($scope.metaworkflows, function(value, key) {
				if (value.wfId == $scope.tempMetaWorkflow.wfId || value.id == $scope.tempMetaWorkflow.wfId) {
					value.name = $scope.tempMetaWorkflow.name;
				}
			});
			$scope.showNotification('MetaWorkflow updated !');
			
			$scope.getMetaWorkflow($scope.tempMetaWorkflow.wfId);
		}).error(function(err) {
			$scope.showError(err.message);
			$scope.hideSpinner();
		});
	};
	
	$scope.changeWfStartMode = function(wfId, val) {
		$scope.showSpinner();
		$http.get('wf_atomic_workflow.enable?start=' + val + "&id="	+ wfId).success(function(data) {
			$scope.hideSpinner();
			$scope.getMetaWorkflow($scope.currentMetaWorkflow.wfId);
		}).error(function(err) {
			$scope.showError(err.message);
			$scope.hideSpinner();
		});
	}
	
	$scope.listValidValuesForUserParam = function(func) {
		if (!$scope.validParamValuesCache[func]) {
			$scope.showSpinner();
			try {
				$scope.validParamValuesCache[func] = eval(func);
			} catch (e) {
				alert('Error evaluating function: ' + func);
				$scope.validParamValuesCache[func] = [];
			}
			$scope.hideSpinner();
		}
		return $scope.validParamValuesCache[func];
	}
	
	
	$scope.listWorkflowsUserParams = function(wfId) {
		$scope.showSpinner();

		$scope.currentUserParams = {};
		
		$http.get('workflow_user_params.json?wf=' + wfId)
        .success(
            function(data) {
            	$scope.hideSpinner();
            	$scope.currentUserParams = {
            		'wfId' : wfId,
            		'data' : data  
            	};
            }
        ).error(
            function(err) {
            	$scope.showError(err.message);
            	$scope.hideSpinner();
            }
        );
		
	}	
	
	$scope.saveWorkflowsUserParams = function() {
		$scope.showSpinner();
		
		$http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded; charset=UTF-8";
		$http.post('save_user_params.do', $.param({
			'wf' : $scope.currentUserParams.wfId,
			'params' : JSON.stringify($scope.currentUserParams.data)
		})).success(function(b) {
			$scope.hideSpinner();
			$scope.showNotification('Workflow updated !');
			$scope.getMetaWorkflow($scope.currentMetaWorkflow.wfId);
		}).error(function(err) {
			$scope.hideSpinner();
			$scope.showError(err.message);

		});
	}
	
	$scope.updateMetaWorkflowHistory = function() {
		$scope.updateHistory($scope.currentMetaWorkflow.innerWfs);
	};
	
	$scope.updateHistory = function(ids) {
		$scope.currentHistory = [];
		$scope.showSpinner();
		$http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded; charset=UTF-8";
		$http.post('wf_journal.find', $.param({
			'wfs' : JSON.stringify(ids)
		})).success(function(data) {
			$scope.hideSpinner();
			$scope.currentHistory = data;
			$('#monitorWfModal').modal('show')
		}).error(function(err) {
			$scope.hideSpinner();
			$scope.showError(err.message);
		});
	};
}
