using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Runtime.Serialization;

namespace Utility
{
    [Serializable]
    public class DynamicSerializable : DynamicObject, ISerializable
    {
        private readonly Dictionary<string, object> _dictionary = new Dictionary<string, object>();

        #region ISerializable Members

        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            foreach (var kvp in _dictionary)
            {
                info.AddValue(kvp.Key, kvp.Value);
            }
        }

        #endregion

        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            return TrySetMember(binder.Name, value);
        }

        public bool TrySetMember(string memberName, object value)
        {
            if (!_dictionary.ContainsKey(memberName))
            {
                _dictionary.Add(memberName, value);
            }
            else
            {
                _dictionary[memberName] = value;
            }
            return true;
        }

        public void SetMember(string memberName, object value)
        {
            TrySetMember(memberName, value);
        }

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            return TryGetMember(binder.Name, out result);
        }

        public bool TryGetMember(string memberName, out object result)
        {
            return _dictionary.TryGetValue(memberName, out result);
        }

        public object GetMember(string memberName)
        {
            object result;
            bool found = TryGetMember(memberName, out result);

            if (!found)
                throw new InvalidOperationException(string.Format("The member {0} does not exist.", memberName));

            return result;
        }
    }

    [KnownType(typeof (DynamicSerializable))]
    [DataContract]
    public class Root
    {
        [DataMember]
        public string Name { get; set; }

        [DataMember]
        public dynamic DynamicValues { get; set; }
    }
}