//	Contour - Android drawing teacher application
//	Copyright (C) 2014  Johannes Riedmann
//	
//	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 3 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.
//	
//	You should have received a copy of the GNU General Public License
//	along with this program.  If not, see <http://www.gnu.org/licenses/>.

package com.j0h1.contour.server.rest;

import java.util.ArrayList;
import java.util.Calendar;

import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;

import com.j0h1.contour.server.dao.DAOImage;
import com.j0h1.contour.server.dao.DAOSession;
import com.j0h1.contour.server.dao.DAOSessionException;
import com.j0h1.contour.server.dao.impl.DAOImageImpl;
import com.j0h1.contour.server.dao.impl.DAOSessionImpl;
import com.j0h1.contour.server.rest.pojo.Image;
import com.j0h1.contour.server.rest.pojo.Session;
import com.j0h1.contour.server.rest.pojo.SessionResponseList;
import com.j0h1.contour.server.rest.pojo.Track;
import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException;
import com.sun.org.apache.xml.internal.security.utils.Base64;

/**
 * The methods of this service class are invoked by requesting the defined URL paths.
 * The response of this service is either a single Session object or a List of Session objects.
 * @author Johannes Riedmann
 *
 */
@Path("session")
public class SessionService {
	
	/**
	 * This method responds to it's specified path by generating a XML document
	 * containing a list of sessions for the given playerId and trackId.
	 * This list contains the top10 sessions for the given trackId/playerId and
	 * is ordered descending by the score.
	 * @param playerId	If playerId equals Integer.MAX_VALUE, the global top10
	 * 					sessions are returned. Otherwise this method will return
	 * 					the top 10 sessions for the specified playerId.
	 * @param trackId	Integer.MAX_VALUE as trackId indicates a query for custom
	 * 					sessions. For other values bigger than 0, this method responds with
	 * 					the top 10 sessions for the specified track.
	 * @return	Responds with a list of the top 10 sessions, ordered descending by
	 * 			the achieved score, mapped to a XML document. If no sessions were
	 * 			found, a empty list is returned.
	 */
	@GET
	@Produces(MediaType.APPLICATION_XML)
	@Path("player/{playerId}/track/{trackId}")
	public SessionResponseList getTop10Sessions(@PathParam("playerId") int playerId, 
			@PathParam("trackId") int trackId) {
		DAOSession sessionDao = new DAOSessionImpl();
		
		SessionResponseList sessionList = new SessionResponseList();
		ArrayList<Session> sessions = new ArrayList<Session>();
		
		if (trackId != Integer.MAX_VALUE) {
			// get track sessions for specific user and track
			try {
				sessions = sessionDao.getTrackSessions(playerId, trackId);
			} catch (DAOSessionException ex) {
				// feedback on HTTP service not needed, because it should
				// be running without supervision
			}
		} else {
			// get top custom sessions for specific user
			try {
				sessions = sessionDao.getCustomSessions(playerId);
			} catch (DAOSessionException ex) {
				// feedback on HTTP service not needed, because it should
				// be running without supervision
			}			
		}
		
		sessionList.setList(sessions);
		
		return sessionList;
	}
	
	/**
	 * Persists a session, defined in the formParams that are defined in the request,
	 * to the database.
	 * @param formParams	Contain all the data that is needed to persist the
	 * 						drawing session successfully.
	 * @return	A plain text String that says "success" of session is persisted
	 * 			successfully.
	 */
	@POST
	public String persistSession(MultivaluedMap<String, String> formParams) {
		String trackId = formParams.getFirst("trackId");
		String username = formParams.getFirst("username");
		String score = formParams.getFirst("score");
		
		// create a new Session
		Session session = new Session();
		Track track = new Track();
		track.setTrackId(Integer.valueOf(trackId));
		session.setTrack(track);
		session.setScore(Double.valueOf(score));
		session.setDate(Calendar.getInstance().getTimeInMillis());
		
		if (Integer.valueOf(trackId) == Integer.MAX_VALUE) {
			// if it's a custom session, persist original image and score image
			String originalData = formParams.getFirst("originalData");
			String edgeData = formParams.getFirst("edgeData");
			String imagename = formParams.getFirst("imagename");
			
			Image drawing = new Image();
			Image scoreImage = new Image();
			
			try {
				// decode base64 encoded drawing data
				byte[] base64DrawingData = Base64.decode(
						formParams.getFirst("drawing" + Integer.MAX_VALUE));
				
				drawing.setData(base64DrawingData);
				
				// decode base64 encoded score image data
				byte[] base64ScoreImage = Base64.decode(
						formParams.getFirst("scoreimage" + Integer.MAX_VALUE));
				
				scoreImage.setData(base64ScoreImage);
				scoreImage.setScore(Double.valueOf(
						formParams.getFirst("score" + Integer.MAX_VALUE)));
			} catch (Base64DecodingException e) {
				// feedback on HTTP service not needed, because it should
				// be running without supervision
			}
			
			if (drawing.getData() != null && scoreImage.getData() != null) {
				// persist custom session
				DAOSession sessionDao = new DAOSessionImpl();
				
				try {
					sessionDao.persistCustomSession(session, username, originalData, 
							edgeData, imagename, drawing, scoreImage);
				} catch (DAOSessionException ex) {
					// feedback on HTTP service not needed, because it should
					// be running without supervision
				}
			}
		} else {
			// request images for current track
			DAOImage imageDao = new DAOImageImpl();
			ArrayList<Image> edgeImages = imageDao.
					findEdgeImagesByTrackId(Integer.parseInt(trackId), "en");
			
			// extract drawing and score image data
			ArrayList<Image> drawings = new ArrayList<Image>();
			ArrayList<Image> scoreImages = new ArrayList<Image>();
			
			for (int i = 0; i < edgeImages.size(); i++) {
				int imageId = edgeImages.get(i).getImageId();
				
				// extract data and define drawing
				Image tempDrawing = new Image();
				tempDrawing.setImageId(imageId);
				
				try {
					byte[] drawingData = Base64.decode(
							formParams.getFirst("drawing" + imageId));
					tempDrawing.setData(drawingData);
				} catch (Base64DecodingException e) {
					// feedback on HTTP service not needed, because it should
					// be running without supervision
				}
				
				drawings.add(tempDrawing);
				
				// extract data and define score image
				Image tempScoreImage = new Image();
				tempScoreImage.setImageId(imageId);
				tempScoreImage.setScore(Double.valueOf(
						formParams.getFirst("score" + imageId)));
				
				try {
					byte[] scoreImageData = Base64.decode(
							formParams.getFirst("scoreimage" + imageId));
					tempScoreImage.setData(scoreImageData);
				} catch (Base64DecodingException e) {
					// feedback on HTTP service not needed, because it should
					// be running without supervision
				}
				
				scoreImages.add(tempScoreImage);
			}
			
			// persist track session
			DAOSession sessionDao = new DAOSessionImpl();
			
			try {
				sessionDao.persistTrackSession(session, username, drawings, scoreImages);
			} catch (DAOSessionException ex) {
				// feedback on HTTP service not needed, because it should
				// be running without supervision
			}
		}
		
		return "success";
	}

}
