/*
 * Bernoulli Compiler
 * Copyright (c) Cornell University
 * Department of Computer Science
 * 
 * Kamen Yotov (kamen@yotov.org)
 * 
 * $Source: C:/CVS/kyotov/kyotov/Research/BC/Core/Global.cs,v $
 * $Revision: 1.4 $
 * $Date: 2002/10/25 20:40:34 $
 */

using System;
using System.IO;
using System.Diagnostics;
using System.Reflection;

namespace BC.Core
{
	public class Global
	{
		public static UI.GetStringDelegate GetString;

		static Global ()
		{
			GetString = new UI().GetString;
		}

		public static string Indent (string s, int i)
		{
			StringReader r = new StringReader(s);
			StringWriter w = new StringWriter();

			string l;

			while ((l = r.ReadLine()) != null)
				w.WriteLine("{0}{1}", new string(' ', i * 2), l);

			return w.ToString();
		}

		public static int[] FirstElement (Array a)
		{
			int[] x = new int[a.Rank];

			x[0] = a.GetLowerBound(0) - 1;

			return x;
		}

		public static bool NextElement (Array a, ref int[] x)
		{
			for (int i = 0; i < a.Rank; i++)
				if (x[i] < a.GetUpperBound(i))
				{
					x[i]++;

					for (int j = i + 1; j < a.Rank; j++)
						x[j] = a.GetLowerBound(j);

					return true;
				}

			return false;
		}

		public static object Clone (object o)
		{
			if (o == null)
				return null;
			else
			{
				Type t = o.GetType();

				if (o is ICloneable)
					return ((ICloneable)o).Clone();
				else if (t.IsArray)
				{
					Array n = (Array)((Array)o).Clone();

					for (int[] x = FirstElement(n); NextElement(n, ref x);)
						n.SetValue(Clone(n.GetValue(x)), x);

					return n;
				}
				else if (t.IsClass)
				{
					object n = t.GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(o, new object[0]);
						
					foreach (FieldInfo fi in t.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public))
						if (fi.FieldType.IsClass)
							fi.SetValue(n, Clone(fi.GetValue(o)));
						else
							fi.SetValue(n, fi.GetValue(o));

					return n;
				}
				else
				{
					Debug.Assert(t.IsValueType);

					return o;
				}
			}
		}

		public static Array AppendToArray (Array a, object o)
		{
			Array r = Array.CreateInstance(a.GetType().GetElementType(), a.GetLength(0) + 1);
			
			a.CopyTo(r, 0);

			r.SetValue(o, r.Length - 1);

			return r;
		}
	}
}
