#!/usr/bin/perl -w

#*****************************************************************************
# 
#  install-dict - Script to update dictionaries configuration for OpenOffice.org
# 
#  Initial version by: Federico Mena Quintero <federico@ximian.com>
#  Future improvements by: Michael Meeks <michael.meeks@novell.com>
#			   Petr Mladek <pmladek@suse.cz>
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License version 2, as
#  published by the Free Software Foundation.
# 
#  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.
# 
#*****************************************************************************

use strict;
use File::Temp qw/ tempfile /;

my $Debug = $ENV{'OOO_DEBUG'};
my $DefaultDictDir = '/usr/lib64/ooo-2.3/share/dict/ooo';

if ($Debug && $DefaultDictDir =~ /^\@/) {
    $DefaultDictDir = '/usr/lib/ooo-2.1/share/dict/ooo';
}

my $DefaultSharedDictDir = "/usr/share/myspell";


sub usage() {
    print "This tool symlinks OpenOffice.org dictionaries from the given shared location\n" .
          "to the OpenOffice.org home. It also updates the related config file.\n\n" .
	  
	  "Usage:\n" . 
	  "\tinstall-dict [-r] [-s shared_dict_dir] [ooo_dict_dir]\n\n" .
	  
	  "Options:\n" .
	  "\t-r just remove unused symlinks and update config file\n" .
	  "\t-s allow to redefine the default directory for shared dictionaries\n";
}

# simply remove all invalid symlinks from the given directory
sub remove_unused_symlinks {
    my $dir = shift;
    my $dirhandle;
    my $fname;

    opendir ($dirhandle, $dir) || die "can't opendir $dir: $!";
    while ($fname = readdir ($dirhandle)) {
	unless (-r "$dir/$fname") {
	    (unlink "$dir/$fname") || die "can't unlink $dir/$fname: $!";
	}
    }
    closedir ($dirhandle);
}

# create the symlink if it does already not exist
sub update_symlink($$) {
    my ($target, $link_name) = @_;
    unless (-r "$link_name") {
	symlink ("$target", "$link_name") || die "can't crate symlink $link_name -> $target: $!";
    }
}

# create symlinks from the OOo tree to the shared dictionaries
sub link_shared_dict_files {
    my ($shared_dict_dir, $dict_dir) = @_;
    return unless -d $shared_dict_dir;

    my $shared_dicts = get_dicts ("$shared_dict_dir");
    foreach my $dict (keys %$shared_dicts) {
	if ($dict =~ m/^[a-z]+(_[A-Z]+)?$/) {
	    update_symlink("$shared_dict_dir/$dict.dic", "$dict_dir/$dict.dic");
	    update_symlink("$shared_dict_dir/$dict.aff", "$dict_dir/$dict.aff");
	} elsif ($dict =~ m/^hyph_[a-z]+(_[A-Z]+)?$/) {
	    update_symlink("$shared_dict_dir/$dict.dic", "$dict_dir/$dict.dic");
	} elsif ($dict =~ m/^th_[a-z]+(_[A-Z]+)?(_v2)?$/) {
	    update_symlink("$shared_dict_dir/$dict.dat", "$dict_dir/$dict.dat");
	    update_symlink("$shared_dict_dir/$dict.idx", "$dict_dir/$dict.idx");
	}
    }
}

# change extesion of a filename
sub change_extension {
    my ($filename, $ext, $newext) = @_;

    $filename =~ s/^(.*)\.($ext)$/$1\.$newext/g;
    return $filename;
}

# get list of installed dictionaries
sub get_dicts($)
{
    my $dir = shift;
    my $dirhandle;
    my $fname;
    my %dicts = ();

    opendir ($dirhandle, $dir) || die "can't opendir $dir: $!";
    while ($fname = readdir ($dirhandle)) {
	if ($fname =~ m/^([a-z]+(_[A-Z]+)?)\.dic$/) {
	    if (-f "$dir/" . change_extension ($fname, "dic", "aff")) {
		$dicts{$1}=0;
	    }
	} elsif ($fname =~ m/^(hyph_[a-z]+(_[A-Z]+)?)\.dic$/) {
		$dicts{$1}=0;
	} elsif ($fname =~ m/^(th_[a-z]+(_[A-Z]+)?(_v2)?)\.dat$/) {
	    if (-f "$dir/" . change_extension ($fname, "dat", "idx")) {
		$dicts{$1}=0;
	    }
	}
    }
    closedir ($dirhandle);
    return \%dicts;
}


# just read the old config file in an array
sub read_config_file($) {
    my $config_filename = shift;
    my @config =();
    
    -e $config_filename || return;
    open (CONFIG_FILE, $config_filename) || die "can't open $config_filename for reading: $!\n";

    while (my $line = <CONFIG_FILE>) {
	chomp $line;
	push @config, $line;
    }
    close CONFIG_FILE;
    return \@config;
}

sub write_heared_config($) {
    my $CONFIG_FILE = shift;

    print $CONFIG_FILE '# List of All Dictionaries to be Loaded by OpenOffice' . "\n" .
		       '# ---------------------------------------------------' . "\n" .
		       '# Each Entry in the list have the following space delimited fields' . "\n" .
		       '#' . "\n" .
		       '# Field 1: Entry Type "DICT" - spellchecking dictionary' . "\n" .
		       '#                     "HYPH" - hyphenation dictionary' . "\n" .
		       '#                     "THES" - thesaurus files' . "\n" .
		       '#' . "\n" .
		       '# Field 2: Language code from Locale "en" or "de" or "pt" ...' . "\n" .
		       '#' . "\n" .
		       '# Field 3: Country Code from Locale "US" or "GB" or "PT"' . "\n" .
		       '#' . "\n" .
		       '# Field 4: Root name of file(s) "en_US" or "hyph_de" or "th_en_US"' . "\n" .
		       '#          (do not add extensions to the name)' . "\n\n";
}

# write the old config file back but remove unused or invalid lines
sub write_fixed_old_config($$$) {
    my ($dicts_ref, $old_config_ref, $CONFIG_FILE) = @_;

    foreach my $line (@$old_config_ref) {
	if ($line =~ m/^\s*DICT\s*([a-z]+)\s+([A-Z]+)\s+([a-z]+(_[A-Z]+)?)\s*$/) {
	    if (defined $dicts_ref->{$3}) {
		# dictionary file exists, so the config line can be used
		print $CONFIG_FILE "$line\n";
		# mark this dictionary configured
		$dicts_ref->{$3}=1;
	    }
	} elsif ($line =~ m/^\s*HYPH\s*([a-z]+)\s+([A-Z]+)\s+(hyph_[a-z]+(_[A-Z]+)?)\s*$/) {
	    if (defined $dicts_ref->{$3}) {
		# dictionary file exists, so the config line can be used
		print $CONFIG_FILE "$line\n";
		# mark this dictionary configured
		$dicts_ref->{$3}=1;
	    }
	} elsif ($line =~ m/^\s*THES\s*([a-z]+)\s+([A-Z]+)\s+(th_[a-z]+(_[A-Z]+)?(_v2)?)\s*$/) {
	    if (defined $dicts_ref->{$3}) {
		# dictionary file exists, so the config line can be used
		print $CONFIG_FILE "$line\n";
		# mark this dictionary configured
		$dicts_ref->{$3}=1;
	    }
	} elsif ($line =~ m/^\s*\#.*/ || $line =~ m/^\s*$/) {
	    print $CONFIG_FILE "$line\n";
	}
    }
}

# add entry for the not yet configured dictionaries
sub write_missing_config($$) {

    my ($dicts_ref, $CONFIG_FILE) = @_;

    foreach my $dict (sort(keys %$dicts_ref)) {
	next if ($dicts_ref->{$dict});
	
	if ($dict =~ m/^([a-z]+)_([A-Z]+)$/) {
	    print $CONFIG_FILE "DICT $1 $2 $1_$2\n";
	} elsif ($dict =~ m/^hyph_([a-z]+)_([A-Z]+)$/) {
	    print $CONFIG_FILE "HYPH $1 $2 hyph_$1_$2\n";
	} elsif ($dict =~ m/^th_([a-z]+)_([A-Z]+)(_v2)?$/) {
	    if (defined $3) {
		print $CONFIG_FILE "THES $1 $2 th_$1_$2$3\n";
	    } else {
		print $CONFIG_FILE "THES $1 $2 th_$1_$2\n";
	    }
	}
    }
}

sub write_config_file($$$) {
    my ($config_filename, $dicts_ref, $old_config_ref)  = @_;
    my $CONFIG_FILE;

    my $write_header=0;
    $write_header=1 unless (-f $config_filename);
    chmod 0644, $config_filename unless (! -f $config_filename);
    open ($CONFIG_FILE, ">$config_filename") || die "can't open $config_filename for writing: $!\n";

    write_heared_config($CONFIG_FILE) if ($write_header);
    write_fixed_old_config($dicts_ref, $old_config_ref, $CONFIG_FILE);
    write_missing_config($dicts_ref, $CONFIG_FILE);

    close CONFIG_FILE;
}    


######################################################################
###########################      MAIN    #############################
######################################################################

my $SharedDictDir = $DefaultSharedDictDir;
my $DictDir = $DefaultDictDir;
my $doLink=1;

while (my $a = shift) {
    if ("$a" eq '--help') {
	usage;
	exit 0;
    } elsif ("$a" eq '-r') {
	$doLink=0;
    } elsif ("$a" eq '-s') {
	$a = shift;
	defined $a && -d "$a" || die "Error: Parameter for the -s option must be a directory.\n";
	$SharedDictDir="$a";
    } else {
	-d "$a" || die "Error: \"$a\" is not an existing  directory\n";
	$DictDir="$a"
    }
}

my $ConfigFilename = $DictDir . "/dictionary.lst";

remove_unused_symlinks ($DictDir);
link_shared_dict_files ($SharedDictDir, $DictDir) if ($doLink);

my $DictsRef = get_dicts ($DictDir);
my $OldConfigRef = read_config_file($ConfigFilename);
write_config_file($ConfigFilename, $DictsRef, $OldConfigRef);
