internal object ParseDictionary(Dictionary <string, object> target, Dictionary <string, object> globalTypes, Type type, object input)
        {
            if (type == typeof(NameValueCollection))
            {
                return(Helper.CreateNV(target));
            }
            if (type == typeof(StringDictionary))
            {
                return(Helper.CreateSD(target));
            }

            if (target.TryGetValue("$i", out object tn))
            {
                ReverseCircularObject.TryGetValue((int)(long)tn, out object v);
                return(v);
            }

            if (target.TryGetValue("$types", out tn))
            {
                UseGlobals = true;
                if (globalTypes == null)
                {
                    globalTypes = new Dictionary <string, object>();
                }
                foreach (KeyValuePair <string, object> kv in (Dictionary <string, object>)tn)
                {
                    globalTypes.Add((string)kv.Value, kv.Key);
                }
            }
            if (globalTypes != null)
            {
                UseGlobals = true;
            }

            bool found = target.TryGetValue("$type", out tn);

            if (found == false && type == typeof(object))
            {
                return(target);   // CreateDataset(d, globaltypes);
            }
            if (found)
            {
                if (UseGlobals)
                {
                    if (globalTypes != null && globalTypes.TryGetValue((string)tn, out object tname))
                    {
                        tn = tname;
                    }
                }
                type = Reflection.Instance.GetTypeFromCache((string)tn);
            }

            if (type == null)
            {
                throw new Exception("Cannot determine type");
            }

            string typename = type.FullName;
            object o        = input;

            if (o == null)
            {
                o = Configuration.ParametricConstructorOverride
                    ? System.Runtime.Serialization.FormatterServices.GetUninitializedObject(type)
                    : Reflection.Instance.FastCreateInstance(type);
            }
            if (CircularObject.TryGetValue(o, out int circount) == false)
            {
                circount = CircularObject.Count + 1;
                CircularObject.Add(o, circount);
                ReverseCircularObject.Add(circount, o);
            }

            Dictionary <string, PropInfo> props = Reflection.Instance.Getproperties(type, typename, Configuration.ShowReadOnlyProperties);

            foreach (KeyValuePair <string, object> kv in target)
            {
                string n = kv.Key;
                object v = kv.Value;

                string name = n;//.ToLower();
                if (name == "$map")
                {
                    ProcessMap(o, props, (Dictionary <string, object>)target[name]);
                    continue;
                }
                if (props.TryGetValue(name, out PropInfo pi) == false)
                {
                    if (props.TryGetValue(name.ToLowerInvariant(), out pi) == false)
                    {
                        continue;
                    }
                }

                if (pi.CanWrite)
                {
                    if (v != null)
                    {
                        object oset = null;

                        switch (pi.Type)
                        {
                        case PropInfoType.Int: oset = (int)Helper.AutoConv(v); break;

                        case PropInfoType.Long: oset = Helper.AutoConv(v); break;

                        case PropInfoType.String: oset = v.ToString(); break;

                        case PropInfoType.Bool: oset = Helper.BoolConv(v); break;

                        case PropInfoType.DateTime: oset = Helper.CreateDateTime((string)v, Configuration.UseUTCDateTime); break;

                        case PropInfoType.Enum: oset = Helper.CreateEnum(pi.pt, v); break;

                        case PropInfoType.Guid: oset = Helper.CreateGuid((string)v); break;

                        case PropInfoType.Array:
                            if (!pi.IsValueType)
                            {
                                oset = CreateArray((List <object>)v, pi.pt, pi.bt, globalTypes);
                            }
                            // what about 'else'?
                            break;

                        case PropInfoType.ByteArray: oset = Convert.FromBase64String((string)v); break;

                        case PropInfoType.DataSet: oset = CreateDataset((Dictionary <string, object>)v, globalTypes); break;

                        case PropInfoType.DataTable: oset = CreateDataTable((Dictionary <string, object>)v, globalTypes); break;

                        case PropInfoType.Hashtable:     // same case as Dictionary
                        case PropInfoType.Dictionary: oset = CreateDictionary((List <object>)v, pi.pt, pi.GenericTypes, globalTypes); break;

                        case PropInfoType.StringKeyDictionary: oset = CreateStringKeyDictionary((Dictionary <string, object>)v, pi.pt, pi.GenericTypes, globalTypes); break;

                        case PropInfoType.NameValue: oset = Helper.CreateNV((Dictionary <string, object>)v); break;

                        case PropInfoType.StringDictionary: oset = Helper.CreateSD((Dictionary <string, object>)v); break;

                        case PropInfoType.Custom: oset = Reflection.Instance.CreateCustom((string)v, pi.pt); break;

                        default:
                        {
                            oset = pi.IsGenericType && pi.IsValueType == false && v is List <object>
                                   ?CreateGenericList((List <object>) v, pi.pt, pi.bt, globalTypes)
                                       : (pi.IsClass || pi.IsStruct || pi.IsInterface) && v is Dictionary <string, object>
                                       ?ParseDictionary((Dictionary <string, object>) v, globalTypes, pi.pt, null)
                                           : v is List <object>
                                           ?CreateArray((List <object>) v, pi.pt, typeof(object), globalTypes)
                                               : pi.IsValueType ? ChangeType(v, pi.changeType) : v;
                        }
                        break;
                        }

                        o = pi.setter(o, oset);
                    }
                }
            }
            return(o);
        }