<#@ template language="C#" debug="True" #>
<#@ output extension="generated.cs" #>
//---------------------------------------------------------------------------------------------------
// <auto-generated>
//    This code was generated by BLToolkit template for T4.
//    Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.
// </auto-generated>
//---------------------------------------------------------------------------------------------------
using System;
using System.Data.SqlTypes;
using System.IO;
using System.Xml;

using Convert = BLToolkit.Common.Convert;

namespace BLToolkit.Mapping
{
	public partial class MemberMapper
	{
<#
		CreateMapper(SimpleMapper,
			"SByte", "Int16",  "Int32",  "Int64",
			"Byte",  "UInt16", "UInt32", "UInt64",
			"Single", "Double", "Char", "Boolean",
			"DateTime", "DateTimeOffset", "Decimal", "Guid", "Stream");
		CreateMapper(EnumNullableMapper, "SByte", "Int16", "Int32", "Int64", "Byte", "UInt16", "UInt32", "UInt64");
		CreateMapper(NullableMapper,     "Char", "Double", "Single", "Boolean", "DateTime", "Decimal", "Guid");
#>

#if !SILVERLIGHT
<#
		CreateMapper(SimpleMapper,  "XmlReader", "XmlDocument");
		CreateMapper(SqlTypeMapper, "Byte", "Int16", "Int32", "Int64", "Single", "Boolean", "Double", "DateTime", "Decimal", "Money", "Guid", "String");
#>

#endif
	}
}

<#+
void CreateMapper(Action<string> mapper, params string[] types)
{
	foreach (string t in types)
		mapper(t);
}

void SimpleMapper(string type)
{
	string getset = type;
	string cast   = "(" + type + ")";

	switch (type)
	{
		case "Stream"      :
		case "XmlReader"   :
		case "XmlDocument" :
			getset = "Value";
			cast   = "";
			break;
	}

#>

		class <#= type #>Mapper : MemberMapper
		{
			<#= type #> _nullValue;
<#+
				switch (type)
				{
					case "Stream"      :
					case "XmlReader"   :
					case "XmlDocument" :
						break;
					default            :
#>

			public override bool IsNull (object o) { return false; }
			public override void SetNull(object o) { MemberAccessor.Set<#= type #>(o, _nullValue); }
<#+
						break;
				}
#>

			public override void SetValue(object o, object value)
			{
				MemberAccessor.Set<#= getset #>(
					o,
					value is <#= type #> ? <#= cast #>value :
					value == null ? _nullValue : MappingSchema.ConvertTo<#= type #>(value));
			}

			public override void Init(MapMemberInfo mapMemberInfo)
			{
				if (mapMemberInfo == null) throw new ArgumentNullException("mapMemberInfo");
<#+
				switch (type)
				{
					case "Guid" :
#>

				if (mapMemberInfo.NullValue != null)
					_nullValue = mapMemberInfo.NullValue is Guid ?
						(Guid)mapMemberInfo.NullValue : new Guid(mapMemberInfo.NullValue.ToString());
<#+
						break;

					case "Stream"      :
					case "XmlReader"   :
					case "XmlDocument" :
#>

				if (mapMemberInfo.NullValue != null)
					_nullValue = mapMemberInfo.MappingSchema.ConvertTo<#= type #>(mapMemberInfo.NullValue);
<#+
						break;

					default:
#>

				_nullValue = Convert.To<#= type #>(mapMemberInfo.NullValue);
<#+

						break;
				}
#>

				base.Init(mapMemberInfo);
			}

			public class Nullable : <#= type #>Mapper
			{
<#+
				switch (type)
				{
					case "Stream"      :
					case "XmlReader"   :
					case "XmlDocument" :
						break;
					default:
#>
				public override bool IsNull(object o) { return Get<#= type #>(o) == _nullValue; }

<#+

						break;
				}
#>
				public override object GetValue(object o)
				{
					var value = MemberAccessor.Get<#= getset #>(o);
					return value == _nullValue ? null : (object)value;
				}
			}
		}
<#+
}

void NullableMapper(string type)
{
#>

		class Nullable<#= type #>Mapper : MemberMapper
		{
			public override bool IsNull (object o) { return GetNullable<#= type #>(o) == null; }
			public override void SetNull(object o) { MemberAccessor.SetNullable<#= type #>(o, null); }

			public override void SetValue(object o, object value)
			{
				MemberAccessor.SetNullable<#= type #>(
					o, value == null || value is <#= type #>? (<#= type #>?)value: MappingSchema.ConvertToNullable<#= type #>(value));
			}
		}
<#+
}

void EnumNullableMapper(string type)
{
#>

		class Nullable<#= type #>Mapper : MemberMapper
		{
			public override bool IsNull (object o) { return GetNullable<#= type #>(o) == null; }
			public override void SetNull(object o) { MemberAccessor.SetNullable<#= type #>(o, null); }

			public override void SetValue(object o, object value)
			{
				MemberAccessor.SetNullable<#= type #>(
					o, value == null || value is <#= type #>? (<#= type #>?)value: MappingSchema.ConvertToNullable<#= type #>(value));
			}

			public class Enum : NullableEnumMapper
			{
				public override void SetValue(object o, object value)
				{
					if (value != null)
					{
						var valueType = value.GetType();
						
						if (valueType != MemberType)
						{
							if (valueType != UnderlyingType)
								value = MappingSchema.ConvertToNullable<#= type #>(value);

							value = System.Enum.ToObject(MemberType, (<#= type #>)value);
						}
					}

					MemberAccessor.SetValue(o, value);
				}
			}
		}
<#+
}

void SqlTypeMapper(string type)
{
#>

		class Sql<#= type #>Mapper : MemberMapper
		{
			public override bool IsNull (object o) { return GetSql<#= type #>(o).IsNull; }
			public override void SetNull(object o) { MemberAccessor.SetSql<#= type #>(o, Sql<#= type #>.Null); }

			public override object GetValue(object o)
			{
				var value = MemberAccessor.GetSql<#= type #>(o);
				return value.IsNull? null: (object)value.Value;
			}

			public override void SetValue(object o, object value)
			{
				MemberAccessor.SetSql<#= type #>(
					o, value is Sql<#= type #>? (Sql<#= type #>)value: MappingSchema.ConvertToSql<#= type #>(value));
			}

			public class Default : Sql<#= type #>Mapper
			{
				public override bool SupportsValue { get { return false; } }

				public override object GetValue(object o)
				{
					return MapTo(base.GetValue(o));
				}

				public override void SetValue(object o, object value)
				{
					base.SetValue(o, MapFrom(value));
				}
			}
		}
<#+
}

#>
