@@ -2,295 +2,15 @@
namespace Dende\SoccerBot;

class Helper {
public static function codeToEmoji($code) {
$alpha3_to_alpha2 = [
'AND' => 'AD',
'ARE' => 'AE',
'AFG' => 'AF',
'ATG' => 'AG',
'AIA' => 'AI',
'ALB' => 'AL',
'ARM' => 'AM',
'ANT' => 'AN',
'AGO' => 'AO',
'ATA' => 'AQ',
'ARG' => 'AR',
'ASM' => 'AS',
'AUT' => 'AT',
'AUS' => 'AU',
'ABW' => 'AW',
'ALA' => 'AX',
'AZE' => 'AZ',
'BIH' => 'BA',
'BRB' => 'BB',
'BGD' => 'BD',
'BEL' => 'BE',
'BFA' => 'BF',
'BGR' => 'BG',
'BHR' => 'BH',
'BDI' => 'BI',
'BEN' => 'BJ',
'BMU' => 'BM',
'BRN' => 'BN',
'BOL' => 'BO',
'BRA' => 'BR',
'BHS' => 'BS',
'BTN' => 'BT',
'BVT' => 'BV',
'BWA' => 'BW',
'BLR' => 'BY',
'BLZ' => 'BZ',
'CAN' => 'CA',
'CCK' => 'CC',
'COD' => 'CD',
'CAF' => 'CF',
'COG' => 'CG',
'CHE' => 'CH',
'CIV' => 'CI',
'COK' => 'CK',
'CHL' => 'CL',
'CMR' => 'CM',
'CHN' => 'CN',
'COL' => 'CO',
'CRI' => 'CR',
'SCG' => 'CS',
'CUB' => 'CU',
'CPV' => 'CV',
'CXR' => 'CX',
'CYP' => 'CY',
'CZE' => 'CZ',
'DEU' => 'DE',
'GER' => 'DE',
'DJI' => 'DJ',
'DNK' => 'DK',
'DMA' => 'DM',
'DOM' => 'DO',
'DZA' => 'DZ',
'ECU' => 'EC',
'ENG' => 'GB',
'NIR' => 'GB',
'WAL' => 'GB',
'EST' => 'EE',
'EGY' => 'EG',
'ESH' => 'EH',
'ERI' => 'ER',
'ESP' => 'ES',
'ETH' => 'ET',
'FIN' => 'FI',
'FJI' => 'FJ',
'FLK' => 'FK',
'FSM' => 'FM',
'FRO' => 'FO',
'FRA' => 'FR',
'GAB' => 'GA',
'GBR' => 'GB',
'GRD' => 'GD',
'GEO' => 'GE',
'GUF' => 'GF',
'GHA' => 'GH',
'GIB' => 'GI',
'GRL' => 'GL',
'GMB' => 'GM',
'GIN' => 'GN',
'GLP' => 'GP',
'GNQ' => 'GQ',
'GRC' => 'GR',
'SGS' => 'GS',
'GTM' => 'GT',
'GUM' => 'GU',
'GNB' => 'GW',
'GUY' => 'GY',
'HKG' => 'HK',
'HMD' => 'HM',
'HND' => 'HN',
'HRV' => 'HR',
'HTI' => 'HT',
'HUN' => 'HU',
'IDN' => 'ID',
'IRL' => 'IE',
'ISR' => 'IL',
'IND' => 'IN',
'IOT' => 'IO',
'IRQ' => 'IQ',
'IRN' => 'IR',
'ISL' => 'IS',
'ITA' => 'IT',
'JAM' => 'JM',
'JOR' => 'JO',
'JPN' => 'JP',
'KEN' => 'KE',
'KGZ' => 'KG',
'KHM' => 'KH',
'KIR' => 'KI',
'COM' => 'KM',
'KNA' => 'KN',
'PRK' => 'KP',
'KOR' => 'KR',
'KWT' => 'KW',
'CYM' => 'KY',
'KAZ' => 'KZ',
'LAO' => 'LA',
'LBN' => 'LB',
'LCA' => 'LC',
'LIE' => 'LI',
'LKA' => 'LK',
'LBR' => 'LR',
'LSO' => 'LS',
'LTU' => 'LT',
'LUX' => 'LU',
'LVA' => 'LV',
'LBY' => 'LY',
'MAR' => 'MA',
'MCO' => 'MC',
'MDA' => 'MD',
'MDG' => 'MG',
'MHL' => 'MH',
'MKD' => 'MK',
'MLI' => 'ML',
'MMR' => 'MM',
'MNG' => 'MN',
'MAC' => 'MO',
'MNP' => 'MP',
'MTQ' => 'MQ',
'MRT' => 'MR',
'MSR' => 'MS',
'MLT' => 'MT',
'MUS' => 'MU',
'MDV' => 'MV',
'MWI' => 'MW',
'MEX' => 'MX',
'MYS' => 'MY',
'MOZ' => 'MZ',
'NAM' => 'NA',
'NCL' => 'NC',
'NER' => 'NE',
'NFK' => 'NF',
'NGA' => 'NG',
'NIC' => 'NI',
'NLD' => 'NL',
'NOR' => 'NO',
'NPL' => 'NP',
'NRU' => 'NR',
'NIU' => 'NU',
'NZL' => 'NZ',
'OMN' => 'OM',
'PAN' => 'PA',
'PER' => 'PE',
'PYF' => 'PF',
'PNG' => 'PG',
'PHL' => 'PH',
'PAK' => 'PK',
'POL' => 'PL',
'SPM' => 'PM',
'PCN' => 'PN',
'PRI' => 'PR',
'PSE' => 'PS',
'PRT' => 'PT',
'PLW' => 'PW',
'PRY' => 'PY',
'QAT' => 'QA',
'REU' => 'RE',
'ROU' => 'RO',
'RUS' => 'RU',
'RWA' => 'RW',
'SAU' => 'SA',
'SLB' => 'SB',
'SYC' => 'SC',
'SDN' => 'SD',
'SWE' => 'SE',
'SGP' => 'SG',
'SHN' => 'SH',
'SVN' => 'SI',
'SJM' => 'SJ',
'SVK' => 'SK',
'SLE' => 'SL',
'SMR' => 'SM',
'SEN' => 'SN',
'SOM' => 'SO',
'SUR' => 'SR',
'STP' => 'ST',
'SLV' => 'SV',
'SYR' => 'SY',
'SWZ' => 'SZ',
'TCA' => 'TC',
'TCD' => 'TD',
'ATF' => 'TF',
'TGO' => 'TG',
'THA' => 'TH',
'TJK' => 'TJ',
'TKL' => 'TK',
'TLS' => 'TL',
'TKM' => 'TM',
'TUN' => 'TN',
'TON' => 'TO',
'TUR' => 'TR',
'TTO' => 'TT',
'TUV' => 'TV',
'TWN' => 'TW',
'TZA' => 'TZ',
'UKR' => 'UA',
'UGA' => 'UG',
'UMI' => 'UM',
'USA' => 'US',
'URY' => 'UY',
'UZB' => 'UZ',
'VAT' => 'VA',
'VCT' => 'VC',
'VEN' => 'VE',
'VGB' => 'VG',
'VIR' => 'VI',
'VNM' => 'VN',
'VUT' => 'VU',
'WLF' => 'WF',
'WSM' => 'WS',
'YEM' => 'YE',
'MYT' => 'YT',
'ZAF' => 'ZA',
'ZMB' => 'ZM',
'ZWE' => 'ZW',
'SUI' => 'CH',
];
if (strlen($code) == 3)
$code = $alpha3_to_alpha2[$code];

$code = strtoupper($code);
$code = str_split($code);

$emoji = "";
$offset = 127397;
foreach ($code as $c){
$emoji .= Helper::utf8(ord($c)+$offset);
}
return $emoji;
}

public static function utf8($num)
{
if($num<=0x7F) return chr($num);
if($num<=0x7FF) return chr(($num>>6)+192).chr(($num&63)+128);
if($num<=0xFFFF) return chr(($num>>12)+224).chr((($num>>6)&63)+128).chr(($num&63)+128);
if($num<=0x1FFFFF) return chr(($num>>18)+240).chr((($num>>12)&63)+128).chr((($num>>6)&63)+128).chr(($num&63)+128);
return '';
}

public static function uniord($c)
{
$ord0 = ord($c{0}); if ($ord0>=0 && $ord0<=127) return $ord0;
$ord1 = ord($c{1}); if ($ord0>=192 && $ord0<=223) return ($ord0-192)*64 + ($ord1-128);
$ord2 = ord($c{2}); if ($ord0>=224 && $ord0<=239) return ($ord0-224)*4096 + ($ord1-128)*64 + ($ord2-128);
$ord3 = ord($c{3}); if ($ord0>=240 && $ord0<=247) return ($ord0-240)*262144 + ($ord1-128)*4096 + ($ord2-128)*64 + ($ord3-128);
return false;
}

public static function timeDifference(\DateTime $dt){
$then = \Carbon\Carbon::instance($dt);
$now = \Carbon\Carbon::now();
$diffInMinutes = $now->diffInMinutes($then);
$diffInDays = $now->diffInDays($then);
$message = "";

if ($diffInMinutes >= 180){
if ($diffInDays >= 1){
//hours
$message = "{$now->diffInHours($then)} Stunden";
$message = "{$now->diffInDays($then)} Tagen";
} else {
//hours and minutes
$nf = new \NumberFormatter("de-DE", \NumberFormatter::SPELLOUT);
@@ -62,6 +62,7 @@ private static function newChat(TelegramChat $telegramChat) {
}
$chat->setChatId($telegramChat->getId());
$chat->setState($chat::$initialState);
$chat->init();
$chat->save();
return $chat;
}
@@ -9,6 +9,7 @@
namespace Dende\SoccerBot\Model;

use Monolog\Logger;
use Symfony\Component\Translation\Translator;
use Telegram\Bot\Objects\Update as TelegramUpdate;


@@ -8,6 +8,7 @@
use Finite\Loader\ArrayLoader;
use Finite\StatefulInterface;
use Monolog\Logger;
use Symfony\Component\Translation\Translator;
use Telegram\Bot\Objects\Update as TelegramUpdate;
use Finite\StateMachine\StateMachine as FiniteStateMachine;

@@ -1,16 +1,39 @@
<?php
namespace Dende\SoccerBot;
namespace Dende\SoccerBot\Model;

use Symfony\Component\Translation\Translator;

class Message
{
protected $text;

public function addLine($text)
{
if (is_null($text)){
$this->text = $text . "\n";;
} else {
$this->text .= $text . "\n";
}
}
private $lines;

function __construct($text = null, $vars = [], $choice = false)
{
$this->lines = [];
if ($text != null){
$this->addLine($text, $vars, $choice);
}
}

public function translate(Translator $lang){
$text = null;
foreach ($this->lines as $line){
if ($text != null){
$text .= "\n";
}
if ($line['choice'] !== false){
$text .= $lang->transChoice($line['text'], $line['choice'], $line['vars']);
} else {
$text .= $lang->trans($line['text'], $line['vars']);
}
}
return $text;
}

public function addLine($text, $vars = [], $choice = false)
{
$this->lines[] = ['text' => $text, 'vars' => $vars, 'choice' => $choice];
}

}
@@ -2,12 +2,13 @@

namespace Dende\SoccerBot\Model;

use Analog\Analog;
use Dende\SoccerBot\Command\CommandFactory;
use Dende\SoccerBot\Exception\CommandNotFoundException;
use Dende\SoccerBot\Exception\EmptyMessageException;
use Dende\SoccerBot\Model\Base\PrivateChat as BasePrivateChat;
use Finite\Loader\ArrayLoader;
use Finite\StatefulInterface;
use Monolog\Logger;
use Telegram\Bot\Objects\Update as TelegramUpdate;
use Finite\StateMachine\StateMachine as FiniteStateMachine;
/**
@@ -25,9 +26,11 @@ class PrivateChat extends BasePrivateChat implements StatefulInterface, ChatInte
public static $initialState = 'muted';
/** @var FiniteStateMachine */
private $fsm;


public function init()
{
$this->fsm = new FiniteStateMachine($this);
$this->fsm = new FiniteStateMachine($this);
$arrayLoader = new ArrayLoader([
'class' => 'PrivateChat',
'states' => [
@@ -85,6 +88,7 @@ public function setFiniteState($state)

/**
* @param TelegramUpdate $update
* @return Message|null
* @throws \Exception
*/
public function handle(TelegramUpdate $update){
@@ -103,14 +107,26 @@ public function handle(TelegramUpdate $update){
$canTransit = false;
}

$response = null;

if ($canTransit){
$this->fsm->apply(['chat' => $this, 'args' => $args]);

$response = $this->fsm->apply(['chat' => $this, 'args' => $args]);

} else {

$state = $this->fsm->getCurrentState();
$command = CommandFactory::createFromString($commandString);
$command->run($this, $args, $state);

try {
$command = CommandFactory::createFromString($commandString);
$response = $command->run($this, $args, $state);
} catch (CommandNotFoundException $e){
Analog::log('cannot transit or execute command ' . $commandString, Analog::WARNING);
}

}

return $response;
}

}
@@ -17,8 +17,4 @@
*/
class Team extends BaseTeam
{
public function getEmoji(){
return Helper::codeToEmoji($this->getCode());
}

}
@@ -5,6 +5,7 @@
use Dende\SoccerBot\Exception;
use Dende\SoccerBot\Model\ChatFactory;
use Analog\Analog;
use Dende\SoccerBot\Model\ChatInterface;
use Telegram\Bot\Api as TelegramApi;
use Telegram\Bot\Objects\Update as TelegramUpdate;
use Finite\StateMachine\StateMachine as FiniteStateMachine;
@@ -17,6 +18,7 @@
use Dende\SoccerBot\Model\MatchQuery;
use Dende\SoccerBot\Model\PrivateChat;
use Dende\SoccerBot\Model\GroupChat;
use Dende\SoccerBot\Model\Message;

/**
* Class SoccerBot
@@ -62,9 +64,6 @@ function run(){
//not too bad
} catch (Exception\InvalidCommandStringException $e){
//not too bad
} catch (\Exception $e){
\Kint::dump($e);

}
}
}
@@ -81,7 +80,9 @@ function handle(TelegramUpdate $update){

$chat = ChatFactory::create($message->getChat());

$chat->handle($update);
$message = $chat->handle($update);

$this->sendMessage($message, $chat);

}

@@ -240,7 +241,7 @@ private function liveticker(Match $match, $newData) {
foreach ($fsms as $fsm){
/** @var FiniteStateMachine $fsm */
if ($fsm->getCurrentState() == 'liveticker'){
$message = "";
$message = new Message();

$homeTeam = $match->getHomeTeam();
$awayTeam = $match->getAwayTeam();
@@ -249,13 +250,11 @@ private function liveticker(Match $match, $newData) {
$chat = $fsm->getObject();

if (array_get($newData, 'status') == 'IN_PLAY'){
$message .= $this->lang->trans(
$message->addLine(
'live.matchStarted',
[
'%homeTeamName%' => $homeTeam->getName(),
'%homeTeamEmoji%' => $homeTeam->getEmoji(),
'%awayTeamName%' => $awayTeam->getName(),
'%awayTeamEmoji%' => $awayTeam->getEmoji()
]
);
}
@@ -272,41 +271,37 @@ private function liveticker(Match $match, $newData) {

if (!empty($goalsScored)){
/** @noinspection PhpUndefinedVariableInspection */
$message .= $this->lang->transChoice(
$message->addLine(
'live.teamScored',
$goalsScored,
[
'%teamScoredName%' => $teamScoredName,
'%teamConcededName%' => $teamConcededName,
'%goals%' => $goalsScored
]
],
$goalsScored
);
$message .= $this->lang->trans(
$message->addLine(
'live.newScore',
[
'%homeTeamEmoji%' => $homeTeam->getEmoji(),
'%homeTeamGoals%' => $match->getHomeTeamGoals(),
'%awayTeamGoals%' => $match->getAwayTeamGoals(),
'%awayTeamEmoji%' => $awayTeam->getEmoji()
]
);
}

if (array_get($newData, 'status') == 'FINISHED'){
$message .= $this->lang->trans(
$message->addLine(
'live.finished',
[
'%homeTeamName%' => $homeTeam->getName(),
'%awayTeamName%' => $awayTeam->getName()
]
);
$message .= $this->lang->trans(
$message->addLine(
'live.finalScore',
[
'%homeTeamEmoji%' => $homeTeam->getEmoji(),
'%homeTeamGoals%' => $match->getHomeTeamGoals(),
'%awayTeamGoals%' => $match->getAwayTeamGoals(),
'%awayTeamEmoji%' => $awayTeam->getEmoji()
]
);
}
@@ -315,9 +310,9 @@ private function liveticker(Match $match, $newData) {
}
}

private function sendMessage($message, $chat){
private function sendMessage(Message $message, ChatInterface $chat){
/** @var PrivateChat|GroupChat $chat */
$this->telegram->sendMessage(['chat_id' => $chat->getChatId(), 'text' => $message, 'parse_mode' => 'Markdown']);
$this->telegram->sendMessage(['chat_id' => $chat->getChatId(), 'text' => $message->translate($this->lang), 'parse_mode' => 'Markdown']);
}

private function liveCommand($chat)
@@ -331,13 +326,6 @@ private function muteCommand($chat)

}

private function infoCommand($chat)
/** @var PrivateChat|GroupChat $chat */
{
$message = $this->lang->trans('command.info', ['%status%' => $this->chatIdToFsm($chat->getChatId())->getCurrentState()]);
$this->sendMessage($message, $chat);
}

private function chatIdToFsm($chatId){
if (array_has($this->states['private'], $chatId)){
return array_get($this->states['private'], $chatId);
@@ -348,62 +336,6 @@ private function chatIdToFsm($chatId){
throw new \Exception("FiniteStateMachine not found");
}

private function currCommand($chat)
{
$message = "";
$currentMatchesCount = MatchQuery::create()->where('matches.status = ?', 'IN_PLAY')->count();
if ($currentMatchesCount > 0){

$message .= $this->lang->transChoice('command.curr.currentMatches', $currentMatchesCount);

$currentMatches = MatchQuery::create()->where('matches.status = ?', 'IN_PLAY')->find();

foreach ($currentMatches as $currentMatch){
$message .= $this->lang->trans(
'command.curr.currentMatch',
[
'%homeTeamName%' => $currentMatch->getHomeTeam()->getName(),
'%homeTeamEmoji%' => $currentMatch->getHomeTeam()->getEmoji(),
'%awayTeamEmoji%' => $currentMatch->getAwayTeam()->getEmoji(),
'%awayTeamName%' => $currentMatch->getAwayTeam()->getName(),
'%homeTeamGoals%' => $currentMatch->getHomeTeamGoals(),
'%awayTeamGoals%' => $currentMatch->getAwayTeamGoals()
]
);
}
} else {
$message .= $this->lang->trans('command.curr.noCurrentMatches');
}
$this->sendMessage($message, $chat);

}

private function nextCommand($chat, $args)
{
$m = ($args && is_numeric($args[0])) ? $args[0] : 1;
$i = 0;
$message = $this->lang->transChoice('command.next.nextMatches', $m) . "\n";
$nextMatches = MatchQuery::create()->where('matches.status = ?', 'TIMED')->orderByDate()->find();
foreach ($nextMatches as $nextMatch){
$difference = Helper::timeDifference($nextMatch->getDate());
$message .= $this->lang->trans(
'command.next.nextMatch',
[
'%homeTeamName%' => $nextMatch->getHomeTeam()->getName(),
'%homeTeamEmoji%' => $nextMatch->getHomeTeam()->getEmoji(),
'%awayTeamEmoji%' => $nextMatch->getAwayTeam()->getEmoji(),
'%awayTeamName%' => $nextMatch->getAwayTeam()->getName(),
'%difference%' => $difference
]
);
$i++;
if ($i < $m)
$message .= "\n";
else
break;
}
$this->sendMessage($message, $chat);
}

private function initTranslation()
{