<?php namespace Intellex\Curly\Content;

use Intellex\Curly\Content\Exception\ContentTypeNotSupportedException;
use Intellex\Curly\Content\Exception\InvalidContentTypeHandlerException;

/**
 * The base type for all content types.
 */
abstract class Type implements TypeHandlerInterface {

	/** @var array The list of handlers manage the various content types. */
	private static $handlers = [];

	/**
	 * Initialize the proper content type.
	 *
	 * @param string $contentType The string representation of the content type.
	 *
	 * @return string $contentType The requested content type.
	 * @throws InvalidContentTypeHandlerException On invalid handler.
	 * @throws ContentTypeNotSupportedException On unrecognized on not supported type.
	 */
	public static function init($contentType) {

		// Make sure the default handlers are loaded
		if (static::$handlers === []) {
			static::registerHandler('~^$~', '\Intellex\Curly\Content\TypeHandlers\Plain');
			static::registerHandler('~text/plain~', '\Intellex\Curly\Content\TypeHandlers\Plain');
			static::registerHandler('~text/xml~', '\Intellex\Curly\Content\TypeHandlers\XML');
			static::registerHandler('~multipart/form-data~', '\Intellex\Curly\Content\TypeHandlers\MultipartFormData');
			static::registerHandler('~application/x-www-form-urlencoded~', '\Intellex\Curly\Content\TypeHandlers\URLEncoded');
			static::registerHandler('~(application|text)/.*?json~', '\Intellex\Curly\Content\TypeHandlers\JSON');
		}

		// Find the handler
		foreach (static::$handlers as $condition => $handler) {
			if (preg_match($condition, $contentType)) {

				// Validate the handlers
				$instance = new $handler($contentType);
				if (!($instance instanceof TypeHandlerInterface)) {
					throw new Exception\InvalidContentTypeHandlerException($handler);
				}

				return $instance;
			}
		}

		throw new Exception\ContentTypeNotSupportedException($contentType);
	}

	/**
	 * Register a new handler for a specified content type.
	 *
	 * @param string $regexp The regular expression used to recognize the content type.
	 * @param string $class  The class to instantiate for this type.
	 */
	public static function registerHandler($regexp, $class) {
		static::$handlers[$regexp] = $class;
	}

}
