edu.cuny.cat.ui.ClientStatePanel.java Source code

Java tutorial

Introduction

Here is the source code for edu.cuny.cat.ui.ClientStatePanel.java

Source

/*
 * JCAT - TAC Market Design Competition Platform
 * Copyright (C) 2006-2010 Jinzhong Niu, Kai Cai
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 */

package edu.cuny.cat.ui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.util.ConcurrentModificationException;
import java.util.List;

import javax.swing.SwingUtilities;

import org.apache.log4j.Logger;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.NumberTickUnit;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;

import edu.cuny.cat.core.AccountHolder;
import edu.cuny.cat.core.Trader;
import edu.cuny.cat.event.AuctionEvent;
import edu.cuny.cat.event.AvailableMarketsAnnouncedEvent;
import edu.cuny.cat.event.AvailableTradersAnnouncedEvent;
import edu.cuny.cat.event.ClientStateUpdatedEvent;
import edu.cuny.cat.event.DayClosedEvent;
import edu.cuny.cat.event.DayOpenedEvent;
import edu.cuny.cat.event.DayOpeningEvent;
import edu.cuny.cat.event.FeesAnnouncedEvent;
import edu.cuny.cat.event.GameOverEvent;
import edu.cuny.cat.event.GameStartedEvent;
import edu.cuny.cat.event.GameStartingEvent;
import edu.cuny.cat.event.ProfitAnnouncedEvent;
import edu.cuny.cat.event.RoundClosedEvent;
import edu.cuny.cat.event.RoundClosingEvent;
import edu.cuny.cat.event.RoundOpenedEvent;
import edu.cuny.cat.registry.Registry;
import edu.cuny.cat.server.ClientState;
import edu.cuny.cat.server.GameClock;
import edu.cuny.cat.server.GameController;
import edu.cuny.jfree.chart.renderer.category.IntervalListBarRenderer;
import edu.cuny.jfree.chart.renderer.category.ValueListShapeRenderer;
import edu.cuny.jfree.data.category.DefaultIntervalListCategoryDataset;
import edu.cuny.jfree.data.category.DefaultValueListCategoryDataset;
import edu.cuny.util.Parameter;
import edu.cuny.util.ParameterDatabase;

/**
 * displays the status of clients, which may be specialist clients only, trader
 * clients only, or clients of both types.
 * 
 * @author Jinzhong Niu
 * @version $Revision: 1.21 $
 */
public class ClientStatePanel extends ViewPanel {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    static Logger logger = Logger.getLogger(ClientStatePanel.class);

    private static final String P_DAYS = "days";

    Registry registry;

    GameClock clock;

    DefaultValueListCategoryDataset eventDataset;

    DefaultIntervalListCategoryDataset progressDataset;

    CategoryPlot categoryPlot;

    NumberAxis yAxis;

    int days = 25;

    int step = 0;

    public ClientStatePanel() {

        registry = GameController.getInstance().getRegistry();
        clock = GameController.getInstance().getClock();

        setTitledBorder("Client Status");

        final CategoryAxis xAxis = new CategoryAxis();
        yAxis = new NumberAxis();
        yAxis.setTickUnit(new NumberTickUnit(1));

        // TODO: to change the colors for different kinds of events
        final ValueListShapeRenderer eventRenderer = new ValueListShapeRenderer();
        eventRenderer.setBaseOutlinePaint(Color.black);
        eventRenderer.setUseOutlinePaint(true);
        eventRenderer.setDrawOutlines(true);
        final IntervalListBarRenderer progressRenderer = new IntervalListBarRenderer();

        categoryPlot = new CategoryPlot();
        categoryPlot.setOrientation(PlotOrientation.HORIZONTAL);
        categoryPlot.setRenderer(0, eventRenderer);
        categoryPlot.setRenderer(1, progressRenderer);

        categoryPlot.setDomainAxis(xAxis);
        categoryPlot.setRangeAxis(yAxis);

        final JFreeChart chart = new JFreeChart(categoryPlot);
        chart.setAntiAlias(false);
        chart.setBackgroundPaint(getBackground());

        categoryPlot.setForegroundAlpha(0.5F);
        categoryPlot.getDomainAxis().setMaximumCategoryLabelWidthRatio(10.0f);
        categoryPlot.setBackgroundPaint(Color.lightGray);
        categoryPlot.setRangeGridlinePaint(Color.white);

        final ChartPanel chartPanel = new ChartPanel(chart);
        chartPanel.setRangeZoomable(false);
        add(chartPanel, BorderLayout.CENTER);
    }

    @Override
    public void setup(final ParameterDatabase parameters, final Parameter base) {
        if (days > clock.getGameLen()) {
            days = clock.getGameLen() + 1;
        }

        days = parameters.getIntWithDefault(base.push(ClientStatePanel.P_DAYS), null, days);
        if (days < 0) {
            days = clock.getGameLen() + 1;
        } else if (days > 50) {
            ClientStatePanel.logger
                    .warn("The number of days shown in " + getClass().getSimpleName() + " is too large !");
        }

        step = days * 2 / 3;
    }

    protected void updateAxisRange(final int day) {
        if (day + 1 >= yAxis.getUpperBound()) {
            yAxis.setLowerBound(yAxis.getLowerBound() + step);
            yAxis.setUpperBound(yAxis.getUpperBound() + step);
        }
    }

    @Override
    protected synchronized void processGameStarting(final GameStartingEvent event) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                yAxis.setLowerBound(-1);
                yAxis.setUpperBound(days);

                eventDataset = new DefaultValueListCategoryDataset();
                eventDataset.setAutomaticChangedEvent(false);
                progressDataset = new DefaultIntervalListCategoryDataset();
                progressDataset.setAutomaticChangedEvent(false);

                categoryPlot.setDataset(0, eventDataset);
                categoryPlot.setDataset(1, progressDataset);

                // useful only to keep specialists in the same order in the plot
                final String specialistIds[] = registry.getSpecialistIds();
                for (final String specialistId : specialistIds) {
                    eventDataset.add(Double.NaN, event.getClass().getSimpleName(), specialistId);
                    progressDataset.setStartValue(Double.NaN, 0, ClientState.getCodeDesc(ClientState.OK),
                            specialistId);
                    progressDataset.setEndValue(Double.NaN, 0, ClientState.getCodeDesc(ClientState.OK),
                            specialistId);
                }
            }
        });
    }

    @Override
    protected void processFeesAnnounced(final FeesAnnouncedEvent event) {
        final double time = event.getDay();
        eventDataset.add(time, event.getClass().getSimpleName(), event.getSpecialist().getId());
    }

    @Override
    protected void processDayOpening(final DayOpeningEvent event) {
        updateAxisRange(event.getDay());
    }

    @Override
    protected void processDayClosed(final DayClosedEvent event) {
        updateGUI();
    }

    @Override
    protected void processGameOver(final GameOverEvent event) {
        updateGUI();
    }

    @Override
    protected void processRoundClosed(final RoundClosedEvent event) {
        updateGUI();
    }

    protected void updateGUI() {
        eventDataset.setChanged();
        progressDataset.setChanged();
    }

    @Override
    protected void processClientStatusUpdated(final ClientStateUpdatedEvent event) {
        SwingUtilities.invokeLater(new Runnable() {

            public void run() {
                try {
                    if ((eventDataset == null) || (progressDataset == null)) {
                        // before the game starts, overlook all events
                        return;
                    }

                    AuctionEvent triggeringEvent = event.getTriggeringEvent();
                    if (triggeringEvent == null) {
                        triggeringEvent = event;
                    }

                    final AccountHolder client = event.getClient();
                    final ClientState prevState = event.getPreviousState();
                    final ClientState curState = event.getCurrentState();

                    // consider only specialist
                    if (client instanceof Trader) {
                        return;
                    }

                    // (others) -> OK: setStartValue
                    // OK -> OK: setEndValue
                    // OK -> (others): setEndValue
                    // (others): addValue

                    double time = Double.NaN;
                    double delta = 0;
                    if (triggeringEvent instanceof GameStartingEvent) {
                        time = 0;
                        delta = -0.3;
                    } else if (triggeringEvent instanceof GameStartedEvent) {
                        time = 0;
                        delta = -0.1;
                    } else if (triggeringEvent instanceof GameOverEvent) {
                        time = triggeringEvent.getDay();
                        delta = 0.3;
                    } else if ((triggeringEvent instanceof DayOpeningEvent)
                            || (triggeringEvent instanceof DayOpenedEvent)
                            || (triggeringEvent instanceof FeesAnnouncedEvent)) {
                        time = triggeringEvent.getDay();
                    } else if ((triggeringEvent instanceof DayClosedEvent)
                            || (triggeringEvent instanceof ProfitAnnouncedEvent)) {
                        time = (double) triggeringEvent.getDay() + 1;
                    } else if (triggeringEvent instanceof RoundOpenedEvent) {
                        time = triggeringEvent.getDay() + (triggeringEvent.getRound() / (double) clock.getDayLen());
                    } else if ((triggeringEvent instanceof RoundClosingEvent)
                            || (triggeringEvent instanceof RoundClosedEvent)) {
                        time = triggeringEvent.getDay()
                                + ((triggeringEvent.getRound() + 1) / (double) clock.getDayLen());
                    } else if ((triggeringEvent instanceof AvailableTradersAnnouncedEvent)
                            || (triggeringEvent instanceof AvailableMarketsAnnouncedEvent)) {
                        time = 0;
                        delta = -0.2;
                    } else {
                        time = triggeringEvent.getDay() + ((triggeringEvent.getRound()
                                + triggeringEvent.getTick() / (double) clock.getRoundLen()) / clock.getDayLen());
                        // if (triggeringEvent instanceof ClientStateUpdatedEvent) {
                        // logger.info(client.getId() + " : "
                        // + CatpMessage.concatenate(triggeringEvent.getTime()));
                        // }
                    }

                    if (!Double.isNaN(time)) {
                        switch (curState.getCode()) {
                        case ClientState.OK:

                            if ((triggeringEvent instanceof GameStartingEvent)
                                    || (triggeringEvent instanceof GameOverEvent)) {
                                eventDataset.add(time + delta, triggeringEvent.getClass().getSimpleName(),
                                        client.getId());
                                updateGUI();
                            }

                            switch (prevState.getCode()) {
                            case ClientState.OK:
                                progressDataset
                                        .setEndValue(time,
                                                progressDataset.getList(ClientState.getCodeDesc(ClientState.OK),
                                                        client.getId()).size() - 1,
                                                ClientState.getCodeDesc(ClientState.OK), client.getId());
                                // logger.info(client.getId() + " OK till " + time + " upon "
                                // + triggeringEvent.getClass().getSimpleName());
                                break;

                            case ClientState.ERROR:
                            case ClientState.READY:
                                final List<?> list = progressDataset
                                        .getList(ClientState.getCodeDesc(ClientState.OK), client.getId());
                                int index = 0;
                                if (list != null) {
                                    index = list.size();

                                }
                                progressDataset.setStartValue(time, index, ClientState.getCodeDesc(ClientState.OK),
                                        client.getId());
                                updateGUI();
                                break;

                            default:
                                ClientStatePanel.logger.error("Invalid client state "
                                        + ClientState.getCodeDesc(prevState.getCode()) + " prior to becoming "
                                        + ClientState.getCodeDesc(curState.getCode()));
                                break;
                            }

                            break;

                        case ClientState.ERROR:
                        case ClientState.FATAL:
                        case ClientState.CONN_CLOSED:

                            if (prevState.getCode() == ClientState.OK) {
                                // normal up to the exception
                                progressDataset
                                        .setEndValue(time,
                                                progressDataset.getList(ClientState.getCodeDesc(ClientState.OK),
                                                        client.getId()).size() - 1,
                                                ClientState.getCodeDesc(ClientState.OK), client.getId());
                                // logger.info(client.getId() + " OK ended " + time);

                            }

                            if (triggeringEvent instanceof ClientStateUpdatedEvent) {
                                eventDataset.add(time + delta, curState.getDescription(), client.getId());
                            } else {
                                eventDataset.add(time + delta, ClientState.getCodeDesc(curState.getCode()) + " at "
                                        + triggeringEvent.getClass().getSimpleName(), client.getId());
                            }
                            break;
                        }
                    }
                } catch (final ConcurrentModificationException e) {
                    ClientStatePanel.logger.error(e);
                }
            }
        });
    }
}