content: /*
   * Copyright 2014 A.C.R. Development
   */
  package acr.browser.thunder;
  
  import java.util.Locale;
  import java.util.regex.Matcher;
  import java.util.regex.Pattern;
  
  import static android.util.Patterns.GOOD_IRI_CHAR;
  
  /**
   * Web Address Parser
   * 
   * This is called WebAddress, rather than URL or URI, because it attempts to
   * parse the stuff that a user will actually type into a browser address widget.
   * 
   * Unlike java.net.uri, this parser will not choke on URIs missing schemes. It
   * will only throw a ParseException if the input is really hosed.
   * 
   * If given an https scheme but no port, fills in port
   */
  public class WebAddress {
  
  	private String mScheme;
  	private String mHost;
  	private int mPort;
  	private String mPath;
  	private String mAuthInfo;
  	static final int MATCH_GROUP_SCHEME = 1;
  	static final int MATCH_GROUP_AUTHORITY = 2;
  	static final int MATCH_GROUP_HOST = 3;
  	static final int MATCH_GROUP_PORT = 4;
  	static final int MATCH_GROUP_PATH = 5;
  	static Pattern sAddressPattern = Pattern.compile(
  	/* scheme */"(?:(http|https|file)\\:\\/\\/)?" +
  	/* authority */"(?:([-A-Za-z0-9$_.+!*'(),;?&=]+(?:\\:[-A-Za-z0-9$_.+!*'(),;?&=]+)?)@)?" +
  	/* host */"([" + GOOD_IRI_CHAR + "%_-][" + GOOD_IRI_CHAR + "%_\\.-]*|\\[[0-9a-fA-F:\\.]+\\])?" +
  	/* port */"(?:\\:([0-9]*))?" +
  	/* path */"(\\/?[^#]*)?" +
  	/* anchor */".*", Pattern.CASE_INSENSITIVE);
  
  	/**
  	 * Parses given URI-like string.
  	 */
  	public WebAddress(String address) {
  
  		if (address == null) {
  			throw new IllegalArgumentException("address can't be null");
  		}
  
  		mScheme = "";
  		mHost = "";
  		mPort = -1;
  		mPath = "/";
  		mAuthInfo = "";
  
  		Matcher m = sAddressPattern.matcher(address);
  		String t;
  		if (!m.matches()) {
  			throw new IllegalArgumentException("Parsing of address '" + address + "' failed");
  		}
  
  		t = m.group(MATCH_GROUP_SCHEME);
  		if (t != null) {
  			mScheme = t.toLowerCase(Locale.ROOT);
  		}
  		t = m.group(MATCH_GROUP_AUTHORITY);
  		if (t != null) {
  			mAuthInfo = t;
  		}
  		t = m.group(MATCH_GROUP_HOST);
  		if (t != null) {
  			mHost = t;
  		}
  		t = m.group(MATCH_GROUP_PORT);
  		if (t != null && !t.isEmpty()) {
  			// The ':' character is not returned by the regex.
  			try {
  				mPort = Integer.parseInt(t);
  			} catch (NumberFormatException ex) {
  				throw new RuntimeException("Parsing of port number failed", ex);
  			}
  		}
  		t = m.group(MATCH_GROUP_PATH);
  		if (t != null && !t.isEmpty()) {
  			/*
  			 * handle busted myspace frontpage redirect with missing initial "/"
  			 */
  			if (t.charAt(0) == '/') {
  				mPath = t;
  			} else {
  				mPath = '/' + t;
  			}
  		}
  
  		/*
  		 * Get port from scheme or scheme from port, if necessary and possible
  		 */
  		if (mPort == 443 && "".equals(mScheme)) {
  			mScheme = "https";
  		} else if (mPort == -1) {
  			if ("https".equals(mScheme)) {
  				mPort = 443;
  			} else {
  				mPort = 80; // default
  			}
  		}
  		if ("".equals(mScheme)) {
  			mScheme = "http";
  		}
  	}
  
  	@Override
  	public String toString() {
  
  		String port = "";
  		if ((mPort != 443 && "https".equals(mScheme)) || (mPort != 80 && "http".equals(mScheme))) {
  			port = ':' + Integer.toString(mPort);
  		}
  		String authInfo = "";
  		if (!mAuthInfo.isEmpty()) {
  			authInfo = mAuthInfo + '@';
  		}
  
  		return mScheme + "://" + authInfo + mHost + port + mPath;
  	}
  
  	public void setScheme(String scheme) {
  		mScheme = scheme;
  	}
  
  	public String getScheme() {
  		return mScheme;
  	}
  
  	public void setHost(String host) {
  		mHost = host;
  	}
  
  	public String getHost() {
  		return mHost;
  	}
  
  	public void setPort(int port) {
  		mPort = port;
  	}
  
  	public int getPort() {
  		return mPort;
  	}
  
  	public void setPath(String path) {
  		mPath = path;
  	}
  
  	public String getPath() {
  		return mPath;
  	}
  
  	public void setAuthInfo(String authInfo) {
  		mAuthInfo = authInfo;
  	}
  
  	public String getAuthInfo() {
  		return mAuthInfo;
  	}
  }
  