/*
 * Bernoulli Compiler
 * Copyright (c) Cornell University
 * Department of Computer Science
 * 
 * Kamen Yotov (kamen@yotov.org)
 * 
 * $Source: C:/CVS/kyotov/kyotov/Research/BC/Core/Machines/IntegerType.cs,v $
 * $Revision: 1.9 $
 * $Date: 2002/10/22 19:41:32 $
 */

using System;
using System.Diagnostics;

namespace BC.Core
{
	using Exceptions;

	namespace Machines
	{
		[Serializable]
		public class IntegerType: MachineType
		{
			public enum SignType
			{
				stNone,
				stSigned,
				stUnsigned,
				stBoth,
			};

			public IntegerType (Type t) :
				base(t)
			{
			}

			public IntegerType () :
				base(typeof(int))
			{
			}

			public decimal MinValue
			{
				get
				{
					return (decimal)Convert.ChangeType(Type.GetField("MinValue").GetValue(null), typeof(decimal));
				}
			}

			public decimal MaxValue
			{
				get
				{
					return (decimal)Convert.ChangeType(Type.GetField("MaxValue").GetValue(null), typeof(decimal));
				}
			}

			public override ASTs.AbstractPrimitiveType ASTType
			{
				get
				{
					ASTs.IntegerType t = new ASTs.IntegerType();

					t.Signed = Signed;
					t.Precision = Precision;

					return t;
				}
			}
					
			public override int Precision
			{
				get
				{
					double dmin = (double)MinValue;
					double dmax = (double)MaxValue;

					double d = dmax - dmin;

					return (int)(Math.Log(d, 2) + 0.5);
				}
			}

			public bool Signed
			{
				get
				{
					return MinValue < 0;
				}
			}

			public bool Contains (decimal d)
			{
				return MinValue <= d && d <= MaxValue;
			}

			protected static readonly IntegerType[] IntegerTypes =
			{
				new IntegerType(typeof(SByte)),	// signed char
				new IntegerType(typeof(Byte)),	// unsigned char
				new IntegerType(typeof(Int16)),	// signed short int
				new IntegerType(typeof(UInt16)),// unsigned short int
				new IntegerType(typeof(Int32)),	// signed (long) int
				new IntegerType(typeof(UInt32)),// unsinged (long) int
				new IntegerType(typeof(Int64)),	// signed long long int
				new IntegerType(typeof(UInt64))	// unsigned long long int
			};

			protected static readonly string digits = "0123456789ABCDEF";

			public static decimal Parse (string c, int b)
			{
				if (c == "")
					return 0;
				else
					return Parse(c.Substring(0, c.Length - 1), b) * b + digits.IndexOf(c[c.Length - 1]);
			}

			public static decimal Parse (string c)
			{
				try
				{
					if (c == "0")
						return 0;
					else if (c.StartsWith("0x"))
						return Parse(c.Substring(2).ToUpper(), 16);
					else if (c.StartsWith("0"))
						return Parse(c, 8);
					else
						return Parse(c, 10);
				}
				catch
				{
					return decimal.MaxValue;
				}
			}

			public static IntegerType Get (string c, SignType s)
			{
				decimal d = Parse(c);

				foreach (IntegerType i in IntegerTypes)
					if (i.Contains(d) && (
						(i.Signed && (s & SignType.stSigned) != SignType.stNone) ||
						(!i.Signed && (s & SignType.stUnsigned) != SignType.stNone)))
						return i;

				return null;
			}

			public static IntegerType Get (int p, SignType s)
			{
				foreach (IntegerType i in IntegerTypes)
					if (i.Precision == p && (
						(i.Signed && (s & SignType.stSigned) != SignType.stNone) ||
						(!i.Signed && (s & SignType.stUnsigned) != SignType.stNone)))
						return i;

				return null;
			}

			public static IntegerType Get (int p, bool s)
			{
				return s ? Get(p, SignType.stSigned) : Get(p, SignType.stUnsigned);
			}

			public static IntegerType Dominator (IntegerType t1, IntegerType t2)
			{
				int i1 = Array.IndexOf(IntegerTypes, t1);
				int i2 = Array.IndexOf(IntegerTypes, t2);

				Debug.Assert(i1 >= 0 && i2 >= 0);

				return IntegerTypes[Math.Max(i1, i2)];
			}
		}
	}
}