#!/usr/bin/perl

# Wiki Translation Tools
# Copyright (C) 2009 Pavel Astakhov
#
#  This program 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 3 of the License, or
#  (at your option) any later version.
#
#  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, see <http://www.gnu.org/licenses/>.
#
# Autor: Pavel Astakhov
# e-mail: pastakhov@yandex.ru

# доделать:
# 0. Указание всех параметров через командную строку (!!!)
# 1. Указание пользователем языка (выбор из списка?)
# 1.1 Автоматическое определение языка пользователя 
# 1.2 Перевести сообщения программы на другие языки
# 2. Работать с файлом настроек (хранить язык выбранный пользователем)
# 3. Дать взможность пользователю указывать любую wiki страницу для обратки (или даже файла)
# 3.1 Также позволить выбирать пользователю нахождение шаблонов для подстановки текста
# 3.2 В качестве шаблонов использовать файлы i18n
# 4. Есть ли необходимость при замене нерегулярными выражениями дать пользователю возможность указать в конце пробел?
# 5. Добавить прогресс бар
# 6. ($include) указание подключения других страниц к шаблону


use utf8;
use open qw(:std :utf8);
use LWP::Simple qw(get);

print "\nWiki Translation Tools rc1.    Copyright (C) 2009 Pavel Astakhov\n";

# функция простой замены текста (регистронезависимый поиск)
# Параметры 0-где искать, 1-что искать, 2-чем заменить
sub repl_use_index
{
  $start_pos = 0; 
  $count_repl = 0; #счетчик количества сделаных замен
  while(($x = index(uc $_[0], uc $_[1], $start_pos)) != -1)
  {
    $newshtml = substr($_[0], 0, $x).$_[2].substr($_[0], $x + length($_[1]));
    $start_pos = $x + length($_[2]); #ищем с конца вставленного текста
    $count_repl +=1;
  }
  return $count_repl;
}

# функция замены текста регулярным выражением (регистронезависимый поиск)
# Параметры 0-где искать, 1-что искать, 2-чем заменить
sub repl_use_regex
{
  # ***************************************************************
  # --------------============== ВНИМАНИЕ ==============--------------- #
  # Cуществует потенциальная опасность ВНЕДРЕНИЯ ВРЕДОНОСНОГО КОДА	#
  # Так как регулярное выражение компилируется динамически		#
  # используя загруженные данные пользователей 				#
  # и затем выполняется в контексте программы,				#
  # необходимо предварительно обработать эти данные			#
  # для предотвращения внедрения в программу вредоносного кода		#
  # и получения неожиданных результатов в результате работы.		#
  # *********************************************************************

  # В регулярном выражении используется разделитель "/".
  # Если пользователь сможет передать неэкранированный символ "/", 
  # то у него будет возможность указать конец регулярного выражения 
  # и следом разместить код, который динамически скомпилируется и будет выполнен!
  # Так же можно получить доступ к переменным программы используя неэкранированные символы $ и @
  # Все эти возможные действия предотвращаются ниже...

  #В параметрах регулярных выражений можно указывать символ "/" в начале и конце строки для обозначения границ регулярного выражения, уберем эти символы.
  #уберем первый символ если он "/" ...
  $_[1] =~ s%^/%%;
  $_[2] =~ s%^/%%;
  #... и последний символ если он "/" и не экранирован [^\\]. При этом пропустим парные символы "\\" которые экранируют сами себя (\\\\)*
  $_[1] =~ s%([^\\](\\\\)*)/$%$1%;
  $_[2] =~ s%([^\\](\\\\)*)/$%$1%;

  #экранировать все незаэкранированные символы "/" 
  $_[1] =~ s%((?<!\\)(\\\\)*)/%$1\\/%g;
  $_[2] =~ s%((?<!\\)(\\\\)*)/%$1\\/%g;
  #Экранируем последний символ, если он "\" если он последний и неэкранированный (он экранирует используемый программой в регулярных выражениях разделитель и вызовет ошибку)
  $_[1] =~ s%(?<!\\)((\\\\)*\\)$%\\$1%;
  $_[2] =~ s%(?<!\\)((\\\\)*\\)$%\\$1%;
  #экранируем все неэкранированные символы $ и @ за исключением используемых для обратной связи, чтобы пресечь использование в выражении переменных программы
  #Просмотры назад (?<!\\) и вперед (?!\d) используются для возможности экранирования каждого из идущих друг за другом символов "$" 
  $_[1] =~ s%(?<!\\)(\\\\)*(\$(?!\d)|@)%$1\\$2%g;
  $_[2] =~ s%(?<!\\)(\\\\)*(\$(?!\d)|@)%$1\\$2%g;

  # Сформируем из полученных и обработанных данных регулярное выражение и выполним его в контексте программы.
  $e = '$count_repl = int($_[0] =~ '."s/$_[1]/$_[2]/mgi)";
  #print $e."\n";
  eval "$e"; warn $@ if $@;
  return $count_repl;
}

print "\nУкажите номер журнала для обработки: ";
my $WTT_number = <STDIN>;

$WTT_number =~ s/[^0-9]*//g;
# доделать нормальный выход из программы
if(length($WTT_number) == 0)
{
  print "Вы не указали данных, я завершаю свою работу\n\n";
  exit 0;
}

# доделать, исключения
$WTT_url = "http://en.opensuse.org/index.php?title=OpenSUSE_Weekly_News/$WTT_number&action=raw";
print "\nЗагружаю страницу \"Еженедельных новостей OpenSUSE\"\n$WTT_url\n";
$newshtml = get( $WTT_url );
print "Загружено ".length($newshtml)." байт\n";

# доделать, исключения
my $rules_url = "http://en.opensuse.org/index.php?title=OpenSUSE_Weekly_News/Translations/translate.RU&action=raw";
print "\nЗагружаю страницу c правилами подстановки текста\n$rules_url\n";
my $ruleshtml = get( $rules_url ); 
print "Загружено ".length($ruleshtml)." байт\n";

print "\nОбрабатка загруженных данных...\n";

my @rules = split "\n", $ruleshtml;
#print @rules;

print "\n";
$|=1;
my $pattern = "";
my $replacement = "";
for my $rule (@rules)
{
  #print $rule." foreach\n";
  if(length($pattern) == 0)
  {
    if(length($rule) == 0)
    {
      print "."; #пустая строка
    }else{
      $pattern = $rule; #это первая непустая строка, запомним ее как $pattern
    }
  }else{
    if($rule =~ /^ *$/) #это вторая строка - она пустая или состоит из одних пробелов ($pattern содержит комментарий)
    {
      if(length($rule) == 0)
      {
	print "#"; #комментарий
      }else{
	print "!"; #строка из пробелов
      }
    }else{ #вторая строка не пустая
      if($pattern =~ /^ /) #$pattern начинается с пробела
      {
	#простая замена текста
	
	$pattern = substr ($pattern, 1); #Удалим первый символ (пробел)
	$pattern =~ s\ *$\\; #Удалим пробелы в конце строки
	#Проверим на указание пользователем пустой строки ( "/" или "//")
	if ($rule =~ m%^/{1,2}$%)
	{
	  $rule = ""; #для подстановки пустой строкой
	}
	
	$rule = substr ($rule, 1) if $rule =~ /^ /; #Удалим первый символ если он является пробелом
	$rule =~ s\ *$\\; #Удалим пробелы в конце строки
	
	print "\$", &repl_use_index($newshtml, $pattern, $rule);
      }else #$pattern не начинается с пробела
      {
	#замена текста при помощи регулярного выражения
	print "s", &repl_use_regex($newshtml, $pattern, $rule);
      }
    }
    $pattern = "";
  }
}
print "\n\n";

# записать результат в файл (и сделать резервную копию старого)
# ********** Нет обработки исключений, доделать **************
my $WTT_file = "OpenSUSE_Weekly_News_$WTT_number";
rename($WTT_file,"$WTT_file~");
open FILE,">$WTT_file";
print FILE $newshtml;
close FILE;
print "Результат моей работы записан в файл \n\"$WTT_file\"\n\n";