/*
 *
 *  * 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.util;

import javax.jcr.ItemExistsException;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;

import org.apache.commons.lang.StringUtils;

import org.exoplatform.commons.utils.CommonsUtils;
import org.exoplatform.container.ExoContainerContext;
import org.exoplatform.container.PortalContainer;
import org.exoplatform.cs.dto.TicketDTO;
import org.exoplatform.cs.entity.TopicEntity;
import org.exoplatform.cs.service.CSConstants;
import org.exoplatform.forum.service.*;
import org.exoplatform.forum.service.filter.model.ForumFilter;
import org.exoplatform.portal.application.PortalRequestContext;
import org.exoplatform.portal.webui.util.Util;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.services.resources.ResourceBundleService;
import org.exoplatform.social.core.identity.model.Identity;
import org.exoplatform.social.core.identity.model.Profile;
import org.exoplatform.social.core.identity.provider.OrganizationIdentityProvider;
import org.exoplatform.social.core.manager.IdentityManager;
import org.exoplatform.social.core.space.SpaceUtils;
import org.exoplatform.webui.form.validator.UserConfigurableValidator;


import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;

public class ForumUtils {
  protected static Log log = ExoLogger.getLogger(ForumUtils.class);

  private static IdentityManager identityManager = PortalContainer.getInstance().getComponentInstanceOfType(IdentityManager.class);

  public static final String FIELD_EXOFORUM_LABEL = "eXoForum".intern();

  public static final String FIELD_SEARCHFORUM_LABEL = "SearchForum".intern();

  public static final String UPLOAD_FILE_SIZE = "uploadFileSizeLimitMB".intern();

  public static final String UPLOAD_AVATAR_SIZE = "uploadAvatarSizeLimitMB".intern();

  public static final String SEARCHFORM_ID = "SearchForm".intern();

  public static final String GOPAGE_ID_T = "goPageTop".intern();

  public static final String GOPAGE_ID_B = "goPageBottom".intern();

  public static final String CATEGORIES = "Categories".intern();

  public static final String CATEGORY = "category".intern();

  public static final String FORUM = "forum".intern();

  public static final String TOPIC = "topic".intern();

  public static final String POST = "post".intern();

  public static final String TAG = "Tag".intern();

  public static final String POLL = "Poll".intern();

  public static final String COMMA = ",".intern();

  public static final String SLASH = "/".intern();

  public static final String EMPTY_STR = "".intern();

  public static final String SPACE_GROUP_ID = SpaceUtils.SPACE_GROUP.replace(SLASH, EMPTY_STR);

  public static final int MAXSIGNATURE = 300;

  public static final int MAXTITLE = 100;

  public static final int DEFAULT_VALUE_UPLOAD_PORTAL = -1;

  public static final long MAXMESSAGE = 10000;

  public static final String HAS_CREATE_TOPIC = "hasCreateTopic";

  public static final String HAS_CREATE_POLL = "hasCreatePoll";

  public static final String VIEW_LAST_POST = "lastpost";
  public static final String EMAIL_VALIDATION_REGEX = "gatein.validators.email.regexp";

  public static String createdForumLink(String type, String id, boolean isPrivate) {
    try {
      String containerName = CommonsUtils.getService(ExoContainerContext.class).getPortalContainerName();
      String pageNodeSelected = Util.getUIPortal().getSelectedUserNode().getURI();
      PortalRequestContext portalContext = Util.getPortalRequestContext();
      return buildLink(portalContext.getPortalURI(), containerName, pageNodeSelected, type, id, isPrivate);
    } catch (Exception e) {
      return id;
    }
  }

  public static String buildLink(String portalURI,
                                 String containerName,
                                 String selectedNode,
                                 String type,
                                 String id,
                                 boolean isPrivate) {
    StringBuilder sb = new StringBuilder();
    portalURI = portalURI.concat(selectedNode).concat(SLASH);
    if (!isPrivate) {
      sb.append(buildForumLink(portalURI, type, id));
    } else {
      String host = portalURI.substring(0, portalURI.indexOf(containerName) - 1);
      sb.append(host)
          .append(SLASH)
          .append(containerName)
          .append(SLASH)
          .append("login?&initialURI=")
          .append(buildForumLink(portalURI.replaceFirst(host, EMPTY_STR), type, id))
          .toString();
    }
    return sb.toString();
  }

  public static boolean isValidEmailAddresses(String addressList) {
    if (StringUtils.isBlank(addressList)) {
      return false;
    }
    addressList = StringUtils.remove(addressList, " ");
    addressList = StringUtils.replace(addressList, ";", COMMA);
    try {
      InternetAddress[] iAdds = InternetAddress.parse(addressList, true);
      String emailRegex = System.getProperty(EMAIL_VALIDATION_REGEX, UserConfigurableValidator.EMAIL_VALIDATION_REGEX);
      for (int i = 0; i < iAdds.length; i++) {
        if (!iAdds[i].getAddress().matches(emailRegex))
          return false;
      }
    } catch (AddressException e) {
      return false;
    }
    return true;
  }

  private static String buildForumLink(String url, String type, String id) {
    StringBuilder link = new StringBuilder(url);
    if (!StringUtils.isBlank(type) && !StringUtils.isBlank(id)) {
      if (link.lastIndexOf(SLASH) == (link.length() - 1))
        link.append(type);
      else
        link.append(SLASH).append(type);
      if (!id.equals(Utils.FORUM_SERVICE))
        link.append(SLASH).append(id);
    }
    return link.toString();
  }

  public static Forum getSpaceForum(ForumService forumService, String groupId) {
    //TODO check if the space forum category holds all data
    Category spaceCategory = forumService.getCategoryIncludedSpace();
    if(spaceCategory == null){
      spaceCategory = new Category();
      spaceCategory.setCategoryName("forumCategorySpaces");
      spaceCategory.setIncludedSpace(true);
      spaceCategory.setCreatedDate(Calendar.getInstance().getTime());
      spaceCategory.setId("forumCategorySpaces");
      try {
        forumService.saveCategory(spaceCategory, true);
      }catch (Exception e) {
        log.error("Problem creating forum category for spaces");
      }
    }
    ForumFilter forumFilter = new ForumFilter();
    forumFilter.categoryId(spaceCategory.getId());
    String spacePrettyName = groupId.replace("/spaces/", "");
    String forumId = Utils.FORUM_SPACE_ID_PREFIX + spacePrettyName;
    Forum spaceForum = forumService.getForum(spaceCategory.getId(), forumId);
    if (spaceForum == null) {
      throw new IllegalStateException("Space Forum was not found: " + spacePrettyName);
    }
    return spaceForum;
  }

  public static void postMessageToTicket(ForumService forumService, TopicEntity ticket, String message) throws Exception {
    Category spaceCategory = forumService.getCategoryIncludedSpace();
    Forum forum = ForumUtils.getSpaceForum(forumService, ticket.getSpace().getGroupId());
    Topic topic = forumService.getTopic(spaceCategory.getId(), forum.getId(), ticket.getId(), null);
    Identity assigneeIdentity = identityManager.getOrCreateIdentity(OrganizationIdentityProvider.NAME,ticket.getAssignee(),false);
    Identity creatorIdentity = identityManager.getOrCreateIdentity(OrganizationIdentityProvider.NAME,ticket.getCreator(),false);
    message = message.replaceAll("\\{0\\}",(String) creatorIdentity.getProfile().getProperty(Profile.FIRST_NAME));
    message = message.replaceAll("\\{1\\}",(String) assigneeIdentity.getProfile().getProperty(Profile.FIRST_NAME));
    Post post = new Post();
    post.setName(topic.getTopicName());
    post.setMessage(message);
    post.setOwner(ticket.getAssignee());
    post.setIcon(topic.getIcon());
    post.setIsWaiting(false);
    post.setIsApproved(true);
    post.setLink(topic.getLink() + SLASH + post.getId());
    forumService.savePost(spaceCategory.getId(), forum.getId(), ticket.getId(), post, true, new MessageBuilder());
  }

  public static Topic getTopicByTicket(ForumService forumService, TopicEntity ticket) throws Exception {
    Category spaceCategory = forumService.getCategoryIncludedSpace();
    Forum forum = ForumUtils.getSpaceForum(forumService, ticket.getSpace().getGroupId());
    return forumService.getTopic(spaceCategory.getId(), forum.getId(), ticket.getId(), null);
  }

  public static void updateForumTags(ForumService forumService, TicketDTO ticketDTO, Topic topic, String oldSeverity, String oldType, String oldStatus) throws Exception {
    ResourceBundleService rb = CommonsUtils.getService(ResourceBundleService.class);
    Tag tagSeverity, tagType, tagStatus;
    List<String> userIds = ForumServiceUtils.getUserPermission(new String[]{"*:" + ticketDTO.getSpaceGroupId()});
    if (userIds != null && !userIds.isEmpty()) {
      tagSeverity = forumService.getTag(Utils.TAG + ticketDTO.getSeverity().name());
      if (tagSeverity == null) {
        tagSeverity = new Tag();
        tagSeverity.setUserTag(userIds.toArray(new String[0]));
        tagSeverity.setName(ticketDTO.getSeverity().name());
        tagSeverity.setId(Utils.TAG + ticketDTO.getSeverity().name());
      }
      tagType = forumService.getTag(Utils.TAG + ticketDTO.getType().name());
      if (tagType == null) {
        tagType = new Tag();
        tagType.setUserTag(userIds.toArray(new String[0]));
        tagType.setName(ticketDTO.getType().name());
        tagType.setId(Utils.TAG + ticketDTO.getType().name());
      }
      String statusName = "";
      try {
        statusName = rb.getResourceBundle("locale.customer-space", Locale.ENGLISH).getString("cs.ticket.status." + ticketDTO.getStatus());
      }catch (Exception exp){
        statusName = ticketDTO.getStatus();
      }
      if (statusName.isEmpty()) {
        statusName = ticketDTO.getStatus();
      }
      tagStatus = forumService.getTag(Utils.TAG + statusName);
      if (tagStatus == null && ticketDTO.getStatus() != null && !ticketDTO.getStatus().isEmpty()) {
        tagStatus = new Tag();
        tagStatus.setUserTag(userIds.toArray(new String[0]));
        tagStatus.setName(statusName);
        tagStatus.setId(Utils.TAG + statusName);
      }

      List<Tag> tags = new ArrayList<>();
      tags.add(tagSeverity);
      tags.add(tagType);
      tags.add(tagStatus);


      boolean notSaved = false;
      do {
        // Save new Tag
        try {
          String oldStatusName = "";
          try {
            oldStatusName = rb.getResourceBundle("locale.customer-space", Locale.ENGLISH).getString("cs.ticket.status." + oldStatus);
          }catch (Exception exp){
            oldStatusName = oldStatus;
          }
          if (oldStatusName == null || oldStatusName.isEmpty()) {
            oldStatusName = oldStatus;
          }
          Tag oldTagStatus = null, oldTagType = null, oldTagSeverity = null;
          if (oldStatusName != null && !oldStatusName.isEmpty()) {
            oldTagStatus = forumService.getTag(Utils.TAG + oldStatusName);
          }
          if (oldType != null && !oldType.isEmpty()) {
            oldTagType = forumService.getTag(Utils.TAG + oldType);
          }
          if (oldSeverity != null && !oldSeverity.isEmpty()) {
            oldTagSeverity = forumService.getTag(Utils.TAG + oldSeverity);
          }
          for (String userId : userIds) {
            if (oldTagStatus != null) {
              forumService.unTag(Utils.TAG + oldStatusName, userId, topic.getPath());
            }
            if (oldTagType != null) {
              forumService.unTag(Utils.TAG + oldType, userId, topic.getPath());
            }
            if (oldTagSeverity != null) {
              forumService.unTag(Utils.TAG + oldSeverity, userId, topic.getPath());
            }
            forumService.addTag(tags, userId, topic.getPath());
          }
          notSaved = false;
        } catch (ItemExistsException e) {
          notSaved = true;
        }
      } while (notSaved);
    } else {
      log.warn("Can't Save new Tag, no users found in the group {}", ticketDTO.getSpaceGroupId());
    }

  }
}
