package org.exoplatform.forum.service.search;

import java.net.URLDecoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.lang.StringEscapeUtils;
import org.exoplatform.commons.api.search.SearchServiceConnector;
import org.exoplatform.commons.api.search.data.SearchContext;
import org.exoplatform.commons.api.search.data.SearchResult;
import org.exoplatform.container.ExoContainer;
import org.exoplatform.container.ExoContainerContext;
import org.exoplatform.container.xml.InitParams;
import org.exoplatform.forum.common.CommonUtils;
import org.exoplatform.forum.service.DataStorage;
import org.exoplatform.forum.service.Forum;
import org.exoplatform.forum.service.ForumSearchResult;
import org.exoplatform.forum.service.Topic;
import org.exoplatform.forum.service.Utils;
import org.exoplatform.portal.config.UserPortalConfigService;
import org.exoplatform.portal.mop.SiteKey;
import org.exoplatform.portal.mop.SiteType;
import org.exoplatform.portal.mop.navigation.NavigationContext;
import org.exoplatform.portal.mop.navigation.NavigationService;
import org.exoplatform.portal.mop.navigation.NodeContext;
import org.exoplatform.portal.mop.navigation.NodeModel;
import org.exoplatform.portal.mop.navigation.Scope;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.services.security.ConversationState;
import org.exoplatform.social.core.space.model.Space;
import org.exoplatform.social.core.space.spi.SpaceService;


/**
 * @author <a href="mailto:alain.defrance@exoplatform.com">Alain Defrance</a>
 */
public class DiscussionSearchConnector extends SearchServiceConnector {
  private static final Log LOG = ExoLogger.getLogger(DiscussionSearchConnector.class);

  private DataStorage storage;

  private SpaceService spaceService;
                              //"/forum/skin/DefaultSkin/webui/skinIcons/48x48/defaultTopic.png";
  private String FIX_ICON = "/eXoSkin/skin/images/themes/default/Icons/AppIcons/uiIconAppDefault.png";
  
  public static final String  SPACES_GROUP           = "spaces";

  public static final String  CATEGORY               = "category";

  private static final String FORUM_PAGE_NAGVIGATION = "forum";

  private static final String FORUM_PORTLET_NAME     = "ForumPortlet";
  
  private static final String FORMAT_DATE           = "EEEEE, MMMMMMMM d, yyyy K:mm a";  


  public DiscussionSearchConnector(InitParams initParams, DataStorage storage, SpaceService spaceService) {
    super(initParams);
    this.storage = storage;
    this.spaceService = spaceService;
  }
  
  @Override
  public Collection<SearchResult> search(SearchContext context, String query, Collection<String> sites, int offset, int limit, String sort, String order) {
    List<SearchResult> results = new ArrayList<SearchResult>();
    if (CommonUtils.isEmpty(query)) {
      return results;
    }
    ExoContainerContext eXoContext = (ExoContainerContext)ExoContainerContext.getCurrentContainer()
        .getComponentInstanceOfType(ExoContainerContext.class);
    String portalName = eXoContext.getPortalContainerName();
    String currentUser = getCurrentUserName();
    try {
      List<ForumSearchResult> searchResults = storage.getUnifiedSearch(query, currentUser, offset, limit, sort, order);
      for (ForumSearchResult searchResult : searchResults) {
        PostId id = new PostId(searchResult.getPath());
        Forum forum = storage.getForum(id.getCategoryId(), id.getForumId());
        Topic topic = storage.getTopicByPath(id.getTopicPath(), false);
        StringBuilder sb = new StringBuilder();
        sb.append(forum.getForumName());
        sb.append(" - " + topic.getPostCount() + " replies");
        //sb.append(" - " + topic.getVoteRating());
        SimpleDateFormat sdf = new SimpleDateFormat(FORMAT_DATE);
        sb.append(" - " + sdf.format(searchResult.getCreatedDate()));        
        String uri = buildLink(context, portalName, id.getCategoryId(), id.getForumId(), id.getTopicId(), topic.getLink());
        String postUri = (searchResult.getType().equals(Utils.POST) ? CommonUtils.SLASH + searchResult.getId() : CommonUtils.EMPTY_STR); 
        UnifiedSearchResult result = new UnifiedSearchResult(
            uri + postUri,
            searchResult.getName(),
            StringEscapeUtils.unescapeHtml(searchResult.getExcerpt()),
            sb.toString(),
            FIX_ICON,
            searchResult.getCreatedDate().getTime(),
            searchResult.getRelevancy(),
            topic.getVoteRating());
        results.add(result);
      }
    } catch (Exception e) {
      LOG.error("Failed in searching.", e);
    }

    return results;
  }
  
  /**
   * Forum build link
   * @param portalName 
   * @param categoryId
   * @param forumId
   * @param topicId
   * @param defaultLink
   * @param router
   * @return
   */
  private String buildLink(SearchContext context, String portalName, String categoryId, String forumId, String topicId, String defaultLink) {
    try {
      String forumURI = null;
      
      //
      if (categoryId.indexOf(SPACES_GROUP) > 0) {
       forumURI = makeURIForSpaceContext(context, portalName, forumId);
       forumURI = URLDecoder.decode(forumURI, "UTF-8");
      } else {
        forumURI = makeURIForPortalContext(context, portalName);
      }
      if (!CommonUtils.isEmpty(forumURI)) {
        return String.format("%s/%s/%s", forumURI, Utils.TOPIC, topicId);
      } else {
        return defaultLink;
      }
    } catch (Exception ex) {
      return CommonUtils.EMPTY_STR;
    }
  }
  
  /**
   * builds URI under Portal site context
   * @param context
   * @param portalName
   * @param siteName
   * @return
   * @throws Exception
   */
  private String makeURIForPortalContext(SearchContext context,
                                        String portalName) throws Exception {
    
    //
    String path = "";
    String siteType = "";
    String siteName = "";
    
    List<String> allSites = getAllPortalSites();
    
    //
    for(String siteName_ : allSites) {
      SiteKey siteKey = SiteKey.portal(siteName_);
      siteType = SiteType.PORTAL.getName();
      path = getSiteName(siteKey);

      if(!CommonUtils.isEmpty(path)) {
        siteName = siteKey.getName();
        break;
      }
    }

    //
    if (Utils.isEmpty(path)) {
      return CommonUtils.EMPTY_STR;
    }
    
    String forumURI = context.handler(portalName)
        .lang("")
        .siteName(siteName)
        .siteType(siteType)
        .path(path)
        .renderLink();
    return String.format("/%s%s", portalName, forumURI);
  }
  
  /**
   * builds URI for Forum what is inside Space context
   * 
   * @param context
   * @param portalName
   * @param forumId
   * @param siteName
   * @return
   * @throws Exception
   */
  private String makeURIForSpaceContext(SearchContext context,
                                        String portalName,
                                        String forumId) throws Exception {
    //
    String path = "";
    String siteType = "";
    
    String prefixId = Utils.FORUM_SPACE_ID_PREFIX;
    String groupId = forumId.replaceFirst(prefixId, "");
    String spaceGroupId = String.format("/%s/%s", SPACES_GROUP, groupId);// /spaces/space1
    SiteKey siteKey = SiteKey.group(spaceGroupId);
    //
    String siteName = spaceGroupId.replaceAll(CommonUtils.SLASH, CommonUtils.COLON);
    
    //
    siteType = SiteType.GROUP.getName();
    
    //
    String forumNavName = getSiteName(siteKey);
    //
    if (Utils.isEmpty(forumNavName)) {
      return CommonUtils.EMPTY_STR;
    }
    if(spaceService != null) {
      Space space = spaceService.getSpaceByGroupId(spaceGroupId);
      if(space != null){
        groupId = space.getPrettyName();
      }
    }
    path = groupId + CommonUtils.SLASH + forumNavName;
    
    String forumURI = context.handler(portalName)
        .lang("")
        .siteName(siteName)
        .siteType(siteType)
        .path(path)
        .renderLink();
    return String.format("/%s%s", portalName, forumURI);
  }
  
  
  /**
   * @return
   */
  private List<String> getAllPortalSites() {
    UserPortalConfigService dataStorage = (UserPortalConfigService) ExoContainerContext.getCurrentContainer()
                                                                                       .getComponentInstanceOfType(UserPortalConfigService.class);
    try {
      return dataStorage.getAllPortalNames();
    } catch (Exception e) {
      return new ArrayList<String>();
    }
  }

  /**
   * 
   * @param siteKey
   * @return
   */
  private String getSiteName(SiteKey siteKey) {
    try {
      ExoContainer container = ExoContainerContext.getCurrentContainer();
      NavigationService navService = (NavigationService) container.getComponentInstance(NavigationService.class);
      NavigationContext nav = navService.loadNavigation(siteKey);
      NodeContext<NodeContext<?>> parentNodeCtx = navService.loadNode(NodeModel.SELF_MODEL, nav, Scope.ALL, null);

      Collection<NodeContext<?>> children = parentNodeCtx.getNodes();
      if (siteKey.getType() == SiteType.GROUP) {
        children = parentNodeCtx.get(0).getNodes();
      }
      Iterator<NodeContext<?>> it = children.iterator();
      
      NodeContext<?> child = null;
      while (it.hasNext()) {
        child = it.next();
        if (FORUM_PAGE_NAGVIGATION.equals(child.getName()) || child.getName().indexOf(FORUM_PORTLET_NAME) >= 0) {
          return child.getName();
        }
      }
      return CommonUtils.EMPTY_STR;
    } catch (Exception e) {
      return CommonUtils.EMPTY_STR;
    }
  }
  
  /**
   * 
   * @return
   */
  private String getCurrentUserName() {
    return ConversationState.getCurrent().getIdentity().getUserId();
  }

}
