#!/usr/bin/perl -w
# v 1.3 (2009-09-02) (c)dimio
# Основной цикл работы скрипта.
# 1. Получаем из соотв. таблицы базы кол-во блогов (BlogID = X), создаем из них массив1 на Х эл-тов.
# 2. Производим перебор массива1, при этом в цикле перебора делаем следующее:
 # 2.1. Делаем запрос к локальной БД чтобы получить для текущего блога список GameID еще не опубл. игр;
 # 2.2. Для полученных значений BlogID и GameID делаем запрос к базе для формирования тела сообщения
 # 		(см. ф-ю prepare_message);
 # 2.3. Публикуем сообщение в соответствующем блоге (путем прямого внесения строк в соотв. таблицу БД
 # 		целевого блога).
 # 2.4. В случае успешной публикации - обновляем запись в столбце DateOfPost таблицы BlogsContent локальной БД.
# 4. По окончанию перебора массива1 завершаем работу программы.
use strict;
use DBI;
use encoding 'utf8';

# Настройки для подключения к локальной БД
my $db_type = 'SQLite';
# путь к базе, применяемый в случае запуска на сервере dimio.org
# my $db_name = '~/sqlite_db/gb_blogs.sqlite';
# путь к базе, прим. при запуске с домашней машины
my $db_name = '../sqlite_db/gb_blogs.sqlite';
my $db_hostname = 'localhost';
my $db_dest_host = 'localhost'; # адрес базы данных блогов (localhost если запускать локально)
my $db_login = '';
my $db_password = '';

########## ТЕЛО ПРОГРАММЫ ##########
my $dbh = &db_connect($db_type,$db_name,$db_hostname,$db_login,$db_password); # подключаемся к БД, получаем дескриптор подключения

# 1. Получение массивов исходных данных
my @BlogsID; # определяем массив исх. данных
&prepare_BlogID($dbh, \@BlogsID);

# 2. Перебор массива с номерами блогов
foreach my $BlogID (@BlogsID){

	# 2.1. Получаем список еще не публиковавшихся в текущем блоге игр.
	my @GamesID = &prepare_GameID($dbh, $BlogID);

	# 2.1.1. Если таковых игр нет - переходим к след. по списку блогу.
	if(!@GamesID){
		print "No unposted messages for blog N$BlogID.\n" ;
		next;
	}
	my $GameID = $GamesID[int(rand($#GamesID+1))]; # Выбираем случайную игру из списка неопубликованных.

	# 2.2. Получаем данные для создания нового сообщения в блоге для текущей игры и текущего блога
	my ($PostHeader, $PostBody, $PostTags, $table_pref, $screens_URL) = &prepare_message($dbh, $BlogID, $GameID);
	next if !$table_pref;

	# 2.3. Публикация сообщения с описанием игры в блоге.
	redo if &posting_message($PostHeader,$PostBody,$PostTags,$table_pref,$screens_URL,$db_dest_host) != 1; # если публикация не состоялась - пробуем заново
	&update_local_data($BlogID, $GameID); # обновляем локальную БД, внося дату публикации игры в блоге
}

print "Bust blogging completed.\n";

$dbh->disconnect;
print "Script done.\n";

exit 0;

sub db_connect($$$$$) {
my ($db_type,$db_name,$db_hostname,$db_login,$db_password) = @_;
my $dbh;
if ($db_type eq 'SQLite'){
	$dbh = DBI->connect("DBI:$db_type:$db_name","$db_login","$db_password")
		or die "Connecting: $DBI::errstr\n"; # подключаемся к базе SQL (открывается дескриптор БД)
	$dbh->{unicode} = 1;
}
elsif ($db_type eq 'mysql'){
	$dbh = DBI->connect("DBI:$db_type:$db_name:$db_hostname","$db_login","$db_password")
		or die "Connecting: $DBI::errstr\n"; # подключаемся к базе SQL (открывается дескриптор БД)
	$dbh->{'mysql_enable_utf8'} = 1;
	$dbh->do('SET NAMES utf8');
}

return $dbh;
}

sub prepare_BlogID($$) {
# Функция подготавливает массив исходных данных для дальнейшей работы программы.
my ($dbh, $Blog)  = @_;
# 1. Получить массив, состоящий из BlogID
# Этот запрос получает список из всех BlogID, хранящихся в таблице BlogsContent, для которых
# не заполнены все строки с датой публикации описания игры (т.е. для которых имеются неопубликованные
# описания игр).
my $query = $dbh->prepare("SELECT BlogID FROM BlogsContent WHERE DateOfPost IS NULL GROUP BY BlogID");
$query->execute() or die "$dbh->errstr\n";
while ((my $BlogID) = $query->fetchrow_array){
	push(@$Blog,$BlogID);
}

return 1;
}

sub prepare_GameID($$) {
# Выполняет запрос к локальной базе для получения списка неопубликованных игр при заданном BlogID
my ($dbh, $BlogID)  = @_;
# Получить массив, состоящий из GameID
# Запрос возвращает список еще не опубликованных игр для данного блога.
# Отбираются только игры с заполненными заголовками описаний, что должно гарантировать наличие самих описаний.
my $query = $dbh->prepare("SELECT GameID FROM BlogsContent WHERE BlogID = $BlogID AND DateOfPost IS NULL AND PostHeader NOT NULL");
$query->execute() or die "$dbh->errstr\n";
my @GamesID;
while ((my $GameID) = $query->fetchrow_array){
	push(@GamesID,$GameID);
}

return @GamesID;
}

sub prepare_message($$$) {
# Запрос к базе на получение нужных частей контента из разных таблиц.
# Склеивание результирующего тела будущего сообщения из полученных данных.
my ($dbh, $BlogID, $GameID) = @_;
# Запрос получает из базы необходимые для формирования заметки в блоге данные.
# Данные получаются для текущей игры и текущего блога и кладутся в соотв. переменные.
my $query = $dbh->prepare("SELECT PostHeader,PostBody,PostTags FROM BlogsContent WHERE BlogID = $BlogID AND GameID = $GameID");
$query->execute() or die "$dbh->errstr\n";
(my $tmp) = $query->fetchall_arrayref;
my $PostHeader	= $tmp->[0][0];
my $PostBody	= $tmp->[0][1];
my $PostTags	= $tmp->[0][2];
# Запрос получает префикс для mysql-таблиц, используемых данным блогом.
$query = $dbh->prepare("SELECT WPTablePrefix FROM BlogsMainData WHERE BlogID = $BlogID AND WPTablePrefix NOT NULL");
$query->execute() or die "$dbh->errstr\n";
(my $table_pref) = $query->fetchrow_array;
# Получаем ссылки на скриншоты для текущей игры (ссылки подготавливаются вручную).
$query = $dbh->prepare("SELECT ScreenShotsURL FROM Games WHERE GameID = $GameID");
$query->execute() or die "$dbh->errstr\n";
(my $screens_URL) = $query->fetchrow_array;

return ($PostHeader, $PostBody, $PostTags, $table_pref, $screens_URL);
}

sub date_time {
my ($DAY, $MONTH, $YEAR) = (localtime)[3..5];

my $DATE = join("-", $YEAR+1900, $MONTH+1, $DAY);
my $locTIME = join(":", (localtime)[2,1,0]);
my $gmTIME = join(":", (gmtime)[2,1,0]);

return ($DATE, $locTIME, $gmTIME);
}

sub posting_message($$$$$$) {
# Подключаемся к БД вордпресс и кладем пост в таблицу с соотв. префиксом в имени (префиксы
# у каждого блога свои.
# Вариант N2 - получать из своей локальной базы не префиксы имен таблиц, а имена баз данных
# (если каждый блог будет иметь отдельную БД).
my ($PostHeader, $PostBody, $PostTags, $table_pref, $screens_URL, $db_dest_host) = @_;
# Настройки для подключения к БД блога.
my $db_type = 'mysql';
my $db_name = 'db_namr'; # имя базы данных с таблицами wordpress блогов
my $db_login = 'login'; # логин для неё же
my $db_password = 'password'; # пароль для неё же
# Подготовка необходимых для публикации сообщения данных
my ($DATE, $locTIME, $gmTIME) = &date_time; # генерация времени и даты публикации сообщения
$table_pref .= '_posts'; # определение имени таблицы, хранящей сообщения
my $locdate = $DATE.' '.$locTIME; # создание локальной даты публикации сообщения в формате, пригодном для wordpress
my $gmtdate = $DATE.' '.$gmTIME; # то же для даты по Гринвичу
my $PostURLName = &prepare_post_URL($PostHeader); # генерация будещего адреса статьи с описанием игры на основании заголовка статьи

my $dbh = &db_connect($db_type,$db_name,$db_dest_host,$db_login,$db_password);
my $query = "INSERT INTO $table_pref (post_author, post_date, post_date_gmt, post_content, post_title, post_name)
VALUES (1, '$locdate', '$gmtdate', '$screens_URL $PostBody', '$PostHeader', '$PostURLName');";
my $db_data = $dbh->do($query);
print "$db_data lines added into $table_pref.\n";
$dbh->disconnect;

return $db_data;
}

sub update_local_data($$) {
my ($BlogID, $GameID) = @_;
my $db_type = 'SQLite';
my $db_name = '../sqlite_db/gb_blogs.sqlite';
my $db_hostname = 'localhost';
my $db_login = '';
my $db_password = '';

my $dbh = &db_connect($db_type,$db_name,$db_hostname,$db_login,$db_password);
my $DateOfPost = join(" ", (&date_time)[0,1]);
my $db_data = $dbh->do("UPDATE BlogsContent SET DateOfPost = '$DateOfPost' WHERE BlogID = $BlogID AND GameID = $GameID");
print "$db_data lines updated on $db_name\n\n";

return $db_data;
}

sub prepare_post_URL($) {
	# Функция транслитерации кириллицы, сделанная для преобразования
	# заголовков сообщений в url-адреса, основана на коде nrg:
	# "Автор: nrg
	# Напиcано: Чтв Сен 13 00:04:14 SAMST 2007
	# Обратная связь: nrg@jabber.snc.ru, icq: 813-793."
	# dimio - добавлена очистка от мусора и замена пробелов
my $InLine = shift;

	my %hs=('аА'=>'a' , 'бБ'=>'b'  , 'вВ'=>'v'  , 'гГ'=>'g', 'дД'=>'d' ,
			'еЕ'=>'e' , 'ёЁ'=>'jo' , 'жЖ'=>'zh' , 'зЗ'=>'z', 'иИ'=>'i' ,
			'йЙ'=>'j' , 'кК'=>'k'  , 'лЛ'=>'l'  , 'мМ'=>'m', 'нН'=>'n' ,
			'оО'=>'o' , 'пП'=>'p'  , 'рР'=>'r'  , 'сС'=>'s', 'тТ'=>'t' ,
			'уУ'=>'u' , 'фФ'=>'f'  , 'хХ'=>'h' , 'цЦ'=>'c', 'чЧ'=>'ch',
			'шШ'=>'sh', 'щЩ'=>'shh', 'ъЪ'=>''   , 'ыЫ'=>'y', 'ьЬ'=>''  ,
			'эЭ'=>'eh', 'юЮ'=>'ju' , 'яЯ'=>'ja' );

	pop@{([\map do{$InLine =~ s/[$_]/$hs{$_}/gi;}, keys %hs])}, $InLine; # преобразуем в транслит по шаблону из хэша
	$InLine =~ s/\s/_/g; # заменим пробелы на подчеркивания
	$InLine =~ s/[^\w]//g; # очистим будущий URL от возможного "мусора" - знаков препинания
return $InLine;
}