context: using System;
  using System.Collections.Generic;
  using System.IO;
  using System.Text;
  using WCell.Util.DB;
  
  namespace WCell.Util.Data
  {
  	public interface IComplexBinaryPersistor : IBinaryPersistor
  	{
  	}
  
  	public interface ISimpleBinaryPersistor : IBinaryPersistor
  	{
  		int BinaryLength { get; }
  	}
  
  	public interface IBinaryPersistor
  	{
  		void Write(BinaryWriter writer, object obj);
  
  		object Read(BinaryReader reader);
  	}
  
  	public interface IStringPersistor
  	{
  		void WriteText(BinaryWriter writer, string text);
  
  		object ReadText(BinaryReader reader);
  	}
  
  	public class ArrayPersistor : IComplexBinaryPersistor
  	{
  		private readonly ArrayDataField m_DataField;
  		private IBinaryPersistor m_UnderlyingPersistor;
  
  		public ArrayPersistor(ArrayDataField field)
  		{
  			m_DataField = field;
  			m_UnderlyingPersistor = BinaryPersistors.GetPersistorNoArray(m_DataField);
  		}
  
  		public ArrayDataField DataField
  		{
  			get { return m_DataField; }
  		}
  
  		public IBinaryPersistor UnderlyingPersistor
  		{
  			get { return m_UnderlyingPersistor; }
  		}
  
  		//public int BinaryLength
  		//{
  		//    get { return m_UnderlyingPersistor.BinaryLength * m_DataField.Length; }
  		//}
  
  		public void Write(BinaryWriter writer, object obj)
  		{
  			var i = 0;
  			if (obj != null)
  			{
  				for (; i < ((Array) obj).Length; i++)
  				{
  					var item = ((Array) obj).GetValue(i);
  					m_UnderlyingPersistor.Write(writer, item);
  				}
  			}
  
  			if (i < m_DataField.Length)
  			{
  				// write default Item as a filler
  				var type = m_DataField.ActualMemberType;
  
  				object deflt;
  				if (type == typeof(string))
  				{
  					deflt = "";
  				}
  				else
  				{
  					deflt = Activator.CreateInstance(type);
  				}
  
  				for (; i < m_DataField.Length; i++)
  				{
  					m_UnderlyingPersistor.Write(writer, deflt);
  				}
  			}
  		}
  
  		public object Read(BinaryReader reader)
  		{
  			var arr = (Array)m_DataField.ArrayProducer.Produce();
  			for (var i = 0; i < m_DataField.Length; i++)
  			{
  				object obj;
  				if (m_UnderlyingPersistor is NestedPersistor)
  				{
  					obj = arr.GetValue(i);
  					((NestedPersistor)m_UnderlyingPersistor).Read(reader, ref obj);
  				}
  				else
  				{
  					obj = m_UnderlyingPersistor.Read(reader);
  				}
  				ArrayUtil.SetValue(arr, i, obj);
  			}
  			return arr;
  		}
  	}
  
  	public class NestedPersistor : IComplexBinaryPersistor
  	{
  		private readonly INestedDataField m_DataField;
  		private IBinaryPersistor[] m_UnderlyingPersistors;
  		private IGetterSetter[] m_accessors;
  
  		public NestedPersistor(
  			INestedDataField dataField)
  		{
  			m_DataField = dataField;
  			m_UnderlyingPersistors = new IBinaryPersistor[m_DataField.InnerFields.Count];
  			m_accessors = new IGetterSetter[m_DataField.InnerFields.Count];
  			var i = 0;
  			foreach (var field in m_DataField.InnerFields.Values)
  			{
  				var persistor = BinaryPersistors.GetPersistor(field);
  				m_UnderlyingPersistors[i] = persistor;
  				m_accessors[i] = field.Accessor;
  				i++;
  			}
  		}
  
  		public INestedDataField DataField
  		{
  			get { return m_DataField; }
  		}
  
  		public IBinaryPersistor[] UnderlyingPersistors
  		{
  			get { return m_UnderlyingPersistors; }
  		}
  
  		public void Write(BinaryWriter writer, object obj)
  		{
  			if (obj == null)
  			{
  				obj = m_DataField.Producer.Produce();
  			}
  
  			for (var i = 0; i < m_UnderlyingPersistors.Length; i++)
  			{
  				var persistor = m_UnderlyingPersistors[i];
  				var val = m_accessors[i].Get(obj);
  				persistor.Write(writer, val);
  			}
  		}
  
  		public object Read(BinaryReader reader)
  		{
  			object obj = null;
  
  			Read(reader, ref obj);
  
  			return obj;
  		}
  
  		public void Read(BinaryReader reader, ref object obj)
  		{
  			if (obj == null)
  			{
  				if (m_DataField.Producer != null)
  				{
  					obj = m_DataField.Producer.Produce();
  				}
  				else
  				{
  					obj = Activator.CreateInstance(m_DataField.BelongsTo.GetActualType());
  				}
  
  			}
  			for (var i = 0; i < m_UnderlyingPersistors.Length; i++)
  			{
  				var persistor = m_UnderlyingPersistors[i];
  				var val = persistor.Read(reader);
  				m_accessors[i].Set(obj, val);
  			}
  		}
  	}
  
  	public static class BinaryPersistors
  	{
  		public static readonly Dictionary<Type, ISimpleBinaryPersistor> SimplePersistors =
  			new Dictionary<Type, ISimpleBinaryPersistor>();
  
  		public static Encoding DefaultEncoding = Encoding.UTF8;
  
  		static BinaryPersistors()
  		{
  			SimplePersistors[typeof(int)] = new Int32Persistor();
  			SimplePersistors[typeof(uint)] = new UInt32Persistor();
  			SimplePersistors[typeof(short)] = new Int16Persistor();
  			SimplePersistors[typeof(ushort)] = new UInt16Persistor();
  			SimplePersistors[typeof(byte)] = new BytePersistor();
  			SimplePersistors[typeof(sbyte)] = new SBytePersistor();
  			SimplePersistors[typeof(long)] = new Int64Persistor();
  			SimplePersistors[typeof(ulong)] = new UInt64Persistor();
  			SimplePersistors[typeof(float)] = new FloatPersistor();
  			SimplePersistors[typeof(double)] = new DoublePersistor();
  			SimplePersistors[typeof(string)] = new StringPersistor();
  			SimplePersistors[typeof(bool)] = new BoolPersistor();
  		}
  
  		public static ISimpleBinaryPersistor GetSimplePersistor(Type type)
  		{
  			ISimpleBinaryPersistor persistor;
  			if (type.IsEnum)
  			{
  
gt: 				type = Enum.GetUnderlyingType(type);