#!/usr/bin/env perl
# Make a zanata.xml for using Zanata.

=pod

=head1 NAME

B<zanata_zanata_xml_make> - Make a zanata.xml for using Zanata

=head1 SYNOPSIS

B<zanata_zanata_xml_make> -h | --help

B<zanata_zanata_xml_make> [options] E<lt>ZanataURLE<gt> [E<lt>projectE<gt> [ E<lt>project-versionE<gt> ] ]

=head1 DESCRIPTION

This program makes zanata.xml according to project information, server supported locales and
local supplied locales.

=head2 Project Information

Project information such as project, project-version and project-type are choose from following order:

1. Command line options

2. zanata.xml from project page if I<ZanataURL>, I<project> and I<project-version> are all given

2. Existing local zanata.xml file

=head2 Server supported locales

Server supported locales, are obtain from sources in following order:

1. zanata.xml from project page if I<ZanataURL>, I<project> and I<project-version> are all given

2. Existing local zanata.xml file

3. Language list page from Zanata server if I<ZanataURL> is given

If none are available, the E<lt>localesE<gt> will not be written to zanata.xml

=head2 Local provided locales

Local provided locales are determined by following:

1. 'locale -a' if B<--mapFromLocale> (-m) is given

2. Local translated file by default

If none are availale, the map-from attribute of E<lt>localeE<gt> will not be written.

The original file will be backed up with '.bak' by default.

=head1 ARGUMENTS

=over 4

=item ZanataUrl

The URL of zanata server, such as 'http://translate.zanata.org/'

=item project

Set project ID.

=item project-version

Set version of the project.

=back

=head1 OPTIONS

=over 4

=item B<-h, --help>:

Print brief help message and exits.

=item B<-m, --mapFromLocale>

Use 'locale -a' for locale mapping instead of finding existing translated files.

This is useful for projects that use the same locale format as 'locale -a', or
new projects that do not have much translation coverge yet.

=item B<-p, --projectType=STRING>

Set the project-type. Valid values are:
'podir', 'gettext', 'properties', 'utf8properties', 'xliff'.

=item B<-b, --baseDir=DIR>

Set the base directory as working directory.
zanata.xml by default is made in this directory,
srcDir and transDir should also related to this directory.

Default is '.'.

=item B<-s, --srcDir=DIR>

Set the source directory.
Source directory is need for some project type (like podir and project-type)
to identify the genuine locale translation files.
Usually this is a directory that contains .pot files.

Either an absolute path or related to the $baseDir

Default is '$baseDir'.

=item B<-t, --transDir=DIR>

Set the translation directory.
Local translation files are searched under this directory and its subdirectories.
Usually this is a directory that contains .po files.

Either an absolute path or related to the $baseDir

Default is '$baseDir'.

=item B<-o, --backupSuffix=STRING>

Set the suffix for backup file.

Default is '.bak'

=item B<-z, --zanataXml=FILE>

Set the output zanata.xml.
Default: ($baseDir/zanata.xml)

=back

=head1 FILES

=item zanata.cfg

Configure file for this program.
Directories will be visited in following order:
'~/.config', '/etc', 'etc' and '.'

See 'man zanata_zanata_xml_make' for more infomation.
=cut

# Ensure it runs on RHEL5
use 5.008_008;
use strict;
use Data::Dumper;
use File::Basename;
use File::Copy;
use File::Find;
use File::Find::Rule;
use File::Spec;
use Getopt::Long;
use Pod::Usage;
## Needed to ensure XML::XPath is listed as a dependency.
use XML::XPath;
use XML::Twig::XPath;
use Cwd;
use lib "lib";
use Zanata::Util;
use Zanata::Util::Locale;
use Zanata::Util::ZanataXML;

# path variables
my $scriptDir=dirname($0);

# Definition
my $zanataNameSpace='http://zanata.org/namespace/config/';

## Parse options
my $help=0;
my %optH=(
    'help' => '\$help'
    , 'baseDir' => '.'
    , 'backupSuffix' => '.bak'
);

GetOptions(\%optH,
    , 'help|h'
    , 'mapFromLocale|m'
    , 'projectType|p=s'
    , 'baseDir|b=s'
    , 'srcDir|s=s'
    , 'transDir|t=s'
    , 'backupSuffix|o=s'
    , 'zanataXml|z=s'
) or pod2usage(-1);

### Display help
pod2usage(1) if $help;
pod2usage( {-verbose=>1}) if @ARGV == 0;

### Setting paths
$optH{'srcDir'}=Zanata::Util::true_path($optH{'baseDir'}, $optH{'srcDir'}, '.');
$optH{'transDir'}=Zanata::Util::true_path($optH{'baseDir'}, $optH{'transDir'}, '.');
$optH{'zanataXml'}=Zanata::Util::true_path($optH{'baseDir'}, $optH{'zanataXml'}, 'zanata.xml');

### Filling projInfo
my %projInfo;
my @argumentList=('url', 'project', 'project-version');
for (my $i=0; $i<$#ARGV+1; $i++){
    $projInfo{$argumentList[$i]}=$ARGV[$i];
    #print "projInfo{". $argumentList[$i]. "}=" . $projInfo{$argumentList[$i]} . "\n";
}
$projInfo{'project-type'}= $optH{'projectType'} if $optH{'projectType'};
#print "projInfo=" . Dumper(%projInfo) . '\n';

### Making zanata.xml
my $twig= XML::Twig::XPath->new(
    twig_handlers =>{
	html => sub {$_->delete()}
    }
    , pretty_print=>'indented');
Zanata::Util::Locale::init();

my %localeH=();

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


## Extract actual mapping from path
sub extract_mapping{
    my ($path)=@_;
    if ($projInfo{'project-type'} eq "gettext" and $path=~/\.po$/){
	$path =~ s/\.po$//;
    }elsif ($projInfo{'project-type'} =~ "\.*properties" and $path=~/\.properties$/){
	$path =~ s/(@[A-Za-z0-9]*)?\.properties$//;
	my @tokens=split(/[_.-]/, $path);
	my $i=-1;
	my $s=$tokens[$i];
	while($tokens[$i]){
	    if (Zanata::Util::Locale::is_locale($tokens[$i])){
		return $s;
	    }
	    $i--;
	    $s=$tokens[$i] . "_" . $s;
	}
	return '';
    }
    return $path;
}


###########################################################
# Main program
#

## If url is given, then connect to zanata to download a new zanata.xml and parse it.

## zanataXmlDownload
## -1: Downloaded but format incorrect
## 0: url is not provided
## 1: Downloaded succeed

my $zanataXml=undef;

## Backup existing zanata.xml
if (-r $optH{'zanataXml'}){
    copy($optH{'zanataXml'}, $optH{'zanataXml'} . $optH{'backupSuffix'});
}

my $zanataUtil=Zanata::Util->init(\%projInfo);

## Try download zanata.xml from server if url is provided.
if ($projInfo{'url'}){
    ## Get the content
    $zanataXml=Zanata::Util::ZanataXML->new_from_url($zanataUtil->{'zanataXmlUrl'});
    warn "[Info] Downloaded from " . $zanataUtil->{'zanataXmlUrl'} . "\n";
}


## If download failed, try existing zanata.xml
if (!$zanataXml and -r $optH{'zanataXml'}){
    warn "[Info] Parsing existing " . $optH{'zanataXml'} ."\n";
    my $content=File::Slurp::read_file($optH{'zanataXml'}) or die "$!";
    $zanataXml=Zanata::Util::ZanataXML->new($content);
}

## If no existing zanata.xml then create a new one.
$zanataXml=Zanata::Util::ZanataXML->new() unless ($zanataXml);

## Fill-in locale from zanata server if zanataXml->locales is empty
unless($zanataXml->get_locales()){
    my $languageHRef=Zanata::Util::Locale::zanata_language_list_parse_locales($zanataUtil);
    if ($languageHRef){
	for my $l (keys %$languageHRef){
	    $zanataXml->update_locale($l);
	}
    }
}

### Fill the project info provided form command line.
for my $f (keys %projInfo){
    $zanataXml->{$f}=$projInfo{$f};
}

############################################################
# Locale mapping
#
my @locales=$zanataXml->get_locales();

## if mapFromLocale is enable, it does not need to search existing traslation
if ($optH{'mapFromLocale'}){

    my %mapFromH={};
    ## Read local locale info to mapFromH
    my @lines=split(/\n/, qx{locale -a});
    for my $line (@lines){
	my @tokens=split(/[.]/, $line);
	next unless $tokens[0] =~ /[_-]/;
	my $mF= $tokens[0];
	$mF=s/-/_/g;
	$mapFromH{$mF}=1;
    }
    for my $l (@locales){
	## Obtain the suggest locales
	my $localeStrLRef=Zanata::Util::Locale::suggest_locales($l);

	for my $lStr (@$localeStrLRef){
	    if (exists $mapFromH{$lStr}){
		## mapFrom found
		$zanataXml->update_locale($l, $lStr);
		last;
	    }
	}
    }

## No need to deal with locale if project-type is not specified.
}elsif ($projInfo{'project-type'}){

    my $dirCompare='';
    if ($projInfo{'project-type'} eq "podir"){
	## Add new locales if pattern appears under $transDir
	$dirCompare=Cwd::abs_path($optH{'srcDir'});
    }

    ## Finding locale mapping
    for my $l (@locales){
	my $pathsRef=undef;

	## Obtain the suggest locales
	my $localeStrLRef=Zanata::Util::Locale::suggest_locales($l);

	## Try the suggest locales until we find a matched path.
	for my $lStr (@$localeStrLRef){
	    #print "lStr=$lStr \n";
	    $pathsRef=Zanata::Util::Locale::find_locale_paths(
		$lStr, $projInfo{'project-type'}
		, Cwd::abs_path($optH{'transDir'}), $dirCompare
	    );
	    if (@$pathsRef){
		last;
	    }
	}

	### pathsRef exists when we found corresponding
	if ($pathsRef){
	    # print "pathsRef[0]=" .$$pathsRef[0] . "\n";

	    ### match path -> mapFrom
	    my $mapFrom=extract_mapping($$pathsRef[0]);

	    ### Update the map-from
	    $zanataXml->update_locale($l, $mapFrom);
	}
    }
}

$zanataXml->to_xml($optH{'zanataXml'});
warn "Done!\n";

