public function loop($main = true) {
		if ($main && $this->manager) {
			$this->manager->onStartup($this);
		}
		
		while (($line = $this->connection->recv())) {
			if (preg_match("~^ping :(.*)?~i", $line, $pong)) {
				if (!$this->connection->send("PONG {$pong[1]}")) {
					throw new \RuntimeException(
						"failed to send PONG to {$this->server}");
				}
			} else {
				$message = new Message($line);
				
				/* management interface invokation */
				if ($main && $this->manager) {
					switch ($message->getType()) {
						case Message::join: $this->manager->onJoin($this, $message); break;
						case Message::part: $this->manager->onPart($this, $message); break;
						case Message::nick: $this->manager->onNick($this, $message); break;
						case Message::priv: $this->manager->onPriv($this, $message); break;
						/* and so on ... */
					}
				}
				
				/* listener interface invokation */
				foreach ($this->listeners as $listener) {
					$response = $listener
						->onReceive($this->connection, $message);
					if ($response) {
						if (($response instanceof Task)) {
							$this->pool
								->submit($response);
							continue;
						}
						
						throw new \RuntimeException(sprintf(
							"%s returned an invalid response, ".
							"expected Task object or nothing",
							get_class($listener)));
					}
				}
			}
			
			if (!$main)
				break;

			$this->pool->collect(function($responder) {
				if ($responder instanceof Task) {
					return $responder->isGarbage();
				} else return true;
			});
		}
		
		if ($main && $this->manager) {
			$this->manager->onShutdown($this);
		}

		return $main ? 
			$this->loop($main) : $this;
	}