#!/usr/bin/perl -w

use strict;

use DBI;
use File::Path qw(make_path);
use Time::Local;

my $exif = 1;
use Image::ExifTool qw(:Public) ;


my $copydb = 1;   #  avoid Phots.app database lock, copy entire database before execution
my $link = 1;
my $album = 1;
my $exec = 1;
my $dup = 1;
my $sync = 1;
my $debug = 1;
my $after = &uniDate2mac(timelocal(0,0,0,1,0,1960));
my $photos = 1;   #  0 for iPhoto, 1 for Photos
my $copydbFile;

my $home = $ENV{'HOME'};
# how to find iPhoto library directory?
my $iPhoto = "$home/Pictures/Photos.photoslibrary";
my $PhotoDB = $iPhoto . "/Database/apdb/Library.apdb";
my $distdir = "$home/Pictures/Photos";


use Getopt::Std;
our($opt_l, $opt_d, $opt_n, $opt_y, $opt_i, $opt_s, $opt_a, $opt_h);

getopts('l:dnhy:ia');

if ($opt_h) {
    print << "EOFEOF";
-y year     only >=year photos are processed
-l iPhotoLibrary Directory
-i iPhoto
-s no sync
-a album only
-n dry run
-d debug
EOFEOF
    exit 0;
}

if ($opt_y) {
    $after = &uniDate2mac(timelocal(0,0,0,1,0,$opt_y));
}

if ($opt_i) {
    $photos = 0;
}

if ($opt_s) {
    $sync = 0;
}

if ($opt_l) {
    if ( -d $opt_l) {
        $iPhoto =  $opt_l;
    } else {
        die("Can't find $opt_l");
    }
}
if ($opt_d) {
    $debug = 1;
}

if ($opt_n) {
    $exec = 0;
}

my $mdb; 

if ($copydb) {
    $copydbFile =  "/tmp/iPhotolink.$$.apdb";
    system("cp",$PhotoDB,"$copydbFile");
print "copy done\n";
    $mdb = DBI->connect("dbi:SQLite:dbname=$copydbFile","","");
print "db connected\n";
}

chdir("$iPhoto");

if ($link && ! $opt_a) {
    my $num = 0;
    my $sql = $mdb->prepare('select * from RKMaster where imageDate >= '.$after." order by imageDate");

    $sql->execute or die("db error $sql->errstr");
    while (my $photo =  $sql->fetchrow_hashref ) {
         next if ( ! -f "Masters/".$photo->{'imagePath'}) ;
         my $dir = $distdir . "/Masters/" . &photoDate($photo);
         my $filename = $dir."/".$photo->{'fileName'};
         print "$dir\n" if ($num++ % 1000 == 0 );
         &makelink($photo,$dir,$filename,$exec);
    }
}

if ($album) {
    my $albumsql = 'select modelId, name from RKAlbum';
    $albumsql .= " where folderUuid='TopLevelAlbums' and albumSubclass=3" if ($photos) ;
    for my $album (@{$mdb->selectall_arrayref($albumsql)}) {
        next if (! $album->[1]);
        next if ( $album->[1] eq "Last Import");
        next if ( $album->[1] eq "最後の読み込み");
        print "\n$album->[1]\n\n";

        my $sqlcmd = 'select * from RKMaster, RKVersion, RKAlbumVersion where RKAlbumVersion.albumId = '.$album->[0] .
              ' and RKMaster.modelId = RKVersion.masterId and RKVersion.modelId = RKAlbumVersion.versionId and RKMaster.imageDate >= '.$after.' order by imageDate';
        my $sql = $mdb->prepare($sqlcmd);
        $sql->execute or die("db error $sql->errstr");
        while (my $photo =  $sql->fetchrow_hashref ) {
             next if ( ! -f "Masters/".$photo->{'imagePath'}) ;
             my $dir = $distdir."/".$album->[1];
             my $filename = $dir."/".$photo->{'fileName'};
             &makelink($photo,$dir,$filename,$exec);
        }
    }
}

system("/bin/chmod -R o+r $distdir") if ($exec);
unlink($copydbFile) if ($copydbFile);

exit 1;

sub makelink {
   my ($photo,$dir,$filename,$exec) = @_;
   my $imagePath = "Masters/".$photo->{'imagePath'};
   my $version = "Previews/".$photo->{'imagePath'};
   $imagePath = $version if ( -f $version );
   my $fileSize = -s $imagePath;
   if ($exec) {
         make_path($dir);
         my $num = 1;
         my $f = $filename;
         while ( $dup && -f $filename ) {
             if (! $sync && $num==1) { print "$filename exists ",(-s $filename), " " ,$fileSize ," " ; }
             if ( -s $filename == $fileSize) { print " skipped \n" if (! $sync) ; return ; }
             $filename = $f;
             $filename =~ s/\./-$num./;
             $num++;
         }
         if (! $photo && $num>1 && ($photo->{orientation}==6 || $photo->{orientation}==8) ) {
             # rotated photo in iPhoto
             return;
         }
         print "$imagePath -> $filename\n" if ($num != 1) ;
         link($imagePath, $filename) if (! $debug);
   } else {
         print "    ln \'",$imagePath,"\' \'", $filename,"\'\n";
   }
}

sub photoDate {
   my ($photo) = @_;
   # mac time is from 2001.1.1 (timelocal(0,0,0,1,0,101))
   # some file has wrong photo date check Exif date 
   if ($exif) {
       my $info = ImageInfo($photo->{'imagePath'});
       if (my $date =  $info->{DateTimeOriginal}) {
            if ($date !~ /0000/ ) {
                $date =~ /(\d+):(\d+):(\d+) (\d+):(\d+):(\d+)/;
                return sprintf("%04d/%02d/%04d-%02d-%02d", $1,$2,$1,$2,$3); #  ."===" .  &macPhotoDat($photo);
            }
       }
   }
   return &macPhotoDate($photo);
}

sub uniDate2mac {
   my ($unix) = @_;
    return $unix - 978274800;
}

sub macDate2unix {
   my ($mac) = @_;
   my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($mac+978274800);
   $year += 1900;
   $mon += 1;
   return sprintf("%04d/%02d/%04d-%02d-%02d", $year,$mon,$year,$mon,$mday);
}

sub macPhotoDate {
   my ($photo) = @_;
   my $mac = $photo->{'imageDate'};
   return &macDate2unix($mac);
}


1;
