Increase performance of nested keys search

* Fixed: insensitiviseMaps and tests

All keys (even nested ones) are now lower-cased recursively.

On the way, map[interface{}]interface{} are cast to map[string]interface{}

* Changed: simplified find() fast path and increase performance

Removed searchMapForKey(), fast path directly integrated into searchMap() and
searchMapWithPathPrefixes()
=> more generic (searchMapForKey() wasn't called everywhere it should have)

At the same time, significantly speed up searchMap() and searchMapWithPathPrefixes(),
which are still used for nested keys: the assumption that map keys are all
lower-cased allows to perform
    val = m[key]
instead of
    for k, v := range m {
      if strings.ToLower(k) == strings.ToLower(key) {
        val = v
      }
    }
=> i.e., directly access the map instead of enumerate the keys
diff --git a/util.go b/util.go
index b0903fb..aec8a99 100644
--- a/util.go
+++ b/util.go
@@ -41,15 +41,23 @@
 
 func insensitiviseMap(m map[string]interface{}) {
 	for key, val := range m {
+		switch val.(type) {
+		case map[interface{}]interface{}:
+			// nested map: cast and recursively insensitivise
+			val = cast.ToStringMap(val)
+			insensitiviseMap(val.(map[string]interface{}))
+		case map[string]interface{}:
+			// nested map: recursively insensitivise
+			insensitiviseMap(val.(map[string]interface{}))
+		}
+
 		lower := strings.ToLower(key)
 		if key != lower {
+			// remove old key (not lower-cased)
 			delete(m, key)
-			m[lower] = val
-			if m2, ok := val.(map[string]interface{}); ok {
-				// nested map: recursively insensitivise
-				insensitiviseMap(m2)
-			}
 		}
+		// update map
+		m[lower] = val
 	}
 }
 
diff --git a/viper.go b/viper.go
index 152e125..8d35fda 100644
--- a/viper.go
+++ b/viper.go
@@ -405,49 +405,22 @@
 	return false
 }
 
-// searchMapForKey may end up traversing the map if the key references a nested
-// item (foo.bar), but will use a fast path for the common case.
-// Note: This assumes that the key given is already lowercase.
-func (v *Viper) searchMapForKey(source map[string]interface{}, lcaseKey string) interface{} {
-	if !strings.Contains(lcaseKey, v.keyDelim) {
-		v, ok := source[lcaseKey]
-		if ok {
-			return v
-		}
-		return nil
-	}
-
-	path := strings.Split(lcaseKey, v.keyDelim)
-	return v.searchMap(source, path)
-}
-
 // searchMap recursively searches for a value for path in source map.
 // Returns nil if not found.
-// Note: This assumes that the path entries are lower cased.
+// Note: This assumes that the path entries and map keys are lower cased.
 func (v *Viper) searchMap(source map[string]interface{}, path []string) interface{} {
 	if len(path) == 0 {
 		return source
 	}
 
-	// Fast path
-	if len(path) == 1 {
-		if v, ok := source[path[0]]; ok {
-			return v
-		}
-		return nil
-	}
-
-	var ok bool
-	var next interface{}
-	for k, v := range source {
-		if k == path[0] {
-			ok = true
-			next = v
-			break
-		}
-	}
-
+	next, ok := source[path[0]]
 	if ok {
+		// Fast path
+		if len(path) == 1 {
+			return next
+		}
+
+		// Nested case
 		switch next.(type) {
 		case map[interface{}]interface{}:
 			return v.searchMap(cast.ToStringMap(next), path[1:])
@@ -456,9 +429,6 @@
 			// if the type of `next` is the same as the type being asserted
 			return v.searchMap(next.(map[string]interface{}), path[1:])
 		default:
-			if len(path) == 1 {
-				return next
-			}
 			// got a value but nested key expected, return "nil" for not found
 			return nil
 		}
@@ -475,6 +445,8 @@
 //
 // This should be useful only at config level (other maps may not contain dots
 // in their keys).
+//
+// Note: This assumes that the path entries and map keys are lower cased.
 func (v *Viper) searchMapWithPathPrefixes(source map[string]interface{}, path []string) interface{} {
 	if len(path) == 0 {
 		return source
@@ -484,17 +456,14 @@
 	for i := len(path); i > 0; i-- {
 		prefixKey := strings.ToLower(strings.Join(path[0:i], v.keyDelim))
 
-		var ok bool
-		var next interface{}
-		for k, v := range source {
-			if strings.ToLower(k) == prefixKey {
-				ok = true
-				next = v
-				break
-			}
-		}
-
+		next, ok := source[prefixKey]
 		if ok {
+			// Fast path
+			if i == len(path) {
+				return next
+			}
+
+			// Nested case
 			var val interface{}
 			switch next.(type) {
 			case map[interface{}]interface{}:
@@ -504,9 +473,6 @@
 				// if the type of `next` is the same as the type being asserted
 				val = v.searchMapWithPathPrefixes(next.(map[string]interface{}), path[i:])
 			default:
-				if len(path) == i {
-					val = next
-				}
 				// got a value but nested key expected, do nothing and look for next prefix
 			}
 			if val != nil {
@@ -626,7 +592,8 @@
 	valType := val
 	if v.typeByDefValue {
 		// TODO(bep) this branch isn't covered by a single test.
-		defVal := v.searchMapForKey(v.defaults, lcaseKey)
+		path := strings.Split(lcaseKey, v.keyDelim)
+		defVal := v.searchMap(v.defaults, path)
 		if defVal != nil {
 			valType = defVal
 		}
@@ -889,16 +856,14 @@
 
 	// if the requested key is an alias, then return the proper key
 	lcaseKey = v.realKey(lcaseKey)
-
-	// Set() override first
-	val = v.searchMapForKey(v.override, lcaseKey)
-	if val != nil {
-		return val
-	}
-
 	path = strings.Split(lcaseKey, v.keyDelim)
 	nested = len(path) > 1
 
+	// Set() override first
+	val = v.searchMap(v.override, path)
+	if val != nil {
+		return val
+	}
 	if nested && v.isPathShadowedInDeepMap(path, v.override) != "" {
 		return nil
 	}
@@ -918,7 +883,6 @@
 			return flag.ValueString()
 		}
 	}
-
 	if nested && v.isPathShadowedInFlatMap(path, v.pflags) != "" {
 		return nil
 	}
@@ -940,7 +904,7 @@
 			return val
 		}
 	}
-	if shadow := v.isPathShadowedInFlatMap(path, v.env); shadow != "" {
+	if nested && v.isPathShadowedInFlatMap(path, v.env) != "" {
 		return nil
 	}
 
@@ -949,7 +913,7 @@
 	if val != nil {
 		return val
 	}
-	if shadow := v.isPathShadowedInDeepMap(path, v.config); shadow != "" {
+	if nested && v.isPathShadowedInDeepMap(path, v.config) != "" {
 		return nil
 	}
 
@@ -958,7 +922,7 @@
 	if val != nil {
 		return val
 	}
-	if shadow := v.isPathShadowedInDeepMap(path, v.kvstore); shadow != "" {
+	if nested && v.isPathShadowedInDeepMap(path, v.kvstore) != "" {
 		return nil
 	}
 
@@ -967,7 +931,7 @@
 	if val != nil {
 		return val
 	}
-	if shadow := v.isPathShadowedInDeepMap(path, v.defaults); shadow != "" {
+	if nested && v.isPathShadowedInDeepMap(path, v.defaults) != "" {
 		return nil
 	}
 
diff --git a/viper_test.go b/viper_test.go
index f34421c..ab1f834 100644
--- a/viper_test.go
+++ b/viper_test.go
@@ -271,7 +271,7 @@
 	assert.False(t, InConfig("state"))
 	assert.Equal(t, "steve", Get("name"))
 	assert.Equal(t, []interface{}{"skateboarding", "snowboarding", "go"}, Get("hobbies"))
-	assert.Equal(t, map[string]interface{}{"jacket": "leather", "trousers": "denim", "pants": map[interface{}]interface{}{"size": "large"}}, Get("clothing"))
+	assert.Equal(t, map[string]interface{}{"jacket": "leather", "trousers": "denim", "pants": map[string]interface{}{"size": "large"}}, Get("clothing"))
 	assert.Equal(t, 35, Get("age"))
 }
 
@@ -639,10 +639,10 @@
 		"age":  35,
 		"owner": map[string]interface{}{
 			"organization": "MongoDB",
-			"Bio":          "MongoDB Chief Developer Advocate & Hacker at Large",
+			"bio":          "MongoDB Chief Developer Advocate & Hacker at Large",
 			"dob":          dob,
 		},
-		"owner.Bio": "MongoDB Chief Developer Advocate & Hacker at Large",
+		"owner.bio": "MongoDB Chief Developer Advocate & Hacker at Large",
 		"type":      "donut",
 		"id":        "0001",
 		"name":      "Cake",
@@ -651,7 +651,7 @@
 		"clothing": map[string]interface{}{
 			"jacket":   "leather",
 			"trousers": "denim",
-			"pants": map[interface{}]interface{}{
+			"pants": map[string]interface{}{
 				"size": "large",
 			},
 		},
@@ -697,7 +697,7 @@
 	assert.False(t, v.InConfig("state"))
 	assert.Equal(t, "steve", v.Get("name"))
 	assert.Equal(t, []interface{}{"skateboarding", "snowboarding", "go"}, v.Get("hobbies"))
-	assert.Equal(t, map[string]interface{}{"jacket": "leather", "trousers": "denim", "pants": map[interface{}]interface{}{"size": "large"}}, v.Get("clothing"))
+	assert.Equal(t, map[string]interface{}{"jacket": "leather", "trousers": "denim", "pants": map[string]interface{}{"size": "large"}}, v.Get("clothing"))
 	assert.Equal(t, 35, v.Get("age"))
 }