CI_Upload changes

- Method chaining support.
- A more abstract resetting of the default settings.
- Added an option to initialize() to disable resetting to default settings.
- Removed method mimes_types() and slightly optimized chunks of code where it was used.
- Added the ability to pass allowed_types as an array.
diff --git a/system/libraries/Upload.php b/system/libraries/Upload.php
index 4939b15..ff1b664 100644
--- a/system/libraries/Upload.php
+++ b/system/libraries/Upload.php
@@ -42,217 +42,210 @@
 	 *
 	 * @var	int
 	 */
-	public $max_size		= 0;
+	public $max_size = 0;
 
 	/**
 	 * Maximum image width
 	 *
 	 * @var	int
 	 */
-	public $max_width		= 0;
+	public $max_width = 0;
 
 	/**
 	 * Maximum image height
 	 *
 	 * @var	int
 	 */
-	public $max_height		= 0;
+	public $max_height = 0;
 
 	/**
 	 * Minimum image width
 	 *
 	 * @var	int
 	 */
-	public $min_width		= 0;
+	public $min_width = 0;
 
 	/**
 	 * Minimum image height
 	 *
 	 * @var	int
 	 */
-	public $min_height		= 0;
+	public $min_height = 0;
 
 	/**
 	 * Maximum filename length
 	 *
 	 * @var	int
 	 */
-	public $max_filename		= 0;
+	public $max_filename = 0;
 
 	/**
 	 * Maximum duplicate filename increment ID
 	 *
 	 * @var	int
 	 */
-	public $max_filename_increment 	= 100;
+	public $max_filename_increment = 100;
 
 	/**
 	 * Allowed file types
 	 *
 	 * @var	string
 	 */
-	public $allowed_types		= '';
+	public $allowed_types = '';
 
 	/**
 	 * Temporary filename
 	 *
 	 * @var	string
 	 */
-	public $file_temp		= '';
+	public $file_temp = '';
 
 	/**
 	 * Filename
 	 *
 	 * @var	string
 	 */
-	public $file_name		= '';
+	public $file_name = '';
 
 	/**
 	 * Original filename
 	 *
 	 * @var	string
 	 */
-	public $orig_name		= '';
+	public $orig_name = '';
 
 	/**
 	 * File type
 	 *
 	 * @var	string
 	 */
-	public $file_type		= '';
+	public $file_type = '';
 
 	/**
 	 * File size
 	 *
 	 * @var	int
 	 */
-	public $file_size		= NULL;
+	public $file_size = NULL;
 
 	/**
 	 * Filename extension
 	 *
 	 * @var	string
 	 */
-	public $file_ext		= '';
+	public $file_ext = '';
 
 	/**
 	 * Force filename extension to lowercase
 	 *
 	 * @var	string
 	 */
-	public $file_ext_tolower		= FALSE;
+	public $file_ext_tolower = FALSE;
 
 	/**
 	 * Upload path
 	 *
 	 * @var	string
 	 */
-	public $upload_path		= '';
+	public $upload_path = '';
 
 	/**
 	 * Overwrite flag
 	 *
 	 * @var	bool
 	 */
-	public $overwrite		= FALSE;
+	public $overwrite = FALSE;
 
 	/**
 	 * Obfuscate filename flag
 	 *
 	 * @var	bool
 	 */
-	public $encrypt_name		= FALSE;
+	public $encrypt_name = FALSE;
 
 	/**
 	 * Is image flag
 	 *
 	 * @var	bool
 	 */
-	public $is_image		= FALSE;
+	public $is_image = FALSE;
 
 	/**
 	 * Image width
 	 *
 	 * @var	int
 	 */
-	public $image_width		= NULL;
+	public $image_width = NULL;
 
 	/**
 	 * Image height
 	 *
 	 * @var	int
 	 */
-	public $image_height		= NULL;
+	public $image_height = NULL;
 
 	/**
 	 * Image type
 	 *
 	 * @var	string
 	 */
-	public $image_type		= '';
+	public $image_type = '';
 
 	/**
 	 * Image size string
 	 *
 	 * @var	string
 	 */
-	public $image_size_str		= '';
+	public $image_size_str = '';
 
 	/**
 	 * Error messages list
 	 *
 	 * @var	array
 	 */
-	public $error_msg		= array();
-
-	/**
-	 * MIME types list
-	 *
-	 * @var	array
-	 */
-	public $mimes			= array();
+	public $error_msg = array();
 
 	/**
 	 * Remove spaces flag
 	 *
 	 * @var	bool
 	 */
-	public $remove_spaces		= TRUE;
+	public $remove_spaces = TRUE;
 
 	/**
 	 * MIME detection flag
 	 *
 	 * @var	bool
 	 */
-	public $detect_mime		= TRUE;
+	public $detect_mime = TRUE;
 
 	/**
 	 * XSS filter flag
 	 *
 	 * @var	bool
 	 */
-	public $xss_clean		= FALSE;
+	public $xss_clean = FALSE;
 
 	/**
 	 * Apache mod_mime fix flag
 	 *
 	 * @var	bool
 	 */
-	public $mod_mime_fix		= TRUE;
+	public $mod_mime_fix = TRUE;
 
 	/**
 	 * Temporary filename prefix
 	 *
 	 * @var	string
 	 */
-	public $temp_prefix		= 'temp_file_';
+	public $temp_prefix = 'temp_file_';
 
 	/**
 	 * Filename sent by the client
 	 *
 	 * @var	bool
 	 */
-	public $client_name		= '';
+	public $client_name = '';
 
 	// --------------------------------------------------------------------
 
@@ -261,14 +254,21 @@
 	 *
 	 * @var	string
 	 */
-	protected $_file_name_override	= '';
+	protected $_file_name_override = '';
+
+	/**
+	 * MIME types list
+	 *
+	 * @var	array
+	 */
+	protected $_mimes = array();
 
 	/**
 	 * CI Singleton
 	 *
 	 * @var	object
 	 */
-	protected $CI;
+	protected $_CI;
 
 	// --------------------------------------------------------------------
 
@@ -278,15 +278,12 @@
 	 * @param	array	$props
 	 * @return	void
 	 */
-	public function __construct($props = array())
+	public function __construct($config = array())
 	{
-		if (count($props) > 0)
-		{
-			$this->initialize($props);
-		}
+		empty($config) OR $this->initialize($config, FALSE);
 
-		$this->mimes =& get_mimes();
-		$this->CI =& get_instance();
+		$this->_mimes =& get_mimes();
+		$this->_CI =& get_instance();
 
 		log_message('debug', 'Upload Class Initialized');
 	}
@@ -297,66 +294,62 @@
 	 * Initialize preferences
 	 *
 	 * @param	array	$config
-	 * @return	void
+	 * @param	bool	$reset
+	 * @return	CI_Upload
 	 */
-	public function initialize($config = array())
+	public function initialize(array $config = array(), $reset = TRUE)
 	{
-		$defaults = array(
-					'max_size'			=> 0,
-					'max_width'			=> 0,
-					'max_height'			=> 0,
-					'min_width'			=> 0,
-					'min_height'			=> 0,
-					'max_filename'			=> 0,
-					'max_filename_increment'	=> 100,
-					'allowed_types'			=> '',
-					'file_temp'			=> '',
-					'file_name'			=> '',
-					'orig_name'			=> '',
-					'file_type'			=> '',
-					'file_size'			=> NULL,
-					'file_ext'			=> '',
-					'file_ext_tolower' => FALSE,
-					'upload_path'			=> '',
-					'overwrite'			=> FALSE,
-					'encrypt_name'			=> FALSE,
-					'is_image'			=> FALSE,
-					'image_width'			=> NULL,
-					'image_height'			=> NULL,
-					'image_type'			=> '',
-					'image_size_str'		=> '',
-					'error_msg'			=> array(),
-					'remove_spaces'			=> TRUE,
-					'detect_mime'			=> TRUE,
-					'xss_clean'			=> FALSE,
-					'mod_mime_fix'			=> TRUE,
-					'temp_prefix'			=> 'temp_file_',
-					'client_name'			=> ''
-				);
+		$reflection = new ReflectionClass($this);
 
-		foreach ($defaults as $key => $val)
+		if ($reset === TRUE)
 		{
-			if (isset($config[$key]))
+			$defaults = $reflection->getDefaultProperties();
+			foreach (array_keys($defaults) as $key)
 			{
-				$method = 'set_'.$key;
-				if (method_exists($this, $method))
+				if ($key[0] === '_')
 				{
-					$this->$method($config[$key]);
+					continue;
+				}
+
+				if (isset($config[$key]))
+				{
+					if ($reflection->hasMethod('set_'.$key))
+					{
+						$this->{'set_'.$key}($config[$key]);
+					}
+					else
+					{
+						$this->$key = $config[$key];
+					}
 				}
 				else
 				{
-					$this->$key = $config[$key];
+					$this->$key = $defaults[$key];
 				}
 			}
-			else
+
+			return $this;
+		}
+
+		foreach ($config as $key => &$value)
+		{
+			if ($key[0] !== '_' && $reflection->hasProperty($key))
 			{
-				$this->$key = $val;
+				if ($reflection->hasMethod('set_'.$key))
+				{
+					$this->{'set_'.$key}($value);
+				}
+				else
+				{
+					$this->$key = $value;
+				}
 			}
 		}
 
 		// if a file_name was provided in the config, use it instead of the user input
 		// supplied file name for all uploads until initialized again
 		$this->_file_name_override = $this->file_name;
+		return $this;
 	}
 
 	// --------------------------------------------------------------------
@@ -487,7 +480,7 @@
 		}
 
 		// Sanitize the file name for security
-		$this->file_name = $this->CI->security->sanitize_filename($this->file_name);
+		$this->file_name = $this->_CI->security->sanitize_filename($this->file_name);
 
 		// Truncate the file name if it's too long
 		if ($this->max_filename > 0)
@@ -602,12 +595,13 @@
 	 * Set Upload Path
 	 *
 	 * @param	string	$path
-	 * @return	void
+	 * @return	CI_Upload
 	 */
 	public function set_upload_path($path)
 	{
 		// Make sure it has a trailing slash
 		$this->upload_path = rtrim($path, '/').'/';
+		return $this;
 	}
 
 	// --------------------------------------------------------------------
@@ -664,11 +658,12 @@
 	 * Set Maximum File Size
 	 *
 	 * @param	int	$n
-	 * @return	void
+	 * @return	CI_Upload
 	 */
 	public function set_max_filesize($n)
 	{
-		$this->max_size = ((int) $n < 0) ? 0 : (int) $n;
+		$this->max_size = ($n < 0) ? 0 : (int) $n;
+		return $this;
 	}
 
 	// --------------------------------------------------------------------
@@ -677,11 +672,12 @@
 	 * Set Maximum File Name Length
 	 *
 	 * @param	int	$n
-	 * @return	void
+	 * @return	CI_Upload
 	 */
 	public function set_max_filename($n)
 	{
-		$this->max_filename = ((int) $n < 0) ? 0 : (int) $n;
+		$this->max_filename = ($n < 0) ? 0 : (int) $n;
+		return $this;
 	}
 
 	// --------------------------------------------------------------------
@@ -690,11 +686,12 @@
 	 * Set Maximum Image Width
 	 *
 	 * @param	int	$n
-	 * @return	void
+	 * @return	CI_Upload
 	 */
 	public function set_max_width($n)
 	{
-		$this->max_width = ((int) $n < 0) ? 0 : (int) $n;
+		$this->max_width = ($n < 0) ? 0 : (int) $n;
+		return $this;
 	}
 
 	// --------------------------------------------------------------------
@@ -703,11 +700,12 @@
 	 * Set Maximum Image Height
 	 *
 	 * @param	int	$n
-	 * @return	void
+	 * @return	CI_Upload
 	 */
 	public function set_max_height($n)
 	{
-		$this->max_height = ((int) $n < 0) ? 0 : (int) $n;
+		$this->max_height = ($n < 0) ? 0 : (int) $n;
+		return $this;
 	}
 
 	// --------------------------------------------------------------------
@@ -716,11 +714,12 @@
 	 * Set minimum image width
 	 *
 	 * @param	int	$n
-	 * @return	void
+	 * @return	CI_Upload
 	 */
 	public function set_min_width($n)
 	{
-		$this->min_width = ((int) $n < 0) ? 0 : (int) $n;
+		$this->min_width = ($n < 0) ? 0 : (int) $n;
+		return $this;
 	}
 
 	// --------------------------------------------------------------------
@@ -729,11 +728,12 @@
 	 * Set minimum image height
 	 *
 	 * @param	int	$n
-	 * @return	void
+	 * @return	CI_Upload
 	 */
 	public function set_min_height($n)
 	{
-		$this->min_height = ((int) $n < 0) ? 0 : (int) $n;
+		$this->min_height = ($n < 0) ? 0 : (int) $n;
+		return $this;
 	}
 
 	// --------------------------------------------------------------------
@@ -742,16 +742,14 @@
 	 * Set Allowed File Types
 	 *
 	 * @param	string	$types
-	 * @return	void
+	 * @return	CI_Upload
 	 */
 	public function set_allowed_types($types)
 	{
-		if ( ! is_array($types) && $types === '*')
-		{
-			$this->allowed_types = '*';
-			return;
-		}
-		$this->allowed_types = explode('|', $types);
+		$this->allowed_types = (is_array($types) OR $types === '*')
+			? $types
+			: explode('|', $types);
+		return $this;
 	}
 
 	// --------------------------------------------------------------------
@@ -762,16 +760,11 @@
 	 * Uses GD to determine the width/height/type of image
 	 *
 	 * @param	string	$path
-	 * @return	void
+	 * @return	CI_Upload
 	 */
 	public function set_image_properties($path = '')
 	{
-		if ( ! $this->is_image())
-		{
-			return;
-		}
-
-		if (function_exists('getimagesize'))
+		if ($this->is_image() && function_exists('getimagesize'))
 		{
 			if (FALSE !== ($D = @getimagesize($path)))
 			{
@@ -783,6 +776,8 @@
 				$this->image_size_str	= $D[3]; // string containing height and width
 			}
 		}
+
+		return $this;
 	}
 
 	// --------------------------------------------------------------------
@@ -794,11 +789,12 @@
 	 * will be run through the XSS filter.
 	 *
 	 * @param	bool	$flag
-	 * @return	void
+	 * @return	CI_Upload
 	 */
 	public function set_xss_clean($flag = FALSE)
 	{
 		$this->xss_clean = ($flag === TRUE);
+		return $this;
 	}
 
 	// --------------------------------------------------------------------
@@ -845,7 +841,7 @@
 			return TRUE;
 		}
 
-		if ( ! is_array($this->allowed_types) OR count($this->allowed_types) === 0)
+		if (empty($this->allowed_types) OR ! is_array($this->allowed_types))
 		{
 			$this->set_error('upload_no_file_types');
 			return FALSE;
@@ -853,15 +849,13 @@
 
 		$ext = strtolower(ltrim($this->file_ext, '.'));
 
-		if ( ! in_array($ext, $this->allowed_types))
+		if ( ! in_array($ext, $this->allowed_types, TRUE))
 		{
 			return FALSE;
 		}
 
 		// Images get some additional checks
-		$image_types = array('gif', 'jpg', 'jpeg', 'png', 'jpe');
-
-		if (in_array($ext, $image_types) && @getimagesize($this->file_temp) === FALSE)
+		if (in_array($ext, array('gif', 'jpg', 'jpeg', 'jpe', 'png'), TRUE) && @getimagesize($this->file_temp) === FALSE)
 		{
 			return FALSE;
 		}
@@ -871,15 +865,11 @@
 			return TRUE;
 		}
 
-		$mime = $this->mimes_types($ext);
-
-		if (is_array($mime) && in_array($this->file_type, $mime, TRUE))
+		if (isset($this->_mimes[$ext]))
 		{
-			return TRUE;
-		}
-		elseif ($mime === $this->file_type)
-		{
-			return TRUE;
+			return is_array($this->_mimes[$ext])
+				? in_array($this->file_type, $this->_mimes[$ext], TRUE)
+				: ($this->_mimes[$ext] === $this->file_type);
 		}
 
 		return FALSE;
@@ -1034,7 +1024,7 @@
 	 * I'm not sure that it won't negatively affect certain files in unexpected ways,
 	 * but so far I haven't found that it causes trouble.
 	 *
-	 * @return	void
+	 * @return	string
 	 */
 	public function do_xss_clean()
 	{
@@ -1088,7 +1078,7 @@
 			return FALSE;
 		}
 
-		return $this->CI->security->xss_clean($data, TRUE);
+		return $this->_CI->security->xss_clean($data, TRUE);
 	}
 
 	// --------------------------------------------------------------------
@@ -1097,20 +1087,22 @@
 	 * Set an error message
 	 *
 	 * @param	string	$msg
-	 * @return	void
+	 * @return	CI_Upload
 	 */
 	public function set_error($msg)
 	{
-		$this->CI->lang->load('upload');
+		$this->_CI->lang->load('upload');
 
 		is_array($msg) OR $msg = array($msg);
 
 		foreach ($msg as $val)
 		{
-			$msg = ($this->CI->lang->line($val) === FALSE) ? $val : $this->CI->lang->line($val);
+			$msg = ($this->_CI->lang->line($val) === FALSE) ? $val : $this->_CI->lang->line($val);
 			$this->error_msg[] = $msg;
 			log_message('error', $msg);
 		}
+
+		return $this;
 	}
 
 	// --------------------------------------------------------------------
@@ -1130,22 +1122,6 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * List of Mime Types
-	 *
-	 * This is a list of mime types. We use it to validate
-	 * the "allowed types" set by the developer
-	 *
-	 * @param	string	$mime
-	 * @return	string
-	 */
-	public function mimes_types($mime)
-	{
-		return isset($this->mimes[$mime]) ? $this->mimes[$mime] : FALSE;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Prep Filename
 	 *
 	 * Prevents possible script execution from Apache's handling
@@ -1169,7 +1145,7 @@
 
 		foreach ($parts as $part)
 		{
-			if ( ! in_array(strtolower($part), $this->allowed_types) OR $this->mimes_types(strtolower($part)) === FALSE)
+			if ( ! in_array(strtolower($part), $this->allowed_types) OR ! isset($this->_mimes[strtolower($part)]))
 			{
 				$filename .= '.'.$part.'_';
 			}
diff --git a/tests/codeigniter/libraries/Upload_test.php b/tests/codeigniter/libraries/Upload_test.php
index a953d83..03eb640 100644
--- a/tests/codeigniter/libraries/Upload_test.php
+++ b/tests/codeigniter/libraries/Upload_test.php
@@ -259,10 +259,4 @@
 		$this->assertEquals('<p>Error test</p>', $this->upload->display_errors());
 	}
 
-	function test_mimes_types()
-	{
-		$this->assertEquals('text/plain', $this->upload->mimes_types('txt'));
-		$this->assertFalse($this->upload->mimes_types('foobar'));
-	}
-
 }
\ No newline at end of file
diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst
index 378494e..b654bc5 100644
--- a/user_guide_src/source/changelog.rst
+++ b/user_guide_src/source/changelog.rst
@@ -289,12 +289,15 @@
 
    -  :doc:`File Uploading Library <libraries/file_uploading>` changes include:
 
-      -  Added **max_filename_increment** config setting.
-      -  Added an **index** parameter to the ``data()`` method.
-      -  Added the **min_width** and **min_height** options for images.
+      -  Added method chaining support.
+      -  Added **max_filename_increment** and **file_ext_tolower** configuration settings.
+      -  Added **min_width** and **min_height** configuration settings for images.
+      -  Added **mod_mime_fix** configuration setting to disable suffixing multiple file extensions with an underscore.
+      -  Added the possibility pass **allowed_types** as an array.
+      -  Added an ``$index`` parameter to the method ``data()``.
+      -  Added a ``$reset`` parameter to method ``initialize()``.
       -  Removed method ``clean_file_name()`` and its usage in favor of :doc:`Security Library <libraries/security>`'s ``sanitize_filename()``.
-      -  Added **file_ext_tolower** config setting.
-      -  Added **mod_mime_fix** option to disable suffixing multiple file extensions with an underscore.
+      -  Removed method ``mimes_types()``.
 
    -  :doc:`Calendar Library <libraries/calendar>` changes include:
 
diff --git a/user_guide_src/source/libraries/file_uploading.rst b/user_guide_src/source/libraries/file_uploading.rst
index d7ba3a6..d93acb8 100644
--- a/user_guide_src/source/libraries/file_uploading.rst
+++ b/user_guide_src/source/libraries/file_uploading.rst
@@ -201,7 +201,7 @@
                                                                        directory must be writable and the path can be absolute or relative.
 **allowed_types**            None              None                    The mime types corresponding to the types of files you allow to be
                                                                        uploaded. Usually the file extension can be used as the mime type.
-                                                                       Separate multiple types with a pipe.
+                                                                       Can be either an array or a pipe-separated string.
 **file_name**                None              Desired file name       If set CodeIgniter will rename the uploaded file to this name. The
                                                                        extension provided in the file name must also be an allowed file type.
                                                                        If no extension is provided in the original file_name will be used.
@@ -254,6 +254,13 @@
 
 .. class:: CI_Upload
 
+	.. method:: initialize([array $config = array()[, $reset = TRUE]])
+
+		:param	array	$config: Preferences
+		:param	bool	$reset: Whether to reset preferences (that are not provided in $config) to their defaults
+		:returns:	CI_Upload instance (method chaining)
+		:rtype:	CI_Upload
+
 	.. method:: do_upload([$field = 'userfile'])
 
 		:param	string	$field: Name of the form field