#!/usr/bin/perl

use strict;
use Cwd;
use DBI;
use Getopt::Long;
use Image::ExifTool 'ImageInfo';
use Image::Magick;
use Pod::Usage;
use Rings::Common;

my $cnt;
my $opt_conf;
my $opt_debug;
my $opt_help;
my $opt_manual;
my $opt_update;

##############################################################################
# Subroutines
##############################################################################

# ------------------------------------------------
# process the files

sub read_and_update {
    my ($pid_start, $pid_end) = @_;

    # get a list to process first because we need to process
    # the potentially large blob one at a time

    my @pid_list;

    my $sel = "SELECT pid ";
    $sel .= "FROM pictures_information ";
    $sel .= "WHERE pid >= $pid_start AND pid <= $pid_end ";
    $sel .= "ORDER BY pid ";

    if ($opt_debug) {
        dbg($sel);
    }

    my $sth = $DBH->prepare($sel);
    $sth->execute();
    if ($sth->err) {
        sql_die($sel, $sth->err, $sth->errstr);
    }
    while (my $row = $sth->fetchrow_hashref) {
        push @pid_list, $row->{pid};
    }

    my $pic_cnt = scalar(@pid_list);
    if ($pic_cnt < 1) {
        print "\n";
        print "No pictures found to update\n";
        return;
    } else {
        print "\n";
        print "$pic_cnt pictures found to examine for updates\n";
        print "\n";
    }

    # now get the pictures one at a time
    foreach my $thisPID (@pid_list) {

        my $sel = "SELECT p.pid,";
        $sel .= "p.camera, ";
        $sel .= "p.date_taken, ";
        $sel .= "p.picture_date, ";
        $sel .= "p.fstop, ";
        $sel .= "p.raw_picture_size, ";
        $sel .= "p.shutter_speed, ";
        $sel .= "p.date_added, ";
        $sel .= "r.picture ";
        $sel .= "FROM pictures_information p ";
        $sel .= "JOIN picture_details r ";
        $sel .= "ON (p.pid = r.pid AND r.size_id = 'raw') ";
        $sel .= "WHERE p.pid = $thisPID ";

        if ($opt_debug) {
            dbg($sel);
        }

        my $sth = $DBH->prepare($sel);
        $sth->execute();
        if ($sth->err) {
            sql_die($sel, $sth->err, $sth->errstr);
        }
        while (my $row = $sth->fetchrow_hashref) {
            my @blob;
            $blob[0] = $row->{picture};
            my $thisPic = Image::Magick->New();
            $thisPic->BlobToImage(@blob);

            my ($width, $height, $size, $format, $compression)
              = $thisPic->Get(
                'width', 'height', 'filesize', 'format', 'compression',
              );

            # Get EXIF data using image info
            my $info              = ImageInfo(\$blob[0]);
            my $camera            = ${$info}{'Model'};
            my $this_datetime     = ${$info}{'CreateDate'};
            my $this_shutterspeed = ${$info}{'ShutterSpeed'};
            my $this_fnumber      = ${$info}{'FNumber'};
            if ($width == 0 || $height == 0) {
                dbg("      width: $width");
                dbg("     height: $height");
                dbg(" Skipping image for $thisPID");
                return;
            }

            if ($opt_debug) {
                dbg("pid: $thisPID");
                dbg("Camera: $camera");
                dbg("DateTime: $this_datetime");
                dbg("FStop: $this_fnumber");
                dbg("Shutter Speed: $this_shutterspeed");
            }

            # update date and time from the camera and the size
            # of the raw image

            if ($this_datetime
                =~ /(\d{4,4})[\:\-](\d{2,2})[\:\-](\d{2,2})[\s\:](\d{2,2})\:(\d{2,2})\:(\d+)/
                && length($camera) > 0)
            {

                my $this_year = $1;
                if ($this_year > 0) {
                    $this_datetime = "$1\-$2\-$3 $4\:$5\:$6";
                } else {
                    $this_datetime = $row->{date_added};
                }

                my $this_pic_size = length($row->{picture});

                my $cmd = 'UPDATE pictures_information SET ';
                $cmd .= 'camera=?,';
                $cmd .= 'picture_date=?,';
                $cmd .= 'fstop=?,';
                $cmd .= 'raw_picture_size=?,';
                $cmd .= 'shutter_speed=?,';
                $cmd .= 'date_last_maint=? ';
                $cmd .= 'WHERE pid=? ';

                if ($opt_debug) {
                    dbg($cmd);
                }

                my $sth_update = $DBH_UPDATE->prepare($cmd);
                if ($opt_update) {
                    print "Updating $thisPID, date taken $this_datetime\n";
                    $sth_update->execute(
                        $camera,        $this_datetime,     $this_fnumber,
                        $this_pic_size, $this_shutterspeed, sql_datetime(),
                        $thisPID,
                    );
                    if ($sth_update->err) {
                        sql_die($cmd, $sth_update->err, $sth_update->errstr);
                    }
                } else {
                    print "For pid $thisPID proposing to set:\n";
                    print "    Camera: $camera\n";
                    print "    Picture Date: $this_datetime\n";
                    print "    FStop: $this_fnumber\n";
                    print "    Picture Size: $this_pic_size\n";
                    print "    Shutter Speed: $this_shutterspeed\n";
                }
            }
        }
    }
}

##############################################################################
# Main Routine
##############################################################################

print ">>> ring-set-info                    v:11-Jul-2006\n";

# -- get options
GetOptions(
    'debug'  => \$opt_debug,
    'conf=s' => \$opt_conf,
    'help'   => \$opt_help,
    'manual' => \$opt_manual,
    'update' => \$opt_update
);

# help the poor souls out
if (!@ARGV || $ARGV[0] == 'help') {
    $opt_help = 1;
}
if ($opt_help) {
    pod2usage(-verbose => 0);
}
if ($opt_manual) {
    pod2usage(-verbose => 2);
}

# Set the picture range to process from the command line
my $pid_start = $ARGV[0];
if ($pid_start < 1) {
    pod2usage(-verbose => 0);
}
my $pid_end = $pid_start;
if ($ARGV[1]) {
    $pid_end = $ARGV[1];
}

# Get configuration settings and initial debugging if requested.
get_config($opt_conf);
if ($opt_debug) {
    $CONF->debug($opt_debug);
}
if ($CONF->debug) {
    dbg("Initialize timer.");
}

# -- read preferences from ./rings
my $pref_file = $ENV{'HOME'} . '/.rings';
my %prefs;
if (-e $pref_file) {
    if ($opt_debug) {
        dbg("Reading $pref_file file");
    }
    open(pref, "<$pref_file");
    while (<pref>) {
        chomp;
        my $inline = $_;
        $inline =~ s/\#.*//;
        if ($opt_debug) {
            dbg("inline:$inline");
        }
        if (length($inline) > 0) {
            if ($inline =~ /^\s*(host|db|user|pass)=(.*)/i) {
                my $attr = lc($1);
                my $val  = $2;
                $val =~ s/\s+$//;
                $prefs{$attr} = $val;
                if ($opt_debug) {
                    dbg("attr:$attr val:$val");
                }
            }
        }
    }
    close pref;
}

read_and_update($pid_start, $pid_end);

exit;

__END__

=head1 NAME

ring-set-info - set picture information from the raw picture

=head1 SYNOPSIS

ring-set-info --start=int [--end=int] [--update] \
              [--host=mysql-host] [--db=databasename] \
              --user=mysql-username --pass=mysql-password
              [--debug] [--help] [--manual]


=head1 DESCRIPTION

Set information from the raw picture.  This works for some digital cameras.

=head1 OPTIONS AND ARGUMENTS

=over 4

=item --start=int

The picture id to start at.  Required.

=item --send=int

The picture id to end at.

=item --host=mysql-hostname

MySQL host name.  If not specified then localhost is used.

=item --db=databasename

The name of the MySQL database.  If not specified then rings is used.

=item --user=mysql-username

MySQL username.  Required.

=item --host=mysql-password

MySQL password.  Required.

=item --update

Actually load the data into the rings database.

=item --help

Displays help text.

=item --manual

Displays more complete help text.

=item --debug

Turns on debugging displays.

=back

=head1 AUTHOR

Bill MacAllister <bill@macallister.grass-valley.ca.us>

=cut
