using MediaBrowser.Model.Serialization;
using ProtoBuf;
using ProtoBuf.Meta;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace MediaBrowser.Common.Implementations.Serialization
{
    /// 
    /// Creates a compiled protobuf serializer based on a set of assemblies
    /// 
    public class ProtobufSerializer : IProtobufSerializer
    {
        /// 
        /// Gets or sets the type model.
        /// 
        /// The type model.
        private TypeModel TypeModel { get; set; }
        /// 
        /// Serializes to stream.
        /// 
        /// The obj.
        /// The stream.
        /// obj
        public void SerializeToStream(object obj, Stream stream)
        {
            if (obj == null)
            {
                throw new ArgumentNullException("obj");
            }
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }
            TypeModel.Serialize(stream, obj);
        }
        /// 
        /// Deserializes from stream.
        /// 
        /// The stream.
        /// The type.
        /// System.Object.
        /// stream
        public object DeserializeFromStream(Stream stream, Type type)
        {
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }
            
            return TypeModel.Deserialize(stream, null, type);
        }
        /// 
        /// Deserializes from stream.
        /// 
        /// 
        /// The stream.
        /// ``0.
        public T DeserializeFromStream(Stream stream)
            where T : class
        {
            return DeserializeFromStream(stream, typeof(T)) as T;
        }
        /// 
        /// Serializes to file.
        /// 
        /// 
        /// The obj.
        /// The file.
        /// file
        public void SerializeToFile(T obj, string file)
        {
            if (string.IsNullOrEmpty(file))
            {
                throw new ArgumentNullException("file");
            }
            
            using (Stream stream = File.Open(file, FileMode.Create))
            {
                SerializeToStream(obj, stream);
            }
        }
        /// 
        /// Deserializes from file.
        /// 
        /// 
        /// The file.
        /// ``0.
        /// file
        public T DeserializeFromFile(string file)
            where T : class
        {
            if (string.IsNullOrEmpty(file))
            {
                throw new ArgumentNullException("file");
            }
            
            using (Stream stream = File.OpenRead(file))
            {
                return DeserializeFromStream(stream);
            }
        }
        /// 
        /// Serializes to bytes.
        /// 
        /// 
        /// The obj.
        /// System.Byte[][].
        /// obj
        public byte[] SerializeToBytes(T obj)
            where T : class
        {
            if (obj == null)
            {
                throw new ArgumentNullException("obj");
            }
            
            using (var stream = new MemoryStream())
            {
                SerializeToStream(obj, stream);
                return stream.ToArray();
            }
        }
        /// 
        /// Creates the specified assemblies.
        /// 
        /// DynamicProtobufSerializer.
        /// assemblies
        public static ProtobufSerializer Create(IEnumerable types)
        {
            if (types == null)
            {
                throw new ArgumentNullException("types");
            }
            
            var model = TypeModel.Create();
            var attributeType = typeof(ProtoContractAttribute);
            // Find all ProtoContracts in the current assembly
            foreach (var type in types.Where(t => Attribute.IsDefined(t, attributeType)))
            {
                model.Add(type, true);
            }
            return new ProtobufSerializer { TypeModel = model.Compile() };
        }
    }
}