﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Script.Serialization;
using System.Collections.ObjectModel;
using System.Dynamic;
using System.Collections;

namespace Shopify {
    public class JsonHelper {
        // json -> dynamic decoder adopted from Shawn Weisfeld, http://bit.ly/jPqVsQ
            public static dynamic Decode(string json) {
                var serializer = new JavaScriptSerializer();
                serializer.RegisterConverters(new[] { new DynamicJsonConverter() });

                dynamic obj = serializer.Deserialize(json, typeof(object));

                return obj;
            }
            public static dynamic Encode(dynamic item) {
                var serializer = new JavaScriptSerializer();
                serializer.RegisterConverters(new JavaScriptConverter[]{ new DynamicJsonConverter() });
                dynamic obj = serializer.Serialize(item);

                return obj;
            }   
            private sealed class DynamicJsonConverter : JavaScriptConverter {
                public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer) {
                    if (dictionary == null)
                        throw new ArgumentNullException("dictionary");

                    return type == typeof(object) ? new DynamicJsonObject(dictionary) : null;
                }

                public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer) {
                    return null;
                }

                public override IEnumerable<Type> SupportedTypes {
                    get { return new ReadOnlyCollection<Type>(new List<Type>(new Type[] { typeof(object) })); }
                }
            }

            private sealed class DynamicJsonObject : DynamicObject {
                private readonly IDictionary<string, object> _dictionary;

                public DynamicJsonObject(IDictionary<string, object> dictionary) {
                    if (dictionary == null)
                        throw new ArgumentNullException("dictionary");
                    _dictionary = dictionary;
                }

                public override bool TryGetMember(GetMemberBinder binder, out object result) {
                    if (!_dictionary.TryGetValue(binder.Name, out result)) {
                        // return null to avoid exception.  caller can check for null this way...
                        result = null;
                        return true;
                    }

                    var dictionary = result as IDictionary<string, object>;
                    if (dictionary != null) {
                        result = new DynamicJsonObject(dictionary);
                        return true;
                    }

                    var arrayList = result as ArrayList;
                    if (arrayList != null && arrayList.Count > 0) {
                        if (arrayList[0] is IDictionary<string, object>)
                            result = new List<object>(arrayList.Cast<IDictionary<string, object>>().Select(x => new DynamicJsonObject(x)));
                        else
                            result = new List<object>(arrayList.Cast<object>());
                    }

                    return true;
                }
            }


    }
}
