#!/usr/bin/perl
# Copyright 2006-2012 Xavier Guerrin
# This file is part of QElectroTech.
# 
# QElectroTech 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 of the License, or
# (at your option) any later version.
# 
# QElectroTech 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 QElectroTech.  If not, see <http://www.gnu.org/licenses/>.

# This script analyzes a QElectroTech Subversion working directory in order to
# output statistics on the translation progress. The output is a table
# conforming to the Dokuwiki syntax, as configured on qelectrotech.org/wiki.
# Typical usage: misc/translations_stat.pl

use strict;
use utf8;
use File::Find;
binmode(STDOUT, ":utf8");

# Configuration
our $working_directory = '.';

my $ok = '[ok]';
my $no = '[no]';
my $todo = 'TODO';

our $default_language = 'fr';
our @misc_desktop_files = qw(misc/qelectrotech.desktop);
our @misc_xml_files     = qw(misc/qelectrotech.xml);
our @readme_files       = qw(CREDIT README INSTALL ELEMENTS.LICENSE build-aux/linux/fedora/README.elements);
our @ordered_languages  = qw(fr en es pt cs pl ca de it ar sl hr el nl be ru ro da pt_br hu sr tr nb ja mn);
our %languages = (
	'fr' => {
		'name'               => 'Français',
		'french_name'        => 'Français',
		'translator_name'    => 'Laurent Trinques',
		'translator_mail_ml' => 'scorpio@qelectrotech.org',
		'qt'                 => 1
	},
	'en' => {
		'name'               => 'English',
		'french_name'        => 'Anglais',
		'translator_name'    => 'Laurent Trinques',
		'translator_mail_ml' => 'scorpio@qelectrotech.org',
		'qt'                 => 1,
		'unix_manual'        => 1,
		'desktop_progress_summary' => $ok,
		'xml_progress_summary' => $ok
	},
	'es' => {
		'name'               => 'Español',
		'french_name'        => 'Espagnol',
		'translator_name'    => 'Alfredo Carreto',
		'translator_mail_ml' => 'electronicos_mx@yahoo.com.mx',
		'qt'                 => 1
	},
	'ru' => {
		'name'               => 'Русский',
		'french_name'        => 'Russe',
		'translator_name'    => 'Yuriy Litkevich & Evgeny Kozlov',
		'translator_mail_ml' => 'evgeny@qelectrotech.org',
		'qt'                 => 1
	},
	'pt' => {
		'name'               => 'Português',
		'french_name'        => 'Portugais',
		'translator_name'    => 'Jose Carlos Martins',
		'translator_mail_ml' => 'jose@qelectrotech.org',
		'qt'                 => 1
	},
	'cs' => {
		'name'               => 'český',
		'french_name'        => 'Tchèque',
		'translator_name'    => 'Pavel Fric',
		'translator_mail_ml' => 'pavelfric@seznam.cz',
		'qt'                 => 1
	},
	'pl' => {
		'name'               => 'Polski',
		'french_name'        => 'Polonais',
		'translator_name'    => 'Pawel Smiech',
		'translator_mail_ml' => 'pawel32640@gmail.com',
		'qt'                 => 1
	},
	'ca' => {
		'name'               => 'Català',
		'french_name'        => 'Catalan',
		'translator_name'    => 'Youssef Ouamalkran & Eduard Amoros',
		'translator_mail_ml' => 'youssefsan@gmail.com',
		'qt'                 => 1
	},
	'ro' => {
		'name'               => 'Română',
		'french_name'        => 'Roumain',
		'translator_name'    => 'Gabi Mandoc & Titus',
		'translator_mail_ml' => 'gabriel.mandoc@gic.ro',
		'qt'                 => 0
	},
	'de' => {
		'name'               => 'Deutsch',
		'french_name'        => 'Allemand',
		'translator_name'    => 'Markus Budde & Jonas Stein &  Noah Braden &  Nuri',
		'translator_mail_ml' => 'markus.budde@msn.com',
		'qt'                 => 1
	},
	'it' => {
		'name'               => 'Italiano',
		'french_name'        => 'Italien',
		'translator_name'    => 'Alessandro Conti & Silvio Brera',
		'translator_mail_ml' => 'dr.slump@alexconti.it',
		'qt'                 => 1
	},
	'ar' => {
		'name'               => 'العربية',
		'french_name'        => 'Arabe',
		'translator_name'    => 'Mohamed Souabni',
		'translator_mail_ml' => 'souabnimohamed@yahoo.fr',
		'qt'                 => 1
	},
	'sl' => {
		'name'               => 'Slovenski',
		'french_name'        => 'Slovene',
		'translator_name'    => 'Uroš Platiše',
		'translator_mail_ml' => 'uros.platise@energycon.eu',
		'qt'                 => 1
	},
	'hr' => {
		'name'               => 'Hrvatski',
		'french_name'        => 'Croate',
		'translator_name'    => 'Antun Marakovic',
		'translator_mail_ml' => 'antun.marakovic@lolaribar.hr',
		'qt'                 => 1
	},
	'el' => {
		'name'               => 'ελληνικά',
		'french_name'        => 'Grec',
		'translator_name'    => 'Nikos Papadopoylos &  Yannis Gyftomitros',
		'translator_mail_ml' => '231036448@freemail.gr',
		'qt'                 => 1
	},
	'nl' => {
		'name'               => 'Nederlands',
		'french_name'        => '‎Néerlandais',
		'translator_name'    => 'Paul Van Deelen & Elbert',
		'translator_mail_ml' => 'shooter@home.nl',
		'qt'                 => 1
	},
	'be' => {
		'name'               => 'Belgium-Flemish',
		'french_name'        => 'Belge-flamand',
		'translator_name'    => 'Ronny Desmedt',
		'translator_mail_ml' => 'r.desmedt@live.be',
		'qt'                 => 1
	},
	'da' => {
		'name'               => 'Dansk',
		'french_name'        => 'Danois',
		'translator_name'    => 'ossau2mation',
		'translator_mail_ml' => '',
		'qt'                 => 1
	},
	'pt_br' => {
		'name'               => 'Brasileiro',
		'french_name'        => 'Brésilien',
		'translator_name'    => 'Hilario & Thiago Cruz',
		'translator_mail_ml' => '',
		'qt'                 => 1
	},
	'hu' => {
		'name'               => 'Magyar',
		'french_name'        => 'Hongrois',
		'translator_name'    => 'Gábor Gubányi',
		'translator_mail_ml' => 'gubanyig@gmail.com',
		'qt'                 => 1
	},
	'sr' => {
		'name'               => 'српски',
		'french_name'        => 'Serbe',
		'translator_name'    => '',
		'translator_mail_ml' => '',
		'qt'                 => 1
	},
	'tr' => {
		'name'               => 'Türk',
		'french_name'        => 'Turc',
		'translator_name'    => 'Aziz & Emir',
		'translator_mail_ml' => 'aziz.karabudak@argevi.com',
		'qt'                 => 1
	},
	'nb' => {
		'name'               => 'Norwegian',
		'french_name'        => 'Norvege',
		'translator_name'    => 'JoelAs',
		'translator_mail_ml' => '',
		'qt'                 => 1
	},
	'ja' => {
		'name'               => '日本語',
		'french_name'        => 'Japonais',
		'translator_name'    => 'Yuki',
		'translator_mail_ml' => 'yuki.atoh@gmail.com',
		'qt'                 => 1,
		'desktop_progress_summary' => $ok,
		'xml_progress_summary' => $ok
	},
	'mn' => {
		'name'               => 'Монгол',
		'french_name'        => 'Mongol',
		'translator_name'    => 'Nathalie',
		'translator_mail_ml' => 'nathalie.roussier@giz.de>',
		'qt'                 => 1,
	}
);

my $head_pattern = '^ %-32s ^ %-22s ^ %-8s ^ %-16s ^ %-16s ^ %-23s ^ %-20s ^ %-11s ^ %-7s ^ %-7s ^ %-7s ^ %-16s ^ %-38s ^'."\n";
my $line_pattern = $head_pattern;
$line_pattern =~ s/\^/\|/g;

# Functions
sub get_pattern_count_in_file {
	my $count = 0, my %params = @_;
	return -3 if (!defined($params{'pattern'}));
	return -2 if (!defined($params{'file'}) || ! -f $params{'file'});
	return -1 if (!open(my $fh, '<', $params{'file'}));
	while (<$fh>) {
		++ $count if (/$params{'pattern'}/);
		last if (defined($params{'limit'}) && $count == $params{'limit'});
	}
	close($fh);
	return $count;
}

sub analyze_element_file {
	return if (($File::Find::name =~ m/\.svn/) || (! -f $_));
	return if ($_ !~ m/(^qet_directory|\.elmt)$/);
	
	# One more element, count it
	our $elements_count;
	++ $elements_count;
	
	# Reports translation stat into the %languages hash
	my $file = $_;
	our %languages;
	for my $lang_key (our @ordered_languages) {
		my $translations_count = get_pattern_count_in_file('file' => $file, 'pattern' => sprintf('<name\s+lang="%s"\s*>', $lang_key));
		if ($translations_count == 1) {
			++ $languages{$lang_key}{'translated_elements_count'};
		} elsif ($translations_count > 1) {
			print STDERR "Multiple translation in $File::Find::name\n";
		}
	}
}

# Action
chdir($working_directory) or die(sprintf('could not chdir to %s', $working_directory));

# Store the total number of elements
our $elements_count = 0;

# Analyze the elements collection
finddepth(\&analyze_element_file, 'elements');

# Complete the "languages" hash with statistics
for my $lang_key (@ordered_languages) {
	my $lang = $languages{$lang_key};
	
	# strings statistics
	my $ts_file = sprintf('lang/qet_%s.ts', $lang_key);
	my $a = $lang->{'translated_strings_count'} = get_pattern_count_in_file('file' => $ts_file, 'pattern' => '<translation>');
	my $b = $lang->{'strings_count'}            = get_pattern_count_in_file('file' => $ts_file, 'pattern' => '<translation');
	my $c = $lang->{'strings_progress'}         = $b ? ($a / $b * 100) : 0;
	if ($lang->{'default'} || ($b && $a == $b)) {
		$lang->{'strings_progress_summary'} = $ok;
	} else {
		$lang->{'strings_progress_summary'} = sprintf('%i/%i (%.1f%%)', $a, $b, $c);
	}
	
	# elements statistics
	my $d = our $elements_count;
	my $e = $lang->{'translated_elements_count'};
	my $f = $lang->{'elements_progress'} = $d ? ($e / $d * 100) : 0;
	if ($d && $d == $e) {
		$lang->{'elements_progress_summary'} = $ok;
	} else {
		$lang->{'elements_progress_summary'} = sprintf('%i/%i (%.1f%%)', $e, $d, $f);
	}
	
	# misc files statistics
	if (!defined($lang->{'desktop_progress_summary'})) {
		my $desktop_count = 0;
		for my $desktop_file (@misc_desktop_files) {
			++ $desktop_count if (get_pattern_count_in_file('file' => $desktop_file, 'pattern' => sprintf('Comment\[%s.*\]', $lang_key), 'limit' => 1) == 1);
		}
		if (@misc_desktop_files && @misc_desktop_files == $desktop_count) {
			$lang->{'desktop_progress_summary'} = $ok;
		} else {
			$lang->{'desktop_progress_summary'} = sprintf('%i/%i', $desktop_count, scalar(@misc_desktop_files));
		}
	}
	
	# misc files statistics
	if (!defined($lang->{'xml_progress_summary'})) {
		my $xml_count = 0;
		for my $xml_file (@misc_xml_files) {
			++ $xml_count if (get_pattern_count_in_file('file' => $xml_file, 'pattern' => sprintf('xml:lang="%s.*"', $lang_key), 'limit' => 1) == 1);
		}
		if (@misc_xml_files && @misc_xml_files == $xml_count) {
			$lang->{'xml_progress_summary'} = $ok;
		} else {
			$lang->{'xml_progress_summary'} = sprintf('%i/%i', $xml_count, scalar(@misc_xml_files));
		}
	}
	
	# Unix manual
	if (!defined($lang->{'unix_manual'})) {
		$lang->{'unix_manual'} = 0;
		if (opendir(my $man_dh, 'man/files')) {
			for my $dir (grep { /^($lang_key(?:\..+)?)$/ } readdir($man_dh)) {
				if (-f 'man/files/'.$dir.'/man1/qelectrotech.1') {
					$lang->{'unix_manual'} = 1;
					last;
				}
			}
			closedir($man_dh);
		}
	}
	
	# CREDIT README INSTALL ELEMENTS.LICENSE files statistics
	for my $file (@readme_files) {
		if (!defined($lang->{$file})) {
			my $header_count = get_pattern_count_in_file(
				'file' => $file,
				'pattern' => sprintf('^\[%s\]$', $lang_key),
				'count' => 1
			);
			$lang->{$file} = ($header_count == 1) ? 1 : 0;
		}
	}
}

# Render a Dokuwiki table displaying the computed statistics
printf($head_pattern, 'Langue', 'Traducteur', 'Qt', 'Application', 'Collection', 'Fichiers misc/*.desktop', 'Fichiers misc/*.xml', 'Manuel Unix', @readme_files);
for my $lang_key (@ordered_languages) {
	my $lang = $languages{$lang_key};
	my @readme_values = ();
	for my $file (@readme_files) {
		push(@readme_values, $lang->{$file} ? $ok : $todo);
	}
	printf(
		$line_pattern,
		sprintf('\'\'[%s]\'\' %s (%s)', $lang_key, $lang->{'name'}, $lang->{'french_name'}),
		$lang->{'translator_name'},
		$lang->{'qt'} ? $ok : $no,
		$lang->{'strings_progress_summary'},
		$lang->{'elements_progress_summary'},
		$lang->{'desktop_progress_summary'},
		$lang->{'xml_progress_summary'},
		$lang->{'unix_manual'} ? $ok : $todo,
		@readme_values
	);
}

# Add date to output
print "\n";
my @date = localtime(time());
printf('Dernière date de mise à jour : %02d/%02d/%04d %02d:%02d'."\n", $date[3], $date[4] + 1, 1900 + $date[5], $date[2], $date[1]);
