/*
 * -------------------------------------------------------------------------
 *      $Id: Database.java,v 1.13 2004/05/26 19:20:42 estewart Exp $
 * -------------------------------------------------------------------------
 *      Copyright (c) 1999 Visual Numerics Inc. All Rights Reserved.
 *
 *      This software is confidential information which is proprietary to
 *      and a trade secret of Visual Numerics, Inc.  Use, duplication or
 *      disclosure is subject to the terms of an appropriate license
 *      agreement.
 *
 *      VISUAL NUMERICS MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE
 *      SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING
 *      BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY,
 *      FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. VISUAL
 *      NUMERICS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
 *      AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR
 *      ITS DERIVATIVES.
 *--------------------------------------------------------------------------
 */

package com.imsl.demo.WallStreet;
import java.util.*;
import java.io.*;

/**
 *
 * @author  brophy
 * @created January 24, 2002
 */
class Database implements Serializable {
    static final long serialVersionUID = -4975277050625648285L;
    private HashMap     hashSeries;

    /** Creates new Database */
    public Database(String filename) throws Exception {
        readAll(filename);
    }

    void save(String filename) throws IOException {
        FileOutputStream fos = new FileOutputStream(filename);
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(this);
        oos.close();
        fos.close();
    }

    static Database load(String filename) throws IOException {
        return load(new FileInputStream(filename));
    }


    static Database load(InputStream is) throws IOException {
        try {
            ObjectInputStream ois = new ObjectInputStream(is);
            Database db = (Database)ois.readObject();
            ois.close();
            return db;
        } catch (ClassNotFoundException e) {
            System.out.println("Error loading database: "+e.getMessage());
            e.printStackTrace();
            return null;
        }
    }


    public String[] getTickers() {
        Set keys = hashSeries.keySet();
        SortedSet ss = new TreeSet();
        Iterator iter = keys.iterator();
        while (iter.hasNext()) {
            ss.add(iter.next());
        }
        return (String[])ss.toArray(new String[0]);
    }

    public Series getSeries(String ticker) {
        return (Series)hashSeries.get(ticker);
    }


    public Series getSeries(String ticker, int period, int interval) {
        Series daily = getSeries(ticker);
        ListSeries listSeries = new ListSeries();
        GregorianCalendar calStart = new GregorianCalendar(2002, 0, 23);
        switch (interval) {
            case Model.INTERVAL_MONTH:
                calStart.add(GregorianCalendar.MONTH, -1);
                break;
            case Model.INTERVAL_YEAR:
                calStart.add(GregorianCalendar.YEAR, -1);
                break;
            case Model.INTERVAL_QUARTER:
                calStart.add(GregorianCalendar.MONTH, -3);
                break;
            case Model.INTERVAL_WEEK:
                calStart.add(GregorianCalendar.DATE, -7);
                break;
        }
        GregorianCalendar cal = new GregorianCalendar();
        int lastPeriod = -1;
        double open = 0;
        double close = 0;
        double high = 0;
        double low = 0;
        double volume = 0;
        Date startDate = null;
        for (int k = 0;  k < daily.date.length;  k++) {
            Date date = new java.util.Date((long)daily.date[k]);
            cal.setTime(date);
            if (cal.before(calStart))  continue;
            int thisPeriod = cal.get(period);
            if (thisPeriod != lastPeriod) {
                if (lastPeriod != -1) {
                    listSeries.add(startDate, high, low, close, open, volume);
                }
                startDate = date;
                open = daily.open[k];
                close = daily.close[k];
                high = daily.high[k];
                low = daily.low[k];
                volume = daily.volume[k];
            } else {
                close = daily.close[k];
                high = Math.max(high,daily.high[k]);
                low = Math.min(low,daily.low[k]);
                volume += daily.volume[k];
            }
            lastPeriod = thisPeriod;
        }
        listSeries.add(startDate, high, low, close, open, volume);
        return new Series(listSeries);
    }


    private void readAll(String filename) throws Exception {
        // read the data
        hashSeries = new HashMap(1000);
        ReadStockData rsd = new ReadStockData(filename);
        while (rsd.next()) {
            String ticker = rsd.getString("Ticker");
            ListSeries listSeries = (ListSeries)hashSeries.get(ticker);
            if (listSeries == null) {
                listSeries = new ListSeries();
                hashSeries.put(ticker, listSeries);
            }
            listSeries.listDate.add(rsd.getObject("Date"));
            listSeries.listHigh.add(rsd.getObject("High"));
            listSeries.listLow.add(rsd.getObject("Low"));
            listSeries.listClose.add(rsd.getObject("Close"));
            listSeries.listOpen.add(rsd.getObject("Open"));
            listSeries.listVolume.add(rsd.getObject("Volume"));
        }
        rsd.close();

        Iterator iter = hashSeries.keySet().iterator();
        while (iter.hasNext()) {
            String ticker = (String)iter.next();
            ListSeries listSeries = (ListSeries)hashSeries.get(ticker);
            Series series = new Series(listSeries);
            hashSeries.put(ticker, series);
        }
    }

    static private class ListSeries {
        List  listDate;
        List  listHigh;
        List  listLow;
        List  listClose;
        List  listOpen;
        List  listVolume;

        ListSeries() {
            listDate = new ArrayList(500);
            listHigh = new ArrayList(500);
            listLow = new ArrayList(500);
            listClose = new ArrayList(500);
            listOpen = new ArrayList(500);
            listVolume = new ArrayList(500);
        }

        void add(java.util.Date date, double high, double low, double close, double open, double volume) {
            listDate.add(date);
            listHigh.add(new Double(high));
            listLow.add(new Double(low));
            listClose.add(new Double(close));
            listOpen.add(new Double(open));
            listVolume.add(new Double(volume));
        }
    }


    static class Series implements Serializable {
        static final long serialVersionUID = 6083341146689785913L;
        String  ticker;
        double  date[];
        double  high[];
        double  low[];
        double  close[];
        double  open[];
        double  volume[];

        Series(ListSeries listSeries) {
            int n = listSeries.listDate.size();
            if (listSeries.listDate.get(0) == null)  n = 0;
            date = new double[n];
            high = new double[n];
            low = new double[n];
            close = new double[n];
            open = new double[n];
            volume = new double[n];
            for (int k = 0;  k < n;  k++) {
                date[k] = ((java.util.Date)listSeries.listDate.get(k)).getTime();
                high[k] = ((Double)listSeries.listHigh.get(k)).doubleValue();
                low[k] = ((Double)listSeries.listLow.get(k)).doubleValue();
                close[k] = ((Double)listSeries.listClose.get(k)).doubleValue();
                open[k] = ((Double)listSeries.listOpen.get(k)).doubleValue();
                volume[k] = ((Double)listSeries.listVolume.get(k)).doubleValue();
            }
        }
    }
}