package PhotoPub::Range;
require Exporter;
@ISA = qw(Exporter);
@EXPORT_OK = qw(&dispahref &dispembedahref &dispimg &dispinfo &rangehtml);

use PhotoPub::Global qw($error);
use PhotoPub::Handlers qw(&handlephoto &parameterhandlephoto);
use PhotoPub::Utils qw(&slurp &doifcount &untaint &uri_escape 
		       &handleparameters &includetag &excludetag
                       &handlepages &handletagoptions
		       &makeabsolutepath &getdefault &getlinkroot);
use PhotoPub::Search qw(&makesearchre &filterrange);
use PhotoPub::Images qw(&picfile &picrange &canonicalname);
use PhotoPub::Cache qw(&imagesize);
use PhotoPub::Annots qw(&getannot);
use PhotoPub::Ages qw(&updateagefromfiles);

use strict;

use HTML::Entities;
use POSIX qw(&floor);

sub dispurl {
  my ($photo,$options,$extra,$styleroot)=@_;
  my $url=&getlinkroot('display');
  $url.="?photo=".&uri_escape(&canonicalname($photo));

  my %imgoptions=defined $options ? (%$options) : ();
  if (defined $imgoptions{'red'} && 
      defined $imgoptions{'green'} &&
      defined $imgoptions{'blue'} &&
      $imgoptions{'red'} == $imgoptions{'blue'} &&
      $imgoptions{'red'} == $imgoptions{'green'})
  {
     $imgoptions{'gamma'} = $imgoptions{'red'};
     delete $imgoptions{'red'};
     delete $imgoptions{'green'};
     delete $imgoptions{'blue'};
  }

  foreach my $entry (keys %imgoptions) {
    $url.='&amp;'.&uri_escape($entry)."=".&uri_escape($imgoptions{$entry});
  }
  &handletagoptions(\$url,$styleroot,$extra);
  return $url;
}

sub dispembedurl {
  my ($photo,$options,$extra,$styleroot)=@_;
  my $url=&getlinkroot('embed');
  $url.="?photo=".&uri_escape(&canonicalname($photo));
  foreach my $entry (keys %$options) {
    $url.='&amp;'.&uri_escape($entry)."=".&uri_escape($options->{$entry});
  }
  &handletagoptions(\$url,$styleroot,$extra);
  return $url;
}

sub dispahref {
  my ($other,$photo,$options,$extra,$styleroot)=@_;
  return '<a'.$other.'href="'.dispurl($photo,$options,$extra,$styleroot).'">';
}

sub dispembedahref {
  my ($other,$photo,$options,$extra,$styleroot)=@_;
  return '<a'.$other.'href="'.dispembedurl($photo,$options,$extra,$styleroot)
             .'">';
}

sub dispimg {
  my ($other,$photo,$options,$extra,$styleroot)=@_;
  my %imgoptions=defined $options ? %{$options} : ();

  my $tagend;
  if (substr($extra,-1) eq '/') {
     $tagend=' />';
     chop $extra;
  } else {
     $tagend='>';
  }  

  foreach my $attrpair (split (/\s+/,$extra)) {
    if(my ($attr,$value) = split (/=/,$attrpair)) {
      $imgoptions{$attr}=$value;
    }
  }

  my ($width,$height)=&imagesize($photo,\%imgoptions);
  if(defined $width) {
     return '<img'.$other.'src="'.&dispurl($photo,$options,$extra,$styleroot).
                   '" alt="Photo '.&canonicalname($photo).'" width="'.$width.
                      '" height="'.$height.'"'.$tagend;
  } else {
     return '<img'.$other.'src="'.&dispurl($photo,$options,$extra,$styleroot).
                   '" alt="Photo '.&canonicalname($photo).'"'.$tagend;
  }
}

sub dispinfo {
  my $photo = shift;
  my $desc = shift || "";
  my $out = '<p><input type="text" name="desc'
              .&uri_escape($photo).'" size=40 value="'.$desc.'">';
  $out .= '<select name="effect'.&uri_escape($photo).'">';
  foreach (qw(none rotate90 rotate180 rotate270)) {
    $out .= " <option value=\"$_\"";
    $out .= " selected" if $_ eq "none";
    $out .= ">$_</option>";
  }
  $out .= "</select>";
  return $out;
}

sub rangehtml {
  my ($options,$printheader,$printout)=@_;

  my $debug=exists $options->{'debug'} ? $options->{'debug'} : 0;

  if( $debug >= 1 ) {
    # Do the headers early, so we can output to the browser soon
    # Might lead to some of the headers being wrong though
    &$printheader();
    print "<pre>\n";
  }

  my $range=$options->{'range'}
    or &$error(type=>'userinput',message=>'Must supply range parameter');
  &makeabsolutepath(\$range);

  my $style=$options->{'style'};
  $style=&getdefault('rangestyle') unless defined $style;
  &$error(type=>'userinput',message=>'style not given and no default defined')
    unless defined $style;

  my $rangetemplate=&handlephoto('rangetemplate',$style);

  my $search=$options->{'search'};
  my $searchre;
  $searchre=&makesearchre($search) if defined $search;

  &$error(type=>'userinput',message=>"Range style $style not defined") 
    unless defined $rangetemplate;

  my $template=slurp($rangetemplate) 
    or &$error(type => 'config', message => "Couldn't open template file");

  my @params=&handleparameters($options,\$template);

  # Export $styleroot, the path of the stylesheet, into the template
  # This should go away if we can find a nice way to do relative style 
  # references here like in album.pl
  my $styleroot = substr( $style, 0, rindex( $style, '/' ) );
  $template=~s/\$styleroot/$styleroot/ieg;

  &updateagefromfiles($rangetemplate);

  my @photos=&picrange($range);

  # Do search now
  &filterrange($searchre,\@photos) if defined $search;

  # Split the range into multiple pages if requested to do so
  my $startnum=0;
  my $endnum=scalar @photos - 1;

  if( $debug >= 1 ) {
    print "<pre>";
    foreach my $ph (@photos) {
      print $ph."\n";
    }
    print "$endnum\n</pre>";
  }

  #    Do proper blank range page here
  #    -------------------------------
  if($endnum == -1 ) {
    if(defined $search) {
      &$error(type=>'userinput',
	      message=>"No photos were found in $range satisfying your ".
	      "search criteria");
    } else {
      &$error(type=>'userinput',
	      message=>"That range \($range\) contains no entries - perhaps ". 
	      "you specified an incorrect range?");
    }
  }


  # string for links to different pages of the same range, if needed

  my $rangequery;

  $rangequery=&getlinkroot('range').'?range='.&uri_escape($range);
  &handlepages($options,\$template,\$startnum,\$endnum,
	       sub {
		 if(exists $options->{'album'}) {
		   $rangequery.="&amp;album=".&uri_escape($options->{'album'});
		 }
		 $rangequery.="&amp;style=".&uri_escape($style);
		 foreach my $param (@params) {
		   next if $param eq 'album';
		   $rangequery.='&amp;'.&uri_escape($param)
		     .'='.&uri_escape($options->{$param});
		 }
	       },
	       sub {
		 my ($pagenum)=@_;
		 return "$rangequery&amp;page=$pagenum";
	       });
  
  # shorten @photos to account for the pages
  @photos = @photos[$startnum..$endnum];

  while ($template =~ s/\<rangefit\s+heightthumb\s+(\w+)\s+(\d+)x(\d+)\>//i) {
    my $rangefitvar = lc($1);
    my $fitwidth = $2;
    my $fitheight = $3;
    # account for gaps
    $fitwidth -= 10+10*(scalar @photos);
    $fitheight -= 20;
    my $totalaspect = 0;
    my $maxaspect = 0;
    foreach my $photo (@photos) {
      my $photooptions=&getannot($photo,'options');
      my ($width,$height) = &imagesize($photo,$photooptions);
      my $aspect = $width/$height;
      $totalaspect += $aspect;
      $maxaspect = $aspect if $aspect > $maxaspect;
    }
    my $maxheight = $fitwidth < $fitheight * $totalaspect 
      ? $fitwidth / $totalaspect
	: $fitheight;
    my $maxwidth = $maxheight * $maxaspect;
    my $thumb = floor($maxwidth).'x'.floor($maxheight);
    $template =~ s/\$$rangefitvar/$thumb/gi;
  }

  if( $debug >= 1 ) {
    print "<pre>\nstart $startnum\nend $endnum\n";
    foreach my $p (@photos) {
      print $p."\n";
    }
    print "</pre>\n";
  }

  my $title;
  if(exists $options->{'album'}) {
    my $rangeinfo
      =&parameterhandlephoto('rangeinfo',$options->{'album'},$range);
    $title=$rangeinfo->{'description'} if defined $rangeinfo;
  }

  # perhaps HTML should be stripped completely?
  if(defined $title) {
    &includetag('iftitle',\$template);
    &excludetag('ifnotitle',\$template);
    $template=~s/\$title/&encode_entities($title)/ieg;
  } else {
    &excludetag('iftitle',\$template);
    &includetag('ifnotitle',\$template);
    $template=~s/\$title//ig;
  }

  $template=~s/\$range/&encode_entities($range)/ieg;

  my $out="";
  my ($pre,$repeat,$repoptions,$post);
  
  while(($pre,$repoptions,$repeat,$post)
	=($template=~/^(.*?)\<REPEAT PICTURE(.*?)\>(.*?)\<\/REPEAT\>(.*)$/si)) {
    
    my $count=1;

    my $dophoto = sub {
      my ($photo,$section)=@_;
      my $descr=&getannot($photo,'description');
      my $photooptions=&getannot($photo,'options');
      if(defined $descr) {
	&includetag('ifdescr',\$section);
	# allowhtml setting will already have caused $descr to be HTML escaped 
	# if necessary
	$section=~s/\$description/$descr/ig;
      } else {
	&excludetag('ifdescr',\$section);
	$section=~s/\$description//ig;
      }
      # We control count and it's only numbers => not escaped
      $section=~s/\$counter/$count/gi;
      my $filesizek=int((-s &picfile($photo)) / 1024);
      # likewise filesizek is a number.
      $section=~s/\$photo/$photo/gi;
      $section=~s/\$filesizek/$filesizek/gi;
      $section=~s/\$picid/&encode_entities(&canonicalname($photo))/gie;
      $section=~s/\<img(.*?)picture(.*?)\>/&dispimg($1,$photo,$photooptions,$2,$styleroot)/gies;
      $section=~s/\<a(.*?)picture(.*?)\>/&dispahref($1,$photo,$photooptions,$2,$styleroot)/gies;
      $section=~s/\<a(.*?)embed(.*?)\>/&dispembedahref($1,$photo,$photooptions,$2,$styleroot)/gies;
      $section=~s/\<editinfo\>/&dispinfo($photo,$descr)/gies;
      $section=&doifcount($section,$count,$#photos+1);
      $out.=$section;
      $count++;
    };
    
    $out.=$pre;

    my $innercount=1;
    if($repoptions=~/inner\=(\d+)/si) { $innercount=$1; }

    if($innercount==1) {
      foreach my $photo (@photos) {
	&$dophoto($photo,$repeat);
      }
    } else {
      my @tempphotos=@photos;
      
      while (@tempphotos) {
	my @thesephotos=();
	my $i=0;
	while($i<$innercount && @tempphotos) {
	  push @thesephotos,shift @tempphotos;
	  $i++;
	}
	
	my $temprepeat=$repeat;
	my ($preinner,$inner,$postinner);
	
	while( ($preinner,$inner,$postinner)
	       =($temprepeat=~/^(.*?)\<inner\>(.*?)\<\/inner\>(.*?)$/si)) {
	  $out.=$preinner;
	  
	  foreach my $photo (@thesephotos) {
	    &$dophoto($photo,$inner);
	  }
	  
	  $count-=scalar @thesephotos;
	  
	  $temprepeat=$postinner;
	}
	$out.=$temprepeat;
	$count+=scalar @thesephotos;
      }
    }
    $template=$post;
  }

  $out.=$template;

  if( $debug == 0 ) {
    # We now know everything for the headers
    &$printheader();
  }

  &$printout($out);

}
