package org.exoplatform.services.wcm.extensions.publication.lifecycle.authoring;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;

import javax.jcr.Node;
import javax.jcr.Value;
import javax.jcr.ValueFactory;
import javax.jcr.version.Version;
import javax.portlet.PortletMode;

import org.apache.commons.lang3.StringUtils;
import org.exoplatform.commons.utils.PageList;
import org.exoplatform.container.PortalContainer;
import org.exoplatform.ecm.webui.utils.Utils;
import org.exoplatform.portal.application.PortalRequestContext;
import org.exoplatform.portal.config.DataStorage;
import org.exoplatform.portal.config.Query;
import org.exoplatform.portal.config.UserACL;
import org.exoplatform.portal.config.UserPortalConfig;
import org.exoplatform.portal.config.UserPortalConfigService;
import org.exoplatform.portal.config.model.Page;
import org.exoplatform.portal.config.model.PortalConfig;
import org.exoplatform.portal.mop.navigation.Scope;
import org.exoplatform.portal.mop.user.UserNavigation;
import org.exoplatform.portal.mop.user.UserNode;
import org.exoplatform.portal.mop.user.UserPortal;
import org.exoplatform.portal.webui.util.Util;
import org.exoplatform.services.cms.CmsService;
import org.exoplatform.services.cms.jcrext.activity.ActivityCommonService;
import org.exoplatform.services.ecm.publication.IncorrectStateUpdateLifecycleException;
import org.exoplatform.services.listener.ListenerService;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.services.resources.ResourceBundleService;
import org.exoplatform.services.security.IdentityConstants;
import org.exoplatform.services.wcm.extensions.publication.impl.PublicationManagerImpl;
import org.exoplatform.services.wcm.extensions.publication.lifecycle.authoring.ui.UIPublicationContainer;
import org.exoplatform.services.wcm.extensions.publication.lifecycle.impl.LifecyclesConfig.Lifecycle;
import org.exoplatform.services.wcm.extensions.publication.lifecycle.impl.LifecyclesConfig.State;
import org.exoplatform.services.wcm.publication.PublicationDefaultStates;
import org.exoplatform.services.wcm.publication.PublicationUtil;
import org.exoplatform.services.wcm.publication.WCMComposer;
import org.exoplatform.services.wcm.publication.WCMPublicationService;
import org.exoplatform.services.wcm.publication.WebpagePublicationPlugin;
import org.exoplatform.services.wcm.publication.lifecycle.stageversion.config.VersionData;
import org.exoplatform.services.wcm.publication.lifecycle.stageversion.config.VersionLog;
import org.exoplatform.services.wcm.utils.WCMCoreUtils;
import org.exoplatform.webui.core.UIComponent;
import org.exoplatform.webui.form.UIForm;

/**
 * Created by The eXo Platform MEA Author : haikel.thamri@exoplatform.com
 */
public class AuthoringPublicationPlugin extends  WebpagePublicationPlugin {

  /** The log. */
  private static final Log      LOG = ExoLogger.getLogger(AuthoringPublicationPlugin.class.getName());
  private ListenerService       listenerService;
  private ActivityCommonService activityService;

  /**
   * Instantiates a new stage and version publication plugin.
   */
  public AuthoringPublicationPlugin() {
    listenerService = WCMCoreUtils.getService(ListenerService.class);
    activityService = WCMCoreUtils.getService(ActivityCommonService.class);
  }

  /*
   * (non-Javadoc)
   * @see org.exoplatform.services.ecm.publication.PublicationPlugin#changeState
   * (javax.jcr.Node, java.lang.String, java.util.HashMap)
   */

  public void changeState(Node node,
                          String newState,
                          HashMap<String, String> context) throws IncorrectStateUpdateLifecycleException,
                                                                                      Exception {
    // Add mixin mix:versionable
    if (node.canAddMixin(Utils.MIX_VERSIONABLE)) {
      node.addMixin(Utils.MIX_VERSIONABLE);
      node.save();
    }
    if (node.hasProperty(AuthoringPublicationConstant.CURRENT_STATE) && node.getProperty(AuthoringPublicationConstant.CURRENT_STATE)
    		.getString().equals(PublicationDefaultStates.UNPUBLISHED) && node.hasProperty("exo:titlePublished")) {
      node.setProperty("exo:titlePublished",(Value)null);
      
    }

    
    String versionName = context.get(AuthoringPublicationConstant.CURRENT_REVISION_NAME);
    String logItemName = versionName;
    String userId = "";
    try {
      userId = Util.getPortalRequestContext().getRemoteUser();
    } catch (Exception e) {
    userId = node.getSession().getUserID();
  }
    Node selectedRevision = null;
    if (node.getName().equals(versionName) || versionName == null) {
      selectedRevision = node;
      logItemName = node.getName();
    } else {
      selectedRevision = node.getVersionHistory().getVersion(versionName);
    }

    Map<String, VersionData> revisionsMap = getRevisionData(node);
    VersionLog versionLog = null;
    ValueFactory valueFactory = node.getSession().getValueFactory();
    String containerName = context.get("containerName");
    
    if (containerName==null) containerName = PortalContainer.getCurrentPortalContainerName();
    
    if (PublicationDefaultStates.PENDING.equals(newState)) {
      node.setProperty(AuthoringPublicationConstant.CURRENT_STATE, newState);
      versionLog = new VersionLog(logItemName,
                                  newState,
                                  userId,
                                  GregorianCalendar.getInstance(),
                                  AuthoringPublicationConstant.CHANGE_TO_PENDING);
      addLog(node, versionLog);
      VersionData versionData = revisionsMap.get(node.getUUID());
      if (versionData != null) {
        versionData.setAuthor(userId);
        versionData.setState(newState);
      } else {
        versionData = new VersionData(node.getUUID(), newState, userId);
      }
      revisionsMap.put(node.getUUID(), versionData);
      addRevisionData(node, revisionsMap.values());

    } else if (PublicationDefaultStates.APPROVED.equals(newState)) {

      node.setProperty(AuthoringPublicationConstant.CURRENT_STATE, newState);
      versionLog = new VersionLog(logItemName,
                                  newState,
                                  userId,
                                  GregorianCalendar.getInstance(),
                                  AuthoringPublicationConstant.CHANGE_TO_APPROVED);
      addLog(node, versionLog);
      VersionData versionData = revisionsMap.get(node.getUUID());
      if (versionData != null) {
        versionData.setAuthor(userId);
        versionData.setState(newState);
      } else {
        versionData = new VersionData(node.getUUID(), newState, userId);
      }
      revisionsMap.put(node.getUUID(), versionData);
      addRevisionData(node, revisionsMap.values());

    } else if (PublicationDefaultStates.STAGED.equals(newState)) {

      node.setProperty(AuthoringPublicationConstant.CURRENT_STATE, newState);
      versionLog = new VersionLog(logItemName,
                                  newState,
                                  userId,
                                  GregorianCalendar.getInstance(),
                                  AuthoringPublicationConstant.CHANGE_TO_STAGED);
      addLog(node, versionLog);
      VersionData versionData = revisionsMap.get(node.getUUID());
      if (versionData != null) {
        versionData.setAuthor(userId);
        versionData.setState(newState);
      } else {
        versionData = new VersionData(node.getUUID(), newState, userId);
      }
      revisionsMap.put(node.getUUID(), versionData);
      addRevisionData(node, revisionsMap.values());

    } else if (PublicationDefaultStates.ENROLLED.equalsIgnoreCase(newState)) {
      versionLog = new VersionLog(logItemName,
                                  newState,
                                  userId,
                                  GregorianCalendar.getInstance(),
                                  AuthoringPublicationConstant.ENROLLED_TO_LIFECYCLE);
      node.setProperty(AuthoringPublicationConstant.CURRENT_STATE, newState);
      VersionData revisionData = new VersionData(node.getUUID(), newState, userId);
      revisionsMap.put(node.getUUID(), revisionData);
      addRevisionData(node, revisionsMap.values());
      addLog(node, versionLog);
    } else if (PublicationDefaultStates.UNPUBLISHED.equalsIgnoreCase(newState)) {
      versionLog = new VersionLog(selectedRevision.getName(),
                                  PublicationDefaultStates.UNPUBLISHED,
                                  userId,
                                  new GregorianCalendar(),
                                  AuthoringPublicationConstant.CHANGE_TO_UNPUBLISHED);
      
      
      VersionData selectedVersionData = revisionsMap.get(selectedRevision.getUUID());
      if (selectedVersionData != null) {
        selectedVersionData.setAuthor(userId);
        selectedVersionData.setState(PublicationDefaultStates.UNPUBLISHED);
      } else {
        selectedVersionData = new VersionData(selectedRevision.getUUID(),
                                      PublicationDefaultStates.UNPUBLISHED,
                                      userId);
      }
      VersionData versionData = revisionsMap.get(node.getUUID());
      if (versionData != null) {
        versionData.setAuthor(userId);
        versionData.setState(PublicationDefaultStates.UNPUBLISHED);
      } else {
        versionData = new VersionData(selectedRevision.getUUID(),
                                      PublicationDefaultStates.UNPUBLISHED,
                                      userId);
      }
      revisionsMap.put(node.getUUID(), versionData);
      revisionsMap.put(selectedRevision.getUUID(), selectedVersionData);
      
      addLog(node, versionLog);
      // change base version to unpublished state
      if (node.hasProperty("exo:titlePublished")) {
        node.setProperty("exo:titlePublished",(Value)null);
      }
      node.setProperty(AuthoringPublicationConstant.CURRENT_STATE,
                       PublicationDefaultStates.UNPUBLISHED);
      Value value = valueFactory.createValue(selectedRevision);
      Value liveRevision = null;
      if (node.hasProperty(AuthoringPublicationConstant.LIVE_REVISION_PROP)) {
        liveRevision = node.getProperty(AuthoringPublicationConstant.LIVE_REVISION_PROP)
                               .getValue();
      }
      if (liveRevision != null && value.getString().equals(liveRevision.getString())) {
        node.setProperty(AuthoringPublicationConstant.LIVE_REVISION_PROP,
                         (javax.jcr.Value) null);
      }
      addRevisionData(node, revisionsMap.values());
    } else if (PublicationDefaultStates.OBSOLETE.equals(newState)) {
      node.setProperty(AuthoringPublicationConstant.CURRENT_STATE, newState);
      versionLog = new VersionLog(selectedRevision.getName(),
                                  newState,
                                  userId,
                                  GregorianCalendar.getInstance(),
                                  AuthoringPublicationConstant.CHANGE_TO_OBSOLETED);
      addLog(node, versionLog);
      VersionData versionData = revisionsMap.get(selectedRevision.getUUID());
      if (versionData != null) {
        versionData.setAuthor(userId);
        versionData.setState(newState);
      } else {
    	versionData = new VersionData(selectedRevision.getUUID(), newState, userId);
      }
      revisionsMap.put(selectedRevision.getUUID(), versionData);
      addRevisionData(node, revisionsMap.values());
    } else if (PublicationDefaultStates.ARCHIVED.equalsIgnoreCase(newState)) {
      Value value = valueFactory.createValue(selectedRevision);
      Value liveRevision = null;
      if (node.hasProperty(AuthoringPublicationConstant.LIVE_REVISION_PROP)) {
        liveRevision = node.getProperty(AuthoringPublicationConstant.LIVE_REVISION_PROP).getValue();
      }
      if (liveRevision != null && value.getString().equals(liveRevision.getString())) {
        node.setProperty(AuthoringPublicationConstant.LIVE_REVISION_PROP,
                         (javax.jcr.Value) null);
      }
      versionLog = new VersionLog(selectedRevision.getName(),
                                  PublicationDefaultStates.ARCHIVED,
                                  userId,
                                  new GregorianCalendar(),
                                  AuthoringPublicationConstant.CHANGE_TO_ARCHIVED);
      VersionData versionData = revisionsMap.get(selectedRevision.getUUID());
      if (versionData != null) {
        versionData.setAuthor(userId);
        versionData.setState(PublicationDefaultStates.ARCHIVED);
      } else {
        versionData = new VersionData(selectedRevision.getUUID(),
                                      PublicationDefaultStates.ARCHIVED,
                                      userId);
      }
      revisionsMap.put(selectedRevision.getUUID(), versionData);
      addLog(node, versionLog);
      // change base version to archived state
      node.setProperty(AuthoringPublicationConstant.CURRENT_STATE,
                       PublicationDefaultStates.ARCHIVED);
      addRevisionData(node, revisionsMap.values());
    } else if (PublicationDefaultStates.DRAFT.equalsIgnoreCase(newState)) {
      node.setProperty(AuthoringPublicationConstant.CURRENT_STATE, newState);
      versionLog = new VersionLog(logItemName,
                                  newState,
                                  userId,
                                  GregorianCalendar.getInstance(),
                                  AuthoringPublicationConstant.CHANGE_TO_DRAFT);
      addLog(node, versionLog);
      VersionData versionData = revisionsMap.get(node.getUUID());
      if (versionData != null) {
        versionData.setAuthor(userId);
        versionData.setState(newState);
      } else {
        versionData = new VersionData(node.getUUID(), newState, userId);
      }
      revisionsMap.put(node.getUUID(), versionData);
      addRevisionData(node, revisionsMap.values());
    } else if (PublicationDefaultStates.PUBLISHED.equals(newState)) {
      if (!node.isCheckedOut()) {
        node.checkout();
      }
      if (context == null || !context.containsKey("context.action") || !context.get("context.action").equals("delete")) {
        node.setProperty(AuthoringPublicationConstant.LIVE_DATE_PROP, new GregorianCalendar());
        node.save();
      }
      Version liveVersion = node.checkin();
      node.checkout();
      // Change current live revision to unpublished
      Node oldLiveRevision = getLiveRevision(node);
      if (oldLiveRevision != null) {
        VersionData versionData = revisionsMap.get(oldLiveRevision.getUUID());
        if (versionData != null) {
          versionData.setAuthor(userId);
          versionData.setState(PublicationDefaultStates.UNPUBLISHED);
        } else {
          versionData = new VersionData(oldLiveRevision.getUUID(),
                                        PublicationDefaultStates.UNPUBLISHED,
                                        userId);
        }
        revisionsMap.put(oldLiveRevision.getUUID(), versionData);
        versionLog = new VersionLog(oldLiveRevision.getName(),
                                    PublicationDefaultStates.UNPUBLISHED,
                                    userId,
                                    new GregorianCalendar(),
                                    AuthoringPublicationConstant.CHANGE_TO_UNPUBLISHED);
        addLog(node, versionLog);
      }
      versionLog = new VersionLog(liveVersion.getName(),
                                  newState,
                                  userId,
                                  new GregorianCalendar(),
                                  AuthoringPublicationConstant.CHANGE_TO_LIVE);
      addLog(node, versionLog);
      // change base version to published state
      node.setProperty(AuthoringPublicationConstant.CURRENT_STATE,
                       PublicationDefaultStates.PUBLISHED);
      VersionData editableRevision = revisionsMap.get(node.getUUID());
      if (editableRevision != null) {

        PublicationManagerImpl publicationManagerImpl = WCMCoreUtils.getService(PublicationManagerImpl.class, containerName);
        String lifecycleName = node.getProperty("publication:lifecycle").getString();
        Lifecycle lifecycle = publicationManagerImpl.getLifecycle(lifecycleName);
        List<State> states = lifecycle.getStates();
        if (states == null || states.size() <= 0) {
          editableRevision.setState(PublicationDefaultStates.ENROLLED);
        } else {
          editableRevision.setState(states.get(0).getState());
        }
        editableRevision.setAuthor(userId);

      } else {
        editableRevision = new VersionData(node.getUUID(),
                                           PublicationDefaultStates.ENROLLED,
                                           userId);
      }
      revisionsMap.put(node.getUUID(), editableRevision);
      versionLog = new VersionLog(node.getBaseVersion().getName(),
                                  PublicationDefaultStates.DRAFT,
                                  userId,
                                  new GregorianCalendar(),
                                  AuthoringPublicationConstant.ENROLLED_TO_LIFECYCLE);
      Value liveVersionValue = valueFactory.createValue(liveVersion);
      node.setProperty(AuthoringPublicationConstant.LIVE_REVISION_PROP, liveVersionValue);
      VersionData liveRevisionData = new VersionData(liveVersion.getUUID(),
                                                     PublicationDefaultStates.PUBLISHED,
                                                     userId);
      revisionsMap.put(liveVersion.getUUID(), liveRevisionData);
      addRevisionData(node, revisionsMap.values());
    }

    if (!IdentityConstants.SYSTEM.equals(userId)) {
      node.setProperty("publication:lastUser", userId);
    }

    if (!node.isNew())
      node.save();

    //raise event to notify that state is changed
    if (!PublicationDefaultStates.ENROLLED.equalsIgnoreCase(newState)) {

      CmsService cmsService = WCMCoreUtils.getService(CmsService.class);

      if ("true".equalsIgnoreCase(context.get(AuthoringPublicationConstant.IS_INITIAL_PHASE))) {
        listenerService.broadcast(AuthoringPublicationConstant.POST_INIT_STATE_EVENT, cmsService, node);
      } else {
        listenerService.broadcast(AuthoringPublicationConstant.POST_CHANGE_STATE_EVENT, cmsService, node);
        if (activityService.isAcceptedNode(node)) {
          listenerService.broadcast(ActivityCommonService.STATE_CHANGED_ACTIVITY, node, newState);
        }
      }
    }

    listenerService.broadcast(AuthoringPublicationConstant.POST_UPDATE_STATE_EVENT, null, node);
  }

  /*
   * (non-Javadoc)
   * @see
   * org.exoplatform.services.ecm.publication.PublicationPlugin#getPossibleStates
   * ()
   */
  public String[] getPossibleStates() {
    return new String[] { PublicationDefaultStates.ENROLLED, PublicationDefaultStates.DRAFT,
        PublicationDefaultStates.PENDING, PublicationDefaultStates.PUBLISHED,
        PublicationDefaultStates.OBSOLETE };
  }

  public String getLifecycleName() {
    return AuthoringPublicationConstant.LIFECYCLE_NAME;
  }

  public String getLifecycleType() {
    return AuthoringPublicationConstant.PUBLICATION_LIFECYCLE_TYPE;
  }

  /*
   * (non-Javadoc)
   * @see org.exoplatform.services.ecm.publication.PublicationPlugin#getStateUI
   * (javax.jcr.Node, org.exoplatform.webui.core.UIComponent)
   */
  public UIForm getStateUI(Node node, UIComponent component) throws Exception {
    UIPublicationContainer publicationContainer = component.createUIComponent(UIPublicationContainer.class,
                                                                              null,
                                                                              null);
    publicationContainer.initContainer(node);
    return publicationContainer;
  }

  /*
   * (non-Javadoc)
   * @see
   * org.exoplatform.services.ecm.publication.PublicationPlugin#addMixin(javax
   * .jcr.Node)
   */
  public void addMixin(Node node) throws Exception {
    node.addMixin(AuthoringPublicationConstant.PUBLICATION_LIFECYCLE_TYPE);
    String nodetypes = System.getProperty("wcm.nodetypes.ignoreversion");
    if(nodetypes == null || nodetypes.length() == 0)
       nodetypes = "exo:webContent";
    if(!Utils.NT_FILE.equals(node.getPrimaryNodeType().getName()) || Utils.isMakeVersionable(node, nodetypes.split(","))) {
      if (!node.isNodeType(AuthoringPublicationConstant.MIX_VERSIONABLE)) {
        node.addMixin(AuthoringPublicationConstant.MIX_VERSIONABLE);
      }
    }
  }

  /*
   * (non-Javadoc)
   * @see org.exoplatform.services.ecm.publication.PublicationPlugin#canAddMixin
   * (javax.jcr.Node)
   */
  public boolean canAddMixin(Node node) throws Exception {
    return node.canAddMixin(AuthoringPublicationConstant.PUBLICATION_LIFECYCLE_TYPE);
  }

  /**
   * Adds the log.
   *
   * @param node the node
   * @param versionLog the version log
   * @throws Exception the exception
   */
  private void addLog(Node node, VersionLog versionLog) throws Exception {
    Value[] values = node.getProperty(AuthoringPublicationConstant.HISTORY).getValues();
    ValueFactory valueFactory = node.getSession().getValueFactory();
    List<Value> list = new ArrayList<Value>(Arrays.asList(values));
    list.add(valueFactory.createValue(versionLog.toString()));
    node.setProperty(AuthoringPublicationConstant.HISTORY, list.toArray(new Value[] {}));
  }

  /**
   * Adds the revision data.
   *
   * @param node the node
   * @param list the list
   * @throws Exception the exception
   */
  private void addRevisionData(Node node, Collection<VersionData> list) throws Exception {
    List<Value> valueList = new ArrayList<Value>();
    ValueFactory factory = node.getSession().getValueFactory();
    for (VersionData versionData : list) {
      valueList.add(factory.createValue(versionData.toStringValue()));
    }
    node.setProperty(AuthoringPublicationConstant.REVISION_DATA_PROP,
                     valueList.toArray(new Value[] {}));
  }

  /**
   * Gets the revision data.
   *
   * @param node the node
   * @return the revision data
   * @throws Exception the exception
   */
  private Map<String, VersionData> getRevisionData(Node node) throws Exception {
    Map<String, VersionData> map = new HashMap<String, VersionData>();
    try {
      for (Value v : node.getProperty(AuthoringPublicationConstant.REVISION_DATA_PROP).getValues()) {
        VersionData versionData = VersionData.toVersionData(v.getString());
        map.put(versionData.getUUID(), versionData);
      }
    } catch (Exception e) {
      return map;
    }
    return map;
  }

  /**
   * In this publication process, we put the content in Draft state when editing
   * it.
   */
  public void updateLifecyleOnChangeContent(Node node, String remoteUser, String newState) throws Exception {

    String state = node.getProperty(AuthoringPublicationConstant.CURRENT_STATE).getString();
    if (newState == null) {
      PublicationManagerImpl publicationManagerImpl = WCMCoreUtils.getService(PublicationManagerImpl.class);
      Lifecycle lifecycle = publicationManagerImpl.getLifecycle(node.getProperty("publication:lifecycle")
                                                                    .getString());
      List<State> states = lifecycle.getStates();
      if (states != null && states.size() > 0) {
        newState = states.get(0).getState();
      }
    }
    if (state.equals(newState))
      return;

    HashMap<String, String> context = new HashMap<String, String>();
    changeState(node, newState, context);
  }

  /**
   * Gets the live revision.
   *
   * @param node the node
   * @return the live revision
   */
  private Node getLiveRevision(Node node) {
    try {
      String nodeVersionUUID = (node.hasProperty(AuthoringPublicationConstant.LIVE_REVISION_PROP)) ?
        node.getProperty(AuthoringPublicationConstant.LIVE_REVISION_PROP).getString() : null;

      if (StringUtils.isEmpty(nodeVersionUUID)
          && PublicationDefaultStates.PUBLISHED.equals(node.getProperty(AuthoringPublicationConstant.CURRENT_STATE)
                                                           .getString()))
        return node;
      return node.getVersionHistory().getSession().getNodeByUUID(nodeVersionUUID);
    } catch (Exception e) {
      return null;
    }
  }

  /*
   * (non-Javadoc)
   * @see
   * org.exoplatform.services.ecm.publication.PublicationPlugin#getNodeView(
   * javax.jcr.Node, java.util.Map)
   */
  public Node getNodeView(Node node, Map<String, Object> context) throws Exception {
    // don't display content if state is enrolled or obsolete
    WCMPublicationService wcmPublicationService = WCMCoreUtils.getService(WCMPublicationService.class);
    String currentState = wcmPublicationService.getContentState(node);
    if (PublicationDefaultStates.ENROLLED.equals(currentState)
        || PublicationDefaultStates.UNPUBLISHED.equals(currentState))
      return null;

    // if current mode is edit mode
    if (context==null || WCMComposer.MODE_EDIT.equals(context.get(WCMComposer.FILTER_MODE)) ||
        PortletMode.EDIT.toString().equals(context.get(WCMComposer.PORTLET_MODE)))
      return node;

    // if current mode is live mode
    Node liveNode = getLiveRevision(node);
    if (liveNode != null) {
      if (liveNode.hasNode("jcr:frozenNode")) {
        return liveNode.getNode("jcr:frozenNode");
      } 
      return liveNode;
    }
    return null;
  }

  @Override
  /**
   * In this publication process, we put the content in Draft state when editing it.
   */
  public void updateLifecyleOnChangeContent(Node node, String remoteUser)
  throws Exception {
    updateLifecyleOnChangeContent(node, remoteUser, PublicationDefaultStates.DRAFT);
  }

  @Override
  public List<String> getListUserNavigationUri(Page page, String remoteUser) throws Exception {
    List<String> listPageNavigationUri = new ArrayList<String>();
    for (String portalName : getRunningPortals(remoteUser)) {

      UserPortalConfigService userPortalConfigService = WCMCoreUtils.getService(UserPortalConfigService.class);
      UserPortalConfig userPortalCfg = userPortalConfigService.getUserPortalConfig(portalName,
                                                                                   remoteUser,
                                                                                   PortalRequestContext.USER_PORTAL_CONTEXT);
      UserPortal userPortal = userPortalCfg.getUserPortal();

      // get nodes
      List<UserNavigation> navigationList = userPortal.getNavigations();
      for (UserNavigation nav : navigationList) {
        UserNode root = userPortal.getNode(nav, Scope.ALL, null, null);
        List<UserNode> userNodeList = PublicationUtil.findUserNodeByPageId(root, page.getPageId());
        for (UserNode node : userNodeList) {
          listPageNavigationUri.add(PublicationUtil.setMixedNavigationUri(portalName, node.getURI()));
        }
      }
    }
    return listPageNavigationUri;
  }

  @Override
  public byte[] getStateImage(Node node, Locale locale) throws IOException, FileNotFoundException,
          Exception {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public String getUserInfo(Node node, Locale locale) throws Exception {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public String getLocalizedAndSubstituteMessage(Locale locale, String key, String[] values) throws Exception {
    ClassLoader cl=this.getClass().getClassLoader();
    ResourceBundleService bundleService = WCMCoreUtils.getService(ResourceBundleService.class);
    ResourceBundle resourceBundle= bundleService.getResourceBundle(AuthoringPublicationConstant.LOCALIZATION, locale, cl);
    String result = "";
    try {
      result = resourceBundle.getString(key);
    } catch (MissingResourceException e) {
      result = key;
    }
    if(values != null) {
      return String.format(result, (Object[])values);
    }
    return result;
  }

  private List<String> getRunningPortals(String userId) throws Exception {
    List<String> listPortalName = new ArrayList<String>();
    DataStorage service = WCMCoreUtils.getService(DataStorage.class);
    Query<PortalConfig> query = new Query<PortalConfig>(null, null, null, null, PortalConfig.class) ;
    PageList pageList = service.find(query, null) ;
    UserACL userACL = WCMCoreUtils.getService(UserACL.class);
    for(Object object:pageList.getAll()) {
      PortalConfig portalConfig = (PortalConfig)object;
      if(userACL.hasPermission(portalConfig)) {
        listPortalName.add(portalConfig.getName());
      }
    }
    return listPortalName;
  }
}
