Create Decoder struct, start work on Metadata
diff --git a/error.go b/error.go
new file mode 100644
index 0000000..3460799
--- /dev/null
+++ b/error.go
@@ -0,0 +1,32 @@
+package mapstructure
+
+import (
+	"fmt"
+	"strings"
+)
+
+// Error implements the error interface and can represents multiple
+// errors that occur in the course of a single decode.
+type Error struct {
+	Errors []string
+}
+
+func (e *Error) Error() string {
+	points := make([]string, len(e.Errors))
+	for i, err := range e.Errors {
+		points[i] = fmt.Sprintf("* %s", err)
+	}
+
+	return fmt.Sprintf(
+		"%d error(s) decoding:\n\n%s",
+		len(e.Errors), strings.Join(points, "\n"))
+}
+
+func appendErrors(errors []string, err error) []string {
+	switch e := err.(type) {
+	case *Error:
+		return append(errors, e.Errors...)
+	default:
+		return append(errors, e.Error())
+	}
+}
diff --git a/mapstructure.go b/mapstructure.go
index 5c9c196..d2cd7a3 100644
--- a/mapstructure.go
+++ b/mapstructure.go
@@ -14,41 +14,81 @@
 	"strings"
 )
 
-// Error implements the error interface and can represents multiple
-// errors that occur in the course of a single decode.
-type Error struct {
-	Errors []string
+// DecoderConfig is the configuration that is used to create a new decoder
+// and allows customization of various aspects of decoding.
+type DecoderConfig struct {
+	// Metadata is the struct that will contain extra metadata about
+	// the decoding. If this is nil, then no metadata will be tracked.
+	Metadata *Metadata
+
+	// Result is a pointer to the struct that will contain the decoded
+	// value.
+	Result interface{}
 }
 
-func (e *Error) Error() string {
-	points := make([]string, len(e.Errors))
-	for i, err := range e.Errors {
-		points[i] = fmt.Sprintf("* %s", err)
-	}
+// A Decoder takes a raw interface value and turns it into structured
+// data, keeping track of rich error information along the way in case
+// anything goes wrong.
+type Decoder struct {
+	config *DecoderConfig
+}
 
-	return fmt.Sprintf(
-		"%d error(s) decoding:\n\n%s",
-		len(e.Errors), strings.Join(points, "\n"))
+// Metadata contains information about decoding a structure that
+// is tedious or difficult to get otherwise.
+type Metadata struct {
+	// Keys are the keys of the structure which were successfully decoded
+	Keys []string
+
+	// Unused is a slice of keys that were found in the raw value but
+	// weren't decoded since there was no matching field in the result interface
+	Unused []string
 }
 
 // Decode takes a map and uses reflection to convert it into the
 // given Go native structure. val must be a pointer to a struct.
 func Decode(m interface{}, rawVal interface{}) error {
-	val := reflect.ValueOf(rawVal)
+	config := &DecoderConfig{
+		Metadata: nil,
+		Result: rawVal,
+	}
+
+	decoder, err := NewDecoder(config)
+	if err != nil {
+		return err
+	}
+
+	return decoder.Decode(m)
+}
+
+// NewDecoder returns a new decoder for the given configuration. Once
+// a decoder has been returned, the same configuration must not be used
+// again.
+func NewDecoder(config *DecoderConfig) (*Decoder, error) {
+	val := reflect.ValueOf(config.Result)
 	if val.Kind() != reflect.Ptr {
-		return errors.New("val must be a pointer")
+		return nil, errors.New("result must be a pointer")
 	}
 
 	val = val.Elem()
 	if !val.CanAddr() {
-		return errors.New("val must be addressable (a pointer)")
+		return nil, errors.New("result must be addressable (a pointer)")
 	}
 
-	return decode("", m, val)
+	result := &Decoder{
+		config: config,
+	}
+
+	return result, nil
+}
+
+// Decode decodes the given raw interface to the target pointer specified
+// by the configuration.
+func (d *Decoder) Decode(raw interface{}) error {
+	return d.decode("", raw, reflect.ValueOf(d.config.Result).Elem())
 }
 
 // Decodes an unknown data type into a specific reflection value.
-func decode(name string, data interface{}, val reflect.Value) error {
+func (d *Decoder) decode(name string, data interface{}, val reflect.Value) error {
 	dataVal := reflect.ValueOf(data)
 	if !dataVal.IsValid() {
 		// If the data value is invalid, then we just set the value
@@ -72,17 +112,17 @@
 	case reflect.Interface:
 		fallthrough
 	case reflect.String:
-		return decodeBasic(name, data, val)
+		return d.decodeBasic(name, data, val)
 	case reflect.Int:
 		fallthrough
 	case reflect.Uint:
-		return decodeInt(name, data, val)
+		return d.decodeInt(name, data, val)
 	case reflect.Struct:
-		return decodeStruct(name, data, val)
+		return d.decodeStruct(name, data, val)
 	case reflect.Map:
-		return decodeMap(name, data, val)
+		return d.decodeMap(name, data, val)
 	case reflect.Slice:
-		return decodeSlice(name, data, val)
+		return d.decodeSlice(name, data, val)
 	}
 
 	// If we reached this point then we weren't able to decode it
@@ -91,7 +131,7 @@
 
 // This decodes a basic type (bool, int, string, etc.) and sets the
 // value to "data" of that type.
-func decodeBasic(name string, data interface{}, val reflect.Value) error {
+func (d *Decoder) decodeBasic(name string, data interface{}, val reflect.Value) error {
 	dataVal := reflect.ValueOf(data)
 	dataValType := dataVal.Type()
 	if !dataValType.AssignableTo(val.Type()) {
@@ -104,7 +144,7 @@
 	return nil
 }
 
-func decodeInt(name string, data interface{}, val reflect.Value) error {
+func (d *Decoder) decodeInt(name string, data interface{}, val reflect.Value) error {
 	dataVal := reflect.ValueOf(data)
 	dataKind := dataVal.Kind()
 	if dataKind >= reflect.Int && dataKind <= reflect.Int64 {
@@ -152,7 +192,7 @@
 	return nil
 }
 
-func decodeMap(name string, data interface{}, val reflect.Value) error {
+func (d *Decoder) decodeMap(name string, data interface{}, val reflect.Value) error {
 	dataVal := reflect.Indirect(reflect.ValueOf(data))
 	if dataVal.Kind() != reflect.Map {
 		return fmt.Errorf("'%s' expected a map, got '%s'", name, dataVal.Kind())
@@ -174,7 +214,7 @@
 
 		// First decode the key into the proper type
 		currentKey := reflect.Indirect(reflect.New(valKeyType))
-		if err := decode(fieldName, k.Interface(), currentKey); err != nil {
+		if err := d.decode(fieldName, k.Interface(), currentKey); err != nil {
 			errors = appendErrors(errors, err)
 			continue
 		}
@@ -182,7 +222,7 @@
 		// Next decode the data into the proper type
 		v := dataVal.MapIndex(k).Interface()
 		currentVal := reflect.Indirect(reflect.New(valElemType))
-		if err := decode(fieldName, v, currentVal); err != nil {
+		if err := d.decode(fieldName, v, currentVal); err != nil {
 			errors = appendErrors(errors, err)
 			continue
 		}
@@ -201,7 +241,7 @@
 	return nil
 }
 
-func decodeSlice(name string, data interface{}, val reflect.Value) error {
+func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value) error {
 	dataVal := reflect.Indirect(reflect.ValueOf(data))
 	dataValKind := dataVal.Kind()
 	if dataValKind != reflect.Array && dataValKind != reflect.Slice {
@@ -224,7 +264,7 @@
 		currentField := valSlice.Index(i)
 
 		fieldName := fmt.Sprintf("%s[%d]", name, i)
-		if err := decode(fieldName, currentData, currentField); err != nil {
+		if err := d.decode(fieldName, currentData, currentField); err != nil {
 			errors = appendErrors(errors, err)
 		}
 	}
@@ -240,7 +280,7 @@
 	return nil
 }
 
-func decodeStruct(name string, data interface{}, val reflect.Value) error {
+func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value) error {
 	dataVal := reflect.Indirect(reflect.ValueOf(data))
 	dataValKind := dataVal.Kind()
 	if dataValKind != reflect.Map {
@@ -304,7 +344,7 @@
 			fieldName = fmt.Sprintf("%s.%s", name, fieldName)
 		}
 
-		if err := decode(fieldName, rawMapVal.Interface(), field); err != nil {
+		if err := d.decode(fieldName, rawMapVal.Interface(), field); err != nil {
 			errors = appendErrors(errors, err)
 		}
 	}
@@ -315,12 +355,3 @@
 
 	return nil
 }
-
-func appendErrors(errors []string, err error) []string {
-	switch e := err.(type) {
-	case *Error:
-		return append(errors, e.Errors...)
-	default:
-		return append(errors, e.Error())
-	}
-}
diff --git a/mapstructure_test.go b/mapstructure_test.go
index d419e7d..4d664ed 100644
--- a/mapstructure_test.go
+++ b/mapstructure_test.go
@@ -351,7 +351,7 @@
 		t.Fatal("error should exist")
 	}
 
-	if err.Error() != "val must be a pointer" {
+	if err.Error() != "result must be a pointer" {
 		t.Errorf("got unexpected error: %s", err)
 	}
 }