#!perl -w
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
# This script is intended to be called from within the docs build process.
# It gets no parameters.
# It assumes, that the current working directory is the root of the manual.

# The script doesn't use an XML parser (yet?) so care should be taken with
# non-ascii characters.

# TODO:
# - rewrite in java as ant task?

# against fat fingers
use strict;

# for file operations
use FindBin;
use lib $FindBin::Bin;
use Fcntl qw(O_RDONLY O_WRONLY O_CREAT O_TRUNC);
use DocUtil qw(docpath $ignore_files);

# Scratch stuff
my ($ext, $curpath, @mod_files, @suffix);

# get available languages automatically:
# (a) we find out which languages the sitemap provides
# (b) we find out which languages the module files provide
$curpath = docpath();
opendir(DIR, $curpath)
    or die "could not open directory '$curpath' ($!), stopped";

@suffix = map { s/^sitemap\.xml//; $_ }
       grep !/$ignore_files/
    => grep  /^sitemap\.xml/
    => readdir(DIR);

closedir(DIR)
    or die "could not close directory '$curpath' ($!), stopped";

# (b)
$curpath = docpath('mod');
opendir(DIR, $curpath)
    or die "could not open directory '$curpath' ($!), stopped";

@mod_files = grep /\.xml(?:\.[^.]+)?$/
    => grep !/$ignore_files/
    => readdir(DIR);

closedir(DIR)
    or die "could not close directory '$curpath' ($!), stopped";

push @suffix => map { s/^(?:index|directives|quickreference|overrides)\.xml//; $_ }
       grep /^(?:index|directives|quickreference|overrides)\.xml/
    => @{[ @mod_files ]}; # copy, because $_ will be modified inline

# keep only real module files in @mod_files
@mod_files = grep !/^(?:index|directives|quickreference|overrides)\.xml/
    => grep !/-dict\.xml/
    => grep !/^allmodules\.xml/
    => @mod_files;

# now iterate over each unique extension (aka language) and check
# (possible recreate) the particular allmodules.xml file
for $ext (keys %{{map {($_ => undef)} @suffix}}) {
    # the file we finally want to write to
    my $target = docpath("mod/allmodules.xml$ext");

    my @modules;
    if (length($ext)) {
        my %is_translated = map { s/^(.*\.xml).*/$1/; ($_ => 1) }
               grep /\.xml\Q$ext\E$/
            => @{[ @mod_files ]};

        ## write list for dependency evaluation in build.xml
        my $trfile = docpath("mod/.translated$ext");
        sysopen(FILE, $trfile, O_WRONLY | O_CREAT | O_TRUNC)
            or die "could not open '$trfile' for writing ($!), stopped";

        my $content = <<"        TRFILE";
translated=@{[
       join " \\\n\t"
    => sort keys %is_translated
]}
        TRFILE

        print FILE $content
            or die "could not write into '$trfile' ($!), stopped";

        close(FILE)
            or die "could not close '$trfile' after writing ($!), stopped";

        @modules = map { $is_translated{$_} ? "$_$ext" : $_ }
            keys %{{
                map { s/^(.*\.xml).*/$1/; ($_ => undef) } @{[ @mod_files ]}
            }}
    }
    else {
        @modules = grep /\.xml$/ => @mod_files;
    }

    # bring in stable order for better comparison
    @modules = sort stable_order @modules;

    my $content = <<"    XML";
<?xml version="1.0" encoding="UTF-8"?>
<!-- GENERATED FROM XML: DO NOT EDIT -->

<modulefilelist>
  @{[ join "\n  " => map qq{<modulefile>$_</modulefile>} => @modules ]}
</modulefilelist>
    XML

    # now load the current file and get in touch with stored reality
    my $existing = '';
    if (-f $target) {
        local $/; # slurp mode

        sysopen(FILE, $target, O_RDONLY)
            or die "could not open file '$target' ($!), stopped";

        $existing = <FILE>;

        close(FILE)
            or die "could not close file '$target' ($!), stopped";
    }

    # If the stored list doesn't match the computed one,
    # replace the stored list with the computed one.
    unless ($content eq $existing) {
        sysopen(FILE, $target, O_WRONLY | O_CREAT | O_TRUNC)
            or die "could not open file '$target' ($!), stopped";
        
        print FILE $content
            or die "could not write into file '$target' ($!), stopped";

        close(FILE)
            or die "could not close file '$target' ($!), stopped";

        # report success
        print "'allmodules.xml$ext' written.\n";
    }
}

# This sort callback defines a very strict but somewhat
# "natural" sorting order
sub stable_order {
   return -1        if ($a =~ /^core/);
   return  1        if ($b =~ /^core/);
   return $a cmp $b if ($a =~ /^mod_/ and $b =~ /^mod_/);
   return -1        if ($a =~ /^mod_/ and $b !~ /^mod_/);
   return  1        if ($a !~ /^mod_/ and $b =~ /^mod_/);
   (my $x = $a) =~ s/^mpmt?_//;
   (my $y = $b) =~ s/^mpmt?_//;
   return $x cmp $y;
}

__END__
sample file:

<?xml version="1.0" encoding="UTF-8"?>
<!-- GENERATED FROM XML: DO NOT EDIT -->

<modulefilelist>
    <modulefile>core.xml</modulefile>
    <modulefile>mod_actions.xml</modulefile>
    <modulefile>mod_alias.xml</modulefile>
    <!-- ... -->
</modulefilelist>
