package hu.procyon.utils;

public class ParsedUrl {
	
	private String scheme;
	private String userinfo;
	private String hostname;
	private String port;
	private String path;
	private String filename;
	private String query;
	private String fragment;
	
	private String completeUrl;
	private boolean isBuilt = false;
	
	public void setScheme(String scheme) {
		this.scheme = scheme;
	}

	public String getScheme() {
		return scheme;
	}

	public void setUserinfo(String userinfo) {
		this.userinfo = userinfo;
	}

	public String getUserinfo() {
		return userinfo;
	}

	public String getHostname() {
		return hostname;
	}
	
	public void setHostname(String hostname) {
		this.hostname = hostname;
	}
	
	public String getPort() {
		return port;
	}

	public void setPort(String port) {
		this.port = port;
	}

	public String getPath() {
		return path;
	}

	public void setPath(String path) {
		this.path = path;
	}

	public String getFilename() {
		return filename;
	}

	public void setFilename(String filename) {
		this.filename = filename;
	}

	public String getQuery() {
		return query;
	}

	public void setQuery(String query) {
		this.query = query;
	}

	public String getFragment() {
		return fragment;
	}

	public void setFragment(String fragment) {
		this.fragment = fragment;
	}

	public ParsedUrl() {
	}
	
	public ParsedUrl(String url) {
		parse(url);
	}
	
	/*
	 * foo://username:password@example.com:8042/over/there/index.dtb?name=ferret#nose
     * \_/+++[_______________]?\_________/?[__]\__________/[_______]?[_________]?[__]
     * scheme  userinfo          hostname  port  path       filename  query       fragment
	 */
	
	public void parse(String url) {
		int schemeSepPos;
		int pathStartPos;
		boolean pathExists = false;
		String completeHost;
		int atsignPos;
		int portSepPos;
		
		isBuilt = false;
		
		schemeSepPos = url.indexOf("://");
		
		if (schemeSepPos < 1) {
			parseFile(url);
			return;
		}
		scheme = url.substring(0, schemeSepPos);		
		pathStartPos = url.indexOf("/", schemeSepPos + 3);
		if (pathStartPos > -1) {
			pathExists = true;
			completeHost = url.substring(schemeSepPos + 3, pathStartPos);
		}
		else {
			completeHost = url.substring(schemeSepPos + 3);
			pathStartPos = url.length();
		}
		atsignPos = completeHost.indexOf('@');
		if (atsignPos > -1) {
			userinfo = url.substring(schemeSepPos + 3, atsignPos);
		}
		else {
			atsignPos = schemeSepPos + 3;
		}
		if (pathExists) {
			parseFile(url.substring(pathStartPos));
		}
		else {
			path = "/";
		}
		portSepPos = url.indexOf(':', atsignPos);
		if (portSepPos > -1) {
			port = url.substring(portSepPos + 1, pathStartPos);
		}
		else {
			portSepPos = pathStartPos;
		}
		hostname = url.substring(atsignPos + 1, portSepPos);
	}
	
	private void parseFile(String url) {
		int hashmarkPos;
		int questionmarkPos;
		int lastSlashPos;

		hashmarkPos = url.lastIndexOf('#');
		if (hashmarkPos > -1) {
			fragment = url.substring(hashmarkPos + 1);
		}
		else {
			hashmarkPos = url.length();
		}
		questionmarkPos = url.lastIndexOf('?', hashmarkPos);
		if (questionmarkPos > -1) {
			query = url.substring(questionmarkPos + 1, hashmarkPos);
		}
		else {
			questionmarkPos = hashmarkPos;
		}
		lastSlashPos = url.lastIndexOf('/', questionmarkPos);
		if (lastSlashPos < 0) {
			filename = url.substring(0, questionmarkPos);
			
		}
		else {
			filename = url.substring(lastSlashPos + 1, questionmarkPos);
			if (url.charAt(0) == '/') {
				path = url.substring(0, lastSlashPos + 1);
			}
			else {
				path = path + url.substring(0, lastSlashPos + 1);
			}
		}
	}
	
	@Override
	public String toString() {
		if (isBuilt) {
			return completeUrl;
		}
		StringBuffer sb = new StringBuffer();
		if (scheme != null && !scheme.equals("")) {
			sb.append(scheme).append("://");
		}
		if (userinfo != null && !userinfo.equals("")) {
			sb.append(userinfo).append("@");
		}
		if (hostname != null && !hostname.equals("")) {
			sb.append(hostname)
		}
		
		
		return sb.toString();
	}
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		ParsedUrl newParsedUrl = new ParsedUrl();
		newParsedUrl.scheme = this.scheme;
		newParsedUrl.userinfo = this.userinfo;
		newParsedUrl.hostname = this.hostname;
		newParsedUrl.port = this.port;
		newParsedUrl.path = this.path;
		newParsedUrl.filename = this.filename;
		newParsedUrl.query = this.query;
		newParsedUrl.fragment = this.fragment;
		newParsedUrl.completeUrl = this.completeUrl;
		newParsedUrl.isBuilt = this.isBuilt;
		return newParsedUrl;
	}
	
	@Override
	public boolean equals(Object obj) {
		if (obj instanceof ParsedUrl) {
			ParsedUrl urlObj = (ParsedUrl) obj;
			if (urlObj.scheme == this.scheme &&
					urlObj.userinfo == this.userinfo &&
					urlObj.hostname == this.hostname &&
					urlObj.port == this.port &&
					urlObj.path == this.path &&
					urlObj.filename == this.filename &&
					urlObj.query == this.query &&
					urlObj.fragment == this.fragment) {
				return true;
			}
			else {
				return false;
			}
			
		}
		else {
			return false;
		}
	}
	
	@Override
	public int hashCode() {
		return toString().hashCode();
	}

}
