#                                                         -*- Perl -*-
# Copyright (c) 2007  Kazuhiro Ito
#
# 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.
# 
# 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.
#

require 5.005;

use English;
use FreePWING::Sound;
use FreePWING::FPWUtils::FPWUtils;
use Getopt::Long;
use warnings;
use FileHandle;
use Compress::Raw::Zlib;

use vars qw ($name_pos $name_size $content_pos $content_size);
use vars qw ($unzipped $zipped $last_unzipped $last_zipped);
use vars qw ($contents);
use vars qw ($content_handle $content_index_handle);
use vars qw ($index_handle $name_handle);
use vars qw (%fpwoald7_conf);

 MAIN: {
   my %tag_table;

#
# ޥɹԤϤ롣
#
   my ($srcdir, $conf_file);

   if (!GetOptions('workdir=s' => \$work_directory, 
		   'srcdir=s' => \$srcdir, 
		   'conf=s' => \$conf_file)) {
     exit 1;
   }

   require $conf_file;

#
# fpwutils 롣
#
   initialize_fpwutils();

#
# 줫Ϥե뤬ǤˤС롣
#
   unlink($sound_file_name);
   unlink($sound_tag_file_name);
   unlink($sound_fmt_file_name);

   $sound = FreePWING::Sound->new();

#
# ¦ե򳫤
#
   if (!$sound->open($sound_file_name,
		     $sound_tag_file_name,
		     $sound_fmt_file_name)) {
     die "$PROGRAM_NAME: " . $sound->error_message() . "\n";
   }

   if($fpwoald7_conf{'enable_sound'} == 0) {
     goto FINISH;
   }

#
# ɤ߹ߥե򳫤
#
   $srcdir =~ s/([^\/])$/$1\//;

   my $tmp;
   my ($content, $content_name);
   my $output_handle;
   my ($tag_name, $image_name);

   initialize_content_reader($srcdir."us/");
   while (1) {
     ($content_name, $content) = get_next_content();
     $content = get_riff_header($content).$content;

     if (!length($content_name)) {
       last;
     }

     if ($content_name =~ /(.+)\.MP3$/) {
       $tag_name = "us_$1";
       $tag_name =~ s/\./_/g;
	
#
# ǡɲä롣
#

       if (!$sound->add_binary($tag_name, $content)) {
	 die "$PROGRAM_NAME: " . $sound->error_message() . "\n";
       }
       if(verbose_mode()) {
	 print "$tag_name -> $content_name\n";
       }
     }
   }
   finalize_content_reader();
   print "US pronunciation sounds are registerd.\n";


   initialize_content_reader($srcdir."uk/");
   while (1) {
     ($content_name, $content) = get_next_content();
     $content = get_riff_header($content).$content;

     if (!length($content_name)) {
       last;
     }

     if ($content_name =~ /(.+)\.MP3$/) {
       $tag_name = "uk_$1";
       $tag_name =~ s/\./_/g;

#
# ǡɲä롣
#
       if (!$sound->add_binary($tag_name, $content)) {
	 die "$PROGRAM_NAME: " . $sound->error_message() . "\n";
       }
       if (verbose_mode()) {
	 print "$tag_name -> $content_name\n";
       }
     }
   }
   finalize_content_reader();
   print "UK pronunciation sounds are registerd.\n";

# 
# ¦եĤ롣
# 
   printf ("%6d sounds ard registered.\n", $sound->entry_count());
 FINISH:
   if (!$sound->close()) {
     die "$PROGRAM_NAME: " . $sound->error_message() . "\n";
   }

#
# fpwutils θ򤹤롣
#
   finalize_fpwutils();

   exit 0;
}

sub initialize_content_reader {
  my $srcdir = $_[0];
  my $content_filename = $srcdir.'CONTENT.tda';
  my $content_index_filename = $srcdir.'CONTENT.tda.tdz';
  my $index_filename = $srcdir.'files.dat';
  my $name_filename = $srcdir.'NAME.tda';
  my $tmp;

  $content_handle = new FileHandle;
  if (!$content_handle->open("$content_filename", 'r')) {
    die "$PROGRAM_NAME: Failed to open the file, $ERRNO: $content_filename\n";
  }
  binmode $content_handle;
    
  $content_index_handle = new FileHandle;
  if (!$content_index_handle->open("$content_index_filename", 'r')) {
    die "$PROGRAM_NAME: Failed to open the file, $ERRNO: $content_index_filename\n";
  }
  binmode $content_index_handle;
    
  $index_handle = new FileHandle;
  if (!$index_handle->open("$index_filename", 'r')) {
    die "$PROGRAM_NAME: Failed to open the file, $ERRNO: $index_filename\n";
  }
  binmode $index_handle;

  $name_handle = new FileHandle;
  if (!$name_handle->open("$name_filename", 'r')) {
    die "$PROGRAM_NAME: Failed to open the file, $ERRNO: $name_filename\n";
  }
  binmode $name_handle;

  ($name_size, $content_size) = (0, 0);
  ($unzipped, $zipped) = (0, 0);
  ($last_zipped, $last_unzipped) = (0, 0);

  ($name_pos, $content_pos) = get_next_index();
  if($name_pos == -1) {
    die "$PROGRAM_NAME: Unexpected index end.\n";
  }

  return 0;
}

sub finalize_content_reader {
  $content_handle->close();
  $content_index_handle->close();
  $index_handle->close();
  $name_handle->close();

  return 0;
}

sub get_next_index {
  my ($name, $content, $i, $tmp);
  if (read($index_handle, $tmp, 12) == 12) {
    ($name, $i, $content) = unpack("vCxxV", $tmp);
    $name += ($i << 16);
  } else {
    # ǽȥ
    ($name, $content) = (-1, -1);
  }

  return ($name, $content);
}

sub get_next_content {
  my $tmp;
  my ($inflater, $status);
  my ($content_name, $content);

  if($name_size == -1) {
    return ('', '');
  }

  $name_pos += $name_size;
  $content_pos += $content_size;

  ($name_size, $content_size) = get_next_index();
    
  if ($name_size != -1) {
    $name_size -= $name_pos;
    $content_size -= $content_pos;
  }

  if ($unzipped + $last_unzipped <= $content_pos) {
    if (read($content_index_handle, $tmp, 8) != 8) {
      die "$PROGRAM_NAME: Unexpected index structure.\n";
    }
    $unzipped += $last_unzipped;
    $zipped += $last_zipped;
    ($last_unzipped, $last_zipped) = unpack("VV", $tmp);
    if (read($content_handle, $tmp, $last_zipped) != $last_zipped) {
      die "$PROGRAM_NAME: failed to read file\n";
    }
    ($inflater, $status) = new Compress::Raw::Zlib::Inflate();
    if ($status != Z_OK) {
      die "$PROGRAM_NAME: Failed to initialize inflater\n";
    }
    $status = $inflater->inflate($tmp, $contents);
    if ($status != Z_OK && $status != Z_STREAM_END) {
      # Do not die, because original data is incorrect.
      print "$PROGRAM_NAME: warning, failed to inflate, $status\n";
    }
  }

  # ե̾롣
  if ($name_size != -1) {
    if (read($name_handle, $content_name, $name_size) != $name_size) {
      die "$PROGRAM_NAME: failed to read file\n";
    }
  } else {
    if (read($name_handle, $content_name, 1024) == 0) {
      die "$PROGRAM_NAME: failed to read file\n";
    }
  }
  $content_name = substr($content_name, 0, -1);

  # ƥȤ롣
  if ($content_size != -1) {
    $content = substr($contents, $content_pos - $unzipped, $content_size - 1);
  } else {
    $content = substr($contents, $content_pos - $unzipped, -1);
  }

  return ($content_name, $content);
}

sub get_riff_header {
  my $length = length($_[0]);
  my $header = "RIFF";

  $header .= pack("V", $length + 70 - 8);
  $header .= "WAVEfmt ";
  $header .= pack("V", 30);
  $header .= pack("v", 0x55);
  $header .= pack("v", 0x01);
  $header .= pack("V", 16 * 1000);
  $header .= pack("V", 24 * 1000 / 8);
  $header .= pack("v", 1);
  $header .= pack("v", 0);
  $header .= pack("v", 12);
  $header .= pack("v", 1);
  $header .= pack("V", 2);
  $header .= pack("v", 216);
  $header .= pack("v", 1);
  $header .= pack("v", 0x571);

  $header .= "fact";
  $header .= pack("V", 4);
  $header .= pack("V", $length / 108);

  $header .= "data";
  $header .= pack("V", $length);

  return $header;
}
