package ws.prova.parser;

/*
 * Copyright (C) 2002-2007 <a href="mailto:a.kozlenkov@city.ac.uk">Alex Kozlenkov</a>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.Vector;

/**
 * A class encapsulating a String and keeping track of an offset
 * with respect to the initial String
 * due to substring() operations.
 * <p>Title: Prova </p>
 * <p>Description: String encapsulation keeping track of the substring offset</p>
 * <p>Copyright: Copyright (C) 2002-2007</p>
 * <p>Company: City University, London, United Kingdom</p>
 *
 * @author Alex Kozlenkov
 * @version 2.0 <25 March 2007>
 */
public class OffsetString {
	StringBuffer str;
	int offset;
	int lastLine;
	List atoms;
	List lines;
	Vector linePos;

	public OffsetString(final String str, final Vector linePos) {
		this.str = new StringBuffer(str);
		this.str.ensureCapacity(65536);
		this.atoms = new ArrayList();
		this.lines = new ArrayList();
		this.linePos = linePos;
		this.lastLine = 0;
	}

	public StringBuffer getStr() {
		return str;
	}

	public void setStr(final String str) {
		this.str = new StringBuffer(str);
	}

	public int getOffset() {
		return offset;
	}

	public int length() {
		return str.length();
	}

	public char charAt(final int pos) {
		return str.charAt(pos);
	}

	public boolean equals(final String s) {
		return str.toString().equals(s);
	}

	public OffsetString offsetBy(final int offset) {
		this.offset += offset;
		str = new StringBuffer( str.substring(offset) );
		return this;
	}

	public String substring(final int pos, final int offset) {
		return str.substring(pos, offset);
	}

	/**
	 * @param chA
	 * @param chB
	 * @param pos
	 * @return
	 */
	public int pair_diff(final char chA, final char chB, int[] pos) {
		int numA = 0;
		int numB = 0;
		int diff = 0;
		char ch;
		boolean inquotes = false;
		int i = 0;
		for (; i < str.length(); i++) {
			ch = str.charAt(i);
			if (ch == '"') {
				inquotes = !inquotes;
			}
			if (inquotes) {
				continue;
			} else if (ch == chA) {
				numA++;
				diff++;
			} else if (ch == chB) {
				numB++;
				diff--;
				if (diff == 0) {
					pos[0] = i + 1;
					break;
				}
				str.setCharAt(i,']');
			}
		}
		return numA - numB;
	}

	/**
	 * Return the current line given the current <code>offset</code>.
	 * <code>linePos</code> stores the line from which to start a following search.
	 *
	 * @return
	 */
	public int line() {
		int delta = offset;
		if (str.charAt(0) == '.' || str.charAt(0) == ',')
			delta++;
		else if (str.charAt(0) == ':')
			delta += 2;
		for (int i = lastLine; i < linePos.size(); i++) {
			int pos = ((Integer) linePos.elementAt(i)).intValue();
			if (delta < pos) {
				lastLine = i;
				return 1 + i;
			}
		}
		return 1 + linePos.size();
	}

	/**
	 * Add a new atom and record the corresponding line.
	 *
	 * @param s A String representation of the added atom.
	 */
	void add(final String s) {
		atoms.add(s);
		lines.add(new Integer(line()));
	}

	/**
	 * Return the line given the atom index.
	 *
	 * @return
	 */
	public int atomLine(final int atomIndex) {
		return ((Integer) lines.get(atomIndex)).intValue();
	}

	/**
	 * Return a ListIterator for the stored atoms.
	 *
	 * @return
	 */
	public ListIterator listIterator() {
		return atoms.listIterator();
	}
}
