<?php
/**
 * @brief		URL input class for Form Builder
 * @author		<a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
 * @copyright	(c) 2001 - SVN_YYYY Invision Power Services, Inc.
 * @license		http://www.invisionpower.com/legal/standards/
 * @package		IPS Social Suite
 * @since		11 Mar 2013
 * @version		SVN_VERSION_NUMBER
 */

namespace IPS\Helpers\Form;

/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
	header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
	exit;
}

/**
 * URL input class for Form Builder
 */
class _Url extends Text
{
	/**
	 * @brief	Default Options
	 * @code
	 	$childDefaultOptions = array(
	 		'allowedProtocols'	=> array( 'http', 'https' ),	// Allowed protocols. Default is http and https. Be careful changing this not to introduce security issues.
	 		'allowedMimes'		=> 'image/*',					// Sets the allowed mimetype(s). Can be string or array. * is a wildcard. Default is NULL, which allows any mimetypes.
	 		'file'				=> 'Profile',					// If provided, the contents of the URL will be fetched and written as a file, an \IPS\File object will then be returned rather than a string. Provide the extension name which specifies the storage location to use.
	 		'maxFileSize'		=> NULL,						// If provided along with 'file', the resulting file that is written to disk cannot be greater than this size in megabytes. NULL for no limit (default is NULL).
	 	);
	 * @endcode
	 */
	public $childDefaultOptions = array(
		'allowedProtocols'	=> array( 'http', 'https' ),
		'allowedMimes'		=> NULL,
		'file'				=> FALSE,
		'maxFileSize'		=> NULL,
	);
	
	/**
	 * Validate
	 *
	 * @throws	\InvalidArgumentException
	 * @throws	\DomainException
	 * @return	TRUE
	 */
	public function validate()
	{
		parent::validate();
		
		if ( $this->value )
		{
			$value = $this->formatValue();
			
			/* Check the URL is valid */
			if ( !( $value instanceof \IPS\Http\Url ) )
			{
				throw new \InvalidArgumentException('form_url_bad');
			}
			
			/* And that it's an allowed protocol */
			if ( !in_array(  mb_strtolower( $value->data['scheme'] ), $this->options['allowedProtocols'] ) )
			{
				throw new \DomainException('form_url_bad_protocol');
			}
			
			/* Try to fetch it, if necessary */
			if ( $this->options['file'] or $this->options['allowedMimes'] )
			{
				try
				{
					$response = $value->request()->get();
										
					/* Check MIME */
					if ( $this->options['allowedMimes'] )
					{
						$match = FALSE;

						if( isset( $response->httpHeaders['Content-Type'] ) )
						{
							foreach ( is_array( $this->options['allowedMimes'] ) ? $this->options['allowedMimes'] : array( $this->options['allowedMimes'] ) as $mime )
							{
								if ( preg_match( '/^' . str_replace( '~~', '.+', preg_quote( str_replace( '*', '~~', $mime ), '/' ) ) . '$/i', $response->httpHeaders['Content-Type'] ) )
								{
									$match = TRUE;
									break;
								}
							}
						}
						
						if ( !$match )
						{
							throw new \DomainException( 'form_url_bad_mime' );
						}
					}
					
					/* Write file if necessary */
					if ( $this->options['file'] )
					{
						$filename		= preg_replace( "/(.+?)(\?|$)/", "$1", mb_substr( $value, mb_strrpos( $value, '/' ) + 1 ) );
						$response		= (string) $response;

						if( $this->options['maxFileSize'] !== NULL )
						{
							$maxFileSize	= $this->options['maxFileSize'] * 1048576;

							if( \strlen( $response ) > $maxFileSize )
							{
								unset( $response );
								throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack( 'upload_too_big', TRUE, array( 'sprintf' => $this->options['maxFileSize'] ) ), 2 );
							}
						}

						$this->value = \IPS\File::create( $this->options['file'], $filename, $response );
					}
				}
				catch ( \IPS\Http\Request\Exception $e )
				{
					throw new \DomainException( 'form_url_error' );
				}
			}
		}
	}
	
	/**
	 * Get Value
	 *
	 * @return	string
	 */
	public function getValue()
	{
		$val = str_replace( 'feed://', 'http://', parent::getValue() );
		if ( $val and !mb_strpos( $val, '://' ) )
		{
			$val = "http://{$val}";
		}
		
		return $val;
	}
	
	/**
	 * Format Value
	 *
	 * @return	\IPS\Http\Url|string
	 */
	public function formatValue()
	{
		if ( $this->value and !( $this->value instanceof \IPS\Http\Url ) )
		{
			try
			{
				return new \IPS\Http\Url( $this->value );
			}
			catch ( \InvalidArgumentException $e )
			{
				return $this->value;
			}
		}
		
		return $this->value;
	}
}