package cz.hsrs.servlet.provider;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.SQLException;
import java.util.List;

import javax.naming.AuthenticationException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.HttpHeaders;

import cz.hsrs.db.DBJsonUtils;
import cz.hsrs.db.model.UnitPosition;
import cz.hsrs.db.model.UnitTrack;
import cz.hsrs.db.model.composite.LastPosition;
import cz.hsrs.db.model.composite.RealUnit;
import cz.hsrs.db.model.custom.UnitPositionSimple;
import cz.hsrs.db.util.UtilFactory;
import cz.hsrs.servlet.feeder.ServiceParameters;
import cz.hsrs.servlet.security.LoginUser;

/**
 * Servlet implementation class DataService
 * 
 * /DataService?Operation=GetDataByUserName&user=pepa&limit=100
 * /DataService?Operation=GetUnitsList
 * /DataService?Operation=GetUnits
 */
public class DataService extends DBServlet {

    private static final long serialVersionUID = 1L;

    private static final String ASC = "ASC";
    private static final String DESC = "DESC";

    public static final String GET_TRACK = "GetTracks";
    public static final String GET_LAST_POSTION = "GetLastPositions";
    public static final String GET_LAST_POSTION_WITH_STATUS = "GetLastPositionsWithStatus";
    public static final String GET_UNITS = "GetUnits";
    public static final String GET_RECENT_TRACK = "GetRecentTracks";
    public static final String GET_POSITIONS = "GetPositions";
    public static final String GET_POSITIONS_RANGE = "GetPositionsDay";
    public static final String GET_UNITS_LIST = "GetUnitsList";

    private UtilFactory db;

    public DataService() {
        super();
    }


    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        super.doGet(request, response);
        RequestParameters params = new RequestParameters(request);
        
        /* For FarmTelemetry purpose only temporary authentication */
/*       
        String user = params.getUser();
        if(user == null){
            throw new ServletException("Authentication failure, no user specified for request: "+ request.getQueryString());
        }
        else{
            try {
                String testLang = db.userUtil.getUserLanguage(user);
                if(testLang.isEmpty()){
                    throw new ServletException("Authentication failure for request "+ request.getQueryString());
                }
            } catch (SQLException | NoItemFoundException e1) {
                throw new ServletException("Authentication failure for request "+ request.getQueryString());
            }
        }
*/
        /* session authentication method */
        LoginUser loggedUser;
        try {
            loggedUser = getAuthenticatedLoginUser(request);
            String userName = loggedUser.getUserName();
            params.setUser(userName);
        } catch (AuthenticationException e1) {
            throw new ServletException("Authentication failure for request "+ request.getQueryString());
        }

        response.addHeader("Access-Control-Allow-Origin", "*");
        response.addHeader(HttpHeaders.CONTENT_TYPE, "application/json");
        /*
         * /DataService?Operation=GetUnits&user=telemetry&unit_id=356173060488215
         * /DataService?Operation=GetTracks&user=telemetry&limit=500
         * /DataService?Operation=GetLastPositions&user=telemetry
         * /DataService?Operation=GetLastPositionsWithStatus&user=telemetry
         * /DataService?Operation=GetRecentTracks&user=telemetry
         * /DataService?Operation=GetPositions&user=telemetry&limit=500
         * /DataService?Operation=GetPositionsDay&user=telemetry&unit_id=356173060488215&fromTime=2016-02-01&toTime=2016-02-04&ordering=desc
         * /DataService?Operation=GetUnitsList&user=telemetry
         */
        PrintWriter out = response.getWriter();
        try {
            switch (request.getParameter(ServiceParameters.OPERATION)) {
                case GET_UNITS: {
                    DBJsonUtils.writeJSON(out, new RealUnit(), db.userUtil.getLastPositionsByUserNameRes(params.getUser(), params.getUnitId()));
                } break;
                case GET_TRACK: {
                    DBJsonUtils.writeJSON(out, new UnitTrack(), db.userUtil.getTracksByUserName(params.getUser(), params.limit));
                } break;
                case GET_LAST_POSTION: {
                    DBJsonUtils.writeJSON(out, db.userUtil.getLastPositionsByUserName(params.getUser()));
                } break;
                case GET_LAST_POSTION_WITH_STATUS: {
                    List<LastPosition> posList = db.userUtil.getLastPositionWithStatus(params.getUser());
                    DBJsonUtils.writeJSON(out, posList);
                } break;
                case GET_RECENT_TRACK: {
                    DBJsonUtils.writeJSON(out, new UnitTrack(), db.userUtil.getTracksByUserName(params.getUser(), 1000));
                } break;
                case GET_POSITIONS: {
                    DBJsonUtils.writeJSON(out, new UnitPosition(), db.userUtil.getPositionsByUserName(params.getUser(), params.limit));
                } break;
                case GET_POSITIONS_RANGE: {
                    DBJsonUtils.writeJSON(out, new UnitPositionSimple(), db.userUtil.getPositionsTimeRangeByUserName(params.getUser(), params.fromTime, params.toTime, params.getUnitId(), params.getOrdering()));
                } break;
                case GET_UNITS_LIST: {
                    DBJsonUtils.writeJSON(out, db.userUtil.getUnitsByUser(params.getUser()));
                } break;
                default:
                    throw new NullPointerException("No operation specified.");
            }
        } catch (SQLException e) {
            solveGetException(e, out);
        }
    }

    @Override
    public void init() throws ServletException {
        super.init();
        
        try {
            db = new UtilFactory();
        } catch (Exception e) {
            throw new ServletException(e);
        }
    }
    

    /**
     * Request Parameter subclass
     * Parses parameter from the request
     * @author jezekjan
     *
     */
    static class RequestParameters {
        private String user;
        private String fromTime;
        private String toTime;
        private Integer limit;
        private Long unitId;
        private String ordering;

        RequestParameters(HttpServletRequest request) throws NullPointerException{
            Object userO = request.getParameter("user");
            if(userO != null){
                user = userO.toString();
            }
            Object limO = request.getParameter("limit");
            if (limO != null) {
                limit = Integer.parseInt(limO.toString());
            }

            Object fromTimeO = request.getParameter("fromTime");
            if (fromTimeO != null) {
                fromTime = fromTimeO.toString();
            }
            Object toTimeO = request.getParameter("toTime");
            if (toTimeO != null) {
                toTime = toTimeO.toString();
            }
            Object orderingO = request.getParameter("ordering");
            if (orderingO != null) {
                String orderingS = orderingO.toString();
                if(orderingS.isEmpty()){
                    ordering = ASC;
                } else{
                    ordering = orderingS.equalsIgnoreCase(DESC) ? DESC : ASC;
                }
            }else{
                ordering = ASC;
            }
            Object unitO = request.getParameter("unit_id");
            unitId = unitO != null ? Long.parseLong(unitO.toString()) : null;
        }

        public Long getUnitId() {
            return unitId;
        }

        public void setUnitId(long unitId) {
            this.unitId = unitId;
        }
        
        public String getUser() {
            return user;
        }

        public void setUser(String user) {
            this.user = user;
        }

        public Integer getLimit() {
            return limit;
        }

        public void setLimit(Integer limit) {
            this.limit = limit;
        }

        public String getFromTime() {
            return fromTime;
        }

        public void setFromTime(String fromTime) {
            this.fromTime = fromTime;
        }

        public String getToTime() {
            return toTime;
        }

        public void setToTime(String toTime) {
            this.toTime = toTime;
        }

        public String getOrdering() {
            return ordering;
        }

        public void setOrdering(String ordering) {
            this.ordering = ordering;
        }

        @Override
        public String toString() {
            return "RequestParameters [user=" + user + ", fromTime=" + fromTime
                    + ", toTime=" + toTime + ", limit=" + limit + ", unit_id="
                    + unitId + ", ordering=" + ordering + "]";
        }
    }
}