/*
 * Copyright (C) 2003-2008 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.services.cms.documents.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.PathNotFoundException;

import org.exoplatform.container.ExoContainer;
import org.exoplatform.container.ExoContainerContext;
import org.exoplatform.services.cms.documents.FavoriteService;
import org.exoplatform.services.cms.link.LinkManager;
import org.exoplatform.services.jcr.access.PermissionType;
import org.exoplatform.services.jcr.core.ExtendedNode;
import org.exoplatform.services.jcr.ext.app.SessionProviderService;
import org.exoplatform.services.jcr.ext.hierarchy.NodeHierarchyCreator;

/**
 * Created by The eXo Platform SARL
 * Author : Dang Van Minh
 *          minh.dang@exoplatform.com
 * Nov 16, 2009
 * 10:02:04 AM
 */
public class FavoriteServiceImpl implements FavoriteService {

  private static final String EXO_PRIVILEGEABLE = "exo:privilegeable";
  private static final String EXO_FAVORITEFOLDER = "exo:favoriteFolder";
  private static final String NT_UNSTRUCTURED = "nt:unstructured";
  private static final String FAVORITE_ALIAS = "userPrivateFavorites";

  private NodeHierarchyCreator nodeHierarchyCreator;
  private LinkManager linkManager;
  private SessionProviderService sessionProviderService;

  public FavoriteServiceImpl(NodeHierarchyCreator nodeHierarchyCreator, LinkManager linkManager,
      SessionProviderService sessionProviderService) {
    this.nodeHierarchyCreator = nodeHierarchyCreator;
    this.linkManager = linkManager;
    this.sessionProviderService = sessionProviderService;
  }

  /**
   * {@inheritDoc}
   */
  public void addFavorite(Node node, String userName) throws Exception {
    // check if node is symlink
    if (linkManager.isLink(node)) return;

    // check if node has already been favorite node of current user
    Node userFavoriteNode = null;
    try {
      userFavoriteNode = getUserFavoriteFolder(userName);
    } catch (PathNotFoundException e) {
      userFavoriteNode = createFavoriteFolder(userName);
    }

    NodeIterator nodeIter = userFavoriteNode.getNodes();
    while (nodeIter.hasNext()) {
      Node childNode = nodeIter.nextNode();
      if (linkManager.isLink(childNode)) {
        Node targetNode = null;
        try {
          targetNode = linkManager.getTarget(childNode);
        } catch (Exception e) {}
        if (node.isSame(targetNode)) return;
      }
    }
    // add favorite symlink
    linkManager.createLink(userFavoriteNode, node);
    userFavoriteNode.getSession().save();
  }

  /**
   * {@inheritDoc}
   */
  public List<Node> getAllFavoriteNodesByUser(String workspace, String repository, String userName) throws Exception {
    List<Node> ret = new ArrayList<Node>();
    Node userFavoriteNode = getUserFavoriteFolder(userName);
    NodeIterator nodeIter = userFavoriteNode.getNodes();
    while (nodeIter.hasNext()) {
      Node childNode = nodeIter.nextNode();
      if (linkManager.isLink(childNode)) {
        Node targetNode = null;
        try {
          targetNode = linkManager.getTarget(childNode);
        } catch (Exception ex) {}
        if (targetNode != null) ret.add(targetNode);
      }
    }
    return ret;
  }

  /**
   * {@inheritDoc}
   */
  public void removeFavorite(Node node, String userName) throws Exception {
    Node targetNode = null;

    // check if node is symlink
    if (linkManager.isLink(node)) {
      try {
        targetNode = linkManager.getTarget(node);
      } catch (Exception e) { }
      if (targetNode != null) removeFavorite(targetNode, userName);
    } else {
      // remove favorite
      Node userFavoriteNode = getUserFavoriteFolder(userName);
      NodeIterator nodeIter = userFavoriteNode.getNodes();
      while (nodeIter.hasNext()) {
        Node childNode = nodeIter.nextNode();
        if (linkManager.isLink(childNode)) {
          try {
            targetNode = linkManager.getTarget(childNode);
          } catch (Exception e) { }
          if (node.isSame(targetNode)) {
            childNode.remove();
            userFavoriteNode.getSession().save();
            return;
          }
        }
      }
    }
  }

  public boolean isFavoriter(String userName, Node node) throws Exception {
    ExoContainer container = ExoContainerContext.getCurrentContainer();
    LinkManager lnkManager = (LinkManager)container.getComponentInstanceOfType(LinkManager.class);

    if (lnkManager.isLink(node) && lnkManager.isTargetReachable(node)) {
      node = lnkManager.getTarget(node);
    }

    Node userFavoriteNode = null;
    try {
      userFavoriteNode = getUserFavoriteFolder(userName);
    }catch (PathNotFoundException e) {
      return false;
    }

    NodeIterator nodeIter = userFavoriteNode.getNodes();
    while (nodeIter.hasNext()) {
      Node childNode = nodeIter.nextNode();
      if (linkManager.isLink(childNode)) {
        Node targetNode = null;
        try {
          targetNode = linkManager.getTarget(childNode);
        } catch (Exception e) { }
        if (node.isSame(targetNode)) {
          return true;
        }
      }
    }
    return false;
  }

  private Node getUserFavoriteFolder(String userName) throws Exception {
    Node userNode =
      nodeHierarchyCreator.getUserNode(sessionProviderService.getSystemSessionProvider(null), userName);
    String favoritePath = nodeHierarchyCreator.getJcrPath(FAVORITE_ALIAS);
    return userNode.getNode(favoritePath);
  }

  private Node createFavoriteFolder(String userName) throws Exception {
    // Get default favorite path
    Node userNode =
      nodeHierarchyCreator.getUserNode(sessionProviderService.getSystemSessionProvider(null), userName);
    String userFavoritePath = nodeHierarchyCreator.getJcrPath(FAVORITE_ALIAS);

    // Create favorite path
    Node userFavoriteNode = userNode.addNode(userFavoritePath, NT_UNSTRUCTURED);

    // Add Mixin types
    userFavoriteNode.addMixin(EXO_PRIVILEGEABLE);
    userFavoriteNode.addMixin(EXO_FAVORITEFOLDER);

    // Add permission
    Map<String, String[]> permissionsMap = new HashMap<String, String[]>();
    permissionsMap.put(userName, PermissionType.ALL);
    ((ExtendedNode)userFavoriteNode).setPermissions(permissionsMap);

    return userFavoriteNode;
  }

}
