Router improvements

- Make dashes-to-underscores URI segment replacement configurable via ['translate_uri_dashes'].
- Make _set_routing() protected and move the call to the class constructor.
- Remove redudant calls to set_class() and set_method().
- Clean-up/optimize the routes loading procedure.

(fixes issue #2503)
diff --git a/application/config/routes.php b/application/config/routes.php
index a5047a1..3078c3c 100644
--- a/application/config/routes.php
+++ b/application/config/routes.php
@@ -49,7 +49,7 @@
 | RESERVED ROUTES
 | -------------------------------------------------------------------------
 |
-| There are two reserved routes:
+| There are three reserved routes:
 |
 |	$route['default_controller'] = 'welcome';
 |
@@ -62,10 +62,20 @@
 | This route will tell the Router which controller/method to use if those
 | provided in the URL cannot be matched to a valid route.
 |
+|	$route['translate_uri_dashes'] = FALSE;
+|
+| This is not exactly a route, but allows you to automatically route
+| controller and method names that contain dashes. '-' isn't a valid
+| class or method name character, so it requires translation.
+| When you set this option to TRUE, it will replace ALL dashes in the
+| controller and method URI segments.
+|
+| Examples:	my-controller/index	-> my_controller/index
+|		my-controller/my-method	-> my_controller/my_method
 */
-
 $route['default_controller'] = 'welcome';
 $route['404_override'] = '';
+$route['translate_uri_dashes'] = FALSE;
 
 /* End of file routes.php */
 /* Location: ./application/config/routes.php */
\ No newline at end of file
diff --git a/system/core/CodeIgniter.php b/system/core/CodeIgniter.php
index 3fe5c06..c682664 100644
--- a/system/core/CodeIgniter.php
+++ b/system/core/CodeIgniter.php
@@ -165,7 +165,6 @@
  * ------------------------------------------------------
  */
 	$RTR =& load_class('Router', 'core');
-	$RTR->_set_routing();
 
 	// Set any routing overrides that may exist in the main index file
 	if (isset($routing))
diff --git a/system/core/Router.php b/system/core/Router.php
index c86ab9c..cc3916f 100644
--- a/system/core/Router.php
+++ b/system/core/Router.php
@@ -82,6 +82,18 @@
 	public $default_controller;
 
 	/**
+	 * Translate URI dashes
+	 *
+	 * Determines whether dashes in controller & method segments
+	 * should be automatically replaced by underscores.
+	 *
+	 * @var	bool
+	 */
+	public $translate_uri_dashes = FALSE;
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * Class constructor
 	 *
 	 * Runs the route mapping function.
@@ -92,6 +104,7 @@
 	{
 		$this->config =& load_class('Config', 'core');
 		$this->uri =& load_class('URI', 'core');
+		$this->_set_routing();
 		log_message('debug', 'Router Class Initialized');
 	}
 
@@ -105,7 +118,7 @@
 	 *
 	 * @return	void
 	 */
-	public function _set_routing()
+	protected function _set_routing()
 	{
 		// Are query strings enabled in the config file? Normally CI doesn't utilize query strings
 		// since URI segments are more search-engine friendly, but they can optionally be used.
@@ -143,12 +156,14 @@
 			include(APPPATH.'config/'.ENVIRONMENT.'/routes.php');
 		}
 
-		$this->routes = (empty($route) OR ! is_array($route)) ? array() : $route;
-		unset($route);
-
-		// Set the default controller so we can display it in the event
-		// the URI doesn't correlated to a valid controller.
-		$this->default_controller = empty($this->routes['default_controller']) ? FALSE : $this->routes['default_controller'];
+		// Validate & get reserved routes
+		if (isset($route) && is_array($route))
+		{
+			isset($route['default_controller']) && $this->default_controller = $route['default_controller'];
+			isset($route['translate_uri_dashes']) && $this->translate_uri_dashes = $route['translate_uri_dashes'];
+			unset($route['default_controller'], $route['translate_uri_dashes']);
+			$this->routes = $route;
+		}
 
 		// Were there any query string segments? If so, we'll validate them and bail out since we're done.
 		if (count($segments) > 0)
@@ -191,8 +206,6 @@
 			$method = 'index';
 		}
 
-		$this->set_class($class);
-		$this->set_method($method);
 		$this->_set_request(array($class, $method));
 
 		// re-index the routed segments array so it starts with 1 rather than 0
@@ -221,8 +234,16 @@
 			return $this->_set_default_controller();
 		}
 
-		$this->set_class($segments[0]);
+		if ($this->translate_uri_dashes === TRUE)
+		{
+			$segments[0] = str_replace('-', '_', $segments[0]);
+			if (isset($segments[1]))
+			{
+				$segments[1] = str_replace('-', '_', $segments[1]);
+			}
+		}
 
+		$this->set_class($segments[0]);
 		isset($segments[1]) OR $segments[1] = 'index';
 		$this->set_method($segments[1]);
 
@@ -249,13 +270,12 @@
 			return $segments;
 		}
 
-		$temp = str_replace('-', '_', $segments[0]);
+		$test = ($this->translate_uri_dashes === TRUE)
+			? str_replace('-', '_', $segments[0]) : $segments[0];
 
 		// Does the requested controller exist in the root folder?
-		if (file_exists(APPPATH.'controllers/'.$temp.'.php'))
+		if (file_exists(APPPATH.'controllers/'.$test.'.php'))
 		{
-			$segments[0] = $temp;
-			empty($segments[1]) OR $segments[1] = str_replace('-', '_', $segments[1]);
 			return $segments;
 		}
 
@@ -266,11 +286,11 @@
 			$this->set_directory(array_shift($segments));
 			if (count($segments) > 0)
 			{
-				$segments[0] = str_replace('-', '_', $segments[0]);
-				empty($segments[1]) OR $segments[1] = str_replace('-', '_', $segments[1]);
+				$test = ($this->translate_uri_dashes === TRUE)
+					? str_replace('-', '_', $segments[0]) : $segments[0];
 
-				// Does the requested controller exist in the sub-folder?
-				if ( ! file_exists(APPPATH.'controllers/'.$this->directory.$segments[0].'.php'))
+				// Does the requested controller exist in the sub-directory?
+				if ( ! file_exists(APPPATH.'controllers/'.$this->directory.$test.'.php'))
 				{
 					if ( ! empty($this->routes['404_override']))
 					{
diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst
index 0beffb5..efbe860 100644
--- a/user_guide_src/source/changelog.rst
+++ b/user_guide_src/source/changelog.rst
@@ -414,7 +414,7 @@
    -  :doc:`URI Routing <general/routing>` changes include:
 
       -  Added possibility to route requests using callbacks.
-      -  Added possibility to use dashes in the controller and method URI segments (translated to underscores).
+      -  Added a new reserved route (*translate_uri_dashes*) to allow usage of dashes in the controller and method URI segments.
       -  Deprecated methods ``fetch_directory()``, ``fetch_class()`` and ``fetch_method()`` in favor of their respective public properties.
 
    -  :doc:`Language Library <libraries/language>` changes include:
@@ -483,7 +483,7 @@
 -  Fixed a bug (#23, #1238) - delete_all() in the `Database Caching Library <database/caching>` used to delete .htaccess and index.html files, which is a potential security risk.
 -  Fixed a bug in :doc:`Trackback Library <libraries/trackback>` method validate_url() where it didn't actually do anything, due to input not being passed by reference.
 -  Fixed a bug (#11, #183, #863) - CI_Form_validation::_execute() silently continued to the next rule, if a rule method/function is not found.
--  Fixed a bug (#122) Where routed uri string was being reported incorrectly in sub-directories.
+-  Fixed a bug (#122) - routed URI string was being reported incorrectly in sub-directories.
 -  Fixed a bug (#1242) - read_dir() in the :doc:`Zip Library <libraries/zip>` wasn't compatible with Windows.
 -  Fixed a bug (#306) - ODBC driver didn't have an _insert_batch() method, which resulted in fatal error being triggered when insert_batch() is used with it.
 -  Fixed a bug in MSSQL and SQLSrv's _truncate() where the TABLE keyword was missing.
diff --git a/user_guide_src/source/general/routing.rst b/user_guide_src/source/general/routing.rst
index 123257f..5520f59 100644
--- a/user_guide_src/source/general/routing.rst
+++ b/user_guide_src/source/general/routing.rst
@@ -145,7 +145,7 @@
 Reserved Routes
 ===============
 
-There are two reserved routes::
+There are three reserved routes::
 
 	$route['default_controller'] = 'welcome';
 
@@ -165,5 +165,17 @@
 continue loading the default *error_404.php* file at
 *application/views/errors/error_404.php*.
 
+
+::
+
+	$route['translate_uri_dashes'] = FALSE;
+
+As evident by the boolean value, this is not exactly a route. This
+option enables you to automatically replace dashes ('-') with
+underscores in the controller and method URI segments, thus saving you
+additional route entries if you need to do that.
+This is required, because the dash isn't a valid class or method name
+character and would cause a fatal error if you try to use it.
+
 .. important:: The reserved routes must come before any wildcard or
 	regular expression routes.
\ No newline at end of file