#!/usr/bin/env php
<?php
/**
 * @file footage_integrity_test.php
 * @brief will check (by timestamps) if any frames in footage are missing (recording errors)
 * @copyright Copyright (C) 2017 Elphel Inc.
 * @author Elphel Inc. <support-list@support.elphel.com>
 *
 * @par <b>License</b>:
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

set_time_limit(60*60*24);

//$chunksize=10000000; //10MB
$chunksize=10000000; //10MB 
$startMarkerWithExif=chr(hexdec("ff")).chr(hexdec("d8")).chr(hexdec("ff")).chr(hexdec("e1"));
$input_exts = array("img","bin","mov");

// use current dir
$path=".";
$destination = "0";

$move_processed = false;
$processed_subdir = "processed";

$forced_ext = "";

function print_help(){
  global $argv;
  
  echo <<<"TXT"
Help:
  * Usage:
    ~$ {$argv[0]} path=[path-to-dir] dest_path=[dest-subdir] move_processed=[move-processed-files] ext=[forced-ext]
    
    where:
      * path-to-dir            - string - scan this path + 1 dir down
    
  * Examples:

TXT;

}

if ($argv){
  foreach($argv as $k=>$v){
    if ($k==0) continue;
    $args = explode("=",$v);
    if (isset($args[1])) $_GET[$args[0]] = $args[1];
    if ($v=="-h"||$v=="--help"||$v=="help") {
      print_help();
      die();
    }
  }
}

if (isset($_GET['path'])){
  $path=$_GET['path'];
}

$list = preg_grep('/^([^.])/', scandir($path));

$FOOTAGE_ARRAY = Array();

foreach ($list as $item) {
  if (is_dir("$path/$item")){
    if ($item==$processed_subdir) continue;
    $sublist = preg_grep('/^([^.])/', scandir("$path/$item"));
    foreach($sublist as $subitem){
        register_file("$path/$item","$subitem","../$destination");
    }
  }else{
    register_file("$path","$item","$destination");
  }
}

function register_file($path,$file,$destination){

  global $FOOTAGE_ARRAY;

  global $startMarkerWithExif;
  global $chunksize;
  global $input_exts;
  
  if (in_array(get_ext("$path/$file"),$input_exts)) {
    echo "Processing $path/$file\n";
    
    $markers=array();
    $offset =0;
    
    $f=fopen("$path/$file","r");
    
    //first scan
    while (!feof($f)) {
      $pos=0;
      $index=0;
      fseek($f,$offset);
      $s = fread($f,$chunksize);
      while(true){
        $pos=strpos($s,$startMarkerWithExif,$pos);
        if ($pos === false) break;
        $markers[count($markers)]=$offset+$pos;
        $pos++;
      }
      $offset+=(strlen($s)-strlen($startMarkerWithExif)+1); // so each marker will appear once
    }
    
    $markers[count($markers)]=$offset+strlen($s); // full length of the file
   
    echo "  images found: ".(count($markers)-1)."\n";
   
    //second scan
    
    $old_footage_index = 0;
    
    for ($i=0;$i<(count($markers)-1);$i++) {

      fseek($f,$markers[$i]);
      $s = fread($f,$markers[$i+1]-$markers[$i]);

      $tmp_name = "$path/image.tmp";
      file_put_contents($tmp_name,$s);

      $result_name = elphel_specific_result_name($tmp_name);

      //echo "    $result_name\n";
      
      $tmp0 = explode(".",$result_name);
      $tmp1 = explode("_",$tmp0[0]);
      
      if (count($tmp1)==5){
        $footage_index = $tmp1[0]."_".$tmp1[1];
        $footage_subelement = $tmp1[2];
        
        if (!isset($FOOTAGE_ARRAY[$footage_index])){
          //echo "NEW: $footage_index, OLD: $old_footage_index\n";
          $FOOTAGE_ARRAY[$footage_index] = Array();
          $FOOTAGE_ARRAY[$footage_index]['error'] = 0;
          $FOOTAGE_ARRAY[$footage_index]['warning'] = 0;
          if (isset($FOOTAGE_ARRAY[$old_footage_index]['data'][0]['number'])){
            $FOOTAGE_ARRAY[$footage_index]['prevnumber'] = $FOOTAGE_ARRAY[$old_footage_index]['data'][0]['number'];
            //echo "set prev to ".$FOOTAGE_ARRAY[$old_footage_index]['data'][0]['number']."\n";
          }else{
            $FOOTAGE_ARRAY[$footage_index]['prevnumber'] = 0;
          }
          $FOOTAGE_ARRAY[$footage_index]['data'] = Array();
          $old_footage_index = $footage_index;
        }else{
          if ($footage_index!=$old_footage_index){
            #$FOOTAGE_ARRAY[$old_footage_index]['warning'] |= 0x1;
            $FOOTAGE_ARRAY[$footage_index]['warning'] |= 0x1;
            echo "\033[38;5;214m";
            echo "notice: timestamps and ports overlap: $footage_index, index: $footage_subelement";
            echo "\033[0m";
            echo "\n";
          }
        } 
        
        //echo "    pushed to $footage_index: index: $footage_subelement, number: {$tmp1[3]}\n";
        array_push($FOOTAGE_ARRAY[$footage_index]['data'],Array('index'=>$footage_subelement,'number'=>$tmp1[3],'size'=>$tmp1[4]));
      }
      
      unlink($tmp_name);
      //rename($tmp_name,"$path/$destination/$result_name");
    }
    
    // Analysis phase
    foreach($FOOTAGE_ARRAY as $key=>$val){
      if (count($val['data'])==4){
        $in = $val['data'][0]['number'];
        
        if ($in!=($val['prevnumber']+1)&&($val['prevnumber']!=0)){
          //echo "Meet the prevnumber ".$val['prevnumber']." vs current ".$in."\n";
          $FOOTAGE_ARRAY[$key]['error'] |= 0x2;
        }
        
        foreach($val['data'] as $k2=>$v2){
          if ($in!=$v2['number']){
            $FOOTAGE_ARRAY[$key]['error'] |= 0x4;
          }
        }
      }else{
        $FOOTAGE_ARRAY[$key]['error'] |= 0x1;
      }
      
    }
    
    // Report phase
    echo "Total files: $i\n";
    echo "Unique timestamps: ".count($FOOTAGE_ARRAY)."\n";
    
    foreach($FOOTAGE_ARRAY as $key=>$val){
      if      ($val['error']!=0)   echo "\033[91m";
      else if ($val['warning']!=0) echo "\033[38;5;214m";
      //echo "$key: ".implode(",",$val['data']);
      echo "n= ".$val['data'][0]['number']." : ts= $key : ports=";
      
      for($j=0;$j<4;$j++){
        if (isset($val['data'][$j])){
          echo $val['data'][$j]['index'];
        }else{
          echo " ";
        }
        if ($j!=3) echo ",";
      }
      
      echo " : sizes(MB)= ";
      
      for($j=0;$j<4;$j++){
        if (isset($val['data'][$j])){
          $tmp = number_format(round(($val['data'][$j]['size'])/1024/1024,2),2,".","");
        }else{
          $tmp = "";
        }

        echo str_pad($tmp,4);
        
        if ($j!=3) echo ", ";
      }


      if ($val['error']!=0){
        echo " : error code=".$val['error'];
      }
      
      if ($val['error']!=0||$val['warning']!=0) echo "\033[0m";
      echo "\n";
    }
    
    // reset 
    $FOOTAGE_ARRAY = Array();
    
    return 0;
  }else{
    return -1;
  }
}

function elphel_specific_result_name($file){

  global $forced_ext;

  $exif = exif_read_data($file);
  
  $ext = elphel_specific_result_ext($exif,$forced_ext);
  
  //converting GMT a local time GMT+7
  $timestamp_local=strtotime($exif['DateTimeOriginal']);/*-25200;*/
  
  $subsecs = $exif['SubSecTimeOriginal'];
  
  $tmp = explode("_",$exif['Model']);
  if (count($tmp)==2){
    
    if (trim($tmp[0])=="Eyesis4pi393"){
    
      $model = intval(trim($tmp[1]));
      $chn = intval($exif['PageNumber'])+1;
      
      if        ($model==1001) {
        $k=$chn;
      }else  if ($model==1002) {
        $k=$chn+4;
      }else  if ($model==1003) {
        $k=$chn+6;
      }
 
    }else{
      $k = intval($exif['PageNumber'])+1;
    }
    
  }else{
    $k = intval($exif['PageNumber'])+1;
  }
  
  $img_number = $exif['ImageNumber'];
  $fsize = $exif['FileSize'];
  
  return "{$timestamp_local}_{$subsecs}_{$k}_{$img_number}_{$fsize}.$ext";
  
}

function get_ext($filename) {
  return pathinfo($filename, PATHINFO_EXTENSION);
}

/**
 * read image format and return extension, elphel elphel_specific
 * @param array $exif Array returned from the PHP's built-in exif_read_data function
 * @param string $override_ext
 * @return string extension - jpeg or jp4
 */
function elphel_specific_result_ext($exif,$override_ext=""){
  
  //default value
  $ext = "jpeg";
  
  if ($override_ext==""){
    if (isset($exif['MakerNote'][10])){
      $record = ($exif['MakerNote'][10]>>4)&0xf;
      if ($record==5) $ext = "jp4";
    }
  }else{
    $ext = $override_ext;
  }
  return $ext;
}

?>