/*
 * This code is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public 
 * License as published by the Free Software Foundation; either 
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This code is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public 
 * License along with this program; if not, write to the Free 
 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, 
 * MA  02111-1307, USA.
 */
package no.geosoft.cc.currency;



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



/**
 * Currency server based on online currency service at
 * Sauder School of Business, University of British Columbia:
 *
 * http://fx.sauder.ubc.ca/supplement.html
 * 
 * 
 * @author <a href="mailto:info@geosoft.no">GeoSoft</a>
 */   
class SauderCurrencyServer
  implements CurrencyServer
{
  private HashMap  currencies_;     // String -> Currency
  private HashMap  exchangeRates_;  // Currency -> Double
  private Date     date_;


  
  /**
   * Construct a currency server.
   */
  SauderCurrencyServer()
  {
    currencies_    = null;
    exchangeRates_ = null;
    date_          = null;
  }


  
  /**
   * Get name of this currency server.
   * 
   * @return  Name of this currency server.
   */
  public String getName()
  {
    return "Saunder School of Business";
  }
  
  

  /**
   * Get URL of this currency server.
   * 
   * @return  URL of this currency server.
   */
  public String getUrl()
  {
    return "http://fx.sauder.ubc.ca/supplement.html";
  }
  
  
  
  /**
   * Return all currencies supported by this server.
   * 
   * @return Collection of currencies.
   */
  public Collection getCurrencies()
  {
    if (currencies_ == null)
      loadCurrencies();

    return currencies_.values();
  }


  
  /**
   * Return a specfic currency (or null if this currency
   * is not supported).
   * 
   * @param isoCode  ISO code of the currency to get.
   * @return         Requested currency.
   */
  public Currency getCurrency (String isoCode)
  {
    if (currencies_ == null)
      loadCurrencies();
    
    return (Currency) currencies_.get (isoCode);
  }
  


  /**
   * Get exchange rate between this currency and the base
   * currency (US$)
   * 
   * @param currency  Currency to get exchange rate for.
   * @return          Exchange rate between this currency and US$
   */
  public double getExchangeRate (Currency currency)
  {
    Double exchangeRate = (Double) exchangeRates_.get (currency);
    return exchangeRate != null ? exchangeRate.doubleValue() : 0.0;
  }
  


    
  /**
   * Get date of exchange rate information.
   * 
   * @return 
   */
  public Date getDate()
  {
    if (currencies_ == null)
      loadCurrencies();

    return date_;
  }
  


  private void parseDate (BufferedReader reader)
    throws IOException
  {
    while (true) {
      String line = reader.readLine();
      if (line == null) break;
      
      if (line.indexOf ("FX Rates Supplement") != -1) {
        // TODO
        date_ = new Date();
        break;
      }
    }
  }

  

  private void skipPast (BufferedReader reader, String string)
    throws IOException
  {
    while (true) {
      String line = reader.readLine();
      if (line == null) break;

      if (line.indexOf (string) != -1)
        break;
    }
  }
  
  
  private boolean parseCurrency (BufferedReader reader)
    throws IOException
  {
    Currency currency = null;

    skipPast (reader, "<tr");
    skipPast (reader, "<td");    

    String line = reader.readLine();
    if (line == null) return true;  // Done
    
    int pos = line.indexOf ("<tt>");
    if (pos == -1) return true; // Done
    String isoCode = line.substring (pos+4, pos+7);

    try {
      currency = Currency.getInstance (isoCode);
    }
    catch (RuntimeException exception) {
      // System.out.println ("Unknown ISO code: " + isoCode);
    }

    skipPast (reader, "<td");
    skipPast (reader, "<td");        
    skipPast (reader, "<td");
    skipPast (reader, "<td");        
    skipPast (reader, "<td");
    
    line = reader.readLine();
    if (line == null) return true; // Done
    
    int pos1 = line.indexOf (";") + 1;
    int pos2 = line.indexOf ("&", pos1);
    String rateString = line.substring (pos1, pos2);

    double rate = 0.0;
    try {
      rate = Double.parseDouble (rateString);
    }
    catch (Exception exception) {
      exception.printStackTrace();
    }

    if (currency != null) {
      currencies_.put (currency.getCurrencyCode(), currency);
      exchangeRates_.put (currency, new Double (rate));
    }

    return false; // !Done
  }
  
  
  
  private void loadCurrencies()
  {
    currencies_    = new HashMap();
    exchangeRates_ = new HashMap();
    
    try {
      URL url = new URL (getUrl());
      InputStream is = url.openStream();
      BufferedReader reader = new BufferedReader (new InputStreamReader(is));

      parseDate (reader);

      skipPast (reader, "Code");
      skipPast (reader, "<tr>");
      
      while (true) {
        boolean isDone = parseCurrency (reader);
        if (isDone) break;
      }
    }
    catch (Exception exception) {
      exception.printStackTrace();
    }
  }
  

  
  
  /**
   * Testing this class.
   * 
   * @param args  Not used.
   */
  public static void main (String[] args)
  {
    CurrencyServer c = new SauderCurrencyServer();
    c.getCurrencies();
  }
}