/*
 * Bernoulli Compiler
 * Copyright (c) Cornell University
 * Department of Computer Science
 * 
 * Kamen Yotov (kamen@yotov.org)
 * 
 * $Source: C:/CVS/kyotov/kyotov/Research/BC/Core/Lexers/Location.cs,v $
 * $Revision: 1.6 $
 * $Date: 2002/08/15 03:14:12 $
 */

using System;
using System.Collections;
using System.Diagnostics;

namespace BC.Core
{
	namespace Lexers
	{
		public class Location
		{
			protected string f;
			protected string s;
			protected ArrayList l;
			protected int p;
			protected int c;
			protected int x;

			public Location (string f, string s, ArrayList l, int p, int c)
			{
				this.f = f;
				this.s = s;
				this.l = l;
				this.p = p;
				this.c = c;

				x = l.BinarySearch(Position);
				x = x >= 0 ? x + 1 : -x - 1;
			}

			protected int LineStart (int i)
			{
				return (int)l[i - 1];
			}

			public int Position
			{
				get
				{
					return p;
				}
				set
				{
					p = value;
				}
			}

			public int Length
			{
				get
				{
					return c;
				}
				set
				{
					c = value;
				}
			}

			public int End
			{
				get
				{
					return p + c;
				}
				set
				{
					c = value - p;
				}
			}

			public string File
			{
				get
				{
					return f;
				}
			}

			public int Line
			{
				get
				{
					return x;
				}
			}

			public int Column
			{
				get
				{
					return Position - LineStart(Line) + 1;
				}
			}

			public string LineText
			{
				get
				{
					int l = Line;

					string r = "";
				
					foreach (char c in s.Substring(LineStart(l), LineStart(l + 1) - LineStart(l)))
						r += c != '\t' ? c : ' ';

					if (r.IndexOf('\r') < 0)
						r += '\r';
					if (r.IndexOf('\n') < 0)
						r += '\n';

					return r;
				}
			}

			public override string ToString ()
			{
				return string.Format("{0} ({1},{2})\n|{3}|{4}^", File, Line, Column, LineText, new string('_', Column - 1));
			}

			public static Location operator + (Location l1, Location l2)
			{
				Debug.Assert(l1.File == l2.File);

				Location l = new Location(l1.File, l1.s, l1.l, Math.Min(l1.Position, l2.Position), 0);

				l.End = Math.Max(l1.End, l2.End);

				return l;
			}
		}
	}
}