// Common Controller for the montage view
/* jshint -W041 */
/* jslint browser: true*/
/* global saveAs, cordova,StatusBar,angular,console,ionic, moment, imagesLoaded, chrome */
angular.module('zmApp.controllers').controller('MonitorModalCtrl', ['$scope', '$rootScope', 'zm', 'NVRDataModel', '$ionicSideMenuDelegate', '$timeout', '$interval', '$ionicModal', '$ionicLoading', '$http', '$state', '$stateParams', '$ionicHistory', '$ionicScrollDelegate', '$q', '$sce', 'carouselUtils', '$ionicPopup', 'SecuredPopups', '$translate', function($scope, $rootScope, zm, NVRDataModel, $ionicSideMenuDelegate, $timeout, $interval, $ionicModal, $ionicLoading, $http, $state, $stateParams, $ionicHistory, $ionicScrollDelegate, $q, $sce, carouselUtils, $ionicPopup, SecuredPopups, $translate)
{
$scope.animationInProgress = false;
$scope.imageFit = true;
$scope.isModalActive = true;
var intervalModalHandle;
var cycleHandle;
var nphTimer;
var ld = NVRDataModel.getLogin();
$scope.svgReady = false;
$scope.zoneArray = [];
var originalZones = [];
$scope.isZoneEdit = false;
var _moveStart = false;
var targetID = "";
$scope.imageZoomable = true;
$scope.csize = ($rootScope.platformOS == 'desktop') ? 10:20;
window.addEventListener("resize", function(){imageLoaded();}, false);
$rootScope.authSession = "undefined";
$ionicLoading.show(
{
template: $translate.instant('kNegotiatingStreamAuth') + '...',
animation: 'fade-in',
showBackdrop: true,
duration: zm.loadingTimeout,
maxWidth: 300,
showDelay: 0
});
$scope.currentStreamMode = 'single';
NVRDataModel.log("Using stream mode " + $scope.currentStreamMode);
NVRDataModel.debug("MonitorModalCtrl called from " + $ionicHistory.currentStateName());
$rootScope.validMonitorId = $scope.monitors[0].Monitor.Id;
NVRDataModel.getAuthKey($rootScope.validMonitorId, $scope.monitors[0].Monitor.connKey)
.then(function(success)
{
$ionicLoading.hide();
$rootScope.authSession = success;
NVRDataModel.log("Modal: Stream authentication construction: " + $rootScope.authSession);
},
function(error)
{
$ionicLoading.hide();
NVRDataModel.debug("ModalCtrl: Error details of stream auth:" + error);
//$rootScope.authSession="";
NVRDataModel.log("Modal: Error returned Stream authentication construction. Retaining old value of: " + $rootScope.authSession);
});
$interval.cancel(intervalModalHandle);
$interval.cancel(cycleHandle);
intervalModalHandle = $interval(function()
{
loadModalNotifications();
// console.log ("Refreshing Image...");
}.bind(this), 5000);
$timeout.cancel(nphTimer);
nphTimer = $timeout(function()
{
$scope.currentStreamMode = 'jpeg';
NVRDataModel.log("Switching playback via nphzms");
}, zm.nphSwitchTimer);
// This is the PTZ menu
$scope.ptzRadialMenuOptions = {
content: '',
background: '#2F4F4F',
isOpen: true,
toggleOnClick: false,
button:
{
cssClass: "fa fa-arrows-alt",
},
items: [
{
content: '',
cssClass: 'fa fa-chevron-circle-up',
empty: false,
onclick: function()
{
controlPTZ($scope.monitorId, $scope.ptzMoveCommand + 'Down');
}
},
{
content: '',
cssClass: 'fa fa-chevron-circle-up',
empty: false,
onclick: function()
{
controlPTZ($scope.monitorId, $scope.ptzMoveCommand + 'DownLeft');
}
},
{
content: '',
cssClass: 'fa fa-chevron-circle-up',
empty: false,
onclick: function()
{
controlPTZ($scope.monitorId, $scope.ptzMoveCommand + 'Left');
}
},
{
content: 'D',
empty: true,
onclick: function()
{
// console.log('About');
}
},
{
content: '',
cssClass: 'fa fa-chevron-circle-up',
empty: false,
onclick: function()
{
controlPTZ($scope.monitorId, $scope.ptzMoveCommand + 'UpLeft');
}
},
{
content: '',
cssClass: 'fa fa-chevron-circle-up',
empty: false,
onclick: function()
{
controlPTZ($scope.monitorId, $scope.ptzMoveCommand + 'Up');
}
},
{
content: '',
cssClass: 'fa fa-chevron-circle-up',
empty: false,
onclick: function()
{
controlPTZ($scope.monitorId, $scope.ptzMoveCommand + 'UpRight');
}
},
{
content: 'H',
empty: true,
onclick: function()
{
//console.log('About');
}
},
{
content: '',
cssClass: 'fa fa-chevron-circle-up',
empty: false,
onclick: function()
{
controlPTZ($scope.monitorId, $scope.ptzMoveCommand + 'Right');
}
},
{
content: '',
cssClass: 'fa fa-chevron-circle-up',
empty: false,
onclick: function()
{
controlPTZ($scope.monitorId, $scope.ptzMoveCommand + 'DownRight');
}
},
{
content: 'K',
empty: true,
onclick: function()
{
//console.log('About');
}
},
]
};
//-------------------------------------------------------------
// On re-auth, we need a new zms
//-------------------------------------------------------------
$rootScope.$on("auth-success", function()
{
NVRDataModel.debug("MonitorModalCtrl: Re-login detected, resetting everything & re-generating connkey");
NVRDataModel.stopNetwork("MonitorModal-auth success");
$scope.connKey = (Math.floor((Math.random() * 999999) + 1)).toString();
});
$scope.cast = function(mid, mon) {
};
//----------------------------------
// toggles monitor cycling
//----------------------------------
$scope.toggleCycle = function()
{
//console.log ("HERE");
$scope.isCycle = !$scope.isCycle;
var ld = NVRDataModel.getLogin();
ld.cycleMonitors = $scope.isCycle;
NVRDataModel.setLogin(ld);
$scope.cycleText = $scope.isCycle ? $translate.instant('kOn') : $translate.instant('kOff');
if ($scope.isCycle)
{
NVRDataModel.log("re-starting cycle timer");
$interval.cancel(cycleHandle);
cycleHandle = $interval(function()
{
moveToMonitor($scope.monitorId, 1);
// console.log ("Refreshing Image...");
}.bind(this), ld.cycleMonitorsInterval * 1000);
}
else
{
NVRDataModel.log("cancelling cycle timer");
$interval.cancel(cycleHandle);
}
};
//-------------------------------------------------------------
// PTZ enable/disable
//-------------------------------------------------------------
$scope.togglePTZ = function()
{
//console.log("PTZ");
if ($scope.isControllable == '1')
{
//console.log ("iscontrollable is true");
$scope.showPTZ = !$scope.showPTZ;
}
else
{
$ionicLoading.show(
{
template: $translate.instant('kPTZnotConfigured'),
noBackdrop: true,
duration: 3000,
});
}
};
//-------------------------------------------------------------
// Pause and resume handlers
//-------------------------------------------------------------
function onPause()
{
NVRDataModel.debug("ModalCtrl: onpause called");
$interval.cancel(intervalModalHandle);
$interval.cancel(cycleHandle);
// $interval.cancel(modalIntervalHandle);
// FIXME: Do I need to setAwake(false) here?
}
function onResume()
{
NVRDataModel.debug("ModalCtrl: Modal resume called");
if ($scope.isModalActive)
{
NVRDataModel.log("ModalCtrl: Restarting Modal timer on resume");
$interval.cancel(intervalModalHandle);
$interval.cancel(cycleHandle);
var ld = NVRDataModel.getLogin();
intervalModalHandle = $interval(function()
{
loadModalNotifications();
}.bind(this), 5000);
if (ld.cycleMonitors)
{
NVRDataModel.debug("Cycling enabled at " + ld.cycleMonitorsInterval);
$interval.cancel(cycleHandle);
cycleHandle = $interval(function()
{
moveToMonitor($scope.monitorId, 1);
// console.log ("Refreshing Image...");
}.bind(this), ld.cycleMonitorsInterval * 1000);
}
$rootScope.modalRand = Math.floor((Math.random() * 100000) + 1);
}
}
//-------------------------------------------------------------
// Queries the 1.30 API for recording state of current monitor
//-------------------------------------------------------------
function loadModalNotifications()
{
if (NVRDataModel.versionCompare($rootScope.apiVersion, "1.30") == -1)
{
return;
}
if (NVRDataModel.getLogin().enableLowBandwidth)
return;
var status = [$translate.instant('kMonIdle'),
$translate.instant('kMonPreAlarm'),
$translate.instant('kMonAlarmed'),
$translate.instant('kMonAlert'),
$translate.instant('kMonRecord')
];
//console.log ("Inside Modal timer...");
var apiurl = NVRDataModel.getLogin().apiurl;
var alarmurl = apiurl + "/monitors/alarm/id:" + $scope.monitorId + "/command:status.json";
NVRDataModel.log("Invoking " + alarmurl);
$http.get(alarmurl)
.then(function(data)
{
// NVRDataModel.debug ("Success in monitor alarmed status " + JSON.stringify(data));
$scope.monStatus = status[parseInt(data.data.status)];
},
function(error)
{
$scope.monStatus = "";
NVRDataModel.debug("Error in monitor alarmed status ");
});
}
//-------------------------------------------------------------
// Enable/Disable preset list
//-------------------------------------------------------------
$scope.togglePresets = function()
{
$scope.presetOn = !$scope.presetOn;
if ($scope.presetOn)
{
$scope.controlToggle = "hide buttons";
}
else
{
$scope.controlToggle = "show buttons";
}
//console.log("Changing preset to " + $scope.presetOn);
var element = angular.element(document.getElementById("presetlist"));
// bring it in
if ($scope.presetOn)
{
element.removeClass("animated fadeOutUp");
}
else
{
element.removeClass("animated fadeInDown");
element.addClass("animated fadeOutUp");
}
};
$scope.saveZones = function()
{
var str="";
for (var i=0; i < originalZones.length; i++)
{
str = str + "o:"+originalZones[i].coords+"
n:"+$scope.zoneArray[i].coords+"--------------------------------------------------
";
}
$rootScope.zmPopup = SecuredPopups.show('confirm',
{
title: 'Sure',
template: str,
okText: $translate.instant('kButtonOk'),
cancelText: $translate.instant('kButtonCancel'),
});
};
$scope.changeCircleSize = function()
{
$scope.csize = Math.max (($scope.csize + 5) % 31, 10);
};
$scope.toggleZoneEdit = function()
{
$scope.isZoneEdit = !$scope.isZoneEdit;
$scope.connKey = (Math.floor((Math.random() * 999999) + 1)).toString();
if ($scope.isZoneEdit)
{
$ionicScrollDelegate.$getByHandle("imgscroll").zoomTo(1, true);
$scope.imageZoomable = false;
//document.getElementById("imgscroll").zooming="false";
for (var i=0; i < $scope.circlePoints.length; i++)
{
var t = document.getElementById("circle-"+i);
if (t)
{
t.removeEventListener("touchstart",moveStart);
t.removeEventListener("mousedown",moveStart);
//t.removeEventListener("mousemove",moveContinue);
//t.removeEventListener("mouseup",moveStop);
t.addEventListener("touchstart",moveStart);
t.addEventListener("mousedown",moveStart);
//t.addEventListener("mousemove",moveContinue);
//t.addEventListener("mouseup",moveStop);
console.log ("Found circle-"+i);
}
else
{
console.log ("did not find circle-"+i);
}
}
}
else // get out of edit
{
$scope.imageZoomable = true;
}
};
$scope.toggleZone = function()
{
$scope.showZones = !$scope.showZones;
if (!$scope.showZones)
$scope.isZoneEdit = false;
};
$scope.imageLoaded = function()
{
imageLoaded();
};
$scope.checkZoom = function()
{
//var z = $ionicScrollDelegate.$getByHandle("imgscroll").getScrollPosition().zoom;
//imageLoaded();
};
$scope.circleTouch = function (evt)
{
console.log ("TOUCH");
};
//$scope.circleOnDrag = function (evt, ndx)
function recomputePolygons (ax, ay, ndx,z)
{
// we get screen X/Y - need to translate
// to SVG points
console.log ("recompute with",ax,"&",ay);
var svg=document.getElementById('zsvg');
var pt = svg.createSVGPoint();
pt.x = ax;
pt.y = ay;
var svgP = pt.matrixTransform(svg.getScreenCTM().inverse());
$scope.circlePoints[ndx].x = Math.round(svgP.x);
$scope.circlePoints[ndx].y = Math.round(svgP.y);
// get related polygon set
var zi = $scope.circlePoints[ndx].zoneIndex;
var newPoints="";
for ( var i=0; i < $scope.circlePoints.length; i++)
{
if ($scope.circlePoints[i].zoneIndex == zi)
{
newPoints = newPoints + " " +$scope.circlePoints[i].x+","+$scope.circlePoints[i].y;
}
console.log ("recomputed polygon:", newPoints);
}
// console.log ("OLD ZONE FOR:"+zi+" is "+$scope.zoneArray[zi].coords );
//console.log ("NEW ZONE FOR:"+zi+" is "+newPoints);
$scope.zoneArray[zi].coords = newPoints;
//console.log ("INDEX="+ndx+" DRAG="+svgP.x+":"+svgP.y);
}
// credit: http://stackoverflow.com/questions/41411891/most-elegant-way-to-parse-scale-and-re-string-a-string-of-number-co-ordinates?noredirect=1#41411927
// This function scales coords of zones based on current image size
function scaleCoords(string, sx, sy) {
var f = [sx, sy];
return string.split(' ').map(function (a) {
return a.split(',').map(function (b, i) {
return Math.round(b * f[i]);
}).join(',');
}).join(' ');
}
function moveContinue(event)
{
if (!_moveStart) {return;}
console.log ("CONTINUE: target id="+targetID);
/*if(event.preventDefault) event.preventDefault();
if (event.gesture) event.gesture.preventDefault() ;
if (event.gesture) event.gesture.stopPropagation();*/
var x,y;
var z = $ionicScrollDelegate.$getByHandle("imgscroll").getScrollPosition().zoom;
console.log ("zoom is:"+z);
//console.log(event, this, "t");
if (event.touches)
{
//console.log ("TOUCH");
x = event.targetTouches[0].pageX;
y = event.targetTouches[0].pageY;
}
else
{
//console.log ("MOUSE");
x = event.clientX ;
y = event.clientY ;
}
console.log ("X="+x+" Y="+y + " sl="+document.body.scrollLeft+ " sy="+document.body.scrollTop);
$timeout (function() {recomputePolygons (x,y,targetID,1);});
}
function moveStop (event)
{
_moveStart = false;
console.log ("STOP");
}
function moveStart(event)
{
_moveStart=true;
targetID = event.target.id.substring(7);
console.log ("START: target id="+targetID);
if(event.preventDefault) event.preventDefault();
if (event.gesture) event.gesture.preventDefault() ;
if (event.gesture) event.gesture.stopPropagation();
var z = $ionicScrollDelegate.$getByHandle("imgscroll").getScrollPosition().zoom;
console.log ("zoom is:"+z);
var x,y;
// perhaps event.targetTouches[0]?
if (event.touches)
{
//console.log(event.changedTouches[0], this, "t");
x = event.touches[0].pageX;
y = event.touches[0].pageY;
}
else
{
//console.log(event, this, "t");
x = event.clientX ;
y = event.clientY ;
}
console.log ("X="+x+" Y="+y + " sl="+document.body.scrollLeft+ " sy="+document.body.scrollTop);
}
// called when the live monitor image loads
// this is a good time to calculate scaled zone points
function imageLoaded()
{
var img =document.getElementById("singlemonitor");
//$scope.cw = img.naturalWidth;
//$scope.ch = img.naturalHeight;
$scope.cw = img.naturalWidth;
$scope.ch = img.naturalHeight;
//console.log ("REPORTED DIM:" + $scope.cw+ "x"+$scope.ch );
//console.log ("ORIGINAL DIM:" + img.naturalWidth+ "x"+img.naturalHeight);
//https://server/zm/api/zones/forMonitor/7.json
//
$scope.zoneArray = [];
$scope.circlePoints = [];
var ow = $scope.monitor.Monitor.Width;
var oh = $scope.monitor.Monitor.Height;
// console.log ("MONITOR IS: "+JSON.stringify($scope.monitor));
// console.log ("ORIGINAL WH="+ow+"x"+oh);
for (var i=0; i < originalZones.length; i++)
{
var sx = $scope.cw/ow;
var sy = $scope.ch/oh;
//$scope.zoneArray.push({
// coords:scaleCoords(originalZones[i].coords,sx,sy),
// type:originalZones[i].type});
$scope.zoneArray.push({
coords:originalZones[i].coords,
type:originalZones[i].type});
}
// now create a points array for circle handles
for (i=0; i < $scope.zoneArray.length; i++)
{
/*jshint loopfunc: true */
console.log ("ZONE ARRAY="+$scope.zoneArray[i].coords);
$scope.zoneArray[i].coords.split(' ')
.forEach( function(itm)
{
var o=itm.split(',');
$scope.circlePoints.push({x:o[0],y:o[1], zoneIndex:i});
// console.log ("CIRCLE X="+o[0]+"Y="+o[1]);
});
}
}
//-------------------------------------------------------------
// this is checked to make sure we are not pulling images
// when app is in background. This is a problem with Android,
// for example
//-------------------------------------------------------------
$scope.isBackground = function()
{
// console.log ("Is background called from ModalCtrl and returned " +
// NVRDataModel.isBackground());
return NVRDataModel.isBackground();
};
//-------------------------------------------------------------
// Send PTZ command to ZM
// Note: PTZ fails on desktop, don't bother about it
//-------------------------------------------------------------
$scope.controlPTZ = function(monitorId, cmd)
{
controlPTZ(monitorId, cmd);
};
function controlPTZ(monitorId, cmd)
{
//presetGotoX
//presetHome
//curl -X POST "http://server.com/zm/index.php?view=request" -d
//"request=control&user=admin&passwd=xx&id=4&control=moveConLeft"
if (!$scope.ptzMoveCommand)
{
$ionicLoading.show(
{
template: $translate.instant('kPTZNotReady'),
noBackdrop: true,
duration: 2000,
});
return;
}
var ptzData = "";
if (cmd.lastIndexOf("preset", 0) === 0)
{
NVRDataModel.debug("PTZ command is a preset, so skipping xge/lge");
ptzData = {
view: "request",
request: "control",
id: monitorId,
control: cmd,
// xge: "30", //wtf
// yge: "30", //wtf
};
}
else
{
ptzData = {
view: "request",
request: "control",
id: monitorId,
control: cmd,
xge: "30", //wtf
yge: "30", //wtf
};
}
//console.log("Command value " + cmd + " with MID=" + monitorId);
//console.log("PTZDATA is " + JSON.stringify(ptzData));
$ionicLoading.hide();
$ionicLoading.show(
{
template: $translate.instant('kPleaseWait') + "...",
noBackdrop: true,
duration: zm.loadingTimeout,
});
var loginData = NVRDataModel.getLogin();
$ionicLoading.hide();
$ionicLoading.show(
{
template: $translate.instant('kSendingPTZ') + "...",
noBackdrop: true,
duration: zm.loadingTimeout,
});
var req = $http(
{
method: 'POST',
/*timeout: 15000,*/
url: loginData.url + '/index.php',
headers:
{
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json',
},
transformRequest: function(obj)
{
var str = [];
for (var p in obj)
str.push(encodeURIComponent(p) + "=" +
encodeURIComponent(obj[p]));
var foo = str.join("&");
//console.log("****RETURNING " + foo);
return foo;
},
data: ptzData
});
req.success(function(resp)
{
$ionicLoading.hide();
});
req.error(function(resp)
{
$ionicLoading.hide();
//console.log("ERROR: " + JSON.stringify(resp));
NVRDataModel.log("Error sending PTZ:" + JSON.stringify(resp), "error");
});
}
$scope.getZoomLevel = function()
{
//console.log("ON RELEASE");
var zl = $ionicScrollDelegate.$getByHandle("imgscroll").getScrollPosition();
//console.log(JSON.stringify(zl));
};
$scope.onTap = function(m, d)
{
moveToMonitor(m, d);
};
$scope.onSwipe = function(m, d)
{
if ($scope.isZoneEdit)
{
NVRDataModel.log ("swipe disabled as you are in edit mode");
return;
}
var ld = NVRDataModel.getLogin();
if (!ld.canSwipeMonitors) return;
if ($ionicScrollDelegate.$getByHandle("imgscroll").getScrollPosition().zoom != 1)
{
//console.log("Image is zoomed in - not honoring swipe");
return;
}
$scope.monStatus = "";
moveToMonitor(m, d);
};
function moveToMonitor(m, d)
{
if ($scope.isZoneEdit)
{
NVRDataModel.log ("Not cycling, as you are editing zones");
}
var curstate = $ionicHistory.currentStateName();
var found = 0;
var mid;
mid = NVRDataModel.getNextMonitor(m, d);
$scope.showPTZ = false;
// FIXME: clean this up - in a situation where
// no monitors are enabled, will it loop for ever?
do {
mid = NVRDataModel.getNextMonitor(m, d);
m = mid;
//console.log("Next Monitor is " + m);
found = 0;
for (var i = 0; i < $scope.monitors.length; i++)
{
if ($scope.monitors[i].Monitor.Id == mid &&
// if you came from monitors, then ignore noshow
($scope.monitors[i].Monitor.listDisplay != 'noshow' || curstate == "monitors") &&
$scope.monitors[i].Monitor.Function != 'None' &&
$scope.monitors[i].Monitor.Enabled != '0')
{
found = 1;
//console.log(mid + "is part of the monitor list");
NVRDataModel.debug("ModalCtrl: swipe detected, moving to " + mid);
break;
}
else
{
NVRDataModel.debug("skipping " + $scope.monitors[i].Monitor.Id +
" listDisplay=" + $scope.monitors[i].Monitor.listDisplay +
" Function=" + $scope.monitors[i].Monitor.Function +
" Enabled=" + $scope.monitors[i].Monitor.Enabled);
}
}
}
while (found != 1);
var slidein;
var slideout;
var dirn = d;
if (dirn == 1)
{
slideout = "animated slideOutLeft";
slidein = "animated slideInRight";
}
else
{
slideout = "animated slideOutRight";
slidein = "animated slideInLeft";
}
var element = angular.element(document.getElementById("monitorimage"));
element.addClass(slideout)
.one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', outWithOld);
function outWithOld()
{
NVRDataModel.log("ModalCtrl:Stopping network pull...");
NVRDataModel.stopNetwork("MonitorModal-outwithOld");
$scope.rand = Math.floor((Math.random() * 100000) + 1);
$scope.animationInProgress = true;
$timeout(function()
{
element.removeClass(slideout);
element.addClass(slidein)
.one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', inWithNew);
$scope.monitorId = mid;
$scope.monitorName = NVRDataModel.getMonitorName(mid);
$scope.monitor = NVRDataModel.getMonitorObject(mid);
$scope.zoneArray=[];
$scope.circlePoints=[];
getZones();
configurePTZ($scope.monitorId);
}, 200);
}
function inWithNew()
{
element.removeClass(slidein);
$scope.animationInProgress = false;
NVRDataModel.log("New image loaded in");
var ld = NVRDataModel.getLogin();
carouselUtils.setStop(false);
if (ld.useNphZms == true)
{
$scope.currentStreamMode = 'single';
NVRDataModel.log("Setting timer to play nph-zms mode");
// first 5 seconds, load a snapshot, then switch to real FPS display
// this is to avoid initial image load delay
// FIXME: 5 seconds fair?
$timeout.cancel(nphTimer);
nphTimer = $timeout(function()
{
$scope.currentStreamMode = 'jpeg';
NVRDataModel.log("Switching playback via nphzms");
}, zm.nphSwitchTimer);
}
}
$ionicLoading.hide();
}
//-----------------------------------------------------------------------
// Sucess/Error handlers for saving a snapshot of the
// monitor image to phone storage
//-----------------------------------------------------------------------
function SaveSuccess()
{
$ionicLoading.show(
{
template: $translate.instant('kDone'),
noBackdrop: true,
duration: 1000
});
NVRDataModel.debug("ModalCtrl:Photo saved successfuly");
}
function SaveError(e)
{
$ionicLoading.show(
{
template: $translate.instant('kErrorSave'),
noBackdrop: true,
duration: 2000
});
NVRDataModel.log("Error saving image: " + e);
//console.log("***ERROR");
}
//-------------------------------------------------------------
// Turns on or off an alarm forcibly (mode true = on, false = off)
//-------------------------------------------------------------
$scope.enableAlarm = function(mid, mode)
{
if (mode) // trigger alarm
{
$rootScope.zmPopup = SecuredPopups.show('show',
{
title: 'Confirm',
template: $translate.instant('kForceAlarmConfirm') + $scope.monitorName + "?",
buttons: [
{
text: $translate.instant('kButtonYes'),
onTap: function(e)
{
enableAlarm(mid, mode);
}
},
{
text: $translate.instant('kButtonNo'),
onTap: function(e)
{
return;
}
}]
});
}
else
enableAlarm(mid, mode);
function enableAlarm(mid, mode)
{
var apiurl = NVRDataModel.getLogin().apiurl;
var c = mode ? "on" : "off";
var alarmurl = apiurl + "/monitors/alarm/id:" + mid + "/command:" + c + ".json";
NVRDataModel.log("Invoking " + alarmurl);
var status = mode ? $translate.instant('kForcingAlarm') : $translate.instant('kCancellingAlarm');
$ionicLoading.show(
{
template: status,
noBackdrop: true,
duration: zm.largeHttpTimeout,
});
$http.get(alarmurl)
.then(function(data)
{
$ionicLoading.show(
{
template: $translate.instant('kSuccess'),
noBackdrop: true,
duration: 2000,
});
},
function(error)
{
$ionicLoading.show(
{
template: $translate.instant('kAlarmAPIError'),
noBackdrop: true,
duration: 3000,
});
NVRDataModel.debug("Error in enableAlarm " + JSON.stringify(error));
});
}
};
//-----------------------------------------------------------------------
// color for monitor state
//-----------------------------------------------------------------------
$scope.stateColor = function()
{
var status = [$translate.instant('kMonIdle'),
$translate.instant('kMonPreAlarm'),
$translate.instant('kMonAlarmed'),
$translate.instant('kMonAlert'),
$translate.instant('kMonRecord')
];
//console.log ("***MONSTATUS**"+$scope.monStatus+"**");
var color = "";
switch ($scope.monStatus)
{
case "":
color = "background-color:none";
break;
case status[0]:
color = "background-color:#4B77BE";
break;
case status[1]:
color = "background-color:#e67e22";
break;
case status[2]:
color = "background-color:#D91E18";
break;
case status[3]:
color = "background-color:#e67e22";
break;
case status[4]:
color = "background-color:#26A65B";
break;
}
return "padding-left:4px;padding-right:4px;" + color;
};
//-----------------------------------------------------------------------
// Saves a snapshot of the monitor image to phone storage
//-----------------------------------------------------------------------
$scope.saveImageToPhoneWithPerms = function(mid)
{
if ($rootScope.platformOS != 'android')
{
saveImageToPhone(mid);
return;
}
NVRDataModel.debug("ModalCtrl: Permission checking for write");
var permissions = cordova.plugins.permissions;
permissions.hasPermission(permissions.WRITE_EXTERNAL_STORAGE, checkPermissionCallback, null);
function checkPermissionCallback(status)
{
if (!status.hasPermission)
{
SaveError("No permission to write to external storage");
}
permissions.requestPermission(permissions.WRITE_EXTERNAL_STORAGE, succ, err);
}
function succ(s)
{
saveImageToPhone(mid);
}
function err(e)
{
SaveError("Error in requestPermission");
}
};
function saveImageToPhone(mid)
{
$ionicLoading.show(
{
template: $translate.instant('kSavingSnapshot') + '...',
noBackdrop: true,
duration: zm.httpTimeout
});
NVRDataModel.debug("ModalCtrl: SaveImageToPhone called");
var canvas, context, imageDataUrl, imageData;
var loginData = NVRDataModel.getLogin();
var url = loginData.streamingurl +
'/zms?mode=single&monitor=' + mid +
$rootScope.authSession;
NVRDataModel.log("SavetoPhone:Trying to save image from " + url);
var img = new Image();
img.onload = function()
{
// console.log("********* ONLOAD");
canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
context = canvas.getContext('2d');
context.drawImage(img, 0, 0);
imageDataUrl = canvas.toDataURL('image/jpeg', 1.0);
imageData = imageDataUrl.replace(/data:image\/jpeg;base64,/, '');
if ($rootScope.platformOS != "desktop")
{
try
{
cordova.exec(
SaveSuccess,
SaveError,
'Canvas2ImagePlugin',
'saveImageDataToLibrary', [imageData]
);
}
catch (e)
{
SaveError(e.message);
}
}
else
{
var fname = $scope.monitorName + "-" +
moment().format('MMM-DD-YY_HH-mm-ss') + ".png";
canvas.toBlob(function(blob)
{
saveAs(blob, fname);
SaveSuccess();
});
}
};
try
{
img.src = url;
// console.log ("SAVING IMAGE SOURCE");
}
catch (e)
{
SaveError(e.message);
}
}
//-------------------------------------------------------------
//reloaads mon - do we need it?
//-------------------------------------------------------------
$scope.reloadView = function()
{
NVRDataModel.log("Reloading view for modal view, recomputing rand");
$rootScope.modalRand = Math.floor((Math.random() * 100000) + 1);
$scope.isModalActive = true;
};
$scope.scaleImage = function()
{
$scope.imageFit = !$scope.imageFit;
if ($scope.imageFit)
$scope.aspectFit="xMidYMid meet";
else
$scope.aspectFit = "xMidYMid slice";
// console.log("Switching image style to " + $scope.imageFit);
};
$scope.$on('$ionicView.enter', function()
{
//https://server/zm/api/zones/forMonitor/X.json
});
$scope.$on('$ionicView.leave', function()
{
// console.log("**MODAL: Stopping modal timer");
$scope.isModalActive = false;
$interval.cancel(intervalModalHandle);
$interval.cancel(cycleHandle);
});
$scope.$on('$ionicView.beforeLeave', function()
{
NVRDataModel.log("Nullifying the streams...");
var element = document.getElementById("singlemonitor");
if (element)
{
NVRDataModel.debug("Nullifying " + element.src);
element.src = "";
}
});
$scope.$on('$ionicView.unloaded', function()
{
$scope.isModalActive = false;
$interval.cancel(intervalModalHandle);
$interval.cance(cycleHandle);
});
$scope.$on('modal.removed', function()
{
$scope.isModalActive = false;
//console.log("**MODAL REMOVED: Stopping modal timer");
$interval.cancel(intervalModalHandle);
$interval.cancel(cycleHandle);
NVRDataModel.debug("Modal removed - killing connkey");
controlStream(17, "", $scope.connKey, -1);
// Execute action
});
//-------------------------------------------------------------
// called to kill connkey, not sure if we really need it
// I think we are calling window.stop() which is a hammer
// anyway
//-------------------------------------------------------------
function controlStream(cmd, disp, connkey, ndx)
{
// console.log("Command value " + cmd);
if (disp)
{
$ionicLoading.hide();
$ionicLoading.show(
{
template: $translate.instant('kPleaseWait') + '...',
noBackdrop: true,
duration: zm.loadingTimeout,
});
}
var loginData = NVRDataModel.getLogin();
/*
var CMD_NONE = 0;
var CMD_PAUSE = 1;
var CMD_PLAY = 2;
var CMD_STOP = 3;
var CMD_FASTFWD = 4;
var CMD_SLOWFWD = 5;
var CMD_SLOWREV = 6;
var CMD_FASTREV = 7;
var CMD_ZOOMIN = 8;
var CMD_ZOOMOUT = 9;
var CMD_PAN = 10;
var CMD_SCALE = 11;
var CMD_PREV = 12;
var CMD_NEXT = 13;
var CMD_SEEK = 14;
var CMD_QUIT = 17;
var CMD_QUERY = 99;
*/
var myauthtoken = $rootScope.authSession.replace("&auth=", "");
//&auth=
var req = $http(
{
method: 'POST',
/*timeout: 15000,*/
url: loginData.url + '/index.php',
headers:
{
'Content-Type': 'application/x-www-form-urlencoded',
//'Accept': '*/*',
},
transformRequest: function(obj)
{
var str = [];
for (var p in obj)
str.push(encodeURIComponent(p) + "=" +
encodeURIComponent(obj[p]));
var foo = str.join("&");
//console.log("****RETURNING " + foo);
return foo;
},
data:
{
view: "request",
request: "stream",
connkey: connkey,
command: cmd,
auth: myauthtoken,
}
});
req.success(function(resp)
{
if (resp.result == "Ok" && ndx != -1)
{
var ld = NVRDataModel.getLogin();
var apiurl = ld.apiurl + "/events/" + resp.status.event + ".json";
//console.log ("API " + apiurl);
$http.get(apiurl)
.success(function(data)
{
if ($scope.MontageMonitors[ndx].eventUrlTime != data.event.Event.StartTime)
{
var element = angular.element(document.getElementById($scope.MontageMonitors[ndx].Monitor.Id + "-timeline"));
element.removeClass('animated slideInRight');
element.addClass('animated slideOutRight');
$timeout(function()
{
element.removeClass('animated slideOutRight');
element.addClass('animated slideInRight');
$scope.MontageMonitors[ndx].eventUrlTime = data.event.Event.StartTime;
}, 300);
}
})
.error(function(data)
{
$scope.MontageMonitors[ndx].eventUrlTime = "-";
});
}
});
req.error(function(resp)
{
//console.log("ERROR: " + JSON.stringify(resp));
NVRDataModel.log("Error sending event command " + JSON.stringify(resp), "error");
});
}
//-------------------------------------------------------------
// Zoom in and out via +- for desktops
//-------------------------------------------------------------
$scope.zoomImage = function(val)
{
if ($scope.isZoneEdit)
{
$ionicLoading.show(
{
//template: $translate.instant('kError'),
template: 'zoom disabled in zone edit mode',
noBackdrop: true,
duration: 2000
});
return;
}
var zl = parseInt($ionicScrollDelegate.$getByHandle("imgscroll").getScrollPosition().zoom);
if (zl == 1 && val == -1)
{
NVRDataModel.debug("Already zoomed out max");
return;
}
zl += val;
NVRDataModel.debug("Zoom level is " + zl);
$ionicScrollDelegate.$getByHandle("imgscroll").zoomTo(zl, true);
};
//-------------------------------------------------------------
// Retrieves PTZ state for each monitor
//-------------------------------------------------------------
// make sure following are correct:
// $scope.isControllable
// $scope.controlid
//
function configurePTZ(mid)
{
$scope.presetAndControl = $translate.instant('kMore');
$scope.ptzWakeCommand = "";
$scope.ptzSleepCommand = "";
$scope.ptzResetCommand = "";
$scope.ptzMoveCommand = "";
$scope.ptzStopCommand = "";
$scope.zoomInCommand = "";
$scope.zoomOutCommand = "";
$scope.zoomStopCommand = "zoomStop";
$scope.canZoom = false;
$scope.presetOn = true;
$scope.controlToggle = "hide buttons";
NVRDataModel.debug("configurePTZ: called with mid=" + mid);
var ld = NVRDataModel.getLogin();
var url = ld.apiurl + "/monitors/" + mid + ".json";
$http.get(url)
.success(function(data)
{
$scope.isControllable = data.monitor.Monitor.Controllable;
// *** Only for testing - comment out //
//$scope.isControllable = '1';
// for testing only
// $scope.isControllable = 1;
$scope.controlid = data.monitor.Monitor.ControlId;
if ($scope.isControllable == '1')
{
var apiurl = NVRDataModel.getLogin().apiurl;
var myurl = apiurl + "/controls/" + $scope.controlid + ".json";
NVRDataModel.debug("configurePTZ : getting controllable data " + myurl);
$http.get(myurl)
.success(function(data)
{
// *** Only for testing - comment out - start//
/*data.Control.Control.CanSleep = '1';
data.Control.Control.CanWake = '1';
data.Control.Control.CanReset = '1';
data.Control.Control.CanZoom = '1';
data.control.Control.HasPresets = '1';
data.control.Control.HasHomePreset = '1';*/
// *** Only for testing - comment out - end //
$scope.ptzMoveCommand = "move"; // start with as move;
$scope.ptzStopCommand = "";
if (data.control.Control.CanZoom == '1')
{
$scope.canZoom = true;
if (data.control.Control.CanZoomCon == '1')
{
$scope.zoomInCommand = "zoomConTele";
$scope.zoomOutCommand = "zoomConWide";
}
else if (data.control.Control.CanZoomRel == '1')
{
$scope.zoomInCommand = "zoomRelTele";
$scope.zoomOutCommand = "zoomRelWide";
}
else if (data.control.Control.CanZoomAbs == '1')
{
$scope.zoomInCommand = "zoomRelAbs";
$scope.zoomOutCommand = "zoomRelAbs";
}
}
NVRDataModel.debug("configurePTZ: control data returned " + JSON.stringify(data));
if (data.control.Control.CanMoveRel == '1')
{
$scope.ptzMoveCommand = "moveRel";
$scope.ptzStopCommand = "moveStop";
}
// Prefer con over rel if both enabled
// I've tested con
if (data.control.Control.CanMoveCon == '1')
{
$scope.ptzMoveCommand = "moveCon";
$scope.ptzStopCommand = "moveStop";
}
// presets
NVRDataModel.debug("ConfigurePTZ Preset value is " + data.control.Control.HasPresets);
$scope.ptzPresets = [];
if (data.control.Control.HasPresets == '1')
{
//$scope.presetAndControl = $translate.instant('kPresets');
$scope.ptzPresetCount = parseInt(data.control.Control.NumPresets);
NVRDataModel.debug("ConfigurePTZ Number of presets is " + $scope.ptzPresetCount);
for (var p = 0; p < $scope.ptzPresetCount; p++)
{
$scope.ptzPresets.push(
{
name: (p + 1).toString(),
icon: '',
cmd: "presetGoto" + (p + 1).toString(),
style: 'button-royal'
});
}
if (data.control.Control.HasHomePreset == '1')
{
$scope.ptzPresets.unshift(
{
name: '',
icon: "ion-ios-home",
cmd: 'presetHome',
style: 'button-royal'
});
}
}
/*else
{
$scope.presetAndControl = $translate.instant('kMore');
}*/
// lets add these to the end
// strictly speaking, they aren't really presets, but meh for now
// no need to darken these buttons if presets are not there
var buttonAccent = "button-dark";
if ($scope.ptzPresets.length == 0)
{
buttonAccent = "";
}
if (data.control.Control.CanWake == '1')
{
$scope.ptzPresets.push(
{
name: 'W',
icon: "ion-eye",
cmd: 'wake',
style: 'button-royal ' + buttonAccent
});
}
if (data.control.Control.CanSleep == '1')
{
$scope.ptzPresets.push(
{
name: 'S',
icon: "ion-eye-disabled",
cmd: 'sleep',
style: 'button-royal ' + buttonAccent
});
}
if (data.control.Control.CanReset == '1')
{
$scope.ptzPresets.push(
{
name: 'R',
icon: "ion-ios-loop-strong",
cmd: 'reset',
style: 'button-royal ' + buttonAccent
});
}
NVRDataModel.log("ConfigurePTZ Modal: ControlDB reports PTZ command to be " + $scope.ptzMoveCommand);
})
.error(function(data)
{
// console.log("** Error retrieving move PTZ command");
NVRDataModel.log("ConfigurePTZ : Error retrieving PTZ command " + JSON.stringify(data), "error");
});
}
else
{
NVRDataModel.log("configurePTZ " + mid + " is not PTZ controllable");
}
})
.error(function(data)
{
// console.log("** Error retrieving move PTZ command");
NVRDataModel.log("configurePTZ : Error retrieving PTZ command " + JSON.stringify(data), "error");
});
}
function getZones()
{
//https://server/zm/api/zones/forMonitor/7.json
var api = NVRDataModel.getLogin().apiurl+"/zones/forMonitor/"+$scope.monitorId+".json";
NVRDataModel.debug ("Getting zones using:"+api);
originalZones = [];
$http.get (api)
.then (function (succ) {
console.log (JSON.stringify(succ));
for (var i=0; i < succ.data.zones.length; i++)
{
originalZones.push ({
coords:succ.data.zones[i].Zone.Coords,
area: succ.data.zones[i].Zone.Area,
type:succ.data.zones[i].Zone.Type});
}
},
function (err) {
NVRDataModel.debug ("Error getting zones :"+JSON.stringify(err));
});
}
$scope.$on('modal.shown', function()
{
$scope.monStatus = "";
document.addEventListener("pause", onPause, false);
document.addEventListener("resume", onResume, false);
document.addEventListener("mouseup", moveStop, false);
document.addEventListener("touchend", moveStop, false);
document.addEventListener("mousemove", moveContinue, false);
document.addEventListener("touchmove", moveContinue, false);
$scope.showZones = false;
getZones();
var ld = NVRDataModel.getLogin();
//currentEvent = $scope.currentEvent;
$scope.connKey = (Math.floor((Math.random() * 999999) + 1)).toString();
//console.log ("************* GENERATED CONNKEY " + $scope.connKey);
$scope.currentFrame = 1;
$scope.monStatus = "";
$scope.isCycle = ld.cycleMonitors;
$scope.cycleText = $scope.isCycle ? $translate.instant('kOn') : $translate.instant('kOff');
$scope.quality = (NVRDataModel.getBandwidth() == "lowbw") ? zm.monSingleImageQualityLowBW : ld.monSingleImageQuality;
configurePTZ($scope.monitorId);
if (ld.cycleMonitors)
{
NVRDataModel.debug("Cycling enabled at " + ld.cycleMonitorsInterval);
$interval.cancel(cycleHandle);
cycleHandle = $interval(function()
{
moveToMonitor($scope.monitorId, 1);
// console.log ("Refreshing Image...");
}.bind(this), ld.cycleMonitorsInterval * 1000);
}
});
}]);