/*
 *
 *  * Copyright (C) 2003-2016 eXo Platform SAS.
 *  *
 *  * This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Affero 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 org.exoplatform.cs.service;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.lang.StringUtils;
import org.exoplatform.commons.api.persistence.ExoTransactional;
import org.exoplatform.commons.utils.HTMLSanitizer;
import org.exoplatform.cs.dao.EnvironmentDAO;
import org.exoplatform.cs.dao.LogDAO;
import org.exoplatform.cs.dao.SpaceDAO;
import org.exoplatform.cs.dao.TopicDAO;
import org.exoplatform.cs.dto.EnvironmentDTO;
import org.exoplatform.cs.dto.IssueType;
import org.exoplatform.cs.dto.Owner;
import org.exoplatform.cs.dto.TicketDTO;
import org.exoplatform.cs.entity.EnvironmentEntity;
import org.exoplatform.cs.entity.LogEntity;
import org.exoplatform.cs.entity.SpaceEntity;
import org.exoplatform.cs.entity.TopicEntity;
import org.exoplatform.cs.service.util.ForumUtils;
import org.exoplatform.forum.common.CommonUtils;
import org.exoplatform.forum.service.*;
import org.exoplatform.services.listener.ListenerService;
import org.exoplatform.services.organization.User;
import org.exoplatform.services.security.Identity;
import org.exoplatform.social.core.space.SpaceUtils;
import org.exoplatform.task.domain.Project;
import org.exoplatform.task.domain.Status;
import org.exoplatform.task.domain.Task;
import org.exoplatform.task.exception.EntityNotFoundException;
import org.exoplatform.task.service.ProjectService;
import org.exoplatform.task.service.StatusService;
import org.exoplatform.task.service.TaskService;
import org.exoplatform.task.util.ProjectUtil;
import org.exoplatform.task.util.TaskUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStream;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.exoplatform.social.core.identity.model.Profile;
import org.exoplatform.social.core.identity.provider.OrganizationIdentityProvider;
import org.exoplatform.social.core.manager.IdentityManager;

/**
 * Created by The eXo Platform SAS
 *
 * @author boubaker.khanfir@exoplatform.com
 * @since Apr 27, 2016
 */
public class TicketService extends BaseService {
  private static final Logger LOG = LoggerFactory.getLogger(TicketService.class);

  private TaskService         taskService;

  private ForumService        forumService;

  private ProjectService      projectService;

  private StatusService       statusService;

  private ListenerService listenerService;

  private LogDAO              logDAO;

  private IdentityManager identityManager;

  private static final String DATE_FORMAT_DISPLAYED_IN_TICKETS_LIST = "yyyy-MM-dd HH:mm:ss";

  private static final String TOPIC_DEFAULT_DATE_FORMAT = "EE MMM dd HH:mm:ss z yyyy";


  private static final String TASK_DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS";

  private static final DateFormat   DATE_FORMAT_TO_CONVERT_USED_FOR_TICKETS = new SimpleDateFormat(DATE_FORMAT_DISPLAYED_IN_TICKETS_LIST);

  private static final DateFormat   DEFAULT_DATE_FORMAT_USED_FOR_TOPICS = new SimpleDateFormat(TOPIC_DEFAULT_DATE_FORMAT);

  private static final DateFormat DEFAULT_DATE_FORMAT_USED_FOR_TASKS = new SimpleDateFormat(TOPIC_DEFAULT_DATE_FORMAT);
  private static final DateFormat DATE_FORMAT_USED_FOR_TASKS = new SimpleDateFormat(TASK_DEFAULT_DATE_FORMAT);

  public TicketService(ForumService forumService,
                       ListenerService listenerService,
                       ProjectService projectService,
                       StatusService statusService,
                       TaskService taskService,
                       EnvironmentDAO environmentDAO,
                       SpaceDAO spaceDAO,
                       TopicDAO topicDAO,
                       LogDAO logDAO,
                       IdentityManager identityManager) {
    super(environmentDAO, spaceDAO, topicDAO, null);
    this.taskService = taskService;
    this.forumService = forumService;
    this.statusService = statusService;
    this.projectService = projectService;
    this.listenerService = listenerService;
    this.logDAO = logDAO;
    this.identityManager = identityManager;
  }

  public EnvironmentDTO getTopicEnvironment(String topicId) {
    if (StringUtils.isBlank(topicId)) {
      throw new IllegalStateException("Parameter 'topicId' is null");
    }
    TopicEntity topicEntity = topicDAO.find(topicId);
    if (topicEntity.getEnvironment() == null) {
      return null;
    }
    return convert(topicEntity.getEnvironment());
  }

  public List<TicketDTO> getTicketsOfSpace(String id) {
    List<TopicEntity> entities = topicDAO.getTopicsBySpace(id, null);
    SpaceEntity space = spaceDAO.find(id);
    List<TicketDTO> tickets = new ArrayList<TicketDTO>();
    for (TopicEntity topicEntity : entities) {
      tickets.add(convertToDTO(topicEntity));
    }
    return tickets;
  }

  public List<TicketDTO> getTickets(String selectedSpace, boolean allTickets, String selectedStatus) {
    List<TopicEntity> entities;
    if(allTickets) {
      if(selectedSpace != null && !selectedSpace.isEmpty()) {
        entities = topicDAO.getTopicsBySpace(selectedSpace, selectedStatus);
      } else {
          if(selectedStatus != null && !selectedStatus.isEmpty()) {
              entities = topicDAO.findByStatus(selectedStatus);
          } else {
              entities = topicDAO.findAll();
          }
      }
    } else {
      if(selectedSpace != null && !selectedSpace.isEmpty()) {
        entities = topicDAO.getOpenTicketsBySpace(selectedSpace,selectedStatus);
      } else {
        entities = topicDAO.getOpenTicketsByStatus(selectedStatus);
      }
    }
    return convertToDTO(entities);
  }

  public List<TicketDTO> getAssignedTickets(String assignee, String selectedSpace, boolean allTickets, String selectedStatus){
    List<TopicEntity> tickets = new ArrayList<>();
    if(selectedSpace != null && !selectedSpace.isEmpty()){
      tickets = topicDAO.getTopicsByAssignee(assignee, selectedSpace, allTickets, selectedStatus);
    }else {
      tickets = topicDAO.getTopicsByAssignee(assignee, allTickets, selectedStatus);
    }
    return convertToDTO(tickets);
  }


  public List<TicketDTO> getMyTickets(String creator, String selectedSpace, boolean allTickets, String selectedStatus){
    List<TopicEntity> tickets = new ArrayList<>();
    if(selectedSpace != null && !selectedSpace.isEmpty()){
      tickets = topicDAO.getTopicsByCreator(creator, selectedSpace, allTickets, selectedStatus);
    }else {
      tickets = topicDAO.getTopicsByCreator(creator, allTickets, selectedStatus);
    }
    return convertToDTO(tickets);
  }



  public String getManagersGroupId(String spaceGroupId) throws Exception {
    SpaceEntity space = spaceDAO.find(spaceGroupId);
    return space.getManagersGroupId();
  }

  public SpaceEntity getSpaceByGroupId(String  groupID) {
    return spaceDAO.find(groupID);
  }

  /** Update Ticket
   *  @param ticketDTO the customer ticket
   *  @param user The user who updated the ticket
   *  @throws Exception if broadcasting the event failed
   *  @return TicketDTO updated
   *
   */
  public TicketDTO updateTicket(TicketDTO ticketDTO, User user) throws Exception {
    //TODO Why do we need an entity as a parameter here
    Map<String,String> changes = new HashMap<>();
    TopicEntity topicEntity = topicDAO.find(ticketDTO.getId());
    EnvironmentEntity environment = null;

    ticketDTO.setCreator(topicEntity.getCreator());
    if (ticketDTO.getAssignee() != null && !(ticketDTO.getAssignee().equals(topicEntity.getAssignee()))) {
      changes.put(CSConstants.OLD_ASSIGNEE,topicEntity.getAssignee());
      changes.put(CSConstants.NEW_ASSIGNEE,ticketDTO.getAssignee());
    }
    if(!IssueType.PRODUCT.equals(ticketDTO.getType())) {
      String oldSeverity = null, oldType = null, oldStatus = null;
      if (!(ticketDTO.getSeverity().equals(topicEntity.getSeverity()))) {
        oldSeverity = topicEntity.getSeverity().name();
        changes.put(CSConstants.OLD_SEVERITY,oldSeverity);
        changes.put(CSConstants.NEW_SEVERITY,ticketDTO.getSeverity().name());
      }
      if (!(ticketDTO.getType().equals(topicEntity.getType()))) {
        oldType = topicEntity.getType().name();
        changes.put(CSConstants.OLD_TYPE,oldType);
        changes.put(CSConstants.NEW_TYPE,ticketDTO.getType().name());
      }
      if (!(ticketDTO.getStatus().equals(topicEntity.getStatus()))) {
        oldStatus = topicEntity.getStatus();
        changes.put(CSConstants.OLD_STATUS,topicEntity.getStatus());
        changes.put(CSConstants.NEW_STATUS,ticketDTO.getStatus());
      }
      try {
        Category spaceCategory = forumService.getCategoryIncludedSpace();
        Forum forum = ForumUtils.getSpaceForum(forumService,ticketDTO.getSpaceGroupId());
        Topic topic = forumService.getTopic(spaceCategory.getId(), forum.getId(), topicEntity.getId(), null);
        ForumUtils.updateForumTags(forumService, ticketDTO, topic, oldSeverity, oldType, oldStatus);
      } catch (Exception e) {
        LOG.error("Could not update topic {} with tags", topicEntity.getLink(), e);
      }
      if (ticketDTO.getEnvironmentId() != null) {
        environment = environmentDAO.find(ticketDTO.getEnvironmentId());
      }
    }
    changes.put(CSConstants.USERID, user.getUserName());

    convertToEntity(ticketDTO, topicEntity, environment);
    topicEntity.setUpdateDate(Calendar.getInstance());
    topicDAO.update(topicEntity);
    listenerService.broadcast(CSConstants.TICKET_UPDATED,topicEntity,changes);
    SpaceEntity spaceEntity = spaceDAO.find(ticketDTO.getSpaceGroupId());
    return convertToDTO(topicEntity);
  }

  /**
   * Update the creator on the entity
   * @param ticketDTO the ticket to update
   * @param creator the creator of the ticket
   */
  public void updateTicketCreator(TicketDTO ticketDTO, String creator) throws Exception {

    TopicEntity topicEntity = topicDAO.find(ticketDTO.getId());
    topicEntity.setCreator(creator);
    topicDAO.update(topicEntity);
  }

  /**
   * Update the creator on the entity
   * @param ticketDTO the ticket to update
   * @param owner the creator of the ticket
   */
  public void updateTicketOwner(TicketDTO ticketDTO, Owner owner) throws Exception {

    TopicEntity topicEntity = topicDAO.find(ticketDTO.getId());
    topicEntity.setOwner(owner);
    topicDAO.update(topicEntity);
  }


  /**
   * Update the link on the entity
   * @param ticket the ticket to update
   * @param link the link of the ticket
   */
  public void updateTicketLink(TicketDTO ticket, String link){
    TopicEntity entity = topicDAO.find(ticket.getId());
    entity.setLink(link);
    topicDAO.update(entity);
  }


  @ExoTransactional
  public void createTicket(TicketDTO ticketDTO, User user, String spaceLink) throws Exception {
    if (user == null) {
      throw new IllegalArgumentException("Method saveUser - argument user is null");
    }
    String email = user.getEmail();
    if (StringUtils.isBlank(email)) {
      throw new IllegalArgumentException("Method saveUser - argument user.email is null");
    }
    if (ticketDTO == null) {
      throw new IllegalArgumentException("Method saveUser - argument ticketDTO is null");
    }
    if (!ticketDTO.verifySaveConditions()) {
      throw new IllegalArgumentException("Method saveUser - argument ticketDTO is not conform: " + ticketDTO);
    }

    SpaceEntity spaceEntity = spaceDAO.find(ticketDTO.getSpaceGroupId());
    if (spaceEntity == null) {
      throw new IllegalStateException("Method saveUser - Space is not found");
    }

    Date currentDate = CommonUtils.getGreenwichMeanTime().getTime();
    long tagIndex = spaceEntity.getTagIndex();
    TopicEntity topicEntity = new TopicEntity();

    if (IssueType.PRODUCT.equals(ticketDTO.getType())) {
      Task task = new Task();
      task.setDescription(ticketDTO.getDescription());
      task.setTitle(ticketDTO.getTitle());
      task.setAssignee(spaceEntity.getTaskDefaultAssignee());
      ticketDTO.setAssignee(spaceEntity.getTaskDefaultAssignee());
      task.setCreatedBy(user.getUserName());
      task.setPriority(spaceEntity.getTaskPriority());
      task.setCreatedTime(currentDate);
      Date startDate = ticketDTO.retrieveFormattedStartDate();
      task.setStartDate(startDate);
      Date endDate = ticketDTO.retrieveFormattedEndDate();
      task.setEndDate(endDate);
      task.setDueDate(endDate);

      Status status = getSpaceProjectStatus(ticketDTO.getSpaceGroupId(), user.getUserName());
      task.setStatus(status);
      task = taskService.createTask(task);

      ticketDTO.setId("" + task.getId());
      String ticketDateTask = convertDate(DEFAULT_DATE_FORMAT_USED_FOR_TASKS, task.getCreatedTime().toString());
      ticketDTO.setStartDate(ticketDateTask);
      String space = ForumUtils.getSpaceForum(forumService,spaceEntity.getGroupId()).getForumName();
      String SpaceName = SpaceUtils.cleanString(space);
      String taskLink = "/portal/g/:spaces:" + SpaceName + "/" + SpaceName + "/tasks" + TaskUtil.URL_TASK_DETAIL + task.getId();
      ticketDTO.setLink(taskLink);
      convertToEntity(ticketDTO, topicEntity, null);
      topicDAO.create(topicEntity);
      Map<String,String> data = new HashMap<>();
      data.put(CSConstants.USERID,user.getUserName());
      listenerService.broadcast(CSConstants.TICKET_CREATED,topicEntity,data);
    } else if (IssueType.INCIDENT.equals(ticketDTO.getType()) || IssueType.INFORMATION.equals(ticketDTO.getType())) {
      Topic newTopic = new Topic();
      newTopic.setTopicName(HTMLSanitizer.sanitize("[" + spaceEntity.getTagPrefix() + "-" + tagIndex + "] " + ticketDTO.getTitle()));
      List<FileItem> files = ticketDTO.getFiles();
      if (files != null && !files.isEmpty()) {
        List<ForumAttachment> forumAttachments = new ArrayList<ForumAttachment>();
        for (final FileItem fileItem : files) {
          ForumAttachment attachment = new BufferAttachment() {
            private static final long serialVersionUID = 1221108176051647731L;

            @Override
            public InputStream getInputStream() throws Exception {
              return fileItem.getInputStream();
            }
          };
          attachment.setName(fileItem.getName());
          attachment.setMimeType(fileItem.getContentType());
          forumAttachments.add(attachment);
        }
        newTopic.setAttachments(forumAttachments);
      }

      Category spaceCategory = forumService.getCategoryIncludedSpace();
      if (spaceCategory == null) {
        throw new IllegalStateException("Cannot find Forum Spaces category.");
      }
      String groupId = spaceEntity.getGroupId();

      Forum spaceForum = ForumUtils.getSpaceForum(forumService, groupId);
      String link;
      if(spaceLink != null && !spaceLink.isEmpty()){
        link = spaceLink + "/forum/topic/" + newTopic.getId();
      } else {
        link = ForumUtils.createdForumLink(ForumUtils.TOPIC, newTopic.getId(), false);
        link = link.replace("/ticket", "/forum");
      }
      ticketDTO.setLink(link);
      ticketDTO.setStatus(CSConstants.STATUS_OPEN);

      newTopic.setModifiedBy(user.getUserName());
      newTopic.setModifiedDate(currentDate);
      // encode XSS script
      String message = HTMLSanitizer.sanitize(ticketDTO.getDescription());
      newTopic.setDescription(message);
      newTopic.setLink(link);
      newTopic.setIsNotifyWhenAddPost(email);
      newTopic.setIsWaiting(false);
      newTopic.setIsClosed(false);
      newTopic.setIsLock(false);
      newTopic.setIsModeratePost(false);
      newTopic.setIsSticky(false);
      newTopic.setIcon("");
      newTopic.setOwner(user.getUserName());

      // TODO, do we need a specific icon ?
      // newTopic.setIcon("uiIconForumTopic uiIconForumLightGray");

      // Save Topic
      forumService.saveTopic(spaceCategory.getId(), spaceForum.getId(), newTopic, true, false, new MessageBuilder());
      ForumUtils.updateForumTags(forumService, ticketDTO,newTopic,null,null, null);

      // Save entity
      EnvironmentEntity environmentEntity = null;
      if (ticketDTO.getType().equals(IssueType.INCIDENT)) {
        environmentEntity = environmentDAO.find(ticketDTO.getEnvironmentId());
        if (environmentEntity == null) {
          throw new IllegalStateException("Environment with id '" + ticketDTO.getEnvironmentId() + "' is null");
        } else if (environmentEntity.getSpace() == null) {
          // The space is mandatory field, but in case the model has evolved,
          // handle
          // this
          throw new IllegalStateException("Environment's space is null");
        }
      }
      // Increment Tag index
      spaceEntity.setTagIndex(tagIndex + 1);
      spaceDAO.update(spaceEntity);

      // Save ticket
      ticketDTO.setId(newTopic.getId());
      ticketDTO.setLink(newTopic.getLink());
      ticketDTO.setTitle(newTopic.getTopicName());
      ticketDTO.setCreator(user.getUserName());
      ticketDTO.setTicketId(spaceEntity.getTagPrefix() + "-" + tagIndex);
      ticketDTO.setStartDate(newTopic.getCreatedDate().toString());
      ticketDTO.setOwner(Owner.EMPTY);
      convertToEntity(ticketDTO, topicEntity, environmentEntity);
      topicDAO.create(topicEntity);
      Map<String,String> data = new HashMap<>();
      data.put(CSConstants.USERID,user.getUserName());
      listenerService.broadcast(CSConstants.TICKET_CREATED,topicEntity,data);
    } else {
      // In case the types defined IssueType has evolved
      throw new UnsupportedOperationException("Method saveUser - argument ticketDTO.type is not recognized");
    }
  }


  private Status getSpaceProjectStatus(String spaceGroupId, String username) {
    Long spaceProjectId = null;
    if (spaceGroupId != null) {
      List<Project> projects = ProjectUtil.flattenTree(ProjectUtil.getProjectTree(spaceGroupId, projectService), projectService);
      for (Project p : projects) {
        if (p.canView(new Identity(username))) {
          spaceProjectId = p.getId();
        }
      }
    }
    if (spaceProjectId == null) {
      throw new IllegalStateException("Can't fin adequate tasks project for space: " + spaceGroupId);
    }
    Status status = statusService.getDefaultStatus(spaceProjectId);
    return status;
  }

  private void convertToEntity(TicketDTO ticketDTO,
                               TopicEntity topicEntity,
                               EnvironmentEntity environmentEntity) throws Exception{
    topicEntity.setId(ticketDTO.getId());
    topicEntity.setTicketId(ticketDTO.getTicketId());
    topicEntity.setEnvironment(environmentEntity);
    SpaceEntity spaceEntity = spaceDAO.find(ticketDTO.getSpaceGroupId());
    topicEntity.setSpace(spaceEntity);
    topicEntity.setType(ticketDTO.getType());
    topicEntity.setSeverity(ticketDTO.getSeverity());
    topicEntity.setInfoType(ticketDTO.getInfoType());
    topicEntity.setLink(ticketDTO.getLink());
    topicEntity.setAssignee(ticketDTO.getAssignee());
    topicEntity.setOwner(ticketDTO.getOwner());
    topicEntity.setStatus(ticketDTO.getStatus());
    topicEntity.setAttachedJira(ticketDTO.getAttachedJira());
    topicEntity.setUpdateDate(convertToCalendar(ticketDTO.getUpdateDate()));
    topicEntity.setCreationDate(convertToCalendar(ticketDTO.getStartDate()));
    topicEntity.setTitle(ticketDTO.getTitle());
    topicEntity.setCreator(ticketDTO.getCreator());
  }

  /**
   * Converts a Topic entity to a ticket DTO
   * @param topicEntity
   * @return a ticket DTO representing the topic entity
   */
  private TicketDTO convertToDTO(TopicEntity topicEntity) {
    try {
      TicketDTO ticketDTO = new TicketDTO();
      ticketDTO.setId(topicEntity.getId());
      ticketDTO.setTicketId(topicEntity.getTicketId());
      ticketDTO.setEnvironmentName(topicEntity.getEnvironment() == null ? null : topicEntity.getEnvironment().getName());
      ticketDTO.setSeverity(topicEntity.getSeverity());
      ticketDTO.setInfoType(topicEntity.getInfoType());
      ticketDTO.setLink(topicEntity.getLink());
      ticketDTO.setType(topicEntity.getType());
      ticketDTO.setAssignee(topicEntity.getAssignee());
      ticketDTO.setOwner(topicEntity.getOwner());
      ticketDTO.setAttachedJira(topicEntity.getAttachedJira());
      ticketDTO.setSpaceGroupId(topicEntity.getSpace().getGroupId());
      if(topicEntity.getUpdateDate() != null) {
        String updateDate = topicEntity.getUpdateDate().getTime().toString();
        String formattedUpdateDate = convertDate(DEFAULT_DATE_FORMAT_USED_FOR_TOPICS, updateDate);
        ticketDTO.setUpdateDate(formattedUpdateDate);
      }
      if(topicEntity.getTitle() != null && !topicEntity.getTitle().isEmpty()){
        ticketDTO.setTitle(topicEntity.getTitle());
      }
      if (topicEntity.getCreationDate() != null) {
        String startDate = topicEntity.getCreationDate().getTime().toString();
        String ticketDate = convertDate(DEFAULT_DATE_FORMAT_USED_FOR_TOPICS, startDate);
        ticketDTO.setStartDate(ticketDate);
      }
      ticketDTO.setStatus(topicEntity.getStatus());

      switch (topicEntity.getType()) {
        case INFORMATION:
          ticketDTO.setFlow(topicEntity.getSpace().getInformationFlow());
        case INCIDENT:
          ticketDTO.setFlow(topicEntity.getSpace().getIncidentFlow());
          ticketDTO.setEnvironmentId(topicEntity.getEnvironment() == null ? null : topicEntity.getEnvironment().getId());
          break;
        case PRODUCT:
          long taskId = Long.parseLong(topicEntity.getId());
          Task task = null;
          try {
            task = taskService.getTask(taskId);
          } catch (EntityNotFoundException e) {
            LOG.warn("Task with id '{}' was not found", topicEntity.getId());
          }
          if (task == null) {
            break;
          }
          if(topicEntity.getCreationDate() != null){
            String ticketDateTask = DEFAULT_DATE_FORMAT_USED_FOR_TASKS.format(topicEntity.getCreationDate().getTime());
            ticketDTO.setStartDate(ticketDateTask);
          }
          ticketDTO.setStatus(task.getStatus() == null ? "inprogress" : task.getStatus().getName());
          break;
        default:
          break;
      }

      if(topicEntity.getCreator()!=null){
        try {
          ticketDTO.setCreator(identityManager.getOrCreateIdentity(OrganizationIdentityProvider.NAME, topicEntity.getCreator(), false).getProfile().getFullName());
        } catch (Exception e) {
          ticketDTO.setCreator("");
        }
      }else{
        ticketDTO.setCreator("");
      }

      return ticketDTO;
    } catch (Exception e) {
    LOG.error("error converting ticket {} from space of group {}",topicEntity.getId(), topicEntity.getSpace().getGroupId(), e);
  }
    return null;
  }

  private List<TicketDTO> convertToDTO(List<TopicEntity> entities){
    List<TicketDTO> tickets = new ArrayList<TicketDTO>();
    for (TopicEntity topicEntity : entities) {
      SpaceEntity space = topicEntity.getSpace();
      String groupId = space.getGroupId();
      TicketDTO ticket = convertToDTO(topicEntity);
      if(ticket != null) {
        tickets.add(ticket);
      }
    }
    return tickets;
  }

  private String convertDate(DateFormat dateFormat, String startDate) {
    Date date = null;
    try {
      date = dateFormat.parse(startDate);
    } catch (ParseException e) {
      LOG.error("Error when parsing date",e);
    }
    if (date != null) {
      return DATE_FORMAT_TO_CONVERT_USED_FOR_TICKETS.format(date);
    } else {
      return null;
    }
  }


  private Calendar convertToCalendar(String dateToFormat){
    Calendar cal = Calendar.getInstance();
    try {
      Date date = DATE_FORMAT_TO_CONVERT_USED_FOR_TICKETS.parse(dateToFormat);
      cal.setTime(date);
    } catch (Exception e) {
      LOG.debug("Error when converting {} to a date using formatter {} ", dateToFormat, DATE_FORMAT_DISPLAYED_IN_TICKETS_LIST);
    }
    return cal;
  }

  /**
   * Delete a ticket and the related task or forum topic
   * @param ticket The ticket to delete
   */
  public void deleteTicket(TicketDTO ticket) {
    TopicEntity entity = topicDAO.find(ticket.getId());
    if(IssueType.PRODUCT == entity.getType()) {
      try {
        taskService.removeTask(Long.parseLong(entity.getId()));
      } catch (EntityNotFoundException e) {
        LOG.error("Task {} was not found, ticket entry will be deleted!",entity.getId() != null ? entity.getId():"");
      }
    } else {
      try {
        Category spaceCategory = forumService.getCategoryIncludedSpace();
        String groupId = entity.getSpace().getGroupId();
        Forum spaceForum = ForumUtils.getSpaceForum(forumService, groupId);
        forumService.removeTopic(spaceCategory.getId(),spaceForum.getId(),entity.getId());
      } catch (Exception e) {
        LOG.error("Topic {} could not be removed or is not found, ticket entry will be deleted!",entity.getId() != null ? entity.getId():"");
      }
    }
    topicDAO.delete(entity);
  }

  public List<TicketDTO> getTickets(Calendar fromDate, Calendar toDate) {
    List<TopicEntity> tickets = topicDAO.findUpdatedBetween(fromDate,toDate);
    return convertToDTO(tickets);
  }

  public List<TicketDTO> getUpdatedTickets(String status, String space, Calendar fromDate, Calendar toDate) {

    List<TopicEntity> tickets = new ArrayList<>();
    if( isEmpty(space) && isEmpty(status)){
      tickets  = topicDAO.findUpdatedBetween(fromDate,toDate);
    }else if( isEmpty(space) && !isEmpty(status)){
      tickets  = topicDAO.getUpdatedTicketsByStatus(status, fromDate,toDate);
    }else if( !isEmpty(space) && isEmpty(status)){
      tickets  = topicDAO.getUpdatedTicketsBySpace(space, fromDate,toDate);
    }else{
      tickets  = topicDAO.getUpdatedTicketsBySpaceAndStatus(space, status, fromDate,toDate);
    }

    return convertToDTO(tickets);
  }



  public List<TicketDTO> getCreatedTickets(String space, Calendar fromDate, Calendar toDate) {
     List<TopicEntity> tickets = new ArrayList<>();
     if( !isEmpty(space)){
       tickets  = topicDAO.getCreatedTicketsBySpace(space, fromDate,toDate);
     }else {
       tickets  = topicDAO.getCreatedTickets(fromDate,toDate);
     }
    return convertToDTO(tickets);
  }



  public List<TopicEntity> findTicketsForReminder(Calendar toDate) {
    return topicDAO.findTicketsForReminder(toDate);
  }


  public Long getTicketsCount(SpaceEntity space, IssueType type) {
     return topicDAO.countTickets(space,type);
  }

  public List<LogEntity> getUpdatedTickets(Calendar from , Calendar to){
    return logDAO.getupdates(from,to);
  }

  public TicketDTO findById(String ticketId) {
    TopicEntity ticket = topicDAO.find(ticketId);
    return convertToDTO(ticket);
  }

  public TicketDTO findByTicketId(String ticketId) {
    return convertToDTO(topicDAO.findByTicketId(ticketId));
  }

  private boolean isEmpty (String string){
   return string == null || string.isEmpty();
  }


  public List<Object[]>  countCustomerTicketsGroupdBySpace() {

    return topicDAO.countCustomerTicketsGroupdBySpace();

  }

  public List<Object[]>  countCustomerTicketsGroupdByOwner() {

    return topicDAO.countCustomerTicketsGroupdByOwner();

  }
  public List<Object[]>  countCustomerTicketsGroupdByStatus() {

    return topicDAO.countCustomerTicketsGroupdByStatus();

  }

  public List<Object[]>  countSpaceTicketsGroupdByStatus(String space) {

    return topicDAO.countSpaceTicketsGroupdByStatus(space);

  }

  public List<Object[]>  countSpaceTicketsGroupdByOwner(String space) {

    return topicDAO.countSpaceTicketsGroupdByOwner(space);

  }

  public List<Object[]>  countSpaceTicketsGroupdByAssignee(String space) {

    return topicDAO.countSpaceTicketsGroupdByAssignee(space);

  }

    public Long getCustomerOpenTicketsCount() {
        return topicDAO.countOpenCustomerTickets();
    }

    public Long getCustomerClosedTicketsCount() {
        return topicDAO.countClosedCustomerTickets();
    }

    public Long getCustomerOpenTicketsCountByDates(Calendar from, Calendar to) {
        return topicDAO.countOpenCustomerTicketsByDates(from,to);
    }

    public Long getCustomerClosedTicketsCountByDates(Calendar from, Calendar to) {
        return topicDAO.countClosedCustomerTicketsByDates(from,to);
    }

    public List<Object[]>  countCustomerTicketsGroupdByStatusAndDates(Calendar from , Calendar to) {

        return topicDAO.countCustomerTicketsGroupdByStatusAndDates(from,to);

    }

}
