001    /**
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    package org.apache.geronimo.samples.daytrader.client;
018    
019    import java.text.*;
020    import java.util.*;
021    import java.math.BigDecimal;
022    import javax.swing.table.*;
023    
024    public class TradeQuoteAuditStats extends AbstractTableModel {
025            public static final int SYMBOL_COL = 0;
026            public static final int COMPANY_COL = 1;
027            public static final int PRICE_COL = 2;
028            public static final int AUDIT_PRICE_COL = 3;
029            public static final int VOLUME_COL = 4;
030            public static final int AUDIT_VOLUME_COL = 5;
031            public static final int OPEN_COL = 6;
032            public static final int LOW_COL = 7;
033            public static final int HIGH_COL = 8;
034            public static final int CHANGE_COL = 9;
035            public static final int UPDATE_COL = 10;
036    
037      private static String columns[] = {
038                    "Symbol", "Company Name", "Price",
039                    "Audit Price", "Volume", "Audit Volume",
040                    "Open", "Low", "High",
041                    "Change", "Last Update"};
042    
043            private static Class columnClasses[] = {
044                    String.class, String.class, String.class,
045                    AuditModel.class, String.class, AuditModel.class,
046                    String.class, String.class, String.class,
047                    ChangeModel.class, String.class};
048    
049      private int numColumns = columns.length;
050    
051            private NumberFormat nf;
052            private DateFormat df;
053            private Map map;
054            private ArrayList sortedList;
055            private Object lock;
056            private int lastSortCol = SYMBOL_COL;
057            private boolean lastSortForward = true;
058    
059            public TradeQuoteAuditStats() {
060                    init();
061            }
062    
063            public void init() {
064                    map = new HashMap();
065                    sortedList = new ArrayList();
066                    nf = NumberFormat.getCurrencyInstance();
067                    df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
068                    lock = new Object();
069            }
070    
071            public void updateSymbol(String symbol, String company, BigDecimal newPrice, BigDecimal open, BigDecimal low, BigDecimal high, double volume, long publishTime, BigDecimal priceChange, double volumeChange) {
072                    boolean newSymbol = false;
073                    TradeStreamerQuoteDataBean bean;
074    
075                    synchronized(lock) {
076                            bean = getSymbol(symbol);
077                            if (bean == null) { // first time bean was used
078                                    bean = new TradeStreamerQuoteDataBean();
079                                    bean.setSymbol(symbol);
080                                    bean.setCompanyName(company);
081                                    bean.setPrice(newPrice);
082                                    bean.setOpen(open);
083                                    bean.setLow(low);
084                                    bean.setHigh(high);
085                                    bean.setVolume(volume);
086                                    bean.setLastUpdate(new Date(publishTime));
087                                    bean.setAuditPrice(priceChange);
088                                    bean.setAuditVolume(volumeChange);
089                                    bean.setChange(newPrice.subtract(open).doubleValue());
090                                    newSymbol = true;
091                            }
092                            else { // update to an existing bean
093                                    bean.setPrice(newPrice);
094                                    bean.setOpen(open);
095                                    bean.setLow(low);
096                                    bean.setHigh(high);
097                                    bean.setVolume(volume);
098                                    bean.setLastUpdate(new Date(publishTime));
099                                    bean.setAuditPrice((bean.getAuditPrice()).add(priceChange));
100                                    bean.setAuditVolume(bean.getAuditVolume() + volumeChange);
101                                    bean.setChange(newPrice.subtract(open).doubleValue());
102                            }
103    
104                            map.put(symbol, bean);
105    
106                            if (newSymbol) {
107                                    sort(lastSortCol, false);
108                            }
109                    }
110            }
111    
112            public TradeStreamerQuoteDataBean getSymbol(String symbol) {
113                    synchronized(lock) {
114                            TradeStreamerQuoteDataBean quote = (TradeStreamerQuoteDataBean)map.get(symbol);
115                            return quote;
116                    }
117            }
118    
119            public TradeStreamerQuoteDataBean getSymbol(int row) {
120                    synchronized(lock) {
121                            Iterator it = sortedList.iterator();
122                            int ii = 0;
123                            while (true) {
124                                    if (!it.hasNext()) {
125                                            break;
126                                    }
127                                    TradeStreamerQuoteDataBean bean = (TradeStreamerQuoteDataBean)it.next();
128                                    if (ii == row) {
129                                            return bean;
130                                    }
131                                    ii++;
132                            }
133                            return null;
134                    }
135            }
136    
137            public void clearStats() {
138                    synchronized(lock) {
139                            init();
140                    }
141            }
142    
143      public int getColumnCount() {
144        return numColumns;
145      }
146    
147      public int getRowCount() {
148                    synchronized(lock) {
149                            return map.size();
150                    }
151      }
152    
153      public Object getValueAt (int row, int column) {
154                    synchronized(lock) {
155                            Iterator it = sortedList.iterator();
156                            int ii = 0;
157                            while (true) {
158                                    if (!it.hasNext()) {
159                                            break;
160                                    }
161                                    TradeStreamerQuoteDataBean bean = (TradeStreamerQuoteDataBean)it.next();
162                                    double price;
163                                    if (ii == row) {
164                                            switch (column) {
165                                                    case SYMBOL_COL:
166                                                            return bean.getSymbol();
167                                                    case COMPANY_COL:
168                                                            return bean.getCompanyName();
169                                                    case PRICE_COL:
170                                                            price = bean.getPrice().doubleValue();
171                                                            return nf.format(price);
172                                                    case AUDIT_PRICE_COL:
173                                                            return bean.getAuditPriceModel();
174                                                    case VOLUME_COL:
175                                                            return String.valueOf(bean.getVolume());
176                                                    case AUDIT_VOLUME_COL:
177                                                            return bean.getAuditVolumeModel();
178                                                    case OPEN_COL:
179                                                            price = bean.getOpen().doubleValue();
180                                                            return nf.format(price);
181                                                    case LOW_COL:
182                                                            price = bean.getLow().doubleValue();
183                                                            return nf.format(price);
184                                                    case HIGH_COL:
185                                                            price = bean.getHigh().doubleValue();
186                                                            return nf.format(price);
187                                                    case CHANGE_COL:
188                                                            return bean.getChangeModel();
189                                                    case UPDATE_COL:
190                                                            Date update = bean.getLastUpdate();
191                                                            return df.format(update);
192                                                    default:
193                                                            break;
194                                            }
195                                    }
196                                    ii++;
197                            }
198                            return null;
199                    }
200      }
201    
202      public void setValueAt (Object aValue, int row, int column) {
203                    // not editable
204            }
205    
206      public String getColumnName(int columnIndex) {
207        return columns[columnIndex];
208      }
209    
210      public Class getColumnClass(int columnIndex) {
211        return columnClasses[columnIndex];
212      }
213    
214      public boolean isCellEditable(int row, int column) {
215                    return false;
216      }
217    
218            public void sort(int column, boolean fromUserGUI) {
219                    synchronized(lock) {
220                            Collection values = map.values();
221                            sortedList.clear();
222                            sortedList.addAll(values);
223                            // TODO: be more carefull with obect allocation - make static comps?
224                            Comparator comp = new TradeQuoteAuditStatsComparator(column);
225                            Collections.sort(sortedList, comp);
226                            if (fromUserGUI) {
227                                    if (column == lastSortCol) {
228                                            if (lastSortForward) { // if we already sorted forward, reverse
229                                                    Collections.reverse(sortedList);
230                                            }
231                                            lastSortForward = !lastSortForward; // switch the last sort
232                                    }
233                            }
234                            lastSortCol = column;
235                    }
236            }
237    }