context: //
  // Mono.Data.Tds.TdsMetaParameter.cs
  //
  // Author:
  //   Tim Coleman (tim@timcoleman.com)
  //
  // Copyright (C) Tim Coleman, 2002
  //
  
  //
  // Permission is hereby granted, free of charge, to any person obtaining
  // a copy of this software and associated documentation files (the
  // "Software"), to deal in the Software without restriction, including
  // without limitation the rights to use, copy, modify, merge, publish,
  // distribute, sublicense, and/or sell copies of the Software, and to
  // permit persons to whom the Software is furnished to do so, subject to
  // the following conditions:
  // 
  // The above copyright notice and this permission notice shall be
  // included in all copies or substantial portions of the Software.
  // 
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  //
  
  using Mono.Data.Tds.Protocol;
  using System;
  using System.Text;
  
  namespace Mono.Data.Tds {
  	public delegate object FrameworkValueGetter (object rawValue, ref bool updated);
  
  	public class TdsMetaParameter
  	{
  		#region Static 
  		public const int maxVarCharCharacters =  2147483647; // According to MS, max size is 2GB, 1 Byte Characters
  		public const int maxNVarCharCharacters = 1073741823; // According to MS, max size is 2GB, 2 Byte Characters
  		#endregion
  
  		#region Fields
  
  		TdsParameterDirection direction = TdsParameterDirection.Input;
  		byte precision;
  		byte scale;
  		int size;
  		string typeName;
  		string name;
  		bool isSizeSet = false;
  		bool isNullable;
  		object value;
  		bool isVariableSizeType;
  		FrameworkValueGetter frameworkValueGetter;
  		object rawValue;
  		bool isUpdated;
  
  		#endregion // Fields
  
  		public TdsMetaParameter (string name, object value)
  			: this (name, String.Empty, value)
  		{
  		}
  
  		public TdsMetaParameter (string name, FrameworkValueGetter valueGetter)
  			: this (name, String.Empty, null)
  		{
  			frameworkValueGetter = valueGetter;
  		}
  
  		public TdsMetaParameter (string name, string typeName, object value)
  		{
  			ParameterName = name;
  			Value = value;
  			TypeName = typeName;
  			IsNullable = false;
  		}
  
  		public TdsMetaParameter (string name, int size, bool isNullable, byte precision, byte scale, object value)
  		{
  			ParameterName = name;
  			Size = size;
  			IsNullable = isNullable;
  			Precision = precision;
  			Scale = scale;
  			Value = value;
  		}
  
  		public TdsMetaParameter (string name, int size, bool isNullable, byte precision, byte scale, FrameworkValueGetter valueGetter)
  		{
  			ParameterName = name;
  			Size = size;
  			IsNullable = isNullable;
  			Precision = precision;
  			Scale = scale;
  			frameworkValueGetter = valueGetter;
  		}
  
  		#region Properties
  
  		public TdsParameterDirection Direction {
  			get { return direction; }
  			set { direction = value; }
  		}
  
  		public string TypeName {
  			get { return typeName; }
  			set { typeName = value; }
  		}
  
  		public string ParameterName {
  			get { return name; }
  			set { name = value; }
  		}
  
  		public bool IsNullable {
  			get { return isNullable; }
  			set { isNullable = value; }
  		}
  
  		public object Value {
  			get {
  				if (frameworkValueGetter != null) {
  					object newValue = frameworkValueGetter (rawValue, ref isUpdated);
  					if (isUpdated)
  						value = newValue;
  				}
  
  				if (isUpdated) {
  					value = ResizeValue (value);
  					isUpdated = false;
  				}
  				return value;
  			}
  			set {
  				rawValue = this.value = value;
  				isUpdated = true;
  			}
  		}
  
  		public object RawValue {
  			get { return rawValue; }
  			set { Value = value; }
  		}
  
  		public byte Precision {
  			get { return precision; }
  			set { precision = value; }
  		}
  
  		public byte Scale {
  			get { 
  				if (TypeName == "decimal" || TypeName == "numeric") {
  					if (scale == 0 && !Convert.IsDBNull(Value)) {
  						int[] arr = Decimal.GetBits (
  								Convert.ToDecimal(Value));
  						scale = (byte)((arr[3]>>16) & (int)0xFF);
  					}
  				}
  				return scale;
  			}
  			set { scale = value; }
  		}
  
  		public int Size {
  			get { return GetSize (); }
  			set {
  				size = value;
  				isUpdated = true;
  				isSizeSet = true;
  			}
  		}
  
  		public bool IsVariableSizeType
  		{
  			get { return isVariableSizeType; }
  			set { isVariableSizeType = value; }
  		}
  
  		public bool IsVarNVarCharMax
  		{
  			get { return (TypeName == "ntext" && size >= maxNVarCharCharacters); }
  		}
  
  		public bool IsVarCharMax
  		{
  			get { return (TypeName == "text" && size >= maxVarCharCharacters); }
  		}
  
  		public bool IsAnyVarCharMax
  		{
  			get { return IsVarNVarCharMax || IsVarCharMax; }
  		}
  
  		public bool IsNonUnicodeText
  		{
  			get {
  				TdsColumnType colType = GetMetaType();
  				return (colType == TdsColumnType.VarChar ||
  				        colType == TdsColumnType.BigVarChar ||
  				        colType == TdsColumnType.Text ||
  				        colType == TdsColumnType.Char ||
  				        colType == TdsColumnType.BigChar);
  			}
  		}
  
  		public bool IsMoneyType
  		{
  			get {
  				TdsColumnType colType = GetMetaType();
  				return (colType == TdsColumnType.Money ||
  				        colType == TdsColumnType.MoneyN ||
  				        colType == TdsColumnType.Money4 ||
  				        colType == TdsColumnType.SmallMoney);
  			}
  		}
  
  		public bool IsDateTimeType
  		{
  			get {
  				TdsColumnType colType = GetMetaType();
  				return (colType == TdsColumnType.DateTime ||
  				        colType == TdsColumnType.DateTime4 ||
  				        colType == TdsColumnType.DateTimeN);
  			}
  		}
  
  		public bool IsTextType
  		{
  			get {
  				TdsColumnType colType = GetMetaType();
  				return (colType == TdsColumnType.VarChar ||
  				        colType == TdsColumnType.BigVarChar ||
  				        colType == TdsColumnType.BigChar ||
  				        colType == TdsColumnType.Char ||
  				        colType == TdsColumnType.BigNVarChar || 
  				        colType == TdsColumnType.NChar ||
  				        colType == TdsColumnType.Text ||
  				        colType == TdsColumnType.NText);
  			}
  		}
  
  		public bool IsDecimalType
  		{
  			get {
  				TdsColumnType colType = GetMetaType();
  				return (colType == TdsColumnType.Decimal ||
  				        colType == TdsColumnType.Numeric);
  			}
  		}
  
  		#endregion // Properties
  
  		#region Methods
  
  		object ResizeValue (object newValue)
  		{
  			if (newValue == DBNull.Value || newValue == null)
  				return newValue;
  
  			if (!isSizeSet || size <= 0)
  				return newValue;
  
  			// if size is set, truncate the value to specified size
  			string text = newValue as string;
  			if (text != null) {
  				if (TypeName == "nvarchar" || 
  				    TypeName == "nchar" ||
  				    TypeName == "xml") {
  					if (text.Length > size)
  						return text.Substring (0, size);
  				}
  			} else if (newValue.GetType () == typeof (byte [])) {
  				byte [] buffer = (byte []) newValue;
  
gt: 				if (buffer.Length > size) {