package tools.file;

import java.util.ArrayList;

;
/**
 * this class represents a path / a path + a filename filename may be with
 * anchor, e.g.
 * 
 * root/dir1/dir2/example.html#anchoridentifier
 * 
 * @author Martin
 * 
 */
public class Path extends ArrayList<String> {

	/**
	 * filename without path
	 */
	private String filename = "";

	/**
	 * anchor identifier at end of filename (after #)
	 */
	private String anchor = "";

	/**
	 * true, if this path represents an absolute link inside a wiki
	 */
	private boolean isAbsoluteWikiLink = false;

	/**
	 * returns anchor identifier, if there is one
	 * 
	 * @return
	 */
	public String getAnchor() {
		return anchor;
	}

	/**
	 * sets anchor identifier
	 * 
	 * @param anchor
	 */
	public void setAnchor(String anchor) {
		this.anchor = anchor;
	}

	/**
	 * contstructor
	 * 
	 * @param path
	 * @param withFilename
	 * @param isWikiPath
	 */
	public Path(String path, boolean withFilename, boolean isWikiPath) {
		String part = "";

		boolean startsWithColon = false;

		if (path.length() > 0 && path.charAt(0) == ':') {
			startsWithColon = true;
		}

		if (isWikiPath && path.length() > 0 && path.charAt(0) == ':') {
			path = path.substring(1);
		}

		for (int i = 0; i < path.length(); i++) {
			Character c = path.charAt(i);
			if (c == '/' || c == '\\' || (isWikiPath && c == ':')) {
				add(part);
				part = "";
			} else {
				part += c;
			}
		}
		if (!part.isEmpty()) {
			add(part);
		}
		if (withFilename && size() > 0) {
			String s = get(size() - 1);
			remove(size() - 1);
			filename = s;
		}

		if (!filename.isEmpty() && filename.contains("#")) {
			int pos = filename.indexOf('#');
			anchor = filename.substring(pos + 1);
			filename = filename.substring(0, pos);
		}

		isAbsoluteWikiLink = (isWikiPath && (startsWithColon || size() >= 1)
				&& (size() > 0) && (!get(0).equalsIgnoreCase(".")) && (!get(0)
				.equalsIgnoreCase("..")));

		normalize();

	}

	/**
	 * if part of path is ".." and part before is normal directory then delete
	 * both. e.g. before: path == this/../is/a/../example after: path ==
	 * is/example
	 */

	public void normalize() {
		int i = 0;
		while (i < size() - 1) {
			if (get(i + 1).equals("..")
					&& !(get(i).equals(".") || get(i).equals(".."))) {
				remove(i);
				remove(i);
			} else {
				i++;
			}
		}
	}

	/**
	 * change .txt-suffix to .html-suffix
	 */
	public void changeTxtToHtm() {
		if (filename.length() > 4
				&& filename.substring(filename.length() - 4, filename.length())
						.compareToIgnoreCase(".txt") == 0) {
			filename = filename.substring(0, filename.length() - 4);
			filename += ".htm";
		}
	}

	/**
	 * adds path to this path. if added path has ".."-parts, they will get
	 * resolved.
	 * 
	 * @param path
	 */
	public void add(Path path) {
		for (int i = 0; i < path.size(); i++) {
			if (path.get(i).compareTo("..") == 0 && size() > 0) {
				remove(size() - 1);
			} else {
				add(path.get(i));
			}
		}
	}

	/**
	 * constructs path out of given path and filename
	 * 
	 * @param pathWithoutFilename
	 * @param onlyFilename
	 */
	public Path(String pathWithoutFilename, String onlyFilename) {
		String part = "";
		for (int i = 0; i < pathWithoutFilename.length(); i++) {
			Character c = pathWithoutFilename.charAt(i);
			if (c == '/' || c == '\\') {
				add(part);
				part = "";
			} else {
				part += c;
			}
		}
		if (!part.isEmpty()) {
			add(part);
		}
	}

	public Path() {

	}

	/**
	 * returns string representation of path
	 * 
	 * @param withFilename
	 * @return
	 */
	public String toString(boolean withFilename) {
		String ret = "";
		for (int i = 0; i < size(); i++) {
			ret += get(i) + "/";
		}
		if (withFilename) {
			ret += filename;
		}
		if (!anchor.isEmpty()) {
			ret += "#" + anchor;
		}
		return ret;
	}

	/**
	 * Helper method. Given path to current page and wikilink inside this page
	 * this method returns path to linked page relative to current page.
	 * 
	 * @param pathToCurrentPage
	 * @param wikiLink
	 * @return
	 */
	public static Path getPathFromWikiLinkRelativeToCurrentPage(
			Path pathToCurrentPage, Path wikiLink) {
		Path absolutePath = new Path();
		absolutePath.setFilename(wikiLink.getFilename());
		if (wikiLink.size() > 0) {
			if (wikiLink.get(0).equalsIgnoreCase(".")) {
				absolutePath.copyFrom(pathToCurrentPage);
				absolutePath.setFilename(wikiLink.getFilename());
				int indexOfDot = absolutePath.size();
				absolutePath.add(wikiLink);
				absolutePath.remove(indexOfDot);
				absolutePath.normalize();
				absolutePath = absolutePath
						.getPathRelativeTo(pathToCurrentPage);
			} else {
				if (wikiLink.isAbsoluteWikiLink) {
					absolutePath = wikiLink
							.getPathRelativeTo(pathToCurrentPage);
				} else {
					absolutePath.copyFrom(pathToCurrentPage);
					absolutePath.add(wikiLink);
					absolutePath.normalize();
					absolutePath = absolutePath
							.getPathRelativeTo(pathToCurrentPage);
				}
			}
		}
		return absolutePath;
	}

	/**
	 * Returns path to file at given path relative to path given by this object.
	 * 
	 * @param path
	 * @return
	 */
	public Path getPathRelativeTo(Path path) {
		/**
		 * get index upto which both paths are identical
		 */
		int identicalUpto = -1;
		for (int i = 0; i < min(this.size(), path.size()); i++) {
			if (this.get(i).compareToIgnoreCase(path.get(i)) == 0) {
				identicalUpto = i;
			} else {
				break;
			}
		}

		Path ret = new Path();
		for (int i = identicalUpto + 1; i < path.size(); i++) {
			ret.add("..");
		}
		for (int i = identicalUpto + 1; i < size(); i++) {
			ret.add(get(i));
		}

		ret.filename = this.filename;
		ret.anchor = this.anchor;
		return ret;
	}

	/**
	 * build absolute path to page inside wiki
	 * 
	 * @param pathToWiki
	 *            absolute path to wiki in filesystem
	 * @param pathInsideWiki
	 *            path inside wiki
	 */
	public void buildFromWikiPath(Path pathToWiki, String pathInsideWiki) {
		copyFrom(pathToWiki);

	}

	/**
	 * copy from given path object
	 * 
	 * @param path
	 */
	public void copyFrom(Path path) {
		for (int i = 0; i < path.size(); i++) {
			add(path.get(i));
		}
		filename = path.filename;
	}

	/**
	 * returns maximum of two given integers
	 * 
	 * @param a
	 * @param b
	 * @return
	 */
	int max(int a, int b) {
		if (a > b) {
			return a;
		} else {
			return b;
		}
	}

	/**
	 * returns minimum of two given integers
	 * 
	 * @param a
	 * @param b
	 * @return
	 */
	int min(int a, int b) {
		if (a < b) {
			return a;
		} else {
			return b;
		}
	}

	/**
	 * returns filename
	 * 
	 * @return
	 */
	public String getFilename() {
		return filename;
	}

	/**
	 * sets filename
	 * 
	 * @param filename
	 */
	public void setFilename(String filename) {
		this.filename = filename;
	}

	/**
	 * remove last part of path
	 */
	public void removeLastPart() {
		if (size() > 0) {
			remove(size() - 1);
		}
	}

	/**
	 * get part of s which is left of first / or \
	 * 
	 * @param s
	 * @return
	 */
	public static String getLeftDirectory(String s) {
		String ret = "";
		if (s.length() > 0) {
			int i = 0;
			while (i < s.length() && s.charAt(i) != '/' && s.charAt(i) != '\\') {
				i++;
			}
			ret = s.substring(0, i);
		}
		return ret;
	}

	/**
	 * get part of s which is right of leftmost / or \
	 * 
	 * @param s
	 * @return
	 */
	public static String getRightRest(String s) {
		String ret = "";
		if (s.length() > 0) {
			int i = 0;
			while (i < s.length() && s.charAt(i) != '/' && s.charAt(i) != '\\') {
				i++;
			}
			if (i < s.length()) {
				ret = s.substring(i + 1);
			} else {
				ret = "";
			}
		}
		return ret;
	}

	/**
	 * get part of s which is right of last / or \
	 * 
	 * @param s
	 * @return
	 */
	public static String getRightDirectory(String s) {
		String ret = "";
		if (s.length() > 0) {
			int i = s.length() - 1;
			while (i >= 0 && s.charAt(i) != '/' && s.charAt(i) != '\\') {
				i--;
			}
			ret = s.substring(i + 1);
		}
		return ret;
	}

	/**
	 * get part of s which is left of rightmost / or \
	 * 
	 * @param s
	 * @return
	 */
	public static String getLeftRest(String s) {
		String ret = "";
		if (s.length() > 0) {
			int i = s.length() - 1;
			while (i >= 0 && s.charAt(i) != '/' && s.charAt(i) != '\\') {
				i--;
			}
			if (i > 0) {
				ret = s.substring(0, i);
			} else {
				ret = "";
			}
		}
		return ret;
	}

}
