#!/usr/bin/perl -w
#  $Id: probe 18145 2010-04-01 01:13:50Z teetov $
# -----------------------------------------------------------------------------
#  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-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
#       
# -----------------------------------------------------------------------------
#  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 Data::Dumper;
use Device::Conf;
use XML::Simple;
use JSON;

my $PROBE_ONVIF='onvif_probe';
sub parse_profile {
  my $array=shift;
  my @str=sort(@$array);
  push(@str,"END.END.END=END");  #add END mark to the end of array
  my ($in,$pro)=('','');
  my (%cf_in,%cf_pro,%cf);
  foreach (@str) {
    next if not /^(\w+)\.(\w+)\.(\w+)=(.+)$/;
    my($cin,$cpro,$key,$val)=($1,$2,$3,$4);
    if($pro ne $cpro) {
      if($pro ne '') {
        $cf_pro{$pro}={%cf}; 
        %cf=();
      }
      $pro=$cpro;
    } 
    if($in ne $cin) {
      if($in ne '') {
         $cf_in{$in}={%cf_pro};
         %cf_pro=();
      }
      $in=$cin;
    }
    $cf{$key}=$val;
  }
  \%cf_in; 
}

# --------- check required parameters: DEVID,USRNAME,PASSWD,
my $conf=ProbeInit(7);  # 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};

# -- Probe camera MODELID & FIRMWARE --
my %params;
my %result = (MODELID=>'0',FIRMWARE=>'0.0',STATUS=>'OK',RC_SET=>'NONE',AUDIO_SET=>'NONE');
my %onvif_report;
my @output;
my $output=`$PROBE_ONVIF --devip $conf->{DEVIP} --port $conf->{HTTP_PORT} --username $conf->{USRNAME} --password $conf->{PASSWD}`;
@output=split(/\n/,$output);
%onvif_report= map{/(^\w+)=(.+)/} grep {/^\w+=.+/} @output;
if($?==0)   { # system call is completed correctly
  $result{MODELID} =$onvif_report{MODELID};
  $result{FIRMWARE} = $onvif_report{FIRMWARE};
  # -- Check MODELID & FIRMWARE --
  ProbeErr("PCE-0030","Cannot get MODELID or FIRMWARE",$output) unless $result{MODELID};
}else{        # error in system(java) call, let's parse output and identify the problem
  if(exists $onvif_report{STATUS} and $onvif_report{STATUS}=~/ERROR/) {
    ProbeErr("PCE-0401","Cannot connect to device (Authorization error?)");
  }else {
    ProbeErr("PCE-0500","Device does not respond") # this is exampe but all problems should be identified
  }
}


$result{CAMERA}         =$conf->{CAMERA}         if   defined $conf->{CAMERA};
$result{ONVIF_PROFILE}  =$conf->{ONVIF_PROFILE}  if   defined $conf->{ONVIF_PROFILE};

my %onvif_format_decode=(H_264=>'h264',MPEG_4=>'mpeg4', JPEG=>'mjpg');
my $profile=parse_profile(\@output);  #use $profile->{0}->{profile_1_h264}->{RTSP_URL};
if ($conf->{PROBE} eq 'DEFINE') {
  $result{CAMERA_LIST}    =$onvif_report{CAMERA_LIST};
  ($result{CAMERA})       =$result{CAMERA_LIST}=~/(\w+)/        if ! defined $result{CAMERA};
  ($result{ONVIF_PROFILE})=keys %{$profile->{$result{CAMERA}}}  if ! defined $result{ONVIF_PROFILE};
  my %slist;
  my %reduced_profile;
  foreach my $cam (keys %$profile) {
    my @profiles=keys %{$profile->{$cam}};
    next if not @profiles;                                           # ignore if input has no profiles
    $result{ONVIF_PROFILE_LIST}.=',' if $result{ONVIF_PROFILE_LIST}; # separate with comma if something alredy in list 
    $result{ONVIF_PROFILE_LIST}.="$cam:".join('\,',@profiles);
    $reduced_profile{$cam}={};
    foreach my $pro (@profiles) {
       $slist{$cam}=$profile->{$cam}->{$pro}->{SNAPSHOT} if exists $profile->{$cam}->{$pro}->{SNAPSHOT};
       my %info=(MEDIA_FORMAT=>$onvif_format_decode{$profile->{$cam}->{$pro}->{MEDIA_FORMAT}},
                 IMAGESIZE=>$profile->{$cam}->{$pro}->{IMAGESIZE});
       $reduced_profile{$cam}{$pro}=\%info;
    }
  }
  $result{SNAPSHOT_LIST}=$onvif_report{SNAPSHOT_LIST};
  $result{ONVIF_MEDIA_SERVICE}=$onvif_report{ONVIF_MEDIA_SERVICE};
  $result{ONVIF_PTZ_SERVICE}=$onvif_report{ONVIF_PTZ_SERVICE};
  $result{ONVIF_PROFILES}=encode_json(\%reduced_profile);
#  print Dumper \%reduced_profile;
}

# ------------------------ get MEDIA_FORMAT, RTSP_PORT from PROFILE
$result{PROTO}='RTSP';
$result{RTSP_PORT}='554';
my ($rtsp_port,$rtsp_url);
if(defined $result{CAMERA} and defined $result{ONVIF_PROFILE}) { # MEDIA_FORMAT, RTSP_PORT
  $_=$profile->{$result{CAMERA}}->{$result{ONVIF_PROFILE}}->{RTSP_URL}; # rtsp://207.207.163.189:8554/onvif-media/media.amp
  ($rtsp_port,$rtsp_url)= m|rtsp://[^/^:]+(:\d+)?(/.+)$|i;
  $result{RTSP_PORT}=$rtsp_port if defined $rtsp_port;
  $result{RTSP_PORT}=~s/://;                           #remove :
  $result{MEDIA_FORMAT}=$profile->{$result{CAMERA}}->{$result{ONVIF_PROFILE}}->{MEDIA_FORMAT};
  $result{MEDIA_FORMAT}=$onvif_format_decode{$result{MEDIA_FORMAT}} if exists $onvif_format_decode{$result{MEDIA_FORMAT}};
}

# ------------------------ xml
my $descr_name="$ENV{APL_VAR}/conf/$conf->{DEVID}/descr.xml";
my %descr=(default=>{$result{MEDIA_FORMAT}=>{rtsp_url=>$rtsp_url}});
open(DESCR,">$descr_name");
print DESCR XMLout(\%descr,KeyAttr=>[],NoAttr=>1,RootName=>'cam_descriptions');
close DESCR;

# ----------------------- work around  TBD: remove
if(defined $conf->{OBJID} and 1==2) {
  if ($conf->{MEDIA_FORMAT} ne $result{MEDIA_FORMAT}){
     system qq(echo "update _obj_attr set val='$result{MEDIA_FORMAT}' where obj='$conf->{OBJID}' and attr='MEDIA_FORMAT'" |psql);
     system qq(echo "update _objs set rtime=null where  obj='151'" |psql);
  }
}

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


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

# -- set AudioParams --

# -- final report --

ProbeResult(\%result);
