package org.exoplatform.cs.portlet.ticketCharts;

import juzu.*;
import juzu.plugin.jackson.Jackson;
import juzu.template.Template;
import org.exoplatform.commons.juzu.ajax.Ajax;
import org.exoplatform.cs.dao.LogDAO;
import org.exoplatform.cs.dao.TopicDAO;
import org.exoplatform.cs.dto.*;
import org.exoplatform.cs.entity.LogEntity;
import org.exoplatform.cs.entity.SpaceEntity;
import org.exoplatform.cs.portlet.common.CSControllerBase;
import org.exoplatform.cs.service.CSConstants;
import org.exoplatform.cs.service.CSSpaceService;
import org.exoplatform.cs.service.StatsService;
import org.exoplatform.cs.service.tickets.FlowState;
import org.exoplatform.cs.service.tickets.TicketStatusFlowService;
import org.exoplatform.cs.service.util.CSUtils;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.services.organization.User;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import javax.inject.Inject;

import java.math.BigInteger;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;


public class TicketChartsController extends CSControllerBase {

  private static Log  LOG = ExoLogger.getLogger(TicketChartsController.class);
  private String     bundleString;
  ResourceBundle     bundle;
  private List<String> statusList = new ArrayList<String>();
    SimpleDateFormat byDayDateFormat = new SimpleDateFormat("yyyy.MM.dd");
    SimpleDateFormat byMonthDateFormat = new SimpleDateFormat("MMM yyyy");
    SimpleDateFormat byWeekDateFormat = new SimpleDateFormat("YYYY-'W'ww");

    @Inject
    TopicDAO topicDAO;


  @Inject
  TicketStatusFlowService ticketStatusFlowService;

  @Inject
  CSSpaceService spaceService;

  @Inject
  StatsService statsService;


  @Inject
  LogDAO logDao;


    @Inject
    @Path("index.gtmpl")
    Template            indexTmpl;

    @View
    public Response.Content index() {
        return indexTmpl.ok();
    }




    @Ajax
    @Resource
    @MimeType.JSON
    @Jackson
    public Response getBundle(String locale) {
        return super.getBundle(new Locale(locale));
    }


  /**
   * this method returns the static list of ticket types
   *
   * @return
   */
  @Ajax
  @Resource(method = HttpMethod.GET )
  @MimeType.JSON
  @Jackson
  public Map<String, List<FlowState>> loadStatuses() {
    return ticketStatusFlowService.getAllStatuses();
  }




    @Ajax
    @juzu.Resource
    @MimeType.JSON
    @Jackson
    public Response countSpaceTicketsGroupdByOwner(String spaceId) {
        try {
            JSONArray TicketsNumber = new JSONArray();
            List<Object[]> results =topicDAO.countSpaceTicketsGroupdByOwner(spaceId);
            for (int i = 0; i < results.size(); i++) {
                Object[] arr = results.get(i);
                JSONObject data = new JSONObject();
                data.put("owner",((Owner) arr[0])!=null ? ((Owner) arr[0]).name() : "Null");
                data.put("ticketNumber",(Long)arr[1]);
                TicketsNumber.put(data);
            }


            return Response.ok(TicketsNumber.toString());
        } catch (Throwable e) {
            LOG.error("error while getting context", e);
            return Response.status(500);
        }
    }

       @Ajax
    @juzu.Resource
    @MimeType.JSON
    @Jackson
    public Response countSpaceTicketsGroupdByAssignee(String spaceId) {
        try {
            JSONArray TicketsNumber = new JSONArray();
            List<Object[]> results =topicDAO.countSpaceTicketsGroupdByAssignee(spaceId);
            for (int i = 0; i < results.size(); i++) {
                Object[] arr = results.get(i);
                JSONObject data = new JSONObject();
                String assignee = ((String) arr[0])!=null ? ((String) arr[0]).toString() : "Not Assigned";
                data.put("assignee",assignee);
                data.put("ticketNumber",(Long)arr[1]);
                TicketsNumber.put(data);
            }


            return Response.ok(TicketsNumber.toString());
        } catch (Throwable e) {
            LOG.error("error while getting context", e);
            return Response.status(500);
        }
    }

    @Ajax
    @juzu.Resource
    @MimeType.JSON
    @Jackson
    public Response countSpaceTicketsGroupdByStatus(String spaceId) {
        try {
            JSONArray spaceTicketsNumberByStatus = new JSONArray();
            List<Object[]> results =topicDAO.countSpaceTicketsGroupdByStatus(spaceId);
            for (int i = 0; i < results.size(); i++) {
                Object[] arr = results.get(i);
                JSONObject data = new JSONObject();
                data.put("status",(((String) arr[0]).toString()));
                data.put("ticketNumber",(Long)arr[1]);
                spaceTicketsNumberByStatus.put(data);
            }


            return Response.ok(spaceTicketsNumberByStatus.toString());
        } catch (Throwable e) {
            LOG.error("error while getting context", e);
            return Response.status(500);
        }
    }


    @Ajax
    @juzu.Resource
    @MimeType.JSON
    @Jackson
    public Response getTicketsGroupdByByAssignee(String spaceId) {
        try {
            JSONArray TicketsNumber = new JSONArray();
            List<Object[]> results =topicDAO.countSpaceTicketsGroupdByAssignee(spaceId);
            for (int i = 0; i < results.size(); i++) {
                Object[] arr = results.get(i);
                JSONObject data = new JSONObject();
                String assignee = ((String) arr[0])!=null ? ((String) arr[0]).toString() : "Not Assigned";
                data.put("assignee",assignee);
                data.put("ticketNumber",(Long)arr[1]);
                TicketsNumber.put(data);
            }


            return Response.ok(TicketsNumber.toString());
        } catch (Throwable e) {
            LOG.error("error while getting context", e);
            return Response.status(500);
        }
    }






    @Ajax
    @juzu.Resource
    @MimeType.JSON
    @Jackson
    public Response getTicketsGroupdByAssignee(String spaceId, Long startDate, Long endDate, Boolean internal) {
        try {
            List<Object[]> results = new ArrayList<>();
            if(startDate==0 || endDate==0){
                if(spaceId.equals("")){
                    results =topicDAO.countCustomerTicketsGroupdByAssignee(internal);
                }else{
                    results =topicDAO.countSpaceTicketsGroupdByAssignee(spaceId);
                }
            }else{
                Calendar fromDate=Calendar.getInstance();
                fromDate.setTimeInMillis(startDate);
                Calendar toDate=Calendar.getInstance();
                toDate.setTimeInMillis(startDate);
                results =topicDAO.countCustomerTicketsGroupdByAssigneeAndDates(internal, fromDate,toDate);
            }
            JSONArray TicketsNumber = new JSONArray();
            for (int i = 0; i < results.size(); i++) {
                Object[] arr = results.get(i);
                JSONObject data = new JSONObject();
                String assignee = ((String) arr[0])!=null ? ((String) arr[0]).toString() : "Not Assigned";
                data.put("assignee",assignee);
                data.put("ticketNumber",(Long)arr[1]);
                TicketsNumber.put(data);
            }


            return Response.ok(TicketsNumber.toString());
        } catch (Throwable e) {
            LOG.error("error while getting context", e);
            return Response.status(500);
        }
    }



    @Ajax
    @juzu.Resource
    @MimeType.JSON
    @Jackson
    public Response getTicketsGroupdBySpace(Long startDate, Long endDate, Boolean internal) {
        try {
            JSONArray ticketsNumberBySpaceList = new JSONArray();
            List<Object[]> results =topicDAO.countCustomerTicketsGroupdBySpace(internal);
            for (int i = 0; i < results.size(); i++) {
                Object[] arr = results.get(i);
                JSONObject data = new JSONObject();
                SpaceDTO spaceDTO = spaceService.getSpace((((SpaceEntity) arr[0]).getGroupId()));
                data.put("space",spaceDTO.getName());
                data.put("spaceId",((SpaceEntity) arr[0]).getGroupId());
                data.put("ticketNumber",(Long)arr[1]);
                ticketsNumberBySpaceList.put(data);
            }

            return Response.ok(ticketsNumberBySpaceList.toString());
        } catch (Throwable e) {
            LOG.error("error while getting context", e);
            return Response.status(500);
        }
    }


    @Ajax
    @juzu.Resource
    @MimeType.JSON
    @Jackson
    public Response getTicketsGroupdBySeverity(String spaceId, Long startDate, Long endDate, Boolean internal) {
        try {
            List<Object[]> results = new ArrayList<>();
            if(startDate==0 || endDate==0){
                if(spaceId.equals("")){
                    results =topicDAO.countCustomerTicketsGroupdBySeverity(internal);
                }else{
                    results =topicDAO.countSpaceTicketsGroupdBySeverity(spaceId);
                }
            }else{
                Calendar fromDate=Calendar.getInstance();
                fromDate.setTimeInMillis(startDate);
                Calendar toDate=Calendar.getInstance();
                toDate.setTimeInMillis(startDate);
                results =topicDAO.countCustomerTicketsGroupdBySeverityAndDates(internal, fromDate,toDate);
            }
            JSONArray TicketsNumber = new JSONArray();
            for (int i = 0; i < results.size(); i++) {
                Object[] arr = results.get(i);
                JSONObject data = new JSONObject();
                String severity = ((IssueSeverity) arr[0])!=null ? ((IssueSeverity) arr[0]).toString() : "None";
                data.put("severity",severity);
                data.put("ticketNumber",(Long)arr[1]);
                TicketsNumber.put(data);
            }


            return Response.ok(TicketsNumber.toString());
        } catch (Throwable e) {
            LOG.error("error while getting context", e);
            return Response.status(500);
        }
    }


    @Ajax
    @juzu.Resource
    @MimeType.JSON
    @Jackson
    public Response getTicketsGroupdByOwner(String spaceId, Long startDate, Long endDate, Boolean internal) {
        try {
            JSONArray ticketsNumberByOwnerList = new JSONArray();
            List<Object[]> results = new ArrayList<>();
            if(spaceId.equals("")){
                results =topicDAO.countCustomerTicketsGroupdByOwner(internal);
            }else{
                results =topicDAO.countSpaceTicketsGroupdByOwner(spaceId);
            }
            for (int i = 0; i < results.size(); i++) {
                try {
                    Object[] arr = results.get(i);
                    JSONObject data = new JSONObject();
                    if(arr[0]!=null){
                        data.put("owner",(((Owner) arr[0]).name()));
                    }else{
                        data.put("owner","null");
                    }
                    data.put("ticketNumber",(Long)arr[1]);
                    ticketsNumberByOwnerList.put(data);
                } catch (Exception e) {
                }
            }

            return Response.ok(ticketsNumberByOwnerList.toString());
        } catch (Throwable e) {
            LOG.error("error while getting context", e);
            return Response.status(500);
        }
    }


    @Ajax
    @juzu.Resource
    @MimeType.JSON
    @Jackson
    public Response getTicketsGroupdByStatus(String spaceId, Long startDate, Long endDate, Boolean internal) {
        try {
            JSONArray ticketsNumberByStatusList = new JSONArray();
            List<Object[]> results = new ArrayList<>();
            if(spaceId.equals("")){
                results =topicDAO.countCustomerTicketsGroupdByStatus(internal);
            }else{
                results =topicDAO.countSpaceTicketsGroupdByStatus(spaceId);
            }
            for (int i = 0; i < results.size(); i++) {
                Object[] arr = results.get(i);
                JSONObject data = new JSONObject();
                data.put("status",(((String) arr[0]).toString()));
                data.put("ticketNumber",(Long)arr[1]);
                ticketsNumberByStatusList.put(data);
            }

            return Response.ok(ticketsNumberByStatusList.toString());
        } catch (Throwable e) {
            LOG.error("error while getting context", e);
            return Response.status(500);
        }
    }



    @Ajax
    @juzu.Resource
    @MimeType.JSON
    @Jackson
    public Response getTicketsGroupdByStatusAndDates(Long startDate, Long endDate, Boolean internal) {
        try {
            JSONArray ticketsNumberByStatusList = new JSONArray();
            Calendar cFrom =  Calendar.getInstance();
            cFrom.setTimeInMillis(startDate);
            Calendar cTo =  Calendar.getInstance();
            cTo.setTimeInMillis(endDate);

            List<Object[]> results =topicDAO.countCustomerTicketsGroupdByStatusAndDates(internal, cFrom,cTo);
            for (int i = 0; i < results.size(); i++) {
                Object[] arr = results.get(i);
                JSONObject data = new JSONObject();
                data.put("status",(((String) arr[0]).toString()));
                data.put("ticketNumber",(Long)arr[1]);
                ticketsNumberByStatusList.put(data);
            }

            return Response.ok(ticketsNumberByStatusList.toString());
        } catch (Throwable e) {
            LOG.error("error while getting context", e);
            return Response.status(500);
        }
    }



    @Ajax
    @juzu.Resource
    @MimeType.JSON
    @Jackson
    public Response getOpenVsClosedTickets(String spaceId, Long startDate, Long endDate, Boolean internal) {
        try {
            JSONArray ticketsNumberClosedVsOpenedList = new JSONArray();
            Long closed = null;
            Long opened = null;
            if(spaceId.equals("")){
                closed =topicDAO.countClosedCustomerTickets(internal);
                opened =topicDAO.countOpenCustomerTickets(internal);
            }else{
                closed =topicDAO.countClosedSpaceTickets(spaceId);
                opened =topicDAO.countOpenSpaceTickets(spaceId);
            }


                JSONObject data = new JSONObject();
                data.put("status","closed");
                data.put("ticketNumber",closed);
            ticketsNumberClosedVsOpenedList.put(data);
                data = new JSONObject();
                data.put("status","open");
                data.put("ticketNumber",opened);
            ticketsNumberClosedVsOpenedList.put(data);
            return Response.ok(ticketsNumberClosedVsOpenedList.toString());
        } catch (Throwable e) {
            LOG.error("error while getting context", e);
            return Response.status(500);
        }
    }




    @Ajax
    @juzu.Resource
    @MimeType.JSON
    @Jackson
    public Response getOpenVsClosedTicketsByDates(Long startDate, Long endDate, Boolean internal) {
        try {
            JSONArray ticketsNumberClosedVsOpenedList = new JSONArray();
            Calendar cFrom =  Calendar.getInstance();
            cFrom.setTimeInMillis(startDate);
            Calendar cTo =  Calendar.getInstance();
            cTo.setTimeInMillis(endDate);

            Long closed =logDao.countLogsByTypeAndNewValueBetweenDates(cFrom,cTo,LogType.TICKET_STATUS_CHANGED, CSConstants.STATUS_CLOSED, internal).longValue();
            Long opened =logDao.countLogsNumberBetweenDates(cFrom,cTo,LogType.TICKET_CREATED, internal).longValue();

            JSONObject data = new JSONObject();
            data.put("status","closed");
            data.put("ticketNumber",closed);
            ticketsNumberClosedVsOpenedList.put(data);
            data = new JSONObject();
            data.put("status","opened");
            data.put("ticketNumber",opened);
            ticketsNumberClosedVsOpenedList.put(data);
            return Response.ok(ticketsNumberClosedVsOpenedList.toString());
        } catch (Throwable e) {
            LOG.error("error while getting context", e);
            return Response.status(500);
        }
    }


    @Ajax
    @juzu.Resource
    @MimeType.JSON
    @Jackson
    public Response getOpenVSClosedStatLog(String period, Long startDate, Long endDate, Boolean internal) {
        if(period.equals("weekly")){
            return getWeeklyOpenVSClosedStatLog("", startDate,endDate,internal);
        }else{
            return getMonthlyOpenVSClosedStatLog("", startDate,endDate,internal);
        }
    }


    @Ajax
    @juzu.Resource
    @MimeType.JSON
    @Jackson
    public Response getSpaceOpenVSClosedStatLog(String spaceId, String period, Long startDate, Long endDate, Boolean internal) {
        if(period.equals("weekly")){
            return getWeeklyOpenVSClosedStatLog(spaceId, startDate,endDate,internal);
        }else{
            return getMonthlyOpenVSClosedStatLog(spaceId, startDate,endDate,internal);
        }
    }

    @Ajax
    @juzu.Resource
    @MimeType.JSON
    @Jackson
    public Response getWeeklyOpenVSClosedStatLog(String spaceId, Long startDate, Long endDate, Boolean internal) {
        try {
            Calendar fromDate=Calendar.getInstance();
            fromDate.setTimeInMillis(startDate);
            if(startDate==0){
                LogEntity log_ = null;
                if(spaceId.equals("")){
                    List<LogEntity> logList=logDao.getFirstLogByType(LogType.TICKET_CREATED);
                    if(logList.size()>0){
                        log_ = logList.get(0);
                    }
                }else{
                    List<LogEntity> logList=logDao.getFirstLogByTypeAndSpace(spaceId, LogType.TICKET_CREATED);
                    if(logList.size()>0){
                        log_ = logList.get(0);
                    }
                }
                if(log_!=null) {
                    fromDate.setTime(log_.getWhen().getTime());
                }  else
                    return Response.status(204);
            }
            JSONArray statList = new JSONArray();
            fromDate.set(Calendar.HOUR_OF_DAY, 0);
            fromDate.set(Calendar.MINUTE, 0);
            fromDate.set(Calendar.SECOND, 0);
            Calendar toDate=Calendar.getInstance();
            if(endDate!=0){
                toDate.setTimeInMillis(endDate);
            }
            int diff= Calendar.SATURDAY-fromDate.get(Calendar.DAY_OF_WEEK)+2;
            Calendar to_=Calendar.getInstance();
            to_.setTime(fromDate.getTime());
            to_.add(Calendar.DATE, diff);
            while(fromDate.before(toDate)){
                JSONObject data = new JSONObject();

                if(spaceId.equals("")){
                    data.put("statDate",(getDateByPeriod(fromDate.getTime(),"weekly")));
                    data.put("closedTicketNumber",logDao.countLogsByTypeAndNewValueBetweenDates(fromDate,to_,LogType.TICKET_STATUS_CHANGED, CSConstants.STATUS_CLOSED, internal).longValue());
                    data.put("openedTicketNumber",logDao.countLogsNumberBetweenDates(fromDate,to_,LogType.TICKET_CREATED, internal).longValue());
                }else{
                    data.put("statDate",(getDateByPeriod(fromDate.getTime(),"weekly")));
                    data.put("closedTicketNumber",logDao.countLogsByTypeAndNewValueAndSpaceBetweenDates(spaceId, fromDate,to_,LogType.TICKET_STATUS_CHANGED, CSConstants.STATUS_CLOSED).longValue());
                    data.put("openedTicketNumber",logDao.countLogsNumberBySpaceBetweenDates(spaceId, fromDate,to_,LogType.TICKET_CREATED).longValue());
                }
                statList.put(data);
                fromDate.setTime(to_.getTime());
                to_.add(Calendar.DATE, 7);
            }

            return Response.ok(statList.toString());
        } catch (Throwable e) {
            LOG.error("error while getting context", e);
            return Response.status(500);
        }
    }



    @Ajax
    @juzu.Resource
    @MimeType.JSON
    @Jackson
    public Response getMonthlyOpenVSClosedStatLog(String spaceId, Long startDate, Long endDate, Boolean internal) {
        try {
            Calendar fromDate=Calendar.getInstance();
            fromDate.setTimeInMillis(startDate);
            if(startDate==0){
                LogEntity log_ = null;
                if(spaceId.equals("")){
                    List<LogEntity> logList=logDao.getFirstLogByType(LogType.TICKET_CREATED);
                    if(logList.size()>0){
                        log_ = logList.get(0);
                    }
                }else{
                    List<LogEntity> logList=logDao.getFirstLogByTypeAndSpace(spaceId, LogType.TICKET_CREATED);
                    if(logList.size()>0){
                        log_ = logList.get(0);
                    }
                }
                if(log_!=null) {
                    fromDate.setTime(log_.getWhen().getTime());
                }  else
                    return Response.status(204);
            }
            JSONArray statList = new JSONArray();

            fromDate.set(Calendar.HOUR_OF_DAY, 0);
            fromDate.set(Calendar.MINUTE, 0);
            Calendar toDate=Calendar.getInstance();
            if(endDate!=0){
                toDate.setTimeInMillis(endDate);
            }
            Calendar to_=Calendar.getInstance();
            to_.setTime(fromDate.getTime());
            to_.set(Calendar.DAY_OF_MONTH, fromDate.getActualMaximum(Calendar.DAY_OF_MONTH));
            while(fromDate.before(toDate)){
                JSONObject data = new JSONObject();
                if(spaceId.equals("")){
                    data.put("statDate",(getDateByPeriod(fromDate.getTime(),"monthly")));
                    data.put("closedTicketNumber",logDao.countLogsByTypeAndNewValueBetweenDates(fromDate,to_,LogType.TICKET_STATUS_CHANGED, CSConstants.STATUS_CLOSED, internal).longValue());
                    data.put("openedTicketNumber",logDao.countLogsNumberBetweenDates(fromDate,to_,LogType.TICKET_CREATED, internal).longValue());
                }else{
                    data.put("statDate",(getDateByPeriod(fromDate.getTime(),"monthly")));
                    data.put("closedTicketNumber",logDao.countLogsByTypeAndNewValueAndSpaceBetweenDates(spaceId, fromDate,to_,LogType.TICKET_STATUS_CHANGED, CSConstants.STATUS_CLOSED).longValue());
                    data.put("openedTicketNumber",logDao.countLogsNumberBySpaceBetweenDates(spaceId, fromDate,to_,LogType.TICKET_CREATED).longValue());
                }

                statList.put(data);
                fromDate.setTime(to_.getTime());
                fromDate.set(Calendar.MONTH,fromDate.get(Calendar.MONTH)+1);
                fromDate.set(Calendar.DAY_OF_MONTH,1);
                to_.setTime(fromDate.getTime());
                to_.set(Calendar.DAY_OF_MONTH, fromDate.getActualMaximum(Calendar.DAY_OF_MONTH));
            }

            return Response.ok(statList.toString());
        } catch (Throwable e) {
            LOG.error("error while getting context", e);
            return Response.status(500);
        }
    }




    @Ajax
    @juzu.Resource
    @MimeType.JSON
    @Jackson
    public Response getLogbyStatusChartData(String spaceId, String period, Long startDate, Long endDate, Boolean internal) {
        if(period.equals("weekly")){
           return getWeeklyLogbyStatusChartData(spaceId, startDate,endDate,internal);
        }else{
            return getMonthlyLogbyStatusChartData(spaceId, startDate,endDate,internal);
        }
    }

    @Ajax
    @juzu.Resource
    @MimeType.JSON
    @Jackson
    public Response getWeeklyLogbyStatusChartData(String spaceId, Long startDate, Long endDate, Boolean internal) {
        try {
            Calendar fromDate=Calendar.getInstance();
            fromDate.setTimeInMillis(startDate);
            JSONArray ticketsNumberByStatusList = new JSONArray();
            if(startDate==0){
                LogEntity log_ = null;
                if(spaceId.equals("")){
                    List<LogEntity> logList=logDao.getFirstLogByType(LogType.TICKET_STATUS_CHANGED);
                    if(logList.size()>0){
                        log_ = logList.get(0);
                    }
                }else{
                    List<LogEntity> logList=logDao.getFirstLogByTypeAndSpace(spaceId, LogType.TICKET_STATUS_CHANGED);
                    if(logList.size()>0){
                        log_ = logList.get(0);
                    }
                }
                if(log_!=null) {
                    fromDate.setTime(log_.getWhen().getTime());
                }  else
                    return Response.status(204);
            }
            fromDate.set(Calendar.HOUR_OF_DAY, 0);
            fromDate.set(Calendar.MINUTE, 0);
            fromDate.set(Calendar.SECOND, 0);
            Calendar toDate=Calendar.getInstance();
            if(endDate!=0){
                toDate.setTimeInMillis(endDate);
            }
            int diff= Calendar.SATURDAY-fromDate.get(Calendar.DAY_OF_WEEK)+2;
            Calendar to_=Calendar.getInstance();
            to_.setTime(fromDate.getTime());
            to_.add(Calendar.DATE, diff);
            while(fromDate.before(toDate)){
                List<Object[]> results = new ArrayList<>();
                if(spaceId.equals("")){
                    results =logDao.countLogsGroupdByNewValueAndDates(internal,to_);
                }else{
                    results =logDao.countLogsBySpaceGroupdByNewValueAndDates(spaceId,to_);
                }

                JSONObject data = new JSONObject();
                data.put("openedTicketNumber",0);
                data.put("consideredTicketNumber",0);
                data.put("waitingCustomerTicketNumber",0);
                data.put("waitingProductTicketNumber",0);
                data.put("inProgressTicketNumber",0);
                data.put("resolvedTicketNumber",0);
                data.put("resolvedWFVTicketNumber",0);
                data.put("statDate",(getDateByPeriod(fromDate.getTime(),"weekly")));
                for (int i = 0; i < results.size(); i++) {
                    Object[] arr = results.get(i);

                    switch (((String) arr[0])!=null ? ((String) arr[0]).toString()  : "open") {

                        case "open":
                            data.put("openedTicketNumber",((BigInteger)arr[1]).longValue());
                            break;
                        case "considered":
                            data.put("consideredTicketNumber",((BigInteger)arr[1]).longValue());
                            break;
                        case "suspended_wfi":
                            data.put("waitingCustomerTicketNumber",((BigInteger)arr[1]).longValue());
                            break;
                        case "resolved_maintenance":
                            data.put("waitingProductTicketNumber",((BigInteger)arr[1]).longValue());
                            break;
                        case "inprogress":
                            data.put("inProgressTicketNumber",((BigInteger)arr[1]).longValue());
                            break;
                        case "resolved_validated":
                            data.put("resolvedTicketNumber",((BigInteger)arr[1]).longValue());
                            break;
                        case "resolved_wfv":
                            data.put("resolvedWFVTicketNumber",((BigInteger)arr[1]).longValue());
                            break;

                    }

                }
                ticketsNumberByStatusList.put(data);
                fromDate.setTime(to_.getTime());
                to_.add(Calendar.DATE, 7);
            }
            return Response.ok(ticketsNumberByStatusList.toString());
        } catch (Throwable e) {
            LOG.error("error while getting context", e);
            return Response.status(500);
        }
    }

    @Ajax
    @juzu.Resource
    @MimeType.JSON
    @Jackson
    public Response getMonthlyLogbyStatusChartData(String spaceId, Long startDate, Long endDate, Boolean internal) {
        try {
            Calendar fromDate=Calendar.getInstance();
            JSONArray ticketsNumberByStatusList = new JSONArray();
            fromDate.setTimeInMillis(startDate);
            if(startDate==0){
                LogEntity log_ = null;
                if(spaceId.equals("")){
                    List<LogEntity> logList=logDao.getFirstLogByType(LogType.TICKET_STATUS_CHANGED);
                    if(logList.size()>0){
                        log_ = logList.get(0);
                    }
                }else{
                    List<LogEntity> logList=logDao.getFirstLogByTypeAndSpace(spaceId, LogType.TICKET_STATUS_CHANGED);
                    if(logList.size()>0){
                        log_ = logList.get(0);
                    }
                }
                if(log_!=null) {
                    fromDate.setTime(log_.getWhen().getTime());
                }  else
                    return Response.status(204);
            }
            fromDate.set(Calendar.HOUR_OF_DAY, 0);
            fromDate.set(Calendar.MINUTE, 0);
            Calendar toDate=Calendar.getInstance();
            if(endDate!=0){
                toDate.setTimeInMillis(endDate);
            }
            Calendar to_=Calendar.getInstance();
            to_.setTime(fromDate.getTime());
            to_.set(Calendar.DAY_OF_MONTH, fromDate.getActualMaximum(Calendar.DAY_OF_MONTH));
            while(fromDate.before(toDate)){
                List<Object[]> results =logDao.countLogsGroupdByNewValueAndDates(internal,to_);
                JSONObject data = new JSONObject();
                data.put("openedTicketNumber",0);
                data.put("consideredTicketNumber",0);
                data.put("waitingCustomerTicketNumber",0);
                data.put("waitingProductTicketNumber",0);
                data.put("inProgressTicketNumber",0);
                data.put("resolvedTicketNumber",0);
                data.put("closedTicketNumber",0);
                data.put("statDate",(getDateByPeriod(fromDate.getTime(),"monthly")));
                for (int i = 0; i < results.size(); i++) {
                    Object[] arr = results.get(i);

                    switch (((String) arr[0])!=null ? ((String) arr[0]).toString()  : "open") {

                        case "open":
                            data.put("openedTicketNumber",((BigInteger)arr[1]).longValue());
                            break;
                        case "considered":
                            data.put("consideredTicketNumber",((BigInteger)arr[1]).longValue());
                            break;
                        case "suspended_wfi":
                            data.put("waitingCustomerTicketNumber",((BigInteger)arr[1]).longValue());
                            break;
                        case "resolved_maintenance":
                            data.put("waitingProductTicketNumber",((BigInteger)arr[1]).longValue());
                            break;
                        case "inprogress":
                            data.put("inProgressTicketNumber",((BigInteger)arr[1]).longValue());
                            break;
                        case "resolved_validated":
                            data.put("resolvedTicketNumber",((BigInteger)arr[1]).longValue());
                            break;
                        case "resolved_wfv":
                            data.put("resolvedWFVTicketNumber",((BigInteger)arr[1]).longValue());
                            break;

                    }

                }
                ticketsNumberByStatusList.put(data);
                fromDate.setTime(to_.getTime());
                fromDate.set(Calendar.MONTH,fromDate.get(Calendar.MONTH)+1);
                fromDate.set(Calendar.DAY_OF_MONTH,1);
                to_.setTime(fromDate.getTime());
                to_.set(Calendar.DAY_OF_MONTH, fromDate.getActualMaximum(Calendar.DAY_OF_MONTH));
            }
            return Response.ok(ticketsNumberByStatusList.toString());
        } catch (Throwable e) {
            LOG.error("error while getting context", e);
            return Response.status(500);
        }
    }


    @Ajax
    @juzu.Resource
    @MimeType.JSON
    @Jackson
    public Response getData(String currentSpace, Boolean internal, Long startDate, Long endDate) {
        try {

                String curentSpace = getCurrentSpaceId();
            if(curentSpace==null)curentSpace = currentSpace;
            if(curentSpace!=null && curentSpace.equals("/spaces/exo_support")) curentSpace = currentSpace;
            if(curentSpace!=null && curentSpace.equals("/spaces/exo_global_support")) curentSpace = currentSpace;

                if(startDate==0||endDate==0){
                    return getMetrics(curentSpace, internal);
                    }
                    else{
                       return getMetricsByDates(curentSpace, startDate, endDate, internal);
                    }

        } catch (Throwable e) {
            LOG.error("error while getting context", e);
            return Response.status(500);
        }
    }


    @Ajax
    @juzu.Resource
    @MimeType.JSON
    @Jackson
    public Response getMetrics(String curentSpace, Boolean internal) {
        try {
            JSONObject data = new JSONObject();
            data.put("currentSpace",curentSpace);
            if(curentSpace.equals("")){
                long stisfied = topicDAO.countSatisfiedTicketNumber(internal).longValue();
                long notStisfied = topicDAO.countNotSatisfiedTicketNumber(internal).longValue();
                long total = stisfied+notStisfied;
                if(total>0){
                    data.put("customerSatisfactionPrc",stisfied*100/total);
                    data.put("customerTotalVotes",total);
                }else{
                    data.put("customerSatisfactionPrc","--");
                }
                data.put("firstTimeResponceAverage",topicDAO.getTimeToFirstResponseAvg(internal));
                data.put("timeToResolutionAverage",topicDAO.getTimeToResolutionAvg(internal));
            }else{
                long stisfied = topicDAO.countSpaceSatisfiedTicketNumber(curentSpace).longValue();
                long notStisfied = topicDAO.countSpaceNotSatisfiedTicketNumber(curentSpace).longValue();
                long total = stisfied+notStisfied;
                if(total>0){
                    data.put("customerSatisfactionPrc",stisfied*100/total);
                    data.put("customerTotalVotes",total);

                }else{
                    data.put("customerSatisfactionPrc","--");
                    data.put("customerTotalVotes",total);
                }
                data.put("firstTimeResponceAverage",topicDAO.getSpaceTimeToFirstResponseAvg(curentSpace));
                data.put("timeToResolutionAverage",topicDAO.getSpaceTimeToResolutionAvg(curentSpace));
            }
            return Response.ok(data.toString());
        } catch (Throwable e) {
            LOG.error("error while getting context", e);
            return Response.status(500);
        }
    }

    @Ajax
    @juzu.Resource
    @MimeType.JSON
    @Jackson
    public Response getMetricsByDates(String spaceId, Long startDate, Long endDate, Boolean internal) {
        try {
            Calendar fromDate=Calendar.getInstance();
            fromDate.setTimeInMillis(startDate);
            Calendar toDate=Calendar.getInstance();
            toDate.setTimeInMillis(endDate);
            JSONObject data = new JSONObject();
            data.put("currentSpace",spaceId);
            if(spaceId.equals("")) {
                long stisfied = logDao.countLogsByTypeAndNewValueBetweenDates(fromDate, toDate, LogType.CUSTOMER_SATISFACTION_ADDED, "false", internal).longValue();
                long notStisfied = logDao.countLogsByTypeAndNewValueBetweenDates(fromDate, toDate, LogType.CUSTOMER_SATISFACTION_ADDED, "true", internal).longValue();
                long total = stisfied + notStisfied;
                if (total > 0) {
                    data.put("customerSatisfactionPrc", stisfied * 100 / total);
                    data.put("customerTotalVotes", total);
                } else {
                    data.put("customerSatisfactionPrc", "--");
                    data.put("customerTotalVotes", total);
                }
                data.put("firstTimeResponceAverage", logDao.getTimeToFirstResponseAvgBetweenDates(fromDate, toDate, internal));
                data.put("timeToResolutionAverage", logDao.getTimeToResolutionAvgBetweenDates(fromDate, toDate, internal));
            }else{
                long stisfied = logDao.countLogsByTypeAndNewValueAndSpaceBetweenDates(spaceId, fromDate, toDate, LogType.CUSTOMER_SATISFACTION_ADDED, "false").longValue();
                long notStisfied = logDao.countLogsByTypeAndNewValueAndSpaceBetweenDates(spaceId,fromDate, toDate, LogType.CUSTOMER_SATISFACTION_ADDED, "true").longValue();
                long total = stisfied + notStisfied;
                if (total > 0) {
                    data.put("customerSatisfactionPrc", stisfied * 100 / total);
                    data.put("customerTotalVotes", total);
                } else {
                    data.put("customerSatisfactionPrc", "--");
                    data.put("customerTotalVotes", total);
                }
                data.put("firstTimeResponceAverage", logDao.getTimeToFirstResponseAvgBetweenDates(fromDate, toDate, internal));
                data.put("timeToResolutionAverage", logDao.getTimeToResolutionAvgBetweenDates(fromDate, toDate, internal));
            }
            return Response.ok(data.toString());
        } catch (Throwable e) {
            LOG.error("error while getting context", e);
            return Response.status(500);
        }
    }



    /**
     * This service will return the names of all support team members
     * @param ticketDTO
     * @return
     */
    @Ajax
    @Resource(method = HttpMethod.GET)
    @MimeType.JSON
    @Jackson
    public List<User> getSupportUsernames(@Jackson TicketDTO ticketDTO) {
        try {
            return CSUtils.getSupportMembers();
        } catch (Throwable e) {
            LOG.error("Can't retrieve the list of support engineers " + e);
            return null;
        }
    }

    /**
   * this method returns the list of customer spaces
   *
   * @return
   */
  @Ajax
  @Resource(method = HttpMethod.GET )
  @MimeType.JSON
  @Jackson
  public List<SpaceDTO> getSpaces() {
    return spaceService.getAllSpaces();
  }



    @Override
    public Log getLogger() {
        return LOG;
    }



    @Ajax
    @juzu.Resource
    @MimeType.JSON
    @Jackson
    public Response getSatisfactionChartData(String spaceId, String period, Long startDate, Long endDate, Boolean internal) {
        if(period.equals("weekly")){
            return getSatisfactionByWeek(spaceId, startDate,endDate,internal);
        }else{
            return getSatisfactionByMonth(spaceId, startDate,endDate,internal);
        }
    }


    @Ajax
    @juzu.Resource
    @MimeType.JSON
    @Jackson
    public Response getSatisfactionByWeek(String spaceId, Long startDate, Long endDate, Boolean internal) {
        try {
            Calendar fromDate=Calendar.getInstance();
            fromDate.setTimeInMillis(startDate);
            if(startDate==0){
                LogEntity log_ = null;
                if(spaceId.equals("")){
                    List<LogEntity> logList=logDao.getFirstLogByType(LogType.CUSTOMER_SATISFACTION_ADDED);
                    if(logList.size()>0){
                        log_ = logList.get(0);
                    }
                }else{
                    List<LogEntity> logList=logDao.getFirstLogByTypeAndSpace(spaceId, LogType.CUSTOMER_SATISFACTION_ADDED);
                    if(logList.size()>0){
                        log_ = logList.get(0);
                    }

                }
                if(log_!=null) {
                    fromDate.setTime(log_.getWhen().getTime());
                    } else
                    return Response.status(204);
            }
            JSONArray cSatList = new JSONArray();

            fromDate.set(Calendar.HOUR_OF_DAY, 0);
            fromDate.set(Calendar.MINUTE, 0);
            fromDate.set(Calendar.SECOND, 0);
            Calendar toDate=Calendar.getInstance();
            toDate.setTimeInMillis(endDate);
            int diff= Calendar.SATURDAY-fromDate.get(Calendar.DAY_OF_WEEK)+2;
            Calendar to_=Calendar.getInstance();
            to_.setTime(fromDate.getTime());
            to_.add(Calendar.DATE, diff);
            while(fromDate.before(toDate)){
                int stisfied = 0;
                int notStisfied = 0;
                if(spaceId.equals("")) {
                    stisfied  = logDao.countLogsByTypeAndNewValueBetweenDatesGroupedByTickets(fromDate, to_, LogType.CUSTOMER_SATISFACTION_ADDED, "false", internal);
                    notStisfied = logDao.countLogsByTypeAndNewValueBetweenDatesGroupedByTickets(fromDate, to_, LogType.CUSTOMER_SATISFACTION_ADDED, "true", internal);
                }else{
                    stisfied  = logDao.countLogsByTypeAndNewValueAndSpaceBetweenDatesGroupedByTickets(spaceId, fromDate, to_, LogType.CUSTOMER_SATISFACTION_ADDED, "false");
                    notStisfied = logDao.countLogsByTypeAndNewValueAndSpaceBetweenDatesGroupedByTickets(spaceId, fromDate, to_, LogType.CUSTOMER_SATISFACTION_ADDED, "true");
                }
                int total = stisfied+notStisfied;

                JSONObject data = new JSONObject();
                if(total>0){
                    data.put("satisfactionDate",getDateByPeriod(fromDate.getTime(),"weekly"));
                    data.put("customerSatisfactionPrc",stisfied*100/total);
                    data.put("customerTotalVotes",total);
                }else{
                    data.put("satisfactionDate",getDateByPeriod(fromDate.getTime(),"weekly"));
                    data.put("customerSatisfactionPrc","--");
                    data.put("customerTotalVotes",total);
                }

                cSatList.put(data);
                fromDate.setTime(to_.getTime());
                to_.add(Calendar.DATE, 7);
            }

            return Response.ok(cSatList.toString());
        } catch (Throwable e) {
            LOG.error("error while getting context", e);
            return Response.status(500);
        }
    }


    @Ajax
    @juzu.Resource
    @MimeType.JSON
    @Jackson
    public Response getSatisfactionByMonth(String spaceId, Long startDate, Long endDate, Boolean internal) {
        try {
            Calendar fromDate=Calendar.getInstance();
            fromDate.setTimeInMillis(startDate);
            if(startDate==0){
                LogEntity log_ = null;
                if(spaceId.equals("")){
                    List<LogEntity> logList=logDao.getFirstLogByType(LogType.CUSTOMER_SATISFACTION_ADDED);
                    if(logList.size()>0){
                        log_ = logList.get(0);
                    }
                }else{
                    List<LogEntity> logList=logDao.getFirstLogByTypeAndSpace(spaceId, LogType.CUSTOMER_SATISFACTION_ADDED);
                    if(logList.size()>0){
                        log_ = logList.get(0);
                    }
                }
                if(log_!=null) {
                    fromDate.setTime(log_.getWhen().getTime());
                } else
                    return Response.status(204);
            }
            JSONArray cSatList = new JSONArray();

            fromDate.set(Calendar.HOUR_OF_DAY, 0);
            fromDate.set(Calendar.MINUTE, 0);
            Calendar toDate=Calendar.getInstance();
            toDate.setTimeInMillis(endDate);
            Calendar to_=Calendar.getInstance();
            to_.setTime(fromDate.getTime());
            to_.set(Calendar.DAY_OF_MONTH, fromDate.getActualMaximum(Calendar.DAY_OF_MONTH));
            while(fromDate.before(toDate)){
                int stisfied = 0;
                int notStisfied = 0;
                if(spaceId.equals("")) {
                    stisfied  = logDao.countLogsByTypeAndNewValueBetweenDatesGroupedByTickets(fromDate, to_, LogType.CUSTOMER_SATISFACTION_ADDED, "false", internal);
                    notStisfied = logDao.countLogsByTypeAndNewValueBetweenDatesGroupedByTickets(fromDate, to_, LogType.CUSTOMER_SATISFACTION_ADDED, "true", internal);
                }else{
                    stisfied  = logDao.countLogsByTypeAndNewValueAndSpaceBetweenDatesGroupedByTickets(spaceId, fromDate, to_, LogType.CUSTOMER_SATISFACTION_ADDED, "false");
                    notStisfied = logDao.countLogsByTypeAndNewValueAndSpaceBetweenDatesGroupedByTickets(spaceId, fromDate, to_, LogType.CUSTOMER_SATISFACTION_ADDED, "true");
                }
                int total = stisfied+notStisfied;

                JSONObject data = new JSONObject();
                if(total>0){
                    data.put("satisfactionDate",getDateByPeriod(fromDate.getTime(),"monthly"));
                    data.put("customerSatisfactionPrc",stisfied*100/total);
                    data.put("customerTotalVotes",total);
                }else{
                    data.put("satisfactionDate",getDateByPeriod(fromDate.getTime(),"monthly"));
                    data.put("customerSatisfactionPrc","--");
                    data.put("customerTotalVotes",total);
                }

                cSatList.put(data);
                fromDate.setTime(to_.getTime());
                fromDate.set(Calendar.MONTH,fromDate.get(Calendar.MONTH)+1);
                fromDate.set(Calendar.DAY_OF_MONTH,1);
                to_.setTime(fromDate.getTime());
                to_.set(Calendar.DAY_OF_MONTH, fromDate.getActualMaximum(Calendar.DAY_OF_MONTH));
            }

            return Response.ok(cSatList.toString());
        } catch (Throwable e) {
            LOG.error("error while getting context", e);
            return Response.status(500);
        }
    }



    @Ajax
    @juzu.Resource
    @MimeType.JSON
    @Jackson
    public Response getTimeMetrics(String spaceId, String period, Long startDate, Long endDate, Boolean internal) {
        if(period.equals("weekly")){
            return getTimeMetricsByWeek(spaceId, startDate,endDate,internal);
        }else{
            return getTimeMetricsByMonth(spaceId, startDate,endDate,internal);
        }
    }



    @Ajax
    @juzu.Resource
    @MimeType.JSON
    @Jackson
    public Response getTimeMetricsByWeek(String spaceId,Long startDate, Long endDate, Boolean internal) {
        try {
            Calendar fromDate=Calendar.getInstance();
            fromDate.setTimeInMillis(startDate);
            if(startDate==0){

                LogEntity log_ = logDao.getTimeToFirstResponseFirstLog().get(0);
                LogEntity log__ = logDao.getTimeToResolutionFirstLog().get(0);
                if(log_!=null) {
                    fromDate.setTime(log_.getWhen().getTime());
                } else if(log__!=null) {
                    if(log_!=null && log__.getWhen().before(log_.getWhen()))
                        fromDate.setTime(log__.getWhen().getTime());
                } else
                    return Response.status(204);
            }
            JSONArray npsList = new JSONArray();

            fromDate.set(Calendar.HOUR_OF_DAY, 0);
            fromDate.set(Calendar.MINUTE, 0);
            fromDate.set(Calendar.SECOND, 0);
            Calendar toDate=Calendar.getInstance();
            toDate.setTimeInMillis(endDate);
            int diff= Calendar.SATURDAY-fromDate.get(Calendar.DAY_OF_WEEK)+2;
            Calendar to_=Calendar.getInstance();
            to_.setTime(fromDate.getTime());
            to_.add(Calendar.DATE, diff);
            while(fromDate.before(toDate)){
                Double ttfs = null;
                Double ttr = null;
                if(spaceId.equals("")) {
                     ttfs = logDao.getTimeToFirstResponseAvgBetweenDates(fromDate, to_, internal);
                     ttr = logDao.getTimeToResolutionAvgBetweenDates(fromDate, to_, internal);
                }else{
                    ttfs = logDao.getTimeToFirstResponseAvgBySpaceBetweenDates(spaceId, fromDate, to_);
                    ttr = logDao.getTimeToResolutionAvgBySpaceBetweenDates(spaceId,fromDate, to_);
                }
                JSONObject ttfs_ = new JSONObject();
                ttfs_.put("timeMetricsDate",getDateByPeriod(fromDate.getTime(),"weekly"));
                ttfs_.put("timeToFirstResponse",ttfs);
                ttfs_.put("timeToResolution",ttr);
                npsList.put(ttfs_);
                fromDate.setTime(to_.getTime());
                to_.add(Calendar.DATE, 7);
            }

            return Response.ok(npsList.toString());
        } catch (Throwable e) {
            LOG.error("error while getting context", e);
            return Response.status(500);
        }
    }



    @Ajax
    @juzu.Resource
    @MimeType.JSON
    @Jackson
    public Response getTimeMetricsByMonth(String spaceId, Long startDate, Long endDate, Boolean internal) {
        try {
            Calendar fromDate=Calendar.getInstance();
            fromDate.setTimeInMillis(startDate);
            if(startDate==0){
                LogEntity log_=null;
                LogEntity log__=null;
                List<LogEntity> logList=logDao.getTimeToFirstResponseFirstLog();
                if(logList.size()>0){
                    log_ = logList.get(0);
                }
                logList=logDao.getTimeToResolutionFirstLog();
                if(logList.size()>0){
                    log__ = logList.get(0);
                }
                if(log_!=null) {
                    fromDate.setTime(log_.getWhen().getTime());
                } else if(log__!=null) {
                    if(log_!=null && log__.getWhen().before(log_.getWhen()))
                    fromDate.setTime(log__.getWhen().getTime());
                } else
                    return Response.status(204);
            }
            JSONArray npsList = new JSONArray();

            fromDate.set(Calendar.HOUR_OF_DAY, 0);
            fromDate.set(Calendar.MINUTE, 0);
            Calendar toDate=Calendar.getInstance();
            toDate.setTimeInMillis(endDate);
            Calendar to_=Calendar.getInstance();
            to_.setTime(fromDate.getTime());
            to_.set(Calendar.DAY_OF_MONTH, fromDate.getActualMaximum(Calendar.DAY_OF_MONTH));
            while(fromDate.before(toDate)){
                Double ttfs=logDao.getTimeToFirstResponseAvgBetweenDates(fromDate,to_, internal);
                Double ttr=logDao.getTimeToResolutionAvgBetweenDates(fromDate,to_, internal);

                JSONObject ttfs_ = new JSONObject();
                ttfs_.put("timeMetricsDate",getDateByPeriod(fromDate.getTime(),"monthly"));
                ttfs_.put("timeToFirstResponse",ttfs);
                ttfs_.put("timeToResolution",ttr);
                npsList.put(ttfs_);
                fromDate.setTime(to_.getTime());
                fromDate.set(Calendar.MONTH,fromDate.get(Calendar.MONTH)+1);
                fromDate.set(Calendar.DAY_OF_MONTH,1);
                to_.setTime(fromDate.getTime());
                to_.set(Calendar.DAY_OF_MONTH, fromDate.getActualMaximum(Calendar.DAY_OF_MONTH));
            }

            return Response.ok(npsList.toString());
        } catch (Throwable e) {
            LOG.error("error while getting context", e);
            return Response.status(500);
        }
    }

public String getDateByPeriod(Date date, String period){
      if(period.equals("weekly")){
          return byWeekDateFormat.format(date);
      }else if(period.equals("monthly")){
          return byMonthDateFormat.format(date);
      }
      return byDayDateFormat.format(date);
}



    public boolean sameDay(Calendar cal1, Calendar cal2){
        return cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR) && cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR);
    }





}
