#!/bin/bash

###############################################################
#
# The MIT License
#
# Copyright (c) 2005 Olof Holmgren
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
###############################################################

###############################################################
#
# Changelog:
#
# v2.2
#   Removed jhead dependency.
#   
#   A little EXIF information is now added to the HTML
#   output along with a javascript allowing the user
#   to choose whether he/she wants to see this info or not.
#
#   Title changed to "dir1/dir2/.../dirN" instead of "dir"
#
# v2.1
#   Added a slideshow feature. (using javascript & query vars)
#
#   The generated html is now valid HTML 4.01 Transitional.
#
#   Movie files can be handled. The first frame will be
#   grabbed, scaled and thumbnailified.
#
#   All files that can be handled by ImageMagick will now
#   get nice little thumbnails. All other files will also
#   end up in the album. They will get a black box as a
#   thumbnail and a bigger black box as a scaled image.
#
#   Scaled images will never be upscaled to a size larger
#   than the original.
#
#   Added startup option --rebuild. This causes the
#   script to rescale all pictures. The default behaviour
#   have been changed to only scale images if they haven't
#   been scaled before, making it A LOT faster.
#
#   Empty dirs will show up in the album and get an index.html.
#
# v2.0
#   The script is now recursive and can build and connect
#   several folders into one large album consisting of
#   many smaller.
#
# v1.0
#   Initial version. Builds galleries with thumbnails
#   and individual pages for each pic.
#
#############################################################


##############################################
# Settings:
#############################################

# Look & Feel
thumbSize="120x120"
thumbQuality="70"

scaledSize="750x750"
scaledQuality="75"

cols=4
rows=4

slideshowSpeed=5000    # Milliseconds spent on each page in slideshow mode

scaledFormat="jpg"
thumbFormat="jpg"

# Set the look & feel finer by editing the stylesheet below

# Filenames and such
albDir="album"
thumbDir="thumbs"
scaledDir="scaled"
fileSuffix=".html"
htmlPageName="index"
cssFileName="style.css"

##############################################

insertStyleSheet()
{
    echo "
BODY { background-color: white;
       color: black; }

H1 { color: blue;
     font-size: xx-large;
     font-weight: bold;
     text-align: center;
     margin-top: 0.8em;
     margin-bottom: 0.5em; }

H2 { color: black;
     font-size: large;
     font-weight: bold;
     margin-bottom: 0em;
     margin-top: 0em;
     text-align: center; }

H2.filename { margin-top: 1em;
              margin-bottom: 0.5em; }

A { text-decoration: none;
    font-weight: bold; }

A:hover { color: red ! important; }

A:visited { color: blue; }

TD { vertical-align: top;
     padding: 0.5em; }

TABLE { margin-left: auto;
        margin-right: auto;
	margin-top: 0em;
        padding: 0em; }

TABLE.comment { margin-left: auto;
                margin-right: auto;
	        margin-top: 0em;
                width: 35em; }

TABLE.index { padding: 2em; }

TABLE.subgallery { margin-top: 2em;
                   margin-bottom: 1em; }

TD.index { vertical-align: middle;
           text-align: center; }

IMG { border: 0; }

FONT.ahref { font-weight: bold; }

DIV.backtoalbum { margin-top: 0.3em;
                  margin-bottom: 0.5em; }

DIV { text-align: center; }

TABLE.extraInfo { background-color: e1e1ff;
                  margin-top: 0.5em;
                  font-size: small; }

TD.extraInfo { padding: 0.1em; }"  > "$albDir/$cssFileName"
}


insertIndexTable()
{
    echo "<table class=\"index\">" >> "$albDir/$index"
}


insertRow()
{
    echo "<tr>" >> "$albDir/$index"
}


# $1 = path of ahref  $2 = thumbnail
insertIndexTd()
{
    generateJavascriptLink "$1" "<img src=\\\"$thumbDir/$2\\\" alt=\\\"$2\\\">"
    echo "<td class=\"index\">$javaLink" >> "$albDir/$index"
}

# $1 = page to link to  $2 = text in link
generateJavascriptLink()
{
    javaLink="<script language=\"JavaScript\" type=\"text/javascript\">document.write(\"<a href=\\\"$1?exif=\" + exif + \"\\\">$2</a>\");</script>"
}

# $1 = pic to show
insertPicPage()
{
    # /home/user/dirToAlbumify/subAlbum -> /subAlbum    	
    local pathToPic="${PWD##$origPWD}"
    # subAlbum -> subAlbum/picToShow (if subAlbum = "" we get "" -> /picToShow)
    local pathToPic="$pathToPic/$1"
    # /picToShow -> picToShow (if we had subAlbum = "" above. else nothing happens)
    local pathToPic="${pathToPic#/}"
    # subAlbum/picToShow -> ../subAlbum/picToShow (ie we've got a relative link to the pic!)
    local pathToPic="$pathToAlbumRoot$pathToPic"
    

    echo "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">
<html>
<head>
<META http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-15\">
<link rel=stylesheet href=\"$cssFileName\" type=\"text/css\">
<title>$title</title>
<SCRIPT LANGUAGE=\"JavaScript\" type=\"text/javascript\">
function getQueryVar(queryVar)
{
 var query = window.location.search.substring(1);
 var vars = query.split(\"&\");
  
 for (var i=0; i < vars.length; i++)
 {
   var pair = vars[i].split(\"=\");
   if (pair[0] == queryVar)
   {  
     return pair[1];
   }
 }
 return \"\";	 
}

var slideshow = getQueryVar(\"slideshow\");
var exif = getQueryVar(\"exif\");

if (slideshow == \"yes\")
{
  <!--This is one of many scripts which are available at:     *---
  //--http://www.JavaScript.nu/javascript                     *---
  //--This script is FREE, but you MUST let these lines       *---
  //--remain if you use this script.                          *---

  //***---Efter hur många millisekunder ska man skickas vidare. 0=På direkten; 3000=3 sekunder.
  meta_tid=$slideshowSpeed

  //***---Ange till vilken sida man ska komma här nedan." > "$albDir/$currentPicNr$fileSuffix"

    # Spin around to pic1 if we're on the last pic. Else just continue
    if [[ $currentPicNr -eq $nrOfPics ]]
	then
	echo "sida=\"1$fileSuffix?slideshow=yes&exif=\" + exif + \"\"" >> "$albDir/$currentPicNr$fileSuffix"
    else
	echo "sida=\"$nextPicNr$fileSuffix?slideshow=yes&exif=\" + exif + \"\"" >> "$albDir/$currentPicNr$fileSuffix"
    fi

    generateJavascriptLink "$index" "Back to index"
    echo "function meta()
  {
  //***---Ersätt self mot top om den nya sidan ska komma i helskärm. Om sidan ska komma i en viss frame, ersätt self mot parent.FRAMENSNAMN.
  self.location=sida
  }
  setTimeout(\"meta()\",meta_tid)
}
//-->
</SCRIPT>
</head>

<body>
<h1>$realTitle<script language=\"JavaScript\" type=\"text/javascript\">document.write(\"<a href=\\\"$index?exif=\" +exif + \"\\\">${title[$level]}</a>\");</script></h1>

<div>[$javaLink]</div>

<table>
<tr>
<td>" >> "$albDir/$currentPicNr$fileSuffix"

    if [[ $currentPicNr -eq 1 ]]
	then
	generateJavascriptLink "$nrOfPics$fileSuffix" "&lt;&lt;Prev"
	echo "$javaLink" >> "$albDir/$currentPicNr$fileSuffix"
    else 
	generateJavascriptLink "$prevPicNr$fileSuffix" "&lt;&lt;Prev"
	echo "$javaLink" >> "$albDir/$currentPicNr$fileSuffix"
    fi

    echo "<td><h2>Pic $currentPicNr of $nrOfPics</h2>
<td align=\"right\">" >> "$albDir/$currentPicNr$fileSuffix"
    
    if [[ $currentPicNr -eq $nrOfPics ]]
	then
	generateJavascriptLink "1$fileSuffix" "Next&gt;&gt;"
	echo "$javaLink" >> "$albDir/$currentPicNr$fileSuffix"
    else
	generateJavascriptLink "$nextPicNr$fileSuffix" "Next&gt;&gt;"
	echo "$javaLink" >> "$albDir/$currentPicNr$fileSuffix"
    fi

echo "</table>" >> "$albDir/$currentPicNr$fileSuffix"

    # HTML part of the JavaScript/HTML that controls the slideshow
   echo "<div>
         <script language=\"JavaScript\" type=\"text/javascript\">
         if (slideshow == \"yes\")
         {
           document.write(\"<a href=\\\"$currentPicNr$fileSuffix?exif=\" + exif + \"\\\">[Stop slideshow]<\/a>\");
         }
         else
         { " >> "$albDir/$currentPicNr$fileSuffix"
    
    
    # If we're on the last pic in the gallery, turn around and go to pic 1
    # else, just start the slideshow from the next pic
    if [[ $currentPicNr -eq $nrOfPics ]]
	then
	echo "document.write(\"<a href=\\\"1$fileSuffix?slideshow=yes&exif=\" + exif + \"\\\">[Start slideshow]<\/a>\");" >> "$albDir/$currentPicNr$fileSuffix"
    else
	echo "document.write(\"<a href=\\\"$nextPicNr$fileSuffix?slideshow=yes&exif=\" + exif + \"\\\">[Start slideshow]<\/a>\");" >> "$albDir/$currentPicNr$fileSuffix"
    fi
    
    echo "}
         if (exif == \"yes\")
         {
           document.write(\" <a href=\\\"$currentPicNr$fileSuffix?slideshow=\" + slideshow + \"\\\">[Hide EXIF]<\/a>\");
         }
         else
         {
           document.write(\" <a href=\\\"$currentPicNr$fileSuffix?exif=yes&slideshow=\" + slideshow + \"\\\">[Show EXIF]<\/a>\");
         }
          </script> 
          </div>

<h2 class=\"filename\">$1</h2>

<div><a href=\"$pathToPic\"><img src=\"$scaledDir/$1.$scaledFormat\" alt=\"$1\"></a></div>" >> "$albDir/$currentPicNr$fileSuffix"


    # insert comments and exif data
    identify -format "%m" "$1[0]" > /tmp/oh_galleryGen.txt # %m = magic number
    local fileType="";
    read fileType </tmp/oh_galleryGen.txt
    rm /tmp/oh_galleryGen.txt

    if [[ "$fileType" == "JPEG" ]]
	then
	echo "<table class=\"comment\">
        <tr>
        <td class=\"comment\">" >> "$albDir/$currentPicNr$fileSuffix"
	identify -format "%c" "$1[0]" >> "$albDir/$currentPicNr$fileSuffix"	
	echo "</table>" >> "$albDir/$currentPicNr$fileSuffix"

	identify -format "<script language=\"JavaScript\" type=\"text/javascript\">
if (exif == \"yes\")
{
  document.write(\"<table class=\\\"extraInfo\\\"><tr><td class=\\\"extraInfo\\\"><b>Date:</b> %[EXIF:DateTime] | <b>Camera:</b> %[EXIF:Model] | <b>Resolution:</b> %w x %h</table>\");
}
</script>
" "$1" >> "$albDir/$currentPicNr$fileSuffix"
    fi

    echo "</body>
</html>" >> "$albDir/$currentPicNr$fileSuffix"
}


insertNewPage()
{
    local prevIndex="$index"
    index="$htmlPageName$pageNum$fileSuffix"
    let pageNum=$pageNum+1 # See to it that we get index1, index2, ...
    local nextIndex="$htmlPageName$pageNum$fileSuffix"

    local picsOnPage=`expr $cols \* $rows`

    if [[ $nrOfPics -eq 0 ]]
	then
	pagesNeeded=1
    else
	# Bash doesn't do floating point arithmetics
	# so we'll have to do this workaround
	pagesNeeded=0
	tmp=$nrOfPics
	while [[ $tmp -gt 0 ]]
	  do
	  let pagesNeeded=$pagesNeeded+1
	  let tmp=$tmp-$picsOnPage
	done
    fi

    echo "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">
<html>
<head>
<META http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-15\">
<link rel=stylesheet href=\"$cssFileName\" type=\"text/css\">
<title>$title</title>
<SCRIPT LANGUAGE=\"JavaScript\" type=\"text/javascript\">
function getQueryVar(queryVar)
{
 var query = window.location.search.substring(1);
 var vars = query.split(\"&\");
  
 for (var i=0; i < vars.length; i++)
 {
   var pair = vars[i].split(\"=\");
   if (pair[0] == queryVar)
   {  
     return pair[1];
   }
 }
 return \"\";	 
}

var slideshow = getQueryVar(\"slideshow\");
var exif = getQueryVar(\"exif\");
</script>
</head>
<body>
<h1>$realTitle${title[$level]}</h1>" > "$albDir/$index"

    if [[ "$PWD" != "$origPWD" ]] # We came from another directory!
	then
	generateJavascriptLink "../$htmlPageName$fileSuffix" "Back to $oldTitle"
	echo "<div>[$javaLink]" >> "$albDir/$index"
    fi

    echo "<table>
<tr>
<td>" >> "$albDir/$index"

    if [[ $pageNum -ne 1 ]] # not first page -> prev link needed
	then
	insertPageEnd "$prevIndex"
	generateJavascriptLink "$prevIndex" "&lt;&lt;Prev"
	echo "$javaLink" >> "$albDir/$index"
    else
	echo "<font class=\"ahref\">&lt;&lt;Prev</font>" >> "$albDir/$index"
    fi

    echo "
<td>
<h2>Page $pageNum of $pagesNeeded</h2>
<td align=\"right\">" >> "$albDir/$index"

    if [[ $pageNum -lt $pagesNeeded ]] # More pics than can fit on this page -> Include next link
	then
	generateJavascriptLink "$nextIndex" "Next&gt;&gt;" "$albDir/$index"
	echo "$javaLink" >> "$albDir/$index"	
    else
	echo "<font class=\"ahref\">Next&gt;&gt;</font>" >> "$albDir/$index"	
    fi
    
    echo "</table>
<div>" >> "$albDir/$index"

    if [[ $pagesNeeded -gt 1 ]]
	then
	i=""
	while [[ $i -lt $pagesNeeded ]]
	  do
	  let ii=$i+1
	  if [[ $ii -eq $pageNum ]]
	      then
	      echo "[<font class=\"ahref\">$ii</font>] " >> "$albDir/$index"
	  else
	      generateJavascriptLink "$htmlPageName$i$fileSuffix" "$ii"
	      echo "[$javaLink]" >> "$albDir/$index"
	  fi
	  let i=$i+1
	done
    fi

    echo "</div>" >> "$albDir/$index"
}


# $1 = name of page to be ended
insertPageEnd()
{
    # We won't have an open table to close if there's no pics
    # (ie just album links) on the page.
    if [[ $nrOfPics -ne 0 ]]
	then
	echo "</table>" >> "$albDir/$1"
    fi

    echo "</body>
</html>" >> "$albDir/$1"
}


# $1 = dir to link to
insertDirLink()
{
    generateJavascriptLink "$1/$htmlPageName$fileSuffix" "$1"
    echo "$javaLink<br>" >> "$albDir/$index"
}


createDirs()
{
    # Create the albDir
    if [[ ! -e "$albDir" ]]
	then
	mkdir "$albDir"
    elif [[ ! -d "$albDir" ]]
	then
	echo ">>"
	echo ">> ERROR: There is already a file $PWD/$albDir so I can't create that directory"
	echo ">> Rename it or change the variables in the script."
	exit
    fi

    # Create the thumbDir
    if [[ ! -e "$albDir/$thumbDir" ]]
	then
	mkdir "$albDir/$thumbDir"
    elif [[ ! -d "$albDir/$thumbDir" ]]
	then
	echo ">>"
	echo ">> ERROR: There is already a file $PWD/$thumbDir so I can't create that directory"
	echo ">> Rename it or change the variables in the script."
	exit
    fi

    # Create the scaledDir
    if [[ ! -e "$albDir/$scaledDir" ]]
	then
	mkdir "$albDir/$scaledDir"
    elif [[ ! -d "$albDir/$scaledDir" ]]
	then
	echo ">>"
	echo ">> ERROR: There is already a file $PWD/$scaledDir so I can't create that directory"
	echo ">> Rename it or change the variables in the script."
	exit
    fi

    # Create the css
    insertStyleSheet
}


countPics()
{
    nrOfPics=0
    for file in *
      do 
      if [[ ! -d "$file" ]]
	  then
	  let nrOfPics=$nrOfPics+1
      fi
    done
}


findAlbums()
{
    pageNum=""
    pageStarted=0
    for dir in *
      do
      if [[ -d "$dir" ]] && [[ "$PWD/$dir" != "$albDir" ]]
	  then
	  if [[ $pageStarted -eq 0 ]] # Should we create a new page?
	      then
	      insertNewPage
	      echo "<table class=\"subgallery\">
<tr>
<td>
<h2>Subgalleries:</h2>
<td>" >> "$albDir/$index"
	      pageStarted=1
	  fi
	  insertDirLink "$dir"	      
      fi
    done
    
    if [[ $pageStarted -eq 1 ]]
	then
	echo "</table>" >> "$albDir/$index"
    fi
}


genGallery()
{
    currentPicNr=0
    for pic in  *
      do
      if [[ ! -d "$pic" ]] 
	  then      
	  if !(($currentPicNr % (($cols * $rows)))) # Have we filled a page?
	      then
              # Do we need a new page?
	      if [[ $currentPicNr -eq 0 ]]
		  then
		  if [[ $pageStarted -eq 0 ]]
		      then
		      insertNewPage
		  fi
		  insertIndexTable
	      else     #currentPicNr != 0
		  insertNewPage
		  insertIndexTable		  
	      fi
	  fi

          # Do we need a new row?
	  if !(($currentPicNr % $cols))
	      then
	      insertRow
	  fi

	  let prevPicNr=$currentPicNr
	  let currentPicNr=$currentPicNr+1
	  let nextPicNr=$currentPicNr+1
	  
	  echo ">> Adding pic $currentPicNr of $nrOfPics in ${title[level]} ($pic)"
	  
          # scale the image, but only if it hasn't been done already
	  if [[ "$pic" -nt "$albDir/$scaledDir/$pic.$scaledFormat" ]] || [[ "$rebuild" == "true" ]]
	      then
	      convert -format $scaledFormat -size $scaledSize -quality $scaledQuality -thumbnail "$scaledSize>" "$pic[0]" "$albDir/$scaledDir/$pic.$scaledFormat"
	  fi

          # Thumbnail the scaled version, but only if it hasn't been done before
	  if [[ "$pic" -nt "$albDir/$thumbDir/$pic.$thumbFormat" ]] || [[ "$rebuild" == "true" ]]
	      then
	      convert -format $thumbFormat -size $thumbSize -quality $thumbQuality -thumbnail $thumbSize "$albDir/$scaledDir/$pic.$scaledFormat" "$albDir/$thumbDir/$pic.$thumbFormat"
	  fi

	  insertPicPage "$pic" # $pic = pic to show
	  insertIndexTd "$currentPicNr$fileSuffix" "$pic.$thumbFormat" # "page to link to" "thumb to show"
      fi
    done

    # Include an index without pics if we found an empty dir.
    if [[ $nrOfPics -eq 0 ]] && [[ $pageStarted -eq 0 ]]
	then
	insertNewPage
    fi

    insertPageEnd "$index" # remember to close the last page
}


recurse()
{
    # see to it that we get enough ../ when we insert the relative links
    pathToAlbumRoot="../$pathToAlbumRoot"

    # The chunk below takes care of generating headers with correct links
    index="$htmlPageName$fileSuffix"
    realTitle="<script language=\"JavaScript\" type=\"text/javascript\">"
    local i=0
    while [[ $i -lt $level ]]
      do
      realTitle="$realTitle document.write(\"<a href=\\\""
      
      let local "ii=$level-$i"
      while [[ $ii -gt 0 ]]
	do
	realTitle="$realTitle../"
	let "ii=$ii-1"
      done
      realTitle="$realTitle$index?exif=\" + exif + \"\\\">${title[$i]}</a>/\");"
      let "i=$i+1"
    done
    realTitle="$realTitle</script>"

    countPics
    createDirs
    findAlbums
    genGallery
    
    for dir in *
      do
      if [[ -d "$dir" ]] && [[ "$PWD/$dir" != "$albDir" ]]
	  then
	  albDir="$albDir/$dir"	  
	  oldTitle="${PWD##*/}" # oldTitle -> current dir

	  cd "$dir"
	  let "level=$level+1"
	  title[$level]="$dir"
	  recurse
	  let "level=$level-1"
	  cd "../"

	  #title="${title%/*}" # dir1/dir2 -> dir1
	  pathToAlbumRoot="${pathToAlbumRoot%../}" # Strip last ../
	  albDir="${albDir%/*}" # albDir/anotherDir -> albDir
      fi
    done
}


# $x = args
echo ">>"
echo ">> Creating a gallery from $PWD"	

if [[ "$1" == "--rebuild" ]]
    then
    echo ">>"
    echo ">> Doing complete rebuild of album"
    rebuild="true"
fi

albDir="$PWD/$albDir"

# These are used to generate headers with relative links
level=0
title[$level]="${PWD##*/}" # title = last part of $PWD


origPWD="$PWD"

# Used when inserting relative links
pathToAlbumRoot=""


echo ">>"
echo ">> Creating album"
recurse
echo ">> Album done!"

exit