#!/usr/bin/perl -w

# This Perl program creates a makefile ($out_mak) out of the
# configuration file ($in_cfg).


##################################################
# Configuration variables
#

# Input configuration file
my $in_cfg    = "modules.cfg";

# Output directory for C headers and sources
my $c_src_dir = "c_src";

# Output directory for Symbian project file (.mmp)
my $group_dir = "group";

# Makefile to create
my $out_mak   = "libstemmer.mak";

# Modules C header file to create
my $out_mod   = "$c_src_dir/cpix_modules.h";

# Symbian project file to create (.mmp)
my $out_mmp   = "$group_dir/libstemmer.mmp";



##################################################
# Global variables
#

# names of algorithms
my %algorithms = ();

# lists of encodings associates to algorithms
my %algorithm_encs = ();

# list of all encodings
my %encs = ();

# algorithms and their alias
my %aliases = ();



##################################################
# Subroutines
#

# Adds an algorithm / encoding pair to the algorithm_encs structure
sub addAlgEnc($$)
{
  local $alg = shift();
  local $enc = shift();

  if (defined $algorithm_encs{$alg}) {
      local $hashref = $algorithm_encs{$alg};
      $$hashref{$enc}=1;
  } else {
      local %newhash = ($enc => 1);
      $algorithm_encs{$alg}=\%newhash;
  }

  $encs{$enc} = 1;
}


# Reads the configuration
sub readConfig()
{
    open(IN_CFG, $in_cfg) or die "Can't open config file $in_cfg: $!\n";
    local $line;
    while ($line = <IN_CFG>)
    {
        next if $line =~ m/^\s*#/;
        next if $line =~ m/^\s*$/;
        
        local ($alg,$encstr,$alias) = split(/\s+/, $line);
        local $enc;
        
        $algorithms{$alg} = 1;
        $aliases{$alg} = $alias;
        foreach $enc (split(/,/,$encstr))
        {
            addAlgEnc($alg, $enc);
        }
    }
    close(IN_CFG);
}


# Generates a rule for a particular language - encoder tuple
sub generateRuleFor($$)
{
    local $alg = shift();
    local $enc = shift();

    local $utf8Option = "";
    local $sblFile = "algorithms\\$alg\\stem_$enc.sbl";

    if ($enc eq "UTF_8")
    {
        $utf8Option = " -u";

        $sblFile = "algorithms\\$alg\\stem_Unicode.sbl";
        local $iso8859_1 = "algorithms\\$alg\\stem_ISO_8859_1.sbl";
        
        # If the Unicode algorithm does not exist, but the ISO-8859-1
        # does, then we copy the ISO-8859-1 algorithm with the unicode
        # name, as it will do (ISO-8859-1 is a subset of unicode)
        if ( ! -f $sblFile && -f $iso8859_1) {
            print OUT_MAK "$sblFile: $iso8859_1\n";
            print OUT_MAK "\tcopy $iso8859_1 $sblFile\n";
            print OUT_MAK "\n";
        }
    }
    
    local $outFile = "$c_src_dir\\stem_${enc}_$alg";

    print OUT_MAK "\n# rule for generating C sources for $alg ($enc)\n";
    print OUT_MAK "$outFile.c $outFile.h: $sblFile snowball.exe\n";
    print OUT_MAK "\tsnowball.exe $sblFile -o $outFile -eprefix ${alg}_${enc}_ -r ..\\runtime $utf8Option\n";
    print OUT_MAK "\n";
}


# Generates the rules for each language - encoding tuple
sub createSnowballRules()
{
    local $alg;

    foreach $alg (sort keys(%algorithms)) {
        local $encs = $algorithm_encs{$alg};
        local $enc;
        foreach $enc (sort keys(%$encs))
        {
            generateRuleFor($alg, $enc);
        }
    }
}


# Creates the rule for the C sources that should be generated
sub createCSourcesRule()
{
    print OUT_MAK "ALL_CSOURCES = ";

    local $alg;
    local $needNewline = 0;

    foreach $alg (sort keys(%algorithms)) {
        local $encs = $algorithm_encs{$alg};
        local $enc;
        foreach $enc (sort keys(%$encs))
        {
             
            print OUT_MAK " \\\n   " if $needNewline;
            print OUT_MAK "$c_src_dir\\stem_${enc}_${alg}.c $c_src_dir\\stem_${enc}_${alg}.h";
            $needNewline = 1;
        }
    }

    print OUT_MAK "\n\n";
}



# Creates the modules.h file that will serve part of the libstemmer
# library
sub createModulesFile()
{
    open (OUT_MOD, ">$out_mod") or die "Can't open output file `$out_mod': $!\n";

    print OUT_MOD <<EOS;
/* List of stemming modules.
 *
 * This file is generated by $0 from a list of module names in $in_cfg.
 * Do not edit manually.
 *
 */
EOS

    local $alg;
    local $enc;
    local @sortedAlgs = sort keys(%algorithms);
    foreach $alg (@sortedAlgs) {
        my $hashref = $algorithm_encs{$alg};
        foreach $enc (sort keys (%$hashref)) {
            print OUT_MOD "#include \"..\\$c_src_dir\\stem_${enc}_$alg.h\"\n";
        }
    }

    print OUT_MOD <<EOS;

typedef enum {
  ENC_UNKNOWN=0,
EOS

    local $needNewline = 0;
    for $enc (sort keys %encs) {
        print OUT_MOD ",\n" if $needNewline;
        print OUT_MOD "  ENC_${enc}";
        $needNewline = 1;
    }

    print OUT_MOD <<EOS;

} stemmer_encoding_t;

struct stemmer_encoding {
  const char * name;
  stemmer_encoding_t enc;
};
static struct stemmer_encoding encodings[] = {
EOS

    # TODO FIXME CONTINUE HERE *****

    for $enc (sort keys %encs) {
        print OUT_MOD "  {\"${enc}\", ENC_${enc}},\n";
    }
    print OUT_MOD <<EOS;
  {0,ENC_UNKNOWN}
};

struct stemmer_modules {
  const char * name;
  stemmer_encoding_t enc; 
  struct SN_env * (*create)(void);
  void (*close)(struct SN_env *);
  int (*stem)(struct SN_env *);
};

static struct stemmer_modules modules[] = {
EOS

    foreach $alg (sort keys(%aliases)) {
        local $alias = $aliases{$alg};
        local $hashref = $algorithm_encs{$alg};
        local $enc;
        foreach $enc (sort keys(%$hashref))
        {
            local $p = "${alg}_${enc}";
            print OUT_MOD "  {\"$alias\", ENC_$enc, ${p}_create_env, ${p}_close_env, ${p}_stem},\n";
        }
    }
    
    print OUT_MOD <<EOS;
  {0,ENC_UNKNOWN,0,0,0}
};

static const char * algorithm_names[] = {
EOS
    
    foreach $alg (@sortedAlgs) {
        print OUT_MOD "  \"$alg\", \n";
    }
    
    print OUT_MOD <<EOS;
  0
};
EOS

    close (OUT_MOD);
}



# Creates the Symbian project file
sub createMmpFile()
{
    open(OUT_MMP, ">$out_mmp") or die "Can't open $out_mmp for writing: $!\n";

    print OUT_MMP <<EOS;
/*
============================================================================
 Name        : libstemmer.mmp
 Author	     : 
 Copyright   : ??? FIX TODO
 Description : This is the project specification for libstemmer library
               This file is generated - do not edit manually!
               See $0 and $in_cfg.
============================================================================
*/


OPTION CW -wchar_t on


TARGET		  libstemmer.lib
TARGETTYPE	  lib


USERINCLUDE	 ..\\runtime
USERINCLUDE	 ..\\include
USERINCLUDE	 ..\\c_src

SYSTEMINCLUDE    \\epoc32\\include
SYSTEMINCLUDE    \\epoc32\\include\\stdapis
SYSTEMINCLUDE    \\epoc32\\include\\osextensions\\stdapis
SYSTEMINCLUDE    \\epoc32\\include\\osextensions\\stdapis\\stlport


SOURCEPATH	  ..\\runtime
SOURCE    	  api.c
SOURCE    	  utilities.c

SOURCEPATH        ..\\libstemmer
SOURCE            libstemmer.c

SOURCEPATH	  ..\\c_src
EOS

    local $alg;

    foreach $alg (sort keys(%algorithms)) {
        local $encs = $algorithm_encs{$alg};
        local $enc;
        foreach $enc (sort keys(%$encs))
        {
            print OUT_MMP "SOURCE            stem_${enc}_$alg.c\n";
        }
    }

    close(OUT_MMP);
}


# Creates the makefile that will generate the C sources
sub createMakFile()
{
    open(OUT_MAK, ">$out_mak") or die "Can't open $out_mak for writing: $!\n";

    print OUT_MAK <<EOS;
#
# This makefile was generated by $0 based on $in_cfg.
# It
#   (a) generates .c / .h into $c_src_dir using snowball
#   (b) generates .mmp file for Symbian build
#

EOS

    createCSourcesRule();

    print OUT_MAK <<EOS;

# main target
all: \$(ALL_CSOURCES)

EOS

    createSnowballRules();


    close(OUT_MAK);
}


##################################################
# Main
#
readConfig();
createMakFile();
createModulesFile();
createMmpFile();
