#!/usr/bin/perl
#
# Given a directory, recurse the directory and generate a summary of photo files found there
# Copyright (c) 2006 Mike Meredith. All Rights Reserved.
# 0.1: Initial release

use strict;
use Image::ExifTool;

our @fexts = ( 'jpg', 'jpeg', 'crw', 'tif', 'tiff', 'cr2' );
#  File extensions to pay attention to
our $verbose = 0;
#  If true, then output debugging information
our %cameras;
#  Hash of camera models ... will contain ISO:Shutter:Aperture:Flength:Count
our %dates;
#  Hash of dates (YYYY-MM) ... will contain ISO:Shutter:Aperture:Flength:Count

if ($#ARGV != 0) {
  print "Usage:\n\tphoto-summary starting-directory\n";
  exit(1);
}

recursedir($ARGV[0]);
writereport();

# recursedir
#
# Examine every entry in a directory and see if it matches @fexts; if so use recordfile() on it.
# If a directory then call recursedir. Ignore otherwise

sub recursedir {
  my $dir = pop(@_);
  my $entry;
  my @dirstack = ();

  print "Recursing through $dir\n" if $verbose;
  opendir(THIS, $dir) || die "Cannot open $dir";
  while ($entry = readdir(THIS)) {
    if (($entry eq ".") || ($entry eq "..")) {
      # Skip over the obvious
      next;
    }
    if (-d "$dir/$entry") {
      print "$dir/$entry is a directory" if $verbose;
      push @dirstack, "$dir/$entry";
    } else {
      for (my $i = 0; $i <= $#fexts; $i++) {
	if ($entry =~ /\.$fexts[$i]$/i) {
	  process_image("$dir/$entry");
	}
      }
    }
  }

  for (my $i = 0 ; $i <= $#dirstack; $i++) {
    recursedir($dirstack[$i]);
  }
}

# process_image
#
# Use Image::ExifTool to process an image file and extract certain bits :-
#    Model
#    Shutter Speed
#    Aperture
#    Shooting Date/Time
#    Focal Length
#    ISO Speed
# Format of hashes: ISO:Shutter:Aperture:Flength:Count

sub process_image {
  my $image = pop(@_);
  my $info;
  my $camera;
  my $shutter;
  my $date;
  my $aperture;
  my $iso;
  my $flength;

  $info =  Image::ExifTool::ImageInfo($image);

  $camera = $$info{"Model"};
  $aperture = $$info{"Aperture"};
  $date = $$info{"CreateDate"};
  $flength = $$info{"FocalLength"};
  $iso = $$info{"ISO"};
  $shutter = $$info{"ShutterSpeed"};

  if ($shutter =~ /\//) {
    my @words = split(/\//, $shutter);
    $shutter = $words[0] / $words[1];
  }
  $flength =~ s/mm//;
  $flength = int($flength);

  if (defined($cameras{"$camera"})) {
    my @words = split(/:/, $cameras{"$camera"});
    my @w2;
    $words[0] += $iso;
    $words[3] += $shutter;
    $words[4] += 1;

    @w2 = split(/;/, $words[1]);
    if ($aperture == 0) {
      $w2[1] .= "-";
    } else {
      $w2[0] += $aperture;
    }
    $words[1] = join(';', @w2);
    @w2 = split(/;/, $words[2]);
    if ($flength == 0) {
      $w2[1] .= "-";
    } else {
      $w2[0] += $flength;
    }
    $words[2] = join(';', @w2);
    # The complex stuff for Aperture and FLength is to deal with missing values when a manual lens is used.
      
    $cameras{"$camera"} = join(":", @words);
  } else {
    if ($aperture == 0) {
      $aperture = "$aperture;-";
    } else {
      $aperture = "$aperture;";
    }
    if ($flength == 0) {
      $flength = "$flength;-";
    } else {
      $flength = "$flength;";
    }
    $cameras{"$camera"} = join(":", $iso, $aperture, $flength, $shutter, 1);
  }

  $date = substr($date, 0, 7);
  if (defined($dates{"$date"})) {
    my @words = split(/:/, $dates{"$date"});
    my @w2;
    $words[0] += $iso;
    $words[3] += $shutter;
    $words[4] += 1;

    @w2 = split(/;/, $words[1]);
    if ($aperture < 1) {
      $w2[1] .= "-";
    } else {
      $w2[0] += $aperture;
    }
    $words[1] = join(';', @w2);
    @w2 = split(/;/, $words[2]);
    if ($flength < 1) {
      $w2[1] .= "-";
    } else {
      $w2[0] += $flength;
    }
    $words[2] = join(';', @w2);
    # The complex stuff for Aperture and FLength is to deal with missing values when a manual lens is used.
      
    $dates{"$date"} = join(":", @words);
  } else {
    if ($aperture < 1) {
      $aperture = "$aperture;-";
    } else {
      $aperture = "$aperture;";
    }
    if ($flength < 1) {
      $flength = "$flength;-";
    } else {
      $flength = "$flength;";
    }
    $dates{"$date"} = join(":", $iso, $aperture, $flength, $shutter, 1);
  }

}

# writereport
#
# Produce a report

sub writereport {
  my $camera;
  my $data;

  printf "%16s\t%6s\t%6s\t%6s\t%6s\t%6s\n", "Camera", "ISO", "Aper", "Length", "Shutter", "Count";
  while (($camera, $data) = each %cameras) {
    my @words = split(/:/, $data);
    my @w2;
    $words[0] = $words[0] / $words[4];
    @w2 = split(/;/, $words[1]);
    $words[1] = $w2[0] / ($words[4] - length($w2[1]));
    @w2 = split(/;/, $words[2]);
    $words[2] = $w2[0] / ($words[4] - length($w2[1]));
    $words[3] = $words[3] / $words[4];
    printf "%16s\t%6.1f\t%6.1f\t%6.1f\t%6.1f\t%8d\n", $camera, $words[0], $words[1], $words[2], $words[3], $words[4];
  }

#  foreach (sort keys %$info) {
#    print "$_ => $$info{$_}\n";
#  }

  printf "%16s\t%6s\t%6s\t%6s\t%6s\t%6s\n", "Date", "ISO", "Aper", "Length", "Shutter", "Count";
  foreach (sort keys %dates) {
    my $date = $_;
    my @words = split(/:/, $dates{"$date"});
    my @w2;
    $words[0] = $words[0] / $words[4];
    @w2 = split(/;/, $words[1]);
    $words[1] = $w2[0] / ($words[4] - length($w2[1]));
    @w2 = split(/;/, $words[2]);
    $words[2] = $w2[0] / ($words[4] - length($w2[1]));
    $words[3] = $words[3] / $words[4];
    printf "%16s\t%6.1f\t%6.1f\t%6.1f\t%6.1f\t%8d\n", $date, $words[0], $words[1], $words[2], $words[3], $words[4];

  }

}
