Source.java

package edu.udel.cis.vsl.tass.util;

import java.io.File;

import java.util.List;

/**
 * A Source object identifies a specific region of a file. It includes a
 * reference to the File itself, as well as the begin and end co-ordinates for
 * the point in the file. A "coordinate" is a pair (line,column), where line is
 * the line number and column is the character count from the beginning of the
 * line (not exactly "column", because a tab counts as one character).
 * 
 * In addition, the exact text from the file is excerpted and can be obtained
 * from this Source object.
 */
public class Source {

	/** The file referred to by this Source object. */
	private File file = null;

	/** The first line of the region referred to. Indexed from 1*/
	private int firstLine;

	/**
	 * The column within that first line that is the (inclusive) start
	 * point for the region referred to. Indexed from 1
	 */
	private int firstColumn;

	/**
	 * The last line of the region referred to. Indexed from 1
	 */
	private int lastLine;

	/**
	 * The columnd withing that last line that is the (inclusive) end
	 * point for the region referred to. Indexed from 1
	 */
	private int lastColumn;

	private List<String> fileContents = null;

	private String text = null;

	public Source(File file, int firstLine, int lastLine, int firstColumn,
				  int lastColumn) {
		this.file = file;
		this.firstLine = firstLine;
		this.lastLine = lastLine;
		this.firstColumn = firstColumn;
		this.lastColumn = lastColumn;
	}

	public File file() {
		return file;
	}

	public void setFile(File file) {
		this.file = file;
	}

	public void setFileContents(List<String> fileContents) {
		this.fileContents = fileContents;
	}

	public void setText(String text) {
		this.text = text;
	}

	public void setFirstLine(int firstLine) {
		this.firstLine = firstLine;
	}

	public void setLastLine(int lastLine) {
		this.lastLine = lastLine;
	}

	public void setFirstColumn(int firstColumn) {
		this.firstColumn = firstColumn;
	}

	public void setLastColumn(int lastColumn) {
		this.lastColumn = lastColumn;
	}

	public int firstLine() {
		return firstLine;
	}

	public int lastLine() {
		return lastLine;
	}

	public int firstColumn() {
		return firstColumn;
	}

	public int lastColumn() {
		return lastColumn;
	}


	/**
	 * Returns the text set for this source element with setText() if
	 * it has been set, otherwise if setFileContents() has been used
	 * to set associate a file with this source element it will fetch
	 * the source text from that. If neither has been set then text()
	 * returns null
	 */
	public String text() {
		if (text != null) {
			return text;
		}
		if (fileContents == null) {
			return null;
		}
		// Note that firstLine etc. use one based indexing,
		// while fileContents is zero indexed
		if (firstLine == lastLine) {
			return fileContents.get(firstLine-1).substring(firstColumn-1,lastColumn);
		} else {
			StringBuilder sb = new StringBuilder();

			sb.append(fileContents.get(firstLine-1).substring(firstColumn-1));

			//Grabs only the lines strictly between the first and last line:
			for (int i=firstLine();i<lastLine()-1;i++) {
				sb.append(fileContents.get(i));
			}

			sb.append(fileContents.get(lastLine-1).substring(0,lastColumn));
			return sb.toString();
		}
	}

	public String toString() {
		/*
		 * return "File " + file + " line " + firstLine + " column " +
		 * firstColumn + " through line " + lastLine + " column " + lastColumn +
		 * ":\n" + text;
		 */
		String filename = (file == null ? "Unknown file" : file.getName());

		return filename + " " + firstLine + "." + firstColumn + "--" + lastLine
			+ "." + lastColumn + ": \"" + text() + "\"";
	}
}