<commit_before><?php
/**
 * Copyright 2017 The WildPHP Team
 *
 * You should have received a copy of the MIT license with the project.
 * See the LICENSE file for more information.
 */

namespace WildPHP\Core\Channels;

use WildPHP\Core\ComponentContainer;
use WildPHP\Core\Configuration\Configuration;
use WildPHP\Core\Connection\IRCMessages\JOIN;
use WildPHP\Core\Connection\IRCMessages\KICK;
use WildPHP\Core\Connection\IRCMessages\PART;
use WildPHP\Core\Connection\IRCMessages\RPL_NAMREPLY;
use WildPHP\Core\Connection\IRCMessages\RPL_TOPIC;
use WildPHP\Core\Connection\IRCMessages\RPL_WELCOME;
use WildPHP\Core\Connection\Queue;
use WildPHP\Core\ContainerTrait;
use WildPHP\Core\EventEmitter;
use WildPHP\Core\Logger\Logger;
use WildPHP\Core\Users\User;
use WildPHP\Core\Users\UserCollection;

class ChannelStateManager
{
	use ContainerTrait;

	/**
	 * ChannelStateManager constructor.
	 *
	 * @param ComponentContainer $container
	 */
	public function __construct(ComponentContainer $container)
	{
		$events = [
			'irc.line.in.join' => 'processUserJoin',
			'irc.line.in.part' => 'processUserPart',
			'irc.line.in.kick' => 'processUserKick',
			'user.quit' => 'processUserQuit',
			'user.mode.channel' => 'processUserModeChange',

			// 353: RPL_NAMREPLY
			'irc.line.in.353' => 'populateChannel',

			// 332: RPL_TOPIC
			'irc.line.in.332' => 'processChannelTopicChange',

			// 001: RPL_WELCOME
			'irc.line.in.001' => 'joinInitialChannels',
		];

		foreach ($events as $event => $callback)
		{
			EventEmitter::fromContainer($container)
				->on($event, [$this, $callback]);
		}

		$this->setContainer($container);
	}

	/**
	 * @param JOIN $ircMessage
	 * @param Queue $queue
	 */
	public function processUserJoin(JOIN $ircMessage, Queue $queue)
	{
		$prefix = $ircMessage->getPrefix();
		/** @var User $userObject */
		$userObject = UserCollection::fromContainer($this->getContainer())
			->findOrCreateByNickname($ircMessage->getNickname());

		/** @var Channel $channel */
		$channel = ChannelCollection::fromContainer($this->getContainer())
			->requestByChannelName($ircMessage->getChannels()[0], $userObject);
		$accountname = $ircMessage->getIrcAccount();

		// TODO Isn't this really UserStateManager's job?
		$userObject->setIrcAccount($accountname);
		$userObject->setHostname($prefix->getHostname());
		$userObject->setUsername($prefix->getUsername());
		$userObject->getChannelCollection()
			->append($channel);

		$channel->getUserCollection()
			->append($userObject);

		EventEmitter::fromContainer($this->getContainer())
			->emit('user.join', [$userObject, $channel, $queue]);

		Logger::fromContainer($this->getContainer())
			->debug('Added user to channel.',
				[
					'reason' => 'join',
					'nickname' => $userObject->getNickname(),
					'channel' => $channel->getName()
				]);
	}

	/**
	 * @param PART $ircMessage
	 * @param Queue $queue
	 */
	public function processUserPart(PART $ircMessage, Queue $queue)
	{
		/** @var Channel $channel */
		$channel = ChannelCollection::fromContainer($this->getContainer())
			->findByChannelName($ircMessage->getChannels()[0]);

		/** @var User $userObject */
		$userObject = UserCollection::fromContainer($this->getContainer())
			->findByNickname($ircMessage->getNickname());

		if (!$channel->getUserCollection()->contains($userObject))
			return;

		$channel->getUserCollection()->remove($userObject);
		$userObject->getChannelCollection()->remove($channel);

		EventEmitter::fromContainer($this->getContainer())
			->emit('user.part', [$userObject, $channel, $queue]);

		Logger::fromContainer($this->getContainer())
			->debug('Removed user from channel',
				[
					'reason' => 'part',
					'nickname' => $userObject->getNickname(),
					'channel' => $channel->getName()
				]);
	}

	/**
	 * @param KICK $ircMessage
	 * @param Queue $queue
	 */
	public function processUserKick(KICK $ircMessage, Queue $queue)
	{
		/** @var Channel $channel */
		$channel = ChannelCollection::fromContainer($this->getContainer())
			->findByChannelName($ircMessage->getChannel());

		/** @var User $userObject */
		$userObject = UserCollection::fromContainer($this->getContainer())
			->findByNickname($ircMessage->getTarget());

		if (!$channel->getUserCollection()->contains($userObject))
			return;

		$channel->getUserCollection()->remove($userObject);
		$userObject->getChannelCollection()->remove($channel);

		EventEmitter::fromContainer($this->getContainer())
			->emit('user.kick', [$userObject, $channel, $queue]);

		Logger::fromContainer($this->getContainer())
			->debug('Removed user from channel',
				[
					'reason' => 'kick',
					'nickname' => $userObject->getNickname(),
					'channel' => $channel->getName()
				]);
	}

	/**
	 * @param User $userObject
	 */
	public function processUserQuit(User $userObject)
	{
		/** @var Channel[] $channels */
		$channels = ChannelCollection::fromContainer($this->getContainer())
			->values();

		/** @var Channel $channel */
		foreach ($channels as $channel)
		{
			if (!$channel->getUserCollection()->contains($userObject))
				continue;

			$channel->getUserCollection()->remove($userObject);
			$userObject->getChannelCollection()->remove($channel);

			Logger::fromContainer($this->getContainer())
				->debug('Removed user from channel',
					[
						'reason' => 'quit',
						'nickname' => $userObject->getNickname(),
						'channel' => $channel->getName()
					]);
		}<commit_msg>Only remove the channel when it actually exists<commit_after><?php
/**
 * Copyright 2017 The WildPHP Team
 *
 * You should have received a copy of the MIT license with the project.
 * See the LICENSE file for more information.
 */

namespace WildPHP\Core\Channels;

use WildPHP\Core\ComponentContainer;
use WildPHP\Core\Configuration\Configuration;
use WildPHP\Core\Connection\IRCMessages\JOIN;
use WildPHP\Core\Connection\IRCMessages\KICK;
use WildPHP\Core\Connection\IRCMessages\PART;
use WildPHP\Core\Connection\IRCMessages\RPL_NAMREPLY;
use WildPHP\Core\Connection\IRCMessages\RPL_TOPIC;
use WildPHP\Core\Connection\IRCMessages\RPL_WELCOME;
use WildPHP\Core\Connection\Queue;
use WildPHP\Core\ContainerTrait;
use WildPHP\Core\EventEmitter;
use WildPHP\Core\Logger\Logger;
use WildPHP\Core\Users\User;
use WildPHP\Core\Users\UserCollection;

class ChannelStateManager
{
	use ContainerTrait;

	/**
	 * ChannelStateManager constructor.
	 *
	 * @param ComponentContainer $container
	 */
	public function __construct(ComponentContainer $container)
	{
		$events = [
			'irc.line.in.join' => 'processUserJoin',
			'irc.line.in.part' => 'processUserPart',
			'irc.line.in.kick' => 'processUserKick',
			'user.quit' => 'processUserQuit',
			'user.mode.channel' => 'processUserModeChange',

			// 353: RPL_NAMREPLY
			'irc.line.in.353' => 'populateChannel',

			// 332: RPL_TOPIC
			'irc.line.in.332' => 'processChannelTopicChange',

			// 001: RPL_WELCOME
			'irc.line.in.001' => 'joinInitialChannels',
		];

		foreach ($events as $event => $callback)
		{
			EventEmitter::fromContainer($container)
				->on($event, [$this, $callback]);
		}

		$this->setContainer($container);
	}

	/**
	 * @param JOIN $ircMessage
	 * @param Queue $queue
	 */
	public function processUserJoin(JOIN $ircMessage, Queue $queue)
	{
		$prefix = $ircMessage->getPrefix();
		/** @var User $userObject */
		$userObject = UserCollection::fromContainer($this->getContainer())
			->findOrCreateByNickname($ircMessage->getNickname());

		/** @var Channel $channel */
		$channel = ChannelCollection::fromContainer($this->getContainer())
			->requestByChannelName($ircMessage->getChannels()[0], $userObject);
		$accountname = $ircMessage->getIrcAccount();

		// TODO Isn't this really UserStateManager's job?
		$userObject->setIrcAccount($accountname);
		$userObject->setHostname($prefix->getHostname());
		$userObject->setUsername($prefix->getUsername());
		$userObject->getChannelCollection()
			->append($channel);

		$channel->getUserCollection()
			->append($userObject);

		EventEmitter::fromContainer($this->getContainer())
			->emit('user.join', [$userObject, $channel, $queue]);

		Logger::fromContainer($this->getContainer())
			->debug('Added user to channel.',
				[
					'reason' => 'join',
					'nickname' => $userObject->getNickname(),
					'channel' => $channel->getName()
				]);
	}

	/**
	 * @param PART $ircMessage
	 * @param Queue $queue
	 */
	public function processUserPart(PART $ircMessage, Queue $queue)
	{
		/** @var Channel $channel */
		$channel = ChannelCollection::fromContainer($this->getContainer())
			->findByChannelName($ircMessage->getChannels()[0]);

		/** @var User $userObject */
		$userObject = UserCollection::fromContainer($this->getContainer())
			->findByNickname($ircMessage->getNickname());

		if (!$channel->getUserCollection()->contains($userObject))
			return;

		$channel->getUserCollection()->remove($userObject);
		$userObject->getChannelCollection()->remove($channel);

		EventEmitter::fromContainer($this->getContainer())
			->emit('user.part', [$userObject, $channel, $queue]);

		Logger::fromContainer($this->getContainer())
			->debug('Removed user from channel',
				[
					'reason' => 'part',
					'nickname' => $userObject->getNickname(),
					'channel' => $channel->getName()
				]);
	}

	/**
	 * @param KICK $ircMessage
	 * @param Queue $queue
	 */
	public function processUserKick(KICK $ircMessage, Queue $queue)
	{
		/** @var Channel $channel */
		$channel = ChannelCollection::fromContainer($this->getContainer())
			->findByChannelName($ircMessage->getChannel());

		/** @var User $userObject */
		$userObject = UserCollection::fromContainer($this->getContainer())
			->findByNickname($ircMessage->getTarget());

		if (!$channel->getUserCollection()->contains($userObject))
			return;

		$channel->getUserCollection()->remove($userObject);
		$userObject->getChannelCollection()->remove($channel);

		EventEmitter::fromContainer($this->getContainer())
			->emit('user.kick', [$userObject, $channel, $queue]);

		Logger::fromContainer($this->getContainer())
			->debug('Removed user from channel',
				[
					'reason' => 'kick',
					'nickname' => $userObject->getNickname(),
					'channel' => $channel->getName()
				]);
	}

	/**
	 * @param User $userObject
	 */
	public function processUserQuit(User $userObject)
	{
		/** @var Channel[] $channels */
		$channels = ChannelCollection::fromContainer($this->getContainer())
			->values();

		/** @var Channel $channel */
		foreach ($channels as $channel)
		{
			if (!$channel->getUserCollection()->contains($userObject) || !$userObject->getChannelCollection()->contains($channel))
				continue;

			$channel->getUserCollection()->remove($userObject);
			$userObject->getChannelCollection()->remove($channel);

			Logger::fromContainer($this->getContainer())
				->debug('Removed user from channel',
					[
						'reason' => 'quit',
						'nickname' => $userObject->getNickname(),
						'channel' => $channel->getName()
					]);
		}
{'fraction_non_alphanumeric': 0.17228430115405752, 'fraction_numerical': 0.004396409598827624, 'mean_word_length': 4.698851774530271, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 193, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6629427', 'n_tokens_mistral': 3878, 'n_tokens_neox': 3298, 'n_words': 580}