/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package sample.scatterplot.websockets;

import com.sun.grizzly.tcp.Request;
import com.sun.grizzly.websockets.BaseServerWebSocket;
import com.sun.grizzly.websockets.DataFrame;
import com.sun.grizzly.websockets.WebSocket;
import com.sun.grizzly.websockets.WebSocketApplication;
import com.sun.grizzly.websockets.WebSocketListener;
import com.sun.jersey.api.json.JSONJAXBContext;
import com.sun.jersey.api.json.JSONMarshaller;
import com.sun.jersey.api.json.JSONUnmarshaller;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import javax.xml.bind.JAXBException;
import sample.scatterplot.ejb.PlotQueryEjb;
import sample.scatterplot.jaxb.PlotData;
import sample.scatterplot.persistence.PlotSample;
import sample.scatterplot.persistence.PlotType;

/**
 *
 *PlotApplication web socket example. Based on:
 *
 * <ul>
 * <li>http://antwerkz.com/glassfish-web-sockets-sample/:
 *     Post about WebSockets, it comments chat sample application that
 *     goes with grizzly.</li>
 * <li>http://java.net/projects/grizzly/sources/svn/content/trunk/code/samples/websockets/chat/:
 *     Source subversion of the chat application that is commented in
 *     the previous blog.</li>
 * <li>http://grizzly.java.net/nonav/docs/1.9.31/apidocs/:
 *     Javadoc API for grizzly (Glassfish websockets implementation).</li>
 * <li>http://weblogs.java.net/blog/spericas/archive/2010/09/29/web-sockets-and-html5-glassfish:
 *     Another blog entry by Santiago Pericas-Geertsen.</li>
 * </ul>
 *
 * @author ricky
 * 
 */
public class PlotApplication extends WebSocketApplication {

    /**
     * JSON JAXB context to marshall and unmarshall
     */
    JSONJAXBContext ctx = null;

    /**
     * Mappings of the servlet
     */
    Collection<String> mappings = null;

    /**
     * Query ejb
     */
    private PlotQueryEjb plotQueryEjb;

    /**
     * Constructor of the PlotApllication. The EJB must be passed cos Inject
     * does not work here (CDI).
     * @param plotQueryEjb The EJB to use to access DDBB
     * @param mappings THe mappings of the WebSocketsServlet
     */
    public PlotApplication(PlotQueryEjb plotQueryEjb, Collection<String> mappings) {
        try {
            this.plotQueryEjb = plotQueryEjb;
            this.mappings = mappings;
            // create the JSONJAXBContext for our plot
            ctx = new JSONJAXBContext(PlotData.class);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
    }

    /**
     * The request is for the application if it is inside the servlet mappings.
     * It is not a thorough check (just an ends with, no wildcards or whatever).
     * @param request The request to check
     * @return true if some uri ends with some of the mappings
     */
    @Override
    public boolean isApplicationRequest(Request request) {
        final String uri = request.requestURI().toString();
        for (String mapping: mappings) {
            if (uri.endsWith(mapping)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Method to create a new web socket. Just a BaseServerWebSocket is
     * needed.
     * @param listeners The listeners of the socket
     * @return The new websocket created
     * @throws IOException Some error
     */
    @Override
    public WebSocket createSocket(WebSocketListener[] listeners) throws IOException {
        return new BaseServerWebSocket(listeners);
    }

    /**
     * The real onMessage method. The JSON data is unmarshall into the
     * PlotData object. Then the EJB is called to obtain the samples
     * which are added to the PlotData. Finally the filled data is marshall
     * again into JSON and returned.
     * @param socket The WebScoket
     * @param frame The data frame received
     * @throws IOException Some error
     */
    @Override
    public void onMessage(WebSocket socket, DataFrame frame) throws IOException {
        System.err.println("PlotApplication - onMessage: " + frame.getTextPayload());
        StringReader sr = new StringReader(frame.getTextPayload());
        StringWriter sw = new StringWriter();
        try {
            // unmarshall the json sent data
            JSONUnmarshaller unmarshaller = JSONJAXBContext.getJSONUnmarshaller(ctx.createUnmarshaller());
            PlotData data = unmarshaller.unmarshalFromJSON(sr, PlotData.class);
            System.err.println("unmarshalled!");
            // get the dates for the graph
            Calendar cal = Calendar.getInstance();
            cal.setTimeZone(TimeZone.getTimeZone("GMT"));
            Date startDate = null;
            Date endDate = null;
            // get end
            if (data.getEnd() != null) {
                endDate = new Date(Long.parseLong(data.getEnd().substring(1)));
            } else {
                endDate = cal.getTime();
            }
            // get start
            if (data.getStart() != null) {
                startDate = new Date(Long.parseLong(data.getStart().substring(1)));
            } else {
                cal.add(Calendar.DATE, -1);
                startDate = cal.getTime();
            }
            // execute query against data base
            data.setStart(formatTimestamp(startDate));
            data.setEnd(formatTimestamp(endDate));
            PlotType pt = PlotType.valueOf(data.getType());
            data.setLegend(pt.getLegend());
            data.setDescription(pt.getDescription());
            List<PlotSample> list = plotQueryEjb.getPlotSamples(
                    data.getType() + "-findSamplesBetweenDates", startDate, endDate);
            if (list != null && !list.isEmpty()) {
                for (PlotSample s: list) {
                    data.getData().put(formatTimestamp(s.getSampleDate()), s.getSampleValue());
                }
            }
            //  marshall again and send via websockets
            JSONMarshaller marshaller = JSONJAXBContext.getJSONMarshaller(ctx.createMarshaller());
            marshaller.marshallToJSON(data, sw);
            System.err.println("marshalled!");
            socket.send(sw.toString());
        } catch (Exception e) {
            e.printStackTrace();
            throw new IOException(e);
        } finally {
            sr.close();
            sw.close();
        }
    }

    /**
     * All timestamps are generated with a T prefix (JSON rules).
     * @param date The date to print
     * @return The timestamp prefixed by a T
     */
    static public String formatTimestamp(Date date) {
        return "T" + date.getTime();
    }
}

