#!/usr/bin/perl -w
#  $Id$
# -----------------------------------------------------------------------------
#  Purpose:
#    - probe the camera
#    - pre-tune camera befor for retriever (RC and Audio)
# -----------------------------------------------------------------------------
#  Call:
#    probe DEVID=123
#    probe DEVID=123 PROBE=FAST
#    probe DEVID=123 DEVIP=192.168.17.177 [ ... ]
#    probe DEVIP=192.168.17.177 USRNAME=admin PASSWD=pass PROBE=DEFINE
# -----------------------------------------------------------------------------
#  Does:
#   0. can be called without DEVID argument.
#      In this case DEVIP,USRNAME,PASSWD should be provided in command line
#   1. load $APL_CONF/<DEVID>/conf if DEVID is provided
#   2. combine conf and args into one hash
#   3. connect to camera over http and read MODELID and FIRMWARE
#   4. report MODELID|FIRMWARE|STATUS to $APL_CONF/<DEVID>/conf.probe and stdout
#   5. if PROBE=DEFINE then get
#         IMAGESIZE_LIST,MEDIA_FORMAT_LIST
#         AUDIO_LIST,AUDIO_FORMAT_LIST
#         SNAPSHOT (picture)
#   6. set RC camera attributes    if mpeg4 | h264
#   7. set AUDIO camera attributes if AUDIO is on
#   8. example output:
#       AUDIO_SET=OK
#       FIRMWARE=5.02
#       MODELID=Q1755
#       RC_SET=OK
#       STATUS=OK
#       -------------
#       AUDIO_SET=NONE
#       FIRMWARE=5.02
#       MODELID=Q1755
#       RC_SET=NONE
#       STATUS=OK
#       SNAPSHOT=/tmp/probe/192.168.17.177-12367576123.jpg
#       IMAGESIZE_LIST=640x480,480x360,320x240,240x180,176x144,160x120
#       MEDIA_FORMAT_LIST=mjpeg,h264
#       AUDIO_LIST=off,on
#       AUDIO_FORMAT_LIST=g711,g726,aac
#   9. sample errors:
#       STATUS=ERROR: PCE-0001 [101] configuration is not found
#       STATUS=ERROR: PCE-0002 [101] USRNAME and PASSWD should provided
#       STATUS=ERROR: PCE-0003 [101] DEVIP is not defined
#       STATUS=ERROR: PCE-0500 [101] Device does not respond (http://207.107.163.123:80)
#       STATUS=ERROR: PCE-0401 [101] Authorization error
#       STATUS=ERROR: PCE-0403 [101] Forbidden
#       STATUS=ERROR: PCE-0404 [101] Not Found
#       STATUS=ERROR: PCE-0030 [101] Cannot get MODELID
#       note: [101] is DEVID
#  10. warnings:
#       STATUS=WARNING: PCW-0001 [101] MODELID does not match configuration
#       STATUS=WARNING: PCW-0002 [101] FIRMWARE does not match configuration
#       STATUS=WARNING: PCW-0009 [101] PROBE=RESET is not supported
#
# -----------------------------------------------------------------------------
#  Note:
#   1. CAMERAMODEL file is obsolite. ptz_axisv2.pl & ptz_udp.pl has to be modified
#   2. Script mast be in the directory .../camera/<BRAND>/bin/
# -----------------------------------------------------------------------------
#  Author: teetov, 03/22/10
#  Edited by:
#  QA by:
#  Copyright: videoNEXT Network Solutions, Inc, 2010
# -----------------------------------------------------------------------------
#
use strict;
use XML::Simple;
use LWP::UserAgent;
use JSON;
use URI::Escape "uri_unescape";
use Device::Conf ":all";
use SKM::Session;
# cons -------------------------------------------------------------------------
# no code for SKM

# --------- check required parameters: DEVID,USRNAME,PASSWD,
my $conf=ProbeInit();  # uses <BRAND> from path and ARGV
ProbeErr("PCE-0001","configuration is not found") if not defined $conf->{DEVID};
ProbeErr("PCE-0003","DEVIP is not defined")       if not defined $conf->{DEVIP};
ProbeErr("PCE-0002","USRNAME and PASSWD should be provided")
                 if not defined $conf->{USRNAME} or not defined $conf->{PASSWD};
ProbeWarn("PCW-0009","PROBE=RESET is not supported") if $conf->{PROBE} eq 'RESET';                 
# Login on remote system ------------------------------------------------------
my $LoggedIn = 0;
my $SID = '';
my $Token = '';
my $Legacy = 0;

$SKM::Session::UA = UA();
$SKM::Session::UA->cookie_jar({});
($SID, $Token, $Legacy) = OpenSession($conf->{DEVIP}, $conf->{USRNAME}, $conf->{PASSWD});
if (not $SID) {
    ProbeErr("PCE-0401","Authrorization error") if LastCode eq '401';
    ProbeErr("PCE-0031","Cannot login to remote SKM host","Request failed\n".$SKM::Session::Err)
}
# Success
$LoggedIn = 1;
$Token = $SKM::Session::Token; # Must append token to every HTTP API request

#------------------------------------------------------------------------------
# Probe camera MODELID & FIRMWARE
#------------------------------------------------------------------------------
my %result=(MODELID=>'0',FIRMWARE=>'0.0',STATUS=>'OK',RC_SET=>'NONE',AUDIO_SET=>'NONE');

my $resp;
if ($Legacy) { # Perform 3.3-like vctl request
    $resp=ProbeRequest("/api/cgi-bin/vctl.pl?return=info");
    if($resp!~ /^HTTP ERROR/) {
	my $vctl=eval{XMLin($resp)};
	ProbeErr("PCE-0030","Cannot get MODELID or FIRMWARE",$resp) if $@;
	ProbeErr("PCE-0030","Cannot get MODELID or FIRMWARE",$resp) if $vctl->{STATUS} ne 'OK';
	$result{MODELID}=$vctl->{INFO}{VER};
	$result{VERID}=$vctl->{INFO}{VERID};
	$result{BRAND}=$vctl->{INFO}{BRAND};
    } else {
	my ($err)= $resp=~/^HTTP ERROR \[(\d+)\]/;
	ProbeErr("PCE-0500","Device does not respond",$resp) if $err=~/^5\d\d/;
    }
}
else {
    $resp=ProbeRequest("/api/call.php?function=getVersionControlInformation&section=info&token=".$Token);
    if($resp!~ /^HTTP ERROR/) {
	my $vctl = eval { JSON->new->utf8(1)->decode($resp) };
	ProbeErr("PCE-0030","Cannot get MODELID or FIRMWARE",$resp) if $@;
	ProbeErr("PCE-0030","Cannot get MODELID or FIRMWARE",$resp) if $vctl->{error};
	my $info = $vctl->{section}{info};
	$result{MODELID}=$info->{ver};
	$result{MODELID}.= "-legacy" if $Legacy;
	$result{VERID}=$info->{verid};
	$result{BRAND}=$info->{brand};
    }else {
	my ($err)= $resp=~/^HTTP ERROR \[(\d+)\]/;
	ProbeErr("PCE-0500","Device does not respond",$resp) if $err=~/^5\d\d/;
    }
}

ProbeErr("PCE-0030","Cannot get MODELID or FIRMWARE",$resp) if ! $result{MODELID};

# Check MODELID & FIRMWARE ---------------------------------------------------
if(defined $conf->{MODELID} and $result{MODELID} ne $conf->{MODELID}) {
  $result{STATUS}="WARNING: PCW-0001 [$conf->{DEVID}] MODELID does not match configuration";
}elsif(defined $conf->{CAMERAFIRMWARE} and $result{FIRMWARE} ne $conf->{CAMERAFIRMWARE}) {
  $result{STATUS}="WARNING: PCW-0001 [$conf->{DEVID}] FIRMWARE does not match configuration";
}

#------------------------------------------------------------------------------
# get Camera list from SKM host
#------------------------------------------------------------------------------
my %camlist;

if ($conf->{PROBE} eq 'DEFINE') {
    $resp = ProbeRequest("/api/call.php?function=getObjectList&type=camera&withAttributes=false&token=".$Token);
    ProbeErr("PCE-0032","Cannot fetch camera list",$resp) if $resp=~/^HTTP ERROR/;
    my $parsed = eval { JSON->new->utf8(1)->decode($resp) };
    ProbeErr("PCE-0032","Cannot fetch camera list","Malformed JSON in response\n".$resp) if $@;
    ProbeErr("PCE-0032","Cannot fetch camera list","Operation failed\n".$parsed->{error}) if $parsed->{error};
    ProbeErr("PCE-0032","Cannot fetch camera list","Missing 'list' attr in response\n".$resp)
	if ! exists $parsed->{list} or ref($parsed->{list}) ne 'ARRAY';
    # Return error if remote system has no cameras configured
    ProbeErr("PCE-0404","Not Found","Cannot retrieve camera configuration\n")
	if @{$parsed->{list}} == 0;

    foreach my $cam (@{$parsed->{list}}) {
	$camlist{$cam->{obj}} = $cam->{name};
    }
    $result{CAMERA_LIST} = EscapeList(%camlist);
    binmode STDOUT, ":utf8"; # Value may contain utf8 chars
}

#------------------------------------------------------------------------------
# get Sample picture
#------------------------------------------------------------------------------
if($conf->{PROBE} eq 'DEFINE') {
#    $result{SNAPSHOT_LIST}=ProbeSnapshotList(keys %camlist) if %camlist;
    my $sample_path = "$ENV{APL}/var/probe/image";
    my %snaps=();
    foreach my $obj (keys %camlist) {
        my $url = "http://$conf->{DEVIP}:$conf->{HTTP_PORT}/sdi/admincirrus/downloadimage.php?objid=$obj&width=165&height=165";
    	my $resp = UA()->get($url);
    	my $picture = 'ERROR';
    	if ($resp->code eq "200") {         # successfully get respond
    	    mkdir $sample_path if not -d $sample_path;
    	    $picture = "$sample_path/$$-$obj-".time.".jpg";
    	    if(open PIC, ">$picture") {
    		print PIC $resp->content;
    		close PIC;
    	    }
	    else {
    		$picture = "ERROR: cannot write $picture";
    	    }
    	}
    	else {
	    $picture = 'ERROR: http respond '.$resp->code;
    	}
    	$snaps{$obj}=$picture;
    }
    $result{SNAPSHOT_LIST}=EscapeList(%snaps);
}

#------------------------------------------------------------------------------
# interim report & exit
#------------------------------------------------------------------------------
ProbeResult(\%result)  if $conf->{PROBE} =~ /^(DEFINE|FAST)$/;
ProbeResult(\%result)  if $conf->{DEVID}==0;

#------------------------------------------------------------------------------
# get video and audio properties
#------------------------------------------------------------------------------
my $objid = $conf->{CAMERA}; # Input number is a camera objid on remote SKM host
my $authid = ""; # authrorization ID for media stream
my ($rtsp_url,$rtsp_port,$path) = ("",0,"");
my $media_format = "";
my $positionctl = "none";
my $node_ip = ""; # IP of node camera is registered on

# Get ticket from remote SKM host
my $authmng_url = "/api/authmng.php?return=mediastreamauth&streamtype=live&objid=$objid";
if ( $conf->{IFRAMESONLY} eq "on") {
    $authmng_url .= "&iframesonly=1";
    $authmng_url .= "&iframes_maxbitrate=".$conf->{IFRAMES_MAXBITRATE} if exists $conf->{IFRAMES_MAXBITRATE};
}
$resp = ProbeRequest($authmng_url);
ProbeErr("PCE-0040","Error getting video properties",$resp) if $resp=~/^HTTP ERROR/;
ProbeErr("PCE-0040","Error getting video properties","Empty response") if ! $resp;
my $auth = eval { XMLin($resp) };
ProbeErr("PCE-0040","Error getting video properties",
    "Malformed XML in response\n".$resp) if $@;
ProbeErr("PCE-0040","Error getting video properties",
    "Error getting media stream auth\n".$auth->{STATUS}{MESSAGE}) if $auth->{STATUS}{VALUE} ne 'OK';

# Get RTSP URL and authorization ID from response
$authid = $auth->{AUTHORIZATION}{ID};
$rtsp_url = uri_unescape($auth->{AUTHORIZATION}{URL});
ProbeErr("PCE-0040","Error getting video properties","Missing Authrorization data in response\n".$resp)
    if ! $authid or ! $rtsp_url;
($node_ip,$rtsp_port,$path) = $rtsp_url=~m|^rtsp://(.+?):(\d+)(/.+)$|;
ProbeErr("PCE-0040","Error getting video properties","Cannot get RTSP port or Node IP from response\n".$resp)
    if ! $rtsp_port or ! $node_ip;
$result{DEVIP} = $node_ip;
$result{RTSP_PORT} = $rtsp_port;
$result{RTSP_URL} = $path."&authorizationid=".$authid;

# Get MEDIA_FORMAT and POSITIONCTL values for remote camera
$resp = ProbeRequest("/api/call.php?function=getAttributes&obj=$objid&token=".$Token);
ProbeErr("PCE-0040","Error getting video properties",$resp) if $resp=~/^HTTP ERROR/;
my $parsed = eval { JSON->new->utf8(1)->decode($resp) };
ProbeErr("PCE-0040","Error getting video properties","Malformed JSON in response\n".$resp) if $@;
ProbeErr("PCE-0040","Error getting video properties","Operation failed\n".$parsed->{error}) if $parsed->{error};
$media_format = $parsed->{list}{MEDIA_FORMAT};
$positionctl = $parsed->{list}{POSITIONCTL};
ProbeErr("PCE-0040","Error getting video properties","No media format in response\n".$resp) if ! $media_format;
$result{MEDIA_FORMAT} = $media_format;
if ($positionctl and $positionctl ne 'none') {
    $positionctl = 'vchain';
} else {
    $positionctl = 'none';
}

#------------------------------------------------------------------------------
# set RC (rate control) parameters + qality + imagesize
#------------------------------------------------------------------------------

# Set the same Media Format for local camera as it is set on remote one
#$resp = $ua->post("http://s_master/api/call.php", {
#    function   => 'setAttributes',
#    obj        => $conf->{DEVID},
#    attributes => JSON->new->encode(+{MEDIA_FORMAT => $result{MEDIA_FORMAT}})
#});
#eval {
#    die "#HTTP ERROR [".$resp->code."]\n#".$resp->base."\n" if $resp->is_error;
#    $parsed = eval { JSON->new->utf8(1)->decode($resp->content) };
#    die "#Request failed\n#$parsed->{error}\n" if $parsed->{error};
#};
#if ($@) {
#    chomp $@;
#    $result{RC_SET} = "ERROR\n$@";
#}
#else {
#    $result{RC_SET} = 'OK';
#}

# Use direct DB call instead of PHP API (unless got trusted IP support)
require SKM::DB;
SKM::DB->import();
my $dbm;
eval {
    $dbm = DBMaster({PrintError=>0,RaiseError=>1,AutoCommit=>0});
    $dbm->do("update _obj_attr set val=? where obj=? and attr='MEDIA_FORMAT'",
	undef,$result{MEDIA_FORMAT},$conf->{DEVID}
    );
    $dbm->do("update _obj_attr set val=? where obj=? and attr='POSITIONCTL'",
	undef,$positionctl,$conf->{DEVID}
    );
    $dbm->do("update _objs set rtime=null where obj=?",undef,$conf->{DEVID});
    $dbm->commit;
};
if ($@) {
    $result{RC_SET} = "ERROR\n#DB error";
    eval { $dbm->rollback } if $dbm;
}
else {
    $result{RC_SET} = "OK";
}
eval { $dbm->disconnect } if $dbm;

#------------------------------------------------------------------------------
# set AudioParams
#------------------------------------------------------------------------------
if ( $conf->{AUDIO} eq 'on' ) {
# no code for SKM
}

# dirty hack to make old 'SKM' cartridge working
$result{CAMERAMODEL}="vChain";

# final report-----------------------------------------------------------------------
ProbeResult(\%result);

END {
    # Finally, close our session
    if ($LoggedIn) {
	UA()->parse_head(0);
        CloseSession;
    }
}
