#!/usr/bin/perl -w
#
#
# mkGallery - turns a directory full of image files into a "gallery".
#
# Copyright (C) 2000 Daniel M. Lowe	<dan@tangledhelix.com>
#
#
# LICENSE INFORMATION
# -------------------
#
# 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 2
# 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, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
#
# MISCELLANEOUS
# -------------
#
# See the file docs/Utilities.txt for more information.
#
# I haven't tested this under Windows, so use it at your own risk.
#
# You should not need to modify this code directly.  If you do so, and
# want to contribute your changes to MiG, please send me a note with a
# code diff, and if I agree that your change is of use to the general
# public, I will incorporate it into the main codebase of MiG.
#
# However, in general MiG is written with the goal that the user should
# never have to modify actual code to use the software - everything is
# taken care of either automatically, or using configuration files.
#
# Please report any bugs to <mig-bugs@tangledhelix.com>.
#

use strict;
use File::Basename;
use Getopt::Std;

my $myself = File::Basename::basename($0);
my $mydir  = File::Basename::dirname($0);

my $exifProg = $mydir . "/jhead";
my $exifArgs = "-v";
my $exifFile = "exif.inf";

my $allFlag = 0;	# default
my $exifFlag = 0;	# default
my $overwriteFlag = 0;	# default
my $thumbFlag = 0;	# default
my $commentsFlag = 0;	# default
my $interactFlag = 0;	# default

my $defaultSize = 100;		# default
my $defaultQuality = 50;	# default
my $defaultMarker = "th";	# default
my $markerType = "suffix";	# default

my $pkgName = "MiG";
my $url = "http://tangledhelix.com/software/mig/";
my $email = "dan\@tangledhelix.com";
my $migConfig = "mig.cf";
my $globalConfig = $mydir . "/../mig.cfg";

# Parse local config file, if it exists.
if (-r $globalConfig) {
  ($markerType, $defaultMarker) =
      &parseMyConfig($globalConfig, $markerType, $defaultMarker);
}

my %opt = ();
getopts('acehiM:m:q:s:tw', \%opt);

# Prototype variables
my ($item, $file, $ext, $size, $quality, $markerLabel, $marktestpat);
my @contents = ();
my @process = ();
my @noprocess = ();
my %FILE = ();
my %EXT = ();

$allFlag	= 1 if $opt{'a'};	# set "process all images" flag
$commentsFlag	= 1 if $opt{'c'};	# set "process comments" flag
$exifFlag	= 1 if $opt{'e'};	# set "process EXIF info" flag
$thumbFlag	= 1 if $opt{'t'};	# set "thumbnails" flag
$overwriteFlag	= 1 if $opt{'w'};	# set "overwrite" flag
$interactFlag	= 1 if $opt{'i'};	# set "interactive" flag

$size    = $opt{'s'};		# thumbnail size in pixels
$quality = $opt{'q'};		# quality level for thumbnails

$markerLabel = $defaultMarker;
$markerLabel = $opt{'m'} if $opt{'m'};
$markerType = $opt{'M'} if $opt{'M'};

# print help, if asked to.
if ($opt{'h'}) {
  &helpMessage($myself, $pkgName, $url, $email, $exifFile);
  exit(0);
}

# error out and exit if there are both filenames and "-a" specified.
if ($allFlag and $ARGV[0]) {
  print "ERROR: -a specified as well as filenames.\n\n";
  exit(1);
}

# If no files are specified and also no "-a", bail out.
unless ($allFlag or $ARGV[0]) {
  print "ERROR: no filenames specified, and -a not specified.\n\n";
  exit(1);
}

# If "-e" is specified but $exifProg isn't executable, bail out.
if ($exifFlag) {
  unless (-x $exifProg) {
    print "\nERROR: \"-e\" specified, but $exifProg not found.\n";
    print "See the file docs/Utilities.txt for more information.\n\n";
    exit(1);
  }
}

# If none of -c, -e, -t are specified, quit (no action to take).
unless ($commentsFlag or $exifFlag or $thumbFlag) {
  print "ERROR: no action specified.  You must specify at least one\n";
  print "of -c, -e or -t.  More than one is OK, but at least one must\n";
  print "be specified.\n\n";
  exit(1);
}

# If -M is an invalid type, bail out.
if ($markerType ne "prefix" and $markerType ne "suffix") {
  print "ERROR: marker type \"$markerType\" is invalid.\n";
  print "Only \"prefix\" and \"suffix\" are valid.  This could\n";
  print "be specified as an argument for -M, or can be specifed\n";
  print "in your mig.cfg file (see \$markerType)\n\n";
  exit(1);
}

# If -i was used without -c, bail out.
if ($interactFlag and not $commentsFlag) {
  print "ERROR: -i specified without -c.\n\n";
  exit(1);
}

# Set values based on the markerType.
if ($markerType eq "prefix") {
  $markerLabel .= "_";
  $marktestpat = "^" . $markerLabel;
}
if ($markerType eq "suffix") {
  $markerLabel = "_" . $markerLabel;
  $marktestpat = $markerLabel . '$';
}

# Use defaults if they weren't specified.
$size = $defaultSize unless $size;
$quality = $defaultQuality unless $quality;

if ($allFlag) {

  opendir(DIR, ".") or die "Can't open current directory!\n";
  @contents = readdir(DIR);
  closedir(DIR);

  foreach $item (sort(@contents)) {
    if (-f $item) {
      ($file, $ext) = &fileExtension($item);
      if (&testFileType($ext) and $file !~ /$marktestpat/) {
        push (@process, $item);
        $FILE{$item} = $file;
        $EXT{$item} = $ext;
      } else {
        push (@noprocess, $item);
      }
    }
  }

} else {
  foreach $item (@ARGV) {
    ($file, $ext) = &fileExtension($item);
    if (&testFileType($ext) and $file !~ /$marktestpat/) {
      push (@process, $item);
      $FILE{$item} = $file;
      $EXT{$item} = $ext;
    } else {
      push (@noprocess, $item);
    }
  }
}

if ($exifFlag and $overwriteFlag) {
  unlink $exifFile;
}

if ($commentsFlag) {
  print "Processing comments file \"$migConfig\"...\n";
  &processComments($migConfig, ".", $interactFlag, @process);
}

foreach $item (@process) {

  my ($orig_file, $new_file, $SIZE);

  $orig_file = $FILE{$item} . "."    . $EXT{$item};
  if ($markerType eq "prefix") {
    $new_file  = $markerLabel . $FILE{$item} . "." . $EXT{$item};
  } else {
    $new_file  = $FILE{$item} . $markerLabel . "." . $EXT{$item};
  }

  $SIZE = $size . "x" . $size;

  if ($thumbFlag) {
    print "Generating thumbnail \"$new_file\" ...\n";
    system("convert -geometry $SIZE -quality $quality \"$orig_file\" \"$new_file\"");
  }

  if ($exifFlag and $EXT{$item} =~ /^(jpg|jpe|jpeg)$/i) { # only for JPEG
    print "Parsing $orig_file EXIF header...\n";
    &getExifInfo($exifProg, $exifArgs, $exifFile, $orig_file);
  }

}


##
##  Subroutines
##

sub fileExtension {

  my $filename = shift;
  my ($extension, $stripname);

  $extension = $filename;
  $stripname = $filename;

  $stripname =~ s/^(.*)\.([^\.]+)$/$1/;
  $extension =~ s/^.*\.([^\.]+)$/$1/;

  return $stripname, $extension;

}

sub testFileType {

  my $extension = shift;

  if ($extension =~ /^(jpg|jpeg|jpe|png|gif)$/i) {
    return 1;
  } else {
    return 0;
  }

}

sub getExifInfo {

  my $exifProg = shift;
  my $exifArgs = shift;
  my $exifFile = shift;
  my $image = shift;

  open(OUT, ">>$exifFile") or die "Can't open $exifFile for writing\n";

  open(EXIF,"$exifProg $exifArgs \"$image\"|") or die "Can't exec $exifProg\n";
  print OUT "BEGIN $image\n";
  print OUT while <EXIF>;
  print OUT "\n";
  close EXIF;

  close OUT;

  return 1;

}

sub helpMessage {

  my $myself = shift;
  my $pkgName = shift;
  my $url = shift;
  my $email = shift;
  my $exifFile = shift;

  print "\nUsage:\n";
  print "   $myself [ -h ] [ -a ] [ -w ] [ -t ] [ -e ] [ -c ] [ -i ]\n";
  print "\t[ -s <size> ] [ -q <quality> ] [ -M <type> ] [ -m <label> ]\n";
  print "\t[ <file1> <file2> <...> ]\n\n";
  print "      -h : Prints this help message.\n";
  print "      -a : Process all image files in current directory.\n";
  print "      -w : Turn over-write on.  By default, files written such\n";
  print "           as the EXIF file will be appended to rather than\n";
  print "           over-written.  Using \"-w\" indicates the file should\n";
  print "           be over-written instead.\n";
  print "      -t : Generate thumbnail images.\n";
  print "      -e : Build \"$exifFile\" file.\n";
  print "           See the file docs/Utilities.txt - you must build the jhead\n";
  print "           utility (included) before you can use the -e option.\n";
  print "      -c : Generate blank comments for uncommented images.\n";
  print "      -i : \"Interactive\" mode for comments (see docs/Utilities.txt).\n";
  print "      -s : Set pixel size for thumbnails.  See the file docs/Utilities.txt.\n";
  print "      -q : Set quality level for thumbnails.  See the file docs/Utilities.txt.\n";
  print "      -M : Define type of \"prefix\" or \"suffix\".\n";
  print "      -m : thumbnail marker label (default \"th\").  See the file\n";
  print "           docs/Utilities.txt for more information.\n\n";
  print " * If creating thumbnails, \"convert\" must be in your \$PATH.\n";
  print " * This program supports JPEG, PNG and GIF formats.\n";
  print " * The \"-e\" feature only supports JPEG files.\n";
  print "   $pkgName - $url - $email\n\n";

  return 1;

}

sub parseMyConfig {

  my $configFile = shift;
  my $markerType = shift;
  my $defaultMarker = shift;

  my $type = undef;

  unless (open(CF, $configFile)) {
    print "Can't open $configFile for reading, skipping it.\n";
    return $markerType, $defaultMarker;
  }

  while (<CF>) {
    chomp;
    if (/^[\s]*\$markerType/) {
      $type = $_;
      $type =~ s/^.*\$markerType[\s]*=[\s]*["']([^"']*)["'][\s]*;.*$/$1/i;
      $type = lc $type;	# just in case
      if ($type eq "prefix" or $type eq "suffix") {
        $markerType = $type;
      }
    }
    if (/^[\s]*\$markerLabel/) {
      s/^.*\$markerLabel[\s]*=[\s]*["']([^"']*)["'][\s]*;.*$/$1/i;
      $defaultMarker = $1 if $1;
    }
  }
  close CF;

  return $markerType, $defaultMarker;
}

sub processComments {

  my $migConfig = shift;
  my $currDir = shift;
  my $interactFlag = shift;
  my @process = @_;

  my $tempConfig = $migConfig . ".tmp";
  my $commIn = undef;
  my %noadd = ();

  # Bail out if the file is there but it can't be read.
  if (-f $migConfig and not -r $migConfig) {
    print "ERROR: $migConfig exists, but I can't read it.\n";
    print "ERROR: skipping comment processing.\n";
    return 0;
  }

  # bail out if we can't write to it, either.
  if (-f $migConfig and not -w $migConfig) {
    print "ERROR: $migConfig exists, but I can't write to it.\n";
    print "ERROR: skipping comment processing.\n";
    return 0;
  }

  if (-r $migConfig) {
    open(CF, $migConfig);
    while (<CF>) {
      chomp;
      if (/^<comment/i) {
        s/^<comment[\s]+\"([^"]+)\"[\s]*>.*$/$1/i;
        $noadd{$_} = 1 if $_ ne "";
      }
    }
    close CF;
  }

  open(OUT, ">>$migConfig");
  print OUT "\n";
  foreach (@process) {
    unless ($noadd{$_}) {
      print OUT "<Comment \"", $_, "\">\n";
      if ($interactFlag) {
        print "Enter comment for $_: ";
        chomp($commIn = <STDIN>);
        if ($commIn) {
          print OUT "$commIn\n";
        }
      }
      print OUT "</Comment>\n\n";
    }
  }
  close OUT;

  return 1;
}

