var poconsole = angular.module('poconsole', ['ngJustGage', 'n3-line-chart', "ngQuickDate", "ngSails"]);

function isValidDate(d) {
  if ( Object.prototype.toString.call(d) !== "[object Date]" )
    return false;
  return !isNaN(d.getTime());
}

var colors = ['#d7191c','#fdae61','#abdda4','#2b83ba'];

poconsole.config(function(ngQuickDateDefaultsProvider) {
  // Configure with icons from font-awesome
  return ngQuickDateDefaultsProvider.set({
    closeButtonHtml: "<i class='fa fa-times'></i>",
    buttonIconHtml: "<i class='fa fa-clock-o'></i>",
    nextLinkHtml: "<i class='fa fa-chevron-right'></i>",
    prevLinkHtml: "<i class='fa fa-chevron-left'></i>",
    // Take advantage of Sugar.js date parsing
    parseDateFunction: function(str) {
      d = Date.create(str);
      return d.isValid() ? d : null;
    }
  });
});

var dString_to_sqlite = function(dString){
	/**
		* Takes a date string in the form YYYYMMDD_HHmmSS and returns it in SQLite format (YYYY-MM-DD HH:mm:SS)
		* @param {String} dString
		* @return {String} sqliteString
	*/
	var re = /(\d{4})(\d{2})(\d{2})_(\d{2})(\d{2})(\d{2})/;
	var fd = re.exec(dString);
	if (fd){
		var sqliteString = "";
		return sqliteString.concat(fd[1], "-", fd[2], "-", fd[3], " ", fd[4], ":", fd[5], ":", fd[6]);
	} else {
		return null;
	}
};

var sqlite_to_dString = function(sqliteDate){
	/**
		* Takes a sqlite date string in the form YYYY-MM-DD HH:mm:SS and returns it in format YYYYMMDD_HHmmSS
		* @param {String} sqliteDate
		* @return {String} dString
	*/
	var re = /(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/;
	var fd = re.exec(sqliteDate);
	if (fd){
		var dString = "";
		return dString.concat(fd[1], fd[2], fd[3], "_", fd[4], fd[5], fd[6]);
	} else {
		return null;
	}
};

var date_to_dString = function(inpDate){
	var year = inpDate.getFullYear().pad(4);
	var month = (inpDate.getMonth() + 1).pad(2);
	var day = inpDate.getDate().pad(2);
	var hour = inpDate.getHours().pad(2);
	var min = inpDate.getMinutes().pad(2);
	var sec = inpDate.getSeconds().pad(2);
	return "".concat(year, month, day, "_", hour, min, sec);
};

var mysqlDate = function(d){
    var year = d.getFullYear().pad(4);
	var month = (d.getMonth() + 1).pad(2);
	var day = d.getDate().pad(2);
	var hour = d.getHours().pad(2);
	var min = d.getMinutes().pad(2);
	var sec = d.getSeconds().pad(2);
    return "".concat(year, "-", month, "-", day, " ", hour, ":", min, ":", sec);
};

poconsole.factory('Page', function($log) {
    var title = 'default';
    var page = 'default';
    return {
        title: function() {
            return title;
        },
        setTitle: function(newTitle) {
            title = newTitle;
        },
        page: function() {
            return page;
        },
        setPage: function(newPage) {
            page = newPage;
        }
    };
});

poconsole.factory('tags',function($q, $http, $log){
	var getTag = function(id) {
        var deferred = $q.defer();
        var w ={"where":{"id":id}};
        $http.get('/tag', {params:w}).success(function(data) {
        	deferred.resolve({
    			tag:data
    		});
        });
        return deferred.promise;
    };

    var getTagList = function() {
        var deferred = $q.defer();
        $http.get('/tag').success(function(data) {
        	deferred.resolve({
    			tags:data
    		});
        });
        return deferred.promise;
    };

    var getDataTypes = function() {
        var deferred = $q.defer();
        $http.get('/data_type').success(function(data) {
        	deferred.resolve({
    			data_types:data
    		});
        });
        return deferred.promise;
    };

    var getTagHistoryBetween = function(id, start, end){
    	var deferred = $q.defer();
        var w = {'where':{'tagID': id, 'createdAt': {">":mysqlDate(start), "<": mysqlDate(end)}}};
        $http.get("/tag_val", {params:w}).success(function(data) {
        	deferred.resolve({
    			vals:data
    		});
        });
        return deferred.promise;
    };

    var getCurrentValues = function(){
    	var deferred = $q.defer();
        $http.get('/tag_val/latest').success(function(data) {
    		deferred.resolve({
    			vals:data
    		});
        });
        return deferred.promise;
    };

    var createTag = function(tag){
        $http.post('/tag/create', {
            tag: tag.tag,
            name: tag.name,
            tag_class:5,
            deviceID: tag.deviceID,
            units: tag.units,
            minExpected: tag.minExpected,
            maxExpected: tag.maxExpected,
            guarantee_sec: tag.guarantee_sec,
            change_threshold: tag.change_threshold,
            description: tag.description,
            data_type: tag.data_type
        }).success(function(data){
            return data;
        });
    };

    var updateTag = function(tag){
        $log.info("updateTag called with "+ JSON.stringify(tag));
        $http.post('/tag/update/'+ tag.id, {
            tag: tag.tag,
            name: tag.name,
            tag_class:5,
            deviceID: tag.deviceID,
            units: tag.units,
            minExpected: tag.minExpected,
            maxExpected: tag.maxExpected,
            guarantee_sec: tag.guarantee_sec,
            change_threshold: tag.change_threshold,
            description: tag.description,
            data_type: tag.data_type
        }).success(function(data){
            return data;
        }).error(function(err){
            $log.warn("updateTag Error: " + err);
        });
    };

    var deleteTag = function(id){
        var deferred = $q.defer();
        var url = '/tag/' + id;
        $http.delete(url).success(function(data) {
            deferred.resolve({
                data: data
            });
        });
        return deferred.promise;
    };

    var clearSingleTagData = function(id){
        var deferred = $q.defer();
        var url = '/tag_val/clear/' + id;
        $http.get(url).success(function(data) {
            deferred.resolve({
                status: data.status
            });
        });
        return deferred.promise;
    };

    var clearAllTagData = function(){
        var deferred = $q.defer();
        var url = '/tag_val/clear/all';
        $http.get(url).success(function(data) {
            deferred.resolve({
                status: data.status
            });
        });
        return deferred.promise;
    };

    return {
    	getTag: getTag,
    	getTagList: getTagList,
        getDataTypes: getDataTypes,
        getTagHistoryBetween: getTagHistoryBetween,
    	getCurrentValues: getCurrentValues,
        createTag: createTag,
        updateTag: updateTag,
        deleteTag: deleteTag,
        clearSingleTagData: clearSingleTagData,
        clearAllTagData: clearAllTagData
    };
});

poconsole.factory('devices', function($q, $http, $log){
    var getAllDevices = function(){
        var deferred = $q.defer();
        $http.get('/device').success(function(data) {
        	deferred.resolve({
    			devices:data
    		});
        });
        return deferred.promise;
    };

    var getDevice = function(id){
        var deferred = $q.defer();
        $http.get('/device/'+ id).success(function(data) {
        	deferred.resolve({
    			devices:data
    		});
        });
        return deferred.promise;
    };

    var addDevice = function(d){
        $log.info(d);
        $http.post('/device/create', {
            address: d.address,
            device_type: d.device_type.id
        }).success(function(data){
            return data;
        });
    };

    var updateDevice = function(d){
        $http.post('/device/update/' + d.id, {
            address: d.address,
            device_type: d.device_type.id
        }).success(function(data){
            return data;
        });
    };

    var deleteDevice = function(id){
        var deferred = $q.defer();
        var url = '/device/' + id;
        $http.delete(url).success(function(data) {
            deferred.resolve({
                data:data
            });
        });
        return deferred.promise;
    };

    var getDeviceTypes = function(){
        var deferred = $q.defer();
        $http.get('/device_type').success(function(data) {
        	deferred.resolve({
    			device_types:data
    		});
        });
        return deferred.promise;
    };


    return {
        getAllDevices : getAllDevices,
        getDevice: getDevice,
        addDevice: addDevice,
        deleteDevice: deleteDevice,
        updateDevice: updateDevice,
        getDeviceTypes: getDeviceTypes

    };
});

poconsole.factory('config',function($q, $http, $log){

    var getConfig = function(){
        var deferred = $q.defer();
        $http.get('/config').success(function(data) {
        	deferred.resolve({
    			config:data
    		});
        });
        return deferred.promise;
    };

    var submitParameter = function(entry){
        $http.post('/config', {
            parameter: entry.parameter,
            val: entry.val
        }).success(function(data){
            return data;
        });
    };

    var updateParameter = function(entry){
        $http.post('/config/update/' + entry.id, {
            parameter: entry.parameter,
            val: entry.val
        }).success(function(data){
            return data;
        });
    };

    var deleteParameter = function(id){
        $http.delete('/config/' + id).success(function(data){
            return data;
        });
    };

    var getLoggerStatus = function(){
        var deferred = $q.defer();
        $http.get('/json/logger/status').success(function(data) {
        	if(data.status == "OK"){
        		deferred.resolve({
        			running:data.running,
        			status: data.status
        		});
        	} else {
        		deferred.resolve({
        			status:data.status,
        			message: data.message,

        		});
        	}
        });
        return deferred.promise;
    };

    var restartLogger = function(){
        var deferred = $q.defer();
        $http.get('/json/logger/restart').success(function(data) {
        	if(data.status == "OK"){
        		deferred.resolve({
        			status: data.status
        		});
        	} else {
        		deferred.resolve({
        			status:data.status,
        			message: data.message
        		});
        	}
        });
        return deferred.promise;
    };


    return {
        getConfig:getConfig,
        submitParameter: submitParameter,
        getLoggerStatus: getLoggerStatus,
        restartLogger: restartLogger,
        updateParameter: updateParameter,
        deleteParameter: deleteParameter

    };

});

poconsole.controller('mainCtrl', function($scope, Page) {
    $scope.Page = Page;
});

poconsole.controller('dashboardCtrl', function($scope, $route, $http, $sails, Page, $log, tags) {
	Page.setTitle('Dashboard');
    Page.setPage('dashboard');
    $scope.loadDashboard = function(){
        $scope.loading = true;
        var getCurrentValues = tags.getCurrentValues();
        getCurrentValues.then(function(data) {
        	$scope.loading = false;
        	$scope.vals = data.vals;
            $log.info($scope.vals);
        });
    };
    $scope.loadDashboard();

    $sails.get("/tag_val").success(function(data, status, headers, jwr){
        $log.info(data);
    });

    var valHandler = $sails.on('tag_val', function(message){
        if (message.verb === "created"){
            $log.info(message.data);
            for(var i = 0; i < $scope.vals.length; i++){
                if(message.data.tagID == $scope.vals[i].t_id){
                    $scope.vals[i].val = message.data.val;
                    $scope.vals[i].dtime = message.data.createdAt;
                }
            }
        }
    });

    $scope.$on('$destroy', function() {
      $sails.off('tag_val', valHandler);
    });


});

poconsole.controller('tagsCtrl', function($scope, $route, $http, $routeParams, Page, $log, tags, devices) {
	Page.setTitle('Tags');
    Page.setPage('tags');
    $scope.loadTagList = function(){
    	$scope.loading = true;
        var getTagList = tags.getTagList();
        getTagList.then(function(data) {
        	$scope.loading = false;
        	$scope.tags = data.tags;
        });
    };
    $scope.loadTagList();

    var getDataTypes = tags.getDataTypes();
    getDataTypes.then(function(d){
        $scope.data_types = d.data_types;
    });

    var getAllDevices = devices.getAllDevices();
    getAllDevices.then(function(d){
        $scope.devices = d.devices;
    });

    $scope.submitAddTag = function(){
        var createStatus = tags.createTag($scope.newTag);
        $scope.createStatus = createStatus.status;
        $scope.loadTagList();
    };

    $scope.openDeleteTag = function(id){
        var getTag = tags.getTag(id);
        getTag.then(function(data){
            $scope.error = false;
            $scope.dTag = data.tag;
            $log.info("Thinking about deleting tag with parameters: "+ JSON.stringify($scope.dTag));
        });
    };

    $scope.deleteTag = function(id){
        var deleteTag = tags.deleteTag(id);
        deleteTag.then(function(data){
            $log.info("deleting tag "+ id + " status: " + data.status);
            $scope.error = false;
            $scope.loadTagList();
        });
    };

    $scope.openClearTagData = function(id){
        var getTag = tags.getTag(id);
        getTag.then(function(data){
            $scope.error = false;
            $scope.dTagValues = data.tag;
            $log.info("Thinking about deleting tag data with parameters: "+ JSON.stringify($scope.dTagValues));
        });
    };

    $scope.deleteTagValues = function(id){
        var clearSingleTagData = tags.clearSingleTagData(id);
        clearSingleTagData.then(function(data){
            $log.info("deleting tag "+ id + " status: " + data.status);
            $scope.error = false;
            $scope.loadTagList();
        });
    };

    $scope.openEditTag = function(id){
        var getTag = tags.getTag(id);
        getTag.then(function(data){
            $scope.error = false;
            $scope.editTag = data.tag[0];
            $log.info("Started editing tag with parameters: "+ JSON.stringify($scope.editTag));
        });
    };

    $scope.submitEditTag = function(){
        var editStatus = tags.updateTag($scope.editTag);
        $log.info(editStatus);
        $scope.editStatus = editStatus.status;
        $scope.loadTagList();
    };

    $scope.getPlotTags = function(){
        var tags_to_plot = [];
        for(var i =0; i<$scope.tags.length; i ++){
            if ($scope.tags[i].selectedForPlot){
                tags_to_plot.push($scope.tags[i].id);
            }
        }
        $scope.tags_to_plot = tags_to_plot.join();
    };

});

poconsole.controller('tagValsCtrl', function($scope, $route, $http, $routeParams, Page, $log, tags) {
	Page.setTitle('Tag Series');
    Page.setPage('tags');

    if ($routeParams.endDatetime){
        $scope.endDatetime = Date.parse(dString_to_sqlite($routeParams.endDatetime));
    } else {
        $scope.endDatetime = new Date();
    }

    if ($routeParams.startDatetime){
        $scope.startDatetime = Date.parse(dString_to_sqlite($routeParams.startDatetime));
    } else {
        $scope.startDatetime = new Date();
        $scope.startDatetime.setHours($scope.endDatetime.getHours() - 2);
    }
    $log.info({start: $scope.startDatetime, end:$scope.endDatetime});

    $scope.loadTagVals = function(sDTime, eDTime){
        $scope.loading = true;
        var tags_to_get = $routeParams.tagID.split(",");
    	var getTag = tags.getTag(tags_to_get);
        $scope.tags_to_get = tags_to_get.toString();
    	getTag.then(function(tagData){
			$scope.tag = tagData.tag;
		    var getTagHistoryBetween = tags.getTagHistoryBetween(tags_to_get, sDTime, eDTime);
		    getTagHistoryBetween.then(function(data) {

		    	$scope.loading = false;
	    		$scope.data = data;

				$scope.table_vals = $scope.data.vals.map(function(x){
					var ob =  {id: x.id, tagID: x.tagID, dtime: new Date(x.createdAt)};
                    for(var t = 0; t< $scope.tag.length; t++){
                        if ($scope.tag[t].name === x.tagID.name){
                            ob[$scope.tag[t].name] = x.val;
                        } else {
                            ob[$scope.tag[t].name] = null;
                        }
                    }

                    return ob;
				});

                var split_vals = {};
                var all_datetimes = [];
                for(var t=0; t< $scope.tag.length; t++){
                    split_vals[$scope.tag[t].name] = {};
                    split_vals[$scope.tag[t].name].dtimes = [];
                    split_vals[$scope.tag[t].name].vals = [];
                    split_vals[$scope.tag[t].name].ob = {};
                }
                for (var i = 0; i< data.vals.length; i++){
                    split_vals[data.vals[i].tagID.name].ob[data.vals[i].createdAt]= data.vals[i].val;
                    split_vals[data.vals[i].tagID.name].dtimes.push(data.vals[i].createdAt);
                    split_vals[data.vals[i].tagID.name].vals.push(data.vals[i].val);
                    if (all_datetimes.indexOf(data.vals[i].createdAt) == -1){
                        all_datetimes.push(data.vals[i].createdAt);
                    }
                }
                $scope.data.vals = [{dtime:new Date(all_datetimes[0])}];
                for (var ta in split_vals){
                    $scope.data.vals[0][ta] = split_vals[ta].vals[0];
                }

                for (var j = 0; j < all_datetimes.length; j++){
                    var newOb = {dtime: new Date(all_datetimes[j])};
                    for(var tag in split_vals){
                        if(split_vals[tag].ob[all_datetimes[j]] === undefined){
                            newOb[tag] = $scope.data.vals[j][tag];
                        } else {
                            newOb[tag] = split_vals[tag].ob[all_datetimes[j]];
                        }
                    }
                    $scope.data.vals.push(newOb);
                }

	    		$scope.error = false;
	    		$scope.options = {
					series: [

					],
					axes: {
						x: {
							key: "dtime",
							type: "date"
						}
					}
				};
                for(var i2 = 0; i2< $scope.tag.length; i2++){
                    $scope.options.series.push({
                        axis: "y",
                        dataset: "vals",
                        key: $scope.tag[i2].name,
                        label: $scope.tag[i2].name,
                        // color: "#1f77b4",
                        color: colors[i2 % colors.length],
                        type: ['line'],
                        drawDots:false
                    });
                }
		    });
    	});
    };
    $scope.loadTagVals($scope.startDatetime, $scope.endDatetime);
});

poconsole.controller('configCtrl', function($scope, Page, $log, config, devices) {
	Page.setTitle('Configuration');
    Page.setPage('configuration');



    $scope.loadConfig = function(){
        $scope.loading = true;
        var getConfig = config.getConfig();
        getConfig.then(function(data) {
        	$scope.loading = false;
    		$scope.config = data.config;
        });
    };
    $scope.loadConfig();
    $scope.paramError = null;
    var selString = "Select a parameter...";
    $scope.newParam = {
        pSelected: selString,
        parameter: null,
        val: null
    };

    $scope.addParameter = function(){
        if ($scope.newParam.pSelected == selString){
            $scope.paramError = "No parameter selected";
        } else {
            if ($scope.newParam.pSelected == "other") {
                $scope.newParam.parameter = $scope.newParam.pEntry;
            } else {
                $scope.newParam.parameter = $scope.newParam.pSelected;
            }
            config.submitParameter($scope.newParam);
            $scope.loadConfig();
        }
    };

    $scope.checkLogger = function(){
        $scope.loggerLoading = true;
        var checkLoggerStatus = config.getLoggerStatus();
        checkLoggerStatus.then(function(data){
            $scope.loggerLoading = false;
        	if (data.status == "OK"){
        		$scope.loggerRunning = data.running;
        		$scope.error = false;
        	} else {
        		$scope.error = data.message;
        	}
        });
    };
    // $scope.checkLogger();

    $scope.restartLogger = function(){
        var restartLogger = config.restartLogger();
        restartLogger.then(function(data){
        	if (data.status == "OK"){
        		$scope.error = false;
                $scope.checkLogger();
        	} else {
        		$scope.error = data.message;
        	}
        });
    };

    $scope.getDevices = function(){
        var getDevices = devices.getAllDevices();
        getDevices.then(function(d){
            $scope.devices = d.devices;
        });
    };
    $scope.getDevices();


    $scope.addDevice = function(dev){
        var addDevice = devices.addDevice(dev);
        getDevices.then(function(d){
            $scope.getDevices();
        });
    };

    var getDeviceTypes = devices.getDeviceTypes();
    getDeviceTypes.then(function(d){
        $scope.device_types = d.device_types;
    });
});


//*---- FILTERS -----*//
poconsole.filter('dString', function myDateFormat($filter){
	return function(text){
		var  tempdate= new Date(text);
		return $filter('date')(tempdate, "yyyyMMdd'_'HHmmss");
	};
});

poconsole.filter('sqlite_to_local', function sqliteformat($filter){
	return function(text){
		var utcdate= new Date(text + " UTC");
		return $filter('date')(utcdate, "yyyy-MM-dd hh:mm:ss a");
	};
});
