package ps5;


import java.net.*;
import java.io.*;
import java.util.*;

/**
 * QuoteServer is a utility class that can retrieve the latest market value of 
 * a given stock by ticker symbol.
 * The QuoteServer obtains the stock value by using the website: 
 * <a href="http://quote.fool.com"><tt>http://quote.fool.com</tt></a>.
 * Ticker symbols are case insensitive. A valid ticker symbol is one that is currently 
 * registered with either the New York Stock Exchange (NYSE) or NASDAQ.
 * Examples of valid ticker symbols are <tt>MSFT</tt> and <tt>orcl</tt>.
 */


public class QuoteServer {

  protected static final String _URL = "http://quote.fool.com/simple.asp?symbols=";
  protected static final String _TOKEN1 = "mwsimplelast";
  protected static final String _TOKEN2 = "NOBR";
  protected static final String _DELIMITER = "&<>=";    
  protected static final String _NAME_LOOKUP_URL = "http://quote.fool.com/lookup.asp?company=";
  protected static final String _TOKEN3 = "currticker=";
  protected static final String _TOKEN4 = "&symbols=";
  protected static final String _TOKEN5 = "mwsymbollookupstandard"; 

  protected static HashMap names = new HashMap();
  protected static final String USAGE = "USAGE: java ps5.QuoteServer <tickerSymbol>";

  public static void main(String[] args) {
    if(args.length != 1) {
      System.out.println(USAGE);
      return;
    }
      
    try {
      System.out.println(args[0] + " has a stock value of " + getLastValue(args[0]));
      System.out.println(args[0] + " is associated with " + getNameFromTicker(args[0]));
    } catch(Exception e) { System.err.println(e); }
  }

  /** 
   * 
   * Retrieve the latest market value of a stock.
   *
   * @requires tickerSymbol != null
   * @effects Returns a current value for tickerSymbol as a dollar amount with a
   *          period separating dollars and cents. The return value may contain commas.
   *          <p>
   *          Examples: "120.50", "2,243.87".
   * @throws  NoSuchTickerException if tickerSymbol is not a valid NYSE or NASDAQ
   *          symbol and throws
   * @throws WebsiteDataException if there is an error
   *          connecting to the website or some other error occurs.
   */
  public static String getLastValue(String tickerSymbol)
    throws WebsiteDataException, NoSuchTickerException {
    // the web page queried by the code below can be broken into tokens
    // with delimiters being <, >, and =.  The token corresponding to
    // the current stock price comes after the two tokens: mwsimplelast and NOBR.

    String strURLStart = _URL;
    URL urlWebPage = null;
    InputStreamReader isr = null;
    BufferedReader brWebPage = null;
        
    // open the web page for reading
    try {
      //System.out.println(strURLStart + tickerSymbol);
      urlWebPage = new URL(strURLStart + tickerSymbol);
      isr = new InputStreamReader(urlWebPage.openStream());
      brWebPage = new BufferedReader(isr);
    } catch(Exception e) {
      throw new WebsiteDataException();
    }
        
    // find the line with the stock quote on it
    String strLine = null;
    try {
      while(true) {
	strLine = brWebPage.readLine();
	if(strLine == null)
	  {
	    // We can throw NoSuchTickerException if the end of stream is reached since IOException would have occured, otherwise. //@GT
	    throw new NoSuchTickerException("Invalid ticker symbol!");
	    //throw new WebsiteDataException("Failed to get the quote for " + tickerSymbol + "!");
	  }
	//System.out.println(strLine);
	if(strLine.indexOf(_TOKEN1) != -1)
	  break;
      }
    } catch(IOException e) {
      throw new WebsiteDataException();
    }
        
    // find the stock quote in the line
    StringTokenizer strtok = new StringTokenizer(strLine, _DELIMITER);
    while(true) {
      if(strtok.hasMoreTokens() == false)
	throw new NoSuchTickerException("Invalid ticker symbol!");
      if(strtok.nextToken().compareTo(_TOKEN1) == 0)
	break;
    }
    String strNOBR = strtok.nextToken();
    if(!strNOBR.equals(_TOKEN2))
	throw new NoSuchTickerException("Invalid ticker symbol!");
    String strStockValue = strtok.nextToken();


    //format check removed
	
	
    // close the web page stream
    try {
      brWebPage.close();
      isr.close();
    } catch(IOException e) {
      throw new WebsiteDataException();
    }
        
    return strStockValue;
  }

  /**
   * Retrieve the company name associated with a stock. 
   *
   * @requires tickerSymbol != null
   * @effects  Returns the company name associated with tickerSymbol. 
   * @throws NoSuchTickerException if tickerSymbol is not a valid NYSE or NASDAQ
   *          symbol.
   * @throws WebsiteDataException if there is an error
   *          connecting to the website or some other error occurs.
   */ 
  public static String getNameFromTicker(String tickerSymbol) throws WebsiteDataException, NoSuchTickerException {
    String strStockName = (String)QuoteServer.names.get(tickerSymbol);
    if (strStockName != null)
      return strStockName;

    tickerSymbol = tickerSymbol.toUpperCase();
    String strURLStart = _NAME_LOOKUP_URL;
    URL urlWebPage = null;
    
    InputStreamReader isr = null;
    BufferedReader brWebPage = null;
    String nameLookupToken = _TOKEN3+tickerSymbol+_TOKEN4+tickerSymbol;
    
    // open the web page for reading
    // System.out.println(nameLookupToken);
    try {
      urlWebPage = new URL(strURLStart + tickerSymbol);
      isr = new InputStreamReader(urlWebPage.openStream());
      brWebPage = new BufferedReader(isr);
    } catch(Exception e) {
      throw new WebsiteDataException();
    }
    
    // find the line with the stock quote on it
    String strLine = null;
    try {
      while(true) {
	strLine = brWebPage.readLine();
	if(strLine == null) {
	  throw new NoSuchTickerException("Invalid ticker symbol!");
	  //throw new WebsiteDataException("Parse failed!");
	}
	//System.out.println(strLine);
	if(strLine.indexOf(nameLookupToken) != -1)
	  break;
      }
    }
    catch(IOException e) {
      throw new WebsiteDataException();
    }
    
    // find the stock quote in the line
    StringTokenizer strtok = new StringTokenizer(strLine, _DELIMITER);
    
    while(true) {
      if(strtok.hasMoreTokens() == false) {
	throw new NoSuchTickerException("Invalid ticker symbol!");
      }
      if(strtok.nextToken().compareTo(_TOKEN5) == 0) {
	strStockName = strtok.nextToken();
	if (strStockName.substring(0, 5).compareTo("nbsp;") == 0)
	  break;
      }
    }
    
    strStockName = strStockName.substring(5);
    QuoteServer.names.put(tickerSymbol, strStockName);
    return strStockName;
  }
}
