/*
 * Version 1.1
 * CeCILL Copyright (c) 2006-2007, AtolCD, ADULLACT-projet
 * Initiated by AtolCD S.A. & ADULLACT-projet S.A.
 * Developped by AtolCD
 * 
 * contact@atolcd.com
 * contact@adullact-projet.coop
 * 
 * Ce logiciel est un programme informatique servant à faire circuler des 
 * documents au travers d'un circuit de validation, où chaque acteur vise 
 * le dossier, jusqu'à l'étape finale de signature.
 * 
 * Ce logiciel est régi par la licence CeCILL soumise au droit français et
 * respectant les principes de diffusion des logiciels libres. Vous pouvez
 * utiliser, modifier et/ou redistribuer ce programme sous les conditions
 * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA 
 * sur le site "http://www.cecill.info".
 * 
 * En contrepartie de l'accessibilité au code source et des droits de copie,
 * de modification et de redistribution accordés par cette licence, il n'est
 * offert aux utilisateurs qu'une garantie limitée.  Pour les mêmes raisons,
 * seule une responsabilité restreinte pèse sur l'auteur du programme,  le
 * titulaire des droits patrimoniaux et les concédants successifs.
 * 
 * A cet égard  l'attention de l'utilisateur est attirée sur les risques
 * associés au chargement,  à l'utilisation,  à la modification et/ou au
 * développement et à la reproduction du logiciel par l'utilisateur étant 
 * donné sa spécificité de logiciel libre, qui peut le rendre complexe à 
 * manipuler et qui le réserve donc à des développeurs et des professionnels
 * avertis possédant  des  connaissances  informatiques approfondies.  Les
 * utilisateurs sont donc invités à charger  et  tester  l'adéquation  du
 * logiciel à leurs besoins dans des conditions permettant d'assurer la
 * sécurité de leurs systèmes et ou de leurs données et, plus généralement, 
 * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. 
 * 
 * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez 
 * pris connaissance de la licence CeCILL, et que vous en avez accepté les
 * termes.
 *  
 */

package com.atolcd.parapheur.web.bean;

import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.transaction.UserTransaction;

import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.search.QueryParameterDefinition;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.web.app.AlfrescoNavigationHandler;
import org.alfresco.web.app.Application;
import org.alfresco.web.app.context.IContextListener;
import org.alfresco.web.app.context.UIContextService;
import org.alfresco.web.app.servlet.DownloadContentServlet;
import org.alfresco.web.bean.BrowseBean;
import org.alfresco.web.bean.NavigationBean;
import org.alfresco.web.bean.repository.MapNode;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.NodePropertyResolver;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.config.ViewsConfigElement;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.common.component.IBreadcrumbHandler;
import org.alfresco.web.ui.common.component.UIActionLink;
import org.alfresco.web.ui.common.component.UIBreadcrumb;
import org.alfresco.web.ui.common.component.UIModeList;
import org.alfresco.web.ui.common.component.data.UIRichList;
import org.alfresco.web.ui.repo.component.IRepoBreadcrumbHandler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.atolcd.parapheur.model.ParapheurModel;
import com.atolcd.parapheur.repo.EtapeCircuit;
import com.atolcd.parapheur.repo.ParapheurService;

/**
 * Bean providing properties and behaviour for the "parapheur" screens.
 * @author tbr
 *
 */
public class ParapheurBean implements IContextListener
{
   private static Log logger = LogFactory.getLog(ParapheurBean.class);
   private static final String PAGE_NAME_PARAPHEUR = "parapheur";
   private static final String PAGE_NAME_CORBEILLE = "corbeille";
   private static final String PAGE_NAME_DOSSIER = "dossier";

   /** The NodeService to be used by the bean */
   protected static NodeService nodeService;

   /** The ContentService to be used by the bean */
   protected ContentService contentService;

   /** The SearchService bean reference. */
   protected static SearchService searchService;

   /** The NamespaceService bean reference. */
   protected static NamespaceService namespaceService;

   /** The browse bean */
   protected BrowseBean browseBean;

   /** The NavigationBean bean reference */
   protected NavigationBean navigator;

   /** The ParapheurService bean reference*/
   protected static ParapheurService parapheurService;

   /** Views configuration object */
   protected ViewsConfigElement viewsConfig = null;

   /** Component references */
   protected UIRichList parapheurRichList;
   protected UIRichList corbeilleRichList;
   protected UIRichList corbeilleVirtuelleRichList;
   protected UIRichList dossierRichList;
   protected UIRichList parapheursRichList;

   /** Node lists */
   private List<Node> corbeilles;
   private List<Node> dossiers;
   private List<Node> dossiersVirtuels;
   private List<Node> documents;
   private List<Node> parapheurs;

   private List<NodeRef> dossiersNonTermines;
   private Map<NodeRef, Integer> corbeillesChildNumber;
   private Map<NodeRef, Boolean> corbeillesLate;

   /** The current "parapheur" view mode - set to a well known IRichListRenderer identifier */
   private String parapheurViewMode;

   /** The current "parapheur" view page size */
   private int parapheurPageSize;

   /** The current "corbeille" view mode - set to a well known IRichListRenderer identifier */
   private String corbeilleViewMode;

   /** The current "corbeille" view page size */
   private int corbeillePageSize;

   /** The current "dossier" view mode - set to a well known IRichListRenderer identifier */
   private String dossierViewMode;

   /** The current "dossier" view page size */
   private int dossierPageSize;

   /** true if the document carries a PDF viewable version */
   private boolean hasVisual; 

   private NodeRef parapheurCourant;


   /** I18N messages qui n'existent plus dans la class BrowseBean du Alfresco-SDK 1.4*/
   private static final String MSG_ERROR_DELETE_FILE  = "error_delete_file";
   private static final String MSG_ERROR_DELETE_SPACE = "error_delete_space";
   // ------------------------------------------------------------------------------
   // Construction 

   /**
    * Default constructor 
    */
   public ParapheurBean()
   {
      parapheurCourant = null;
      UIContextService.getInstance(FacesContext.getCurrentInstance()).registerBean(this);
      initFromClientConfig();
   }


   // ------------------------------------------------------------------------------
   // Bean property getters and setters 

   /**
    * @param nodeService The NodeService to set.
    */
   public void setNodeService(NodeService _nodeService)
   {
      nodeService = _nodeService;
   }

   /**
    * @return Returns the nodeService.
    */
   public NodeService getNodeService()
   {
      return nodeService;
   }


   /**
    * Sets the content service to use
    * 
    * @param contentService The ContentService
    */
   public void setContentService(ContentService contentService)
   {
      this.contentService = contentService;
   }

   /**
    * @param searchService The SearchService to set.
    */
   public void setSearchService(SearchService _searchService)
   {
      searchService = _searchService;
   }

   /**
    * @param namespaceService The NamespaceService to set.
    */
   public void setNamespaceService(NamespaceService namespaceService)
   {
      ParapheurBean.namespaceService = namespaceService;
   }

   /**
    * Sets the BrowseBean instance to use to retrieve the current document
    * 
    * @param browseBean BrowseBean instance
    */
   public void setBrowseBean(BrowseBean browseBean)
   {
      this.browseBean = browseBean;
   }

   public BrowseBean getBrowseBean()
   {
      return this.browseBean;
   }

   /**
    * @param navigator The NavigationBean to set.
    */
   public void setNavigator(NavigationBean navigator)
   {
      this.navigator = navigator;
   }

   public NavigationBean getNavigator()
   {
      return this.navigator;
   }

   /**
    * 
    * @param parapheurservice The ParapheurService to set.
    */

   public void setParapheurService(ParapheurService parapheurService)
   {
      ParapheurBean.parapheurService = parapheurService;
   }

   public ParapheurService getParapheurService()
   {
      return ParapheurBean.parapheurService;
   }

   /**
    * @param parapheurRichList The parapheurRichList to set.
    */
   public void setParapheurRichList(UIRichList parapheurRichList)
   {
      this.parapheurRichList = parapheurRichList;
   }

   /**
    * @return Returns the parapheurRichList.
    */
   public UIRichList getParapheurRichList()
   {
      return this.parapheurRichList;
   }

   /**
    * @return Returns the "parapheur" View mode. See UIRichList
    */
   public String getParapheurViewMode()
   {
      return this.parapheurViewMode;
   }

   /**
    * @param parapheurViewMode      The "parapheur" View mode to set. See UIRichList.
    */
   public void setParapheurViewMode(String parapheurViewMode)
   {
      this.parapheurViewMode = parapheurViewMode;
   }

   /**
    * @return Returns the parapheurPageSize.
    */
   public int getParapheurPageSize()
   {
      return this.parapheurPageSize;
   }

   /**
    * @param parapheurPageSize The parapheurPageSize to set.
    */
   public void setParapheurPageSize(int parapheurPageSize)
   {
      this.parapheurPageSize = parapheurPageSize;
   }

   /**
    * @param corbeilleRichList The corbeilleRichList to set.
    */
   public void setCorbeilleRichList(UIRichList corbeilleRichList)
   {
      this.corbeilleRichList = corbeilleRichList;
      if (this.corbeilleRichList != null)
      {
         // set the initial sort column and direction
         this.corbeilleRichList.setInitialSortColumn(
               this.viewsConfig.getDefaultSortColumn(PAGE_NAME_CORBEILLE));
         this.corbeilleRichList.setInitialSortDescending(
               this.viewsConfig.hasDescendingSort(PAGE_NAME_CORBEILLE));
      }
   }

   /**
    * @return Returns the corbeilleRichList.
    */
   public UIRichList getCorbeilleRichList()
   {
      return this.corbeilleRichList;
   }

   /**
    * @return Returns the "corbeille" View mode. See UIRichList
    */
   public String getCorbeilleViewMode()
   {
      return this.corbeilleViewMode;
   }

   /**
    * @param corbeilleViewMode      The "corbeille" View mode to set. See UIRichList.
    */
   public void setCorbeilleViewMode(String corbeilleViewMode)
   {
      this.corbeilleViewMode = corbeilleViewMode;
   }

   /**
    * @return Returns the corbeillePageSize.
    */
   public int getCorbeillePageSize()
   {
      return this.corbeillePageSize;
   }

   /**
    * @param corbeillePageSize The corbeillePageSize to set.
    */
   public void setCorbeillePageSize(int corbeillePageSize)
   {
      this.corbeillePageSize = corbeillePageSize;
   }

   /**
    * @param corbeilleVirtuelleRichList The corbeilleVirtuelleRichList to set.
    */
   public void setCorbeilleVirtuelleRichList(UIRichList corbeilleVirtuelleRichList)
   {
      this.corbeilleVirtuelleRichList = corbeilleVirtuelleRichList;
      if (this.corbeilleVirtuelleRichList != null)
      {
         // set the initial sort column and direction
         this.corbeilleVirtuelleRichList.setInitialSortColumn(
               this.viewsConfig.getDefaultSortColumn(PAGE_NAME_CORBEILLE));
         this.corbeilleVirtuelleRichList.setInitialSortDescending(
               this.viewsConfig.hasDescendingSort(PAGE_NAME_CORBEILLE));
      }
   }

   /**
    * @return Returns the corbeilleVirtuelleRichList.
    */
   public UIRichList getCorbeilleVirtuelleRichList()
   {
      return this.corbeilleVirtuelleRichList;
   }

   /**
    * @param dossierRichList The dossierRichList to set.
    */
   public void setDossierRichList(UIRichList dossierRichList)
   {
      this.dossierRichList = dossierRichList;
   }

   /**
    * @return Returns the dossierRichList.
    */
   public UIRichList getDossierRichList()
   {
      return this.dossierRichList;
   }

   /**
    * @return Returns the dossiers View mode. See UIRichList
    */
   public String getDossierViewMode()
   {
      return this.dossierViewMode;
   }

   /**
    * @param dossierViewMode      The dossier View mode to set. See UIRichList.
    */
   public void setDossierViewMode(String dossierViewMode)
   {
      this.dossierViewMode = dossierViewMode;
   }

   /**
    * @return Returns the dossiersPageSize.
    */
   public int getDossierPageSize()
   {
      return this.dossierPageSize;
   }

   /**
    * @param dossierPageSize The dossierPageSize to set.
    */
   public void setDossierPageSize(int dossierPageSize)
   {
      this.dossierPageSize = dossierPageSize;
   }

   /**
    * @param parapheursRichList The parapheursRichList to set.
    */
   public void setParapheursRichList(UIRichList parapheursRichList)
   {
      this.parapheursRichList = parapheursRichList;
   }

   /**
    * @return Returns the parapheursRichList.
    */
   public UIRichList getParapheursRichList()
   {
      return this.parapheursRichList;
   }

   public boolean isHasVisual()
   {
       return hasVisual;
   }


   public void setHasVisual(boolean hasVisual)
   {
       this.hasVisual = hasVisual;
   }


   public List<Node> getCorbeilles()
   {
      if (this.corbeilles == null)
      {
         getNodes();
      }

      return this.corbeilles;
   }

   public List<Node> getDossiers()
   {
      if (this.dossiers == null)
      {
         getNodes();
      }

      return this.dossiers;
   }

   public List<Node> getDossiersVirtuels()
   {
      if (this.dossiersVirtuels == null)
      {
         getNodes();
      }

      return this.dossiersVirtuels;
   }

   /**
    * @return Returns the dossiersNonTermines.
    */
   public List<NodeRef> getDossiersNonTermines()
   {
      if (dossiersNonTermines == null)
      {
         long startTime = 0;
         if (logger.isDebugEnabled())
            startTime = System.currentTimeMillis();

         UserTransaction tx = null;
         try
         {
            FacesContext context = FacesContext.getCurrentInstance();
            tx = Repository.getUserTransaction(context, true);
            tx.begin();

            String dossiersXPath = "/app:company_home/ph:parapheurs//*[(subtypeOf('" + ParapheurModel.TYPE_DOSSIER + "')) " +
            "and @" + ParapheurModel.PROP_TERMINE.toPrefixString(namespaceService) + "='false']";

            dossiersNonTermines = searchService.selectNodes(
                  new NodeRef(Repository.getStoreRef(), Application.getCompanyRootId(context)),
                  dossiersXPath,
                  new QueryParameterDefinition[] {},
                  namespaceService,
                  false);
            
            tx.commit();
         }
         catch (Throwable err)
         {
            Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
                  FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
            logger.error(err.getMessage(), err);

            dossiersNonTermines = Collections.<NodeRef>emptyList();
            try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
         }

         if (logger.isDebugEnabled())
         {
            long endTime = System.currentTimeMillis();
            logger.debug("Tous les dossiers: " + (endTime - startTime) + "ms");
         }
      }

      return dossiersNonTermines;
   }

   public int getCorbeilleChildNumber(NodeRef corbeilleRef)
   {
      if (corbeillesChildNumber == null)
      {
         long startTime = 0;
         if (logger.isDebugEnabled())
            startTime = System.currentTimeMillis();
         
         NodeRef parapheurCourant = parapheurService.getParentParapheur(corbeilleRef);
         corbeillesChildNumber = new HashMap<NodeRef, Integer>();

         List<NodeRef> corbeilles = parapheurService.getCorbeilles(parapheurCourant);
         for (NodeRef corbeille : corbeilles)
         {
            if(parapheurService.isCorbeille(corbeille))
            {
               List<NodeRef> dossiers = parapheurService.getDossiers(corbeille);
               int nb = 0;
               if (dossiers != null && !dossiers.isEmpty())
                  nb = dossiers.size();
               corbeillesChildNumber.put(corbeille, nb);
            }
         }

         int nbDossiersEncours = 0,
         nbDossiersRecuperables = 0;
         for (NodeRef dossierRef : getDossiersNonTermines())
         {
            NodeRef parapheur = parapheurService.getParentParapheur(dossierRef);
            if (parapheur != null && !parapheur.equals(parapheurCourant))
            {
               if (parapheurService.isEmis(dossierRef))
               {
                  if (parapheurService.getEmetteur(dossierRef).equals(parapheurCourant))
                  {
                     nbDossiersEncours ++;
                  }
                  if (parapheurService.isRecuperable(dossierRef))
                  {
                     if (!nodeService.hasAspect(dossierRef, ParapheurModel.ASPECT_SECRETARIAT))
                     {
                        String xpath = ".//*[subtypeOf('" + ParapheurModel.TYPE_ETAPE_CIRCUIT + "') " +
                                "and @" + ParapheurModel.PROP_EFFECTUEE.toPrefixString(namespaceService) + "='false' " +
                                "and ../@" + ParapheurModel.PROP_EFFECTUEE.toPrefixString(namespaceService) + "='true' " +
                                "and ../@" + ParapheurModel.PROP_PASSE_PAR.toPrefixString(namespaceService) + "='" 
                                      + parapheurCourant.toString() + "']";
                        List<NodeRef> etapes = searchService.selectNodes(dossierRef, 
                              xpath, 
                              null, 
                              namespaceService, 
                              false);
                        if (etapes != null && etapes.size() == 1)
                           nbDossiersRecuperables ++;
                     }
                  }
               }
            }
         }
         if (logger.isDebugEnabled())
         {
            long endTime = System.currentTimeMillis();
            logger.debug("Corbeilles virtuelles : " + (endTime - startTime) + "ms");
         }
         corbeillesChildNumber.put(parapheurService.getCorbeille(parapheurCourant, ParapheurModel.NAME_EN_COURS), nbDossiersEncours);
         corbeillesChildNumber.put(parapheurService.getCorbeille(parapheurCourant, ParapheurModel.NAME_RECUPERABLES), nbDossiersRecuperables);

         if (logger.isDebugEnabled())
         {
            long endTime = System.currentTimeMillis();
            logger.debug("Total Resolver ChildNumber : " + (endTime - startTime) + "ms");
         }
      }

      return corbeillesChildNumber.get(corbeilleRef);
   }

   public boolean getCorbeilleLate(NodeRef corbeilleRef)
   {
      if (corbeillesLate == null)
      {
         NodeRef parapheurCourant = parapheurService.getParentParapheur(corbeilleRef);
         corbeillesLate = new HashMap<NodeRef, Boolean>();

         List<NodeRef> corbeilles = parapheurService.getCorbeilles(parapheurCourant);
         
         if (corbeilles != null)
         {
            for (NodeRef corbeille : corbeilles)
            {
               if(parapheurService.isCorbeille(corbeille))
               {
                  corbeillesLate.put(corbeille, Boolean.FALSE);
                  List<NodeRef> dossiers = parapheurService.getDossiers(corbeille);
                  if (dossiers != null)
                  {
                     for (NodeRef dossier : dossiers)
                     {
                        Date limit = (Date)nodeService.getProperty(dossier,ParapheurModel.PROP_DATE_LIMITE);
                        if (limit != null)
                        {
                           Date today = new Date();
                           if (today.after(limit))
                           {
                              corbeillesLate.put(corbeille, Boolean.TRUE);
                              break;
                           }
                        }
                     }
                  }
               }
            }
         }

         NodeRef encoursRef = parapheurService.getCorbeille(parapheurCourant, ParapheurModel.NAME_EN_COURS);
         NodeRef recupRef = parapheurService.getCorbeille(parapheurCourant, ParapheurModel.NAME_RECUPERABLES);

         corbeillesLate.put(encoursRef, Boolean.FALSE);
         corbeillesLate.put(recupRef, Boolean.FALSE);
         for (NodeRef dossierRef : getDossiersNonTermines())
         {
            if (corbeillesLate.get(encoursRef) && corbeillesLate.get(recupRef))
               break;
            else
            {
               if (parapheurService.isEmis(dossierRef))
               {
                  Date limit = (Date)nodeService.getProperty(dossierRef,ParapheurModel.PROP_DATE_LIMITE);
                  if (limit != null)
                  {
                     Date today = new Date();
                     if(today.after(limit))
                     {
                        if (parapheurCourant.equals(parapheurService.getEmetteur(dossierRef)))
                        {
                           corbeillesLate.put(encoursRef, Boolean.TRUE);
                        }
                        
                        if (parapheurService.isRecuperable(dossierRef))
                        {
                           String xpath = ".//*[subtypeOf('" + ParapheurModel.TYPE_ETAPE_CIRCUIT + "') " +
                           "and @" + ParapheurModel.PROP_EFFECTUEE.toPrefixString(namespaceService) + "='false' " +
                           "and ../@" + ParapheurModel.PROP_EFFECTUEE.toPrefixString(namespaceService) + "='true' " +
                           "and ../@" + ParapheurModel.PROP_PASSE_PAR.toPrefixString(namespaceService) + "='" 
                                 + parapheurCourant.toString() + "']";
                           List<NodeRef> etapes = searchService.selectNodes(dossierRef, 
                                 xpath, 
                                 null, 
                                 namespaceService, 
                                 false);
                           if (etapes != null && etapes.size() == 1)
                              corbeillesLate.put(recupRef, Boolean.TRUE);
                        }
                     }
                  }
               }
            }
         }
      }

      return corbeillesLate.get(corbeilleRef);
   }

   public List<Node> getDocuments()
   {
      if (this.documents == null)
      {
         getNodes();
      }

      return this.documents;
   }

   public List<Node> getParapheurs()
   {
      if (this.parapheurs == null)
      {
         getNodes();
      }
      return this.parapheurs;
   }

   public NodeRef getParapheurCourant()
   {
      if (nodeService.exists(this.navigator.getCurrentNode().getNodeRef()))
      {
         if (parapheurService.isParapheur(this.navigator.getCurrentNode().getNodeRef()))
         {
            this.parapheurCourant = this.navigator.getCurrentNode().getNodeRef();
         }
         else
         {
            this.parapheurCourant = parapheurService.getParentParapheur(this.navigator.getCurrentNode().getNodeRef());
         }
      }
      else
      {
         this.parapheurCourant = null;
      }

      return this.parapheurCourant;
   }

   public boolean getCurrentUserOwner()
   {
      boolean res = false;

      if (getParapheurCourant() != null)
      {
         String username = this.navigator.getCurrentUser().getUserName();
         if (parapheurService.isParapheurOwner(this.parapheurCourant, username))
            res = true;
      }

      return res;
   }

   private void getNodes()
   {
      long startTime = 0;
      if (logger.isDebugEnabled())
         startTime = System.currentTimeMillis();

      UserTransaction tx = null;
      try
      {
         FacesContext context = FacesContext.getCurrentInstance();
         tx = Repository.getUserTransaction(context, true);
         tx.begin();

         // get the current space from NavigationBean
         String parentNodeId = this.navigator.getCurrentNodeId();

         NodeRef parentRef;
         if (parentNodeId == null)
         {
            // no specific parent node specified - use the root node
            parentRef = nodeService.getRootNode(Repository.getStoreRef());
         }
         else
         {
            // build a NodeRef for the specified Id and our store
            parentRef = new NodeRef(Repository.getStoreRef(), parentNodeId);
         }


         if (nodeService.exists(parentRef))
         {
            if (parapheurService.isCorbeilleVirtuelle(parentRef))
            {
               this.corbeilles = new ArrayList<Node>();
               this.dossiers = new ArrayList<Node>();
               this.dossiersVirtuels = new ArrayList<Node>();
               this.documents = new ArrayList<Node>();
               this.parapheurs = new ArrayList<Node>();

               QName corbeilleName = nodeService.getPrimaryParent(parentRef).getQName();
               if (ParapheurModel.NAME_EN_COURS.equals(corbeilleName))
               {
                  for (NodeRef dossierRef : getDossiersNonTermines())
                  {
                     if (parapheurService.isEmis(dossierRef))
                     {
                        NodeRef parapheurNodeRef = parapheurService.getEmetteur(dossierRef);
                        if (parapheurNodeRef != null && parapheurNodeRef.equals(this.getParapheurCourant()))
                        {
                           MapNode node = new MapNode(dossierRef, nodeService, true);
                           node.addPropertyResolver("icon", this.browseBean.resolverSpaceIcon);
                           node.addPropertyResolver("smallIcon", this.browseBean.resolverSmallIcon);
                           node.addPropertyResolver("late",this.resolverLate);
                           node.addPropertyResolver("notLate",this.resolverNotLate);
                           node.addPropertyResolver("current", this.resolverCurrent);
                           node.addPropertyResolver("limit", this.resolverLimit);
                           this.dossiersVirtuels.add(node);
                        }
                     }
                  }
               }
               else if (ParapheurModel.NAME_RECUPERABLES.equals(corbeilleName))
               {
                  for (NodeRef dossierRef : getDossiersNonTermines())
                  {
                     if (parapheurService.isRecuperable(dossierRef)
                           && parapheurService.isEmis(dossierRef)
                           && !nodeService.hasAspect(dossierRef, ParapheurModel.ASPECT_SECRETARIAT))
                     {
                        List<EtapeCircuit> circuit = parapheurService.getCircuit(dossierRef);
                        int index = 0;
                        for (EtapeCircuit etape : circuit)
                        {
                           if (!etape.isApproved())
                           {
                              index = circuit.indexOf(etape);
                              break;
                           }
                        }

                        if (index > 0)
                        {
                           EtapeCircuit etapePrecedente = circuit.get(index-1);
                           NodeRef parapheurPrecedent = etapePrecedente.getParapheur();

                           if (parapheurPrecedent != null && parapheurPrecedent.equals(this.getParapheurCourant()))
                           {
                              MapNode node = new MapNode(dossierRef, nodeService, true);
                              node.addPropertyResolver("icon", this.browseBean.resolverSpaceIcon);
                              node.addPropertyResolver("smallIcon", this.browseBean.resolverSmallIcon);
                              node.addPropertyResolver("late",this.resolverLate);
                              node.addPropertyResolver("notLate",this.resolverNotLate);
                              node.addPropertyResolver("current", this.resolverCurrent);
                              node.addPropertyResolver("limit", this.resolverLimit);
                              this.dossiersVirtuels.add(node);
                           }
                        }
                     }
                  }
               }
            }
            else
            {
               List<ChildAssociationRef> childRefs = nodeService.getChildAssocs(parentRef,
                     ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL);
               this.corbeilles = new ArrayList<Node>(childRefs.size());
               this.dossiers = new ArrayList<Node>(childRefs.size());
               this.dossiersVirtuels = new ArrayList<Node>();
               this.documents = new ArrayList<Node>(childRefs.size());
               this.parapheurs = new ArrayList<Node>(childRefs.size());

               for (ChildAssociationRef ref: childRefs)
               {
                  // create our Node representation from the NodeRef
                  NodeRef nodeRef = ref.getChildRef();

                  if (nodeService.exists(nodeRef))
                  {
                     if (parapheurService.isCorbeille(nodeRef)
                           || parapheurService.isCorbeilleVirtuelle(nodeRef)) 
                     {
                        // create our Node representation
                        MapNode node = new MapNode(nodeRef, nodeService, true);
                        node.addPropertyResolver("icon", this.browseBean.resolverSpaceIcon);
                        node.addPropertyResolver("smallIcon", this.browseBean.resolverSmallIcon);
                        node.addPropertyResolver("childCount",this.resolverChildNumber);
                        node.addPropertyResolver("late",this.resolverLate);
                        node.addPropertyResolver("notLate",this.resolverNotLate);

                        this.corbeilles.add(node);
                     }
                     else if (parapheurService.isDossier(nodeRef)) 
                     {
                        // create our Node representation
                        MapNode node = new MapNode(nodeRef, nodeService, true);
                        node.addPropertyResolver("icon", this.browseBean.resolverSpaceIcon);
                        node.addPropertyResolver("smallIcon", this.browseBean.resolverSmallIcon);
                        node.addPropertyResolver("late",this.resolverLate);
                        node.addPropertyResolver("notLate",this.resolverNotLate);
                        node.addPropertyResolver("step",this.resolverStep);

                        this.dossiers.add(node);
                     }
                     else if (parapheurService.isParapheur(nodeRef))
                     {
                        String username = Application.getCurrentUser(FacesContext.getCurrentInstance()).getUserName();
                        if (parapheurService.isParapheurOwner(nodeRef, username)
                              || parapheurService.isParapheurSecretaire(nodeRef, username))
                        {
                           MapNode node = new MapNode(nodeRef, nodeService, true);
                           node.addPropertyResolver("icon", this.browseBean.resolverSpaceIcon);
                           node.addPropertyResolver("smallIcon", this.browseBean.resolverSmallIcon);
                           this.parapheurs.add(node);
                        }
                     }
                     else
                     {
                        // create our Node representation
                        MapNode node = new MapNode(nodeRef, nodeService, true);
                        this.browseBean.setupCommonBindingProperties(node);
                        node.addPropertyResolver("smallIcon", this.browseBean.resolverSmallIcon);
                        node.addPropertyResolver("message", this.resolverContent);
                        node.addPropertyResolver("lu", this.resolverLu);
                        node.addPropertyResolver("visuel", this.resolverVisuel);
                        node.addPropertyResolver("visuelUrl", this.resolverVisuelUrl);
                        this.documents.add(node);
                     }
                  }
               }
            }
         }
         else
         {
            this.corbeilles = Collections.<Node>emptyList();
            this.dossiers = Collections.<Node>emptyList();
            this.dossiersVirtuels = Collections.<Node>emptyList();
            this.documents = Collections.<Node>emptyList();
            this.parapheurs = Collections.<Node>emptyList();
         }

         tx.commit();
      }
      catch (InvalidNodeRefException refErr)
      {
         Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
               FacesContext.getCurrentInstance(), Repository.ERROR_NODEREF), new Object[] {refErr.getNodeRef()}) );
         logger.error(refErr.getMessage(), refErr);

         this.corbeilles = Collections.<Node>emptyList();
         this.dossiers = Collections.<Node>emptyList();
         this.dossiersVirtuels = Collections.<Node>emptyList();
         this.documents = Collections.<Node>emptyList();
         this.parapheurs = Collections.<Node>emptyList();
         try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
      }
      catch (Throwable err)
      {
         Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
               FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
         logger.error(err.getMessage(), err);

         this.corbeilles = Collections.<Node>emptyList();
         this.dossiers = Collections.<Node>emptyList();
         this.dossiersVirtuels = Collections.<Node>emptyList();
         this.documents = Collections.<Node>emptyList();
         this.parapheurs = Collections.<Node>emptyList();
         try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
      }

      if (logger.isDebugEnabled())
      {
         long endTime = System.currentTimeMillis();
         logger.debug("Time to query and build \"parapheur\" nodes: " + (endTime - startTime) + "ms");
      }
   }

   public String getStep(NodeRef nodeRef)
   {
      String res = Application.getMessage(FacesContext.getCurrentInstance(),"workflow_emettre");

      if (parapheurService.isDossier(nodeRef))
      {
         ArrayList<EtapeCircuit> circuit = (ArrayList<EtapeCircuit>) parapheurService.getCircuit(nodeRef);
         if (!circuit.isEmpty())
         {
            if (!parapheurService.isTermine(nodeRef))
            {
               if (circuit.get(0).isApproved())
               {
                  res = Application.getMessage(FacesContext.getCurrentInstance(),"workflow_viser");
                  if (circuit.get(circuit.size()-2).isApproved())
                  {
                     res = Application.getMessage(FacesContext.getCurrentInstance(),"workflow_signer");
                  }
               }
            }
            else
            {
               res = Application.getMessage(FacesContext.getCurrentInstance(),"workflow_raz");
            }
         }
      }
      return res;
   }

   public String getSecretariat(NodeRef dossier)
   {
      String res = "";

      if (parapheurService.isDossier(dossier))
      {
         if (nodeService.hasAspect(dossier,ParapheurModel.ASPECT_SECRETARIAT))
            res = Application.getMessage(FacesContext.getCurrentInstance(), "action_retour_secretariat");
         else
            res = Application.getMessage(FacesContext.getCurrentInstance(), "action_secretariat");
      }

      return res;
   }

   public String getSecretariat()
   {
      return getSecretariat(this.navigator.getCurrentNode().getNodeRef());
   }

   public String getStep()
   {
      return getStep(this.navigator.getCurrentNode().getNodeRef());
   }


   // ------------------------------------------------------------------------------
   // IContextListener implementation 

   /**
    * @see org.alfresco.web.app.context.IContextListener#contextUpdated()
    */
   public void contextUpdated()
   {
      if (logger.isDebugEnabled())
         logger.debug("Invalidating \"parapheur\" components...");

      dossiersNonTermines = null;
      corbeillesChildNumber = null;
      corbeillesLate = null;

      // clear the value for the list components - will cause re-bind to it's data and refresh
      if (this.parapheurRichList != null)
      {
         this.parapheurRichList.setValue(null);
      }

      if (this.corbeilleRichList != null)
      {
         this.corbeilleRichList.setValue(null);
         if (this.corbeilleRichList.getInitialSortColumn() == null)
         {
            // set the initial sort column and direction
            this.corbeilleRichList.setInitialSortColumn(
                  this.viewsConfig.getDefaultSortColumn(PAGE_NAME_CORBEILLE));
            this.corbeilleRichList.setInitialSortDescending(
                  this.viewsConfig.hasDescendingSort(PAGE_NAME_CORBEILLE));
         }
      }

      if (this.corbeilleVirtuelleRichList != null)
      {
         this.corbeilleVirtuelleRichList.setValue(null);
         if (this.corbeilleVirtuelleRichList.getInitialSortColumn() == null)
         {
            // set the initial sort column and direction
            this.corbeilleVirtuelleRichList.setInitialSortColumn(
                  this.viewsConfig.getDefaultSortColumn(PAGE_NAME_CORBEILLE));
            this.corbeilleVirtuelleRichList.setInitialSortDescending(
                  this.viewsConfig.hasDescendingSort(PAGE_NAME_CORBEILLE));
         }
      }

      if (this.dossierRichList != null)
      {
         this.dossierRichList.setValue(null);
      }

      if (this.parapheursRichList != null)
      {
         this.parapheursRichList.setValue(null);
      }

      // reset the lists
      this.corbeilles = null;
      this.dossiers = null;
      this.dossiersVirtuels = null;
      this.documents = null;
      this.parapheurs = null;

   }


   // ------------------------------------------------------------------------------
   // Navigation action event handlers 

   /**
    * Called when the user confirms they wish to delete a "dossier" space
    * 
    * @return The outcome
    */
   public String deleteDossierOK()
   {
      String outcomeOverride = "browse";

      // find out what the parent type of the node being deleted 
      Node node = this.browseBean.getActionSpace();
      ChildAssociationRef assoc = nodeService.getPrimaryParent(node.getNodeRef());
      if (assoc != null)
      {
         NodeRef parent = assoc.getParentRef();
         if (parapheurService.isCorbeille(parent))
         {
            outcomeOverride = "dossierDeleted";
         }
      }

      String outcome = null;
      Node node_space = this.browseBean.getActionSpace();
      if (node_space != null)
      {
         try
         {
            if (logger.isDebugEnabled())
               logger.debug("Trying to delete space: " + node_space.getId());

            nodeService.deleteNode(node_space.getNodeRef());

            // remove this node from the breadcrumb if required
            List<IBreadcrumbHandler> location = navigator.getLocation();
            IBreadcrumbHandler handler = location.get(location.size() - 1);
            if (handler instanceof BrowseBreadcrumbHandler)
            {
               // see if the current breadcrumb location is our node 
               if ( ((BrowseBreadcrumbHandler)handler).getNodeRef().equals(node_space.getNodeRef()) == true )
               {
                  location.remove(location.size() - 1);

                  // now work out which node to set the list to refresh against
                  if (location.size() != 0)
                  {
                     handler = location.get(location.size() - 1);
                     if (handler instanceof BrowseBreadcrumbHandler)
                     {
                        // change the current node Id
                        navigator.setCurrentNodeId(((BrowseBreadcrumbHandler)handler).getNodeRef().getId());
                     }
                     else
                     {
                        // TODO: shouldn't do this - but for now the user home dir is the root!
                        navigator.setCurrentNodeId(Application.getCurrentUser(FacesContext.getCurrentInstance()).getHomeSpaceId());
                     }
                  }
               }
            }

            // add a message to inform the user that the delete was OK 
            String statusMsg = MessageFormat.format(
                  Application.getMessage(FacesContext.getCurrentInstance(), MSG_ERROR_DELETE_FILE), 
                  new Object[]{node_space.getName()});
            Utils.addStatusMessage(FacesMessage.SEVERITY_INFO, statusMsg);

            // clear action context
            this.browseBean.setActionSpace(null);

            // setting the outcome will show the browse view again
            outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME + 
            AlfrescoNavigationHandler.OUTCOME_SEPARATOR + "browse";
         }
         catch (Throwable err)
         {
            Utils.addErrorMessage(Application.getMessage(
                  FacesContext.getCurrentInstance(), MSG_ERROR_DELETE_SPACE) + err.getMessage(), err);
         }
      }
      else
      {
         logger.warn("WARNING: deleteSpaceOK called without a current Space!");
      }

      // if the delete was successful update the outcome
      if (outcome != null)
      {
         //outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME +
         //          AlfrescoNavigationHandler.OUTCOME_SEPARATOR + outcomeOverride;
         outcome = outcomeOverride;
      }

      UIContextService.getInstance(FacesContext.getCurrentInstance()).notifyBeans();

      return outcome;
   }

   /**
    * Called when the user confirms they wish to delete a "document" space
    * 
    * @return The outcome
    */
   public String deleteDocumentOK()
   {

      String outcome = null;

      Node node = this.browseBean.getDocument();
      if (node != null)
      {
         try
         {
            if (logger.isDebugEnabled())
               logger.debug("Trying to delete content node: " + node.getId());

            nodeService.deleteNode(node.getNodeRef());

            // clear action context
            this.browseBean.setDocument(null);

            // setting the outcome will show the browse view again
            outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME +
            AlfrescoNavigationHandler.OUTCOME_SEPARATOR + "browse";
         }
         catch (Throwable err)
         {
            Utils.addErrorMessage(Application.getMessage(
                  FacesContext.getCurrentInstance(), "error_delete_file") + err.getMessage(), err);
         }
      }
      else
      {
         logger.warn("WARNING: deleteFileOK called without a current Document!");
      }

      // if the delete was successful update the outcome
      if (outcome != null)
      {
         // outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME;
         outcome = "documentDeleted";
      }

      return outcome;
   }

   /**
    * Change the current parapheur view mode based on user selection
    * 
    * @param event      ActionEvent
    */
   public void parapheurViewModeChanged(ActionEvent event)
   {
      UIModeList viewList = (UIModeList)event.getComponent();

      // get the view mode ID
      String viewMode = viewList.getValue().toString();

      // set the page size based on the style of display
      setParapheurPageSize(this.viewsConfig.getDefaultPageSize(PAGE_NAME_PARAPHEUR, 
            viewMode));
      if (logger.isDebugEnabled())
         logger.debug("Parapheur view page size set to: " + getParapheurPageSize());

      // push the view mode into the lists
      setParapheurViewMode(viewMode);
   }

   /**
    * Change the current corbeille view mode based on user selection
    * 
    * @param event      ActionEvent
    */
   public void corbeilleViewModeChanged(ActionEvent event)
   {
      UIModeList viewList = (UIModeList)event.getComponent();

      // get the view mode ID
      String viewMode = viewList.getValue().toString();

      // set the page size based on the style of display
      setCorbeillePageSize(this.viewsConfig.getDefaultPageSize(PAGE_NAME_CORBEILLE, 
            viewMode));
      if (logger.isDebugEnabled())
         logger.debug("Corbeille view page size set to: " + getCorbeillePageSize());

      // push the view mode into the lists
      setCorbeilleViewMode(viewMode);
   }

   //  ------------------------------------------------------------------------------
   // Listeners

   /**
    * Event handler called to reset a dossier
    * 
    * @param event The event that was triggered
    */
   public void raz(ActionEvent event)
   {
      UIActionLink link = (UIActionLink)event.getComponent();
      Map<String, String> params = link.getParameterMap();
      String id = params.get("id");

      NodeRef dossierRef = new NodeRef(Repository.getStoreRef(), id);
      NodeRef parentRef = parapheurService.getParentCorbeille(dossierRef);

      UserTransaction tx = null;
      try
      {
         tx = Repository.getUserTransaction(FacesContext.getCurrentInstance());

         tx.begin();
         parapheurService.reprendreDossier(dossierRef);
         tx.commit();
      }
      catch (Throwable e)
      {
         // rollback the transaction
         try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
         Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
               FacesContext.getCurrentInstance(), "error_generic"), e.getMessage()), e);
         logger.error(e.getMessage(), e);
      }

      // Mise à jour de l'interface
      UIContextService.getInstance(FacesContext.getCurrentInstance()).notifyBeans();
      this.browseBean.updateUILocation(parentRef);
      this.browseBean.updateUILocation(parapheurService.getParentParapheur(dossierRef));
      this.browseBean.updateUILocation(parapheurService.getParentCorbeille(dossierRef));
      this.browseBean.updateUILocation(dossierRef);
   }

   /**
    * Event handler called to get a dossier back
    * 
    * @param event The event that was triggered
    */
   public void recuperer(ActionEvent event)
   {
      UIActionLink link = (UIActionLink)event.getComponent();
      Map<String, String> params = link.getParameterMap();
      String id = params.get("id");

      NodeRef dossierRef = new NodeRef(Repository.getStoreRef(), id);
      NodeRef currentRef = parapheurService.getCorbeille(getParapheurCourant(),ParapheurModel.NAME_RECUPERABLES);

      UserTransaction tx = null;
      try
      {
         tx = Repository.getUserTransaction(FacesContext.getCurrentInstance());

         tx.begin();
         parapheurService.recupererDossier(dossierRef);
         tx.commit();
      }
      catch (Throwable e)
      {
         // rollback the transaction
         try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
         Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
               FacesContext.getCurrentInstance(), "error_generic"), e.getMessage()), e);
         logger.error(e.getMessage(), e);
      }

      // Mise à jour de l'interface
      UIContextService.getInstance(FacesContext.getCurrentInstance()).notifyBeans();
      NodeRef parentRef = nodeService.getPrimaryParent(currentRef).getParentRef();
      this.browseBean.updateUILocation(parentRef);
      parentRef = nodeService.getPrimaryParent(dossierRef).getParentRef();
      this.browseBean.updateUILocation(parentRef);
      this.browseBean.updateUILocation(dossierRef);
   }

   public void imprimerDossier(ActionEvent event)
   {
       // TODO
       logger.debug("imprimerDossier");
   }
   // ------------------------------------------------------------------------------
   // Property Resolvers

   public NodePropertyResolver resolverContent = new NodePropertyResolver() {
      public Object get(Node node) 
      {
         String content = null;

         // get the content property from the node and retrieve the 
         // full content as a string (obviously should only be used
         // for small amounts of content)
         ContentReader reader = contentService.getReader(node.getNodeRef(), 
               ContentModel.PROP_CONTENT);

         if (reader != null)
         {
            content = reader.getContentString();
         }

         return content;
      }
   };

   public NodePropertyResolver resolverChildNumber = new NodePropertyResolver() {
      @SuppressWarnings("unchecked")
      public Object get(Node node)
      {
         int noDossiers = getCorbeilleChildNumber(node.getNodeRef());
         return (noDossiers<0?0:noDossiers);
      }
   };

   public NodePropertyResolver resolverLate = new NodePropertyResolver() {
      public Object get(Node node) {

         boolean res = false;
         if (parapheurService.isDossier(node.getNodeRef()))
         {
            NodeRef nodeRef = node.getNodeRef();
            if (!parapheurService.isTermine(nodeRef)
                  && parapheurService.isEmis(nodeRef))
            {
               Date limit = (Date)nodeService.getProperty(nodeRef,ParapheurModel.PROP_DATE_LIMITE);
               if (limit != null)
               {
                  Date today = new Date();
                  if (today.after(limit))
                     res = true;
               }
            }
         }
         else
         {
            long startTime = 0;
            if (logger.isDebugEnabled())
               startTime = System.currentTimeMillis();
            res = getCorbeilleLate(node.getNodeRef());
            if (logger.isDebugEnabled())
            {
               long endTime = System.currentTimeMillis();
               logger.debug("Resolver Late : " + (endTime - startTime) + "ms");
            }
         }

         return new Boolean(res);
      }
   };

   public NodePropertyResolver resolverNotLate = new NodePropertyResolver() {
      public Object get(Node node) {
         Boolean res = !(Boolean)resolverLate.get(node);
         return res;
      }
   };

   public NodePropertyResolver resolverCurrent = new NodePropertyResolver() {
      public Object get(Node node) {
         long startTime = 0;
         if (logger.isDebugEnabled())
            startTime = System.currentTimeMillis();

         String res = "";
         NodeRef nodeRef = node.getNodeRef();

         if (parapheurService.isDossier(nodeRef))
         {
            NodeRef parapheurRef = parapheurService.getParentParapheur(nodeRef);
            res = parapheurService.getNomParapheur(parapheurRef);
            if (nodeService.hasAspect(nodeRef, ParapheurModel.ASPECT_SECRETARIAT))
               res += " (Secrétariat)";
            else
               res += " ("+parapheurService.getNomProprietaire(parapheurRef)+")";
         }
         if (logger.isDebugEnabled())
         {
            long endTime = System.currentTimeMillis();
            logger.debug("Resolver Current: " + (endTime - startTime) + "ms");
         }
         return res;
      }
   };

   public NodePropertyResolver resolverLimit = new NodePropertyResolver() {
      public Object get(Node node) {
         long startTime = 0;
         if (logger.isDebugEnabled())
            startTime = System.currentTimeMillis();

         String res = "";
         NodeRef nodeRef = node.getNodeRef();
         if (parapheurService.isDossier(nodeRef))
         {
            Date limit = (Date)nodeService.getProperty(nodeRef,ParapheurModel.PROP_DATE_LIMITE);
            if (limit != null)
            {
               SimpleDateFormat format = new SimpleDateFormat("dd/MM/y");
               res = format.format(limit);
            }
         }
         if (logger.isDebugEnabled())
         {
            long endTime = System.currentTimeMillis();
            logger.debug("Resolver Limit: " + (endTime - startTime) + "ms");
         }
         return res;
      }
   };

   public NodePropertyResolver resolverStep = new NodePropertyResolver()
   {
      public Object get(Node node)
      {
         long startTime = 0;
         if (logger.isDebugEnabled())
            startTime = System.currentTimeMillis();
         String res = Application.getMessage(FacesContext.getCurrentInstance(),"workflow_emettre");

         NodeRef nodeRef = node.getNodeRef();
         if (parapheurService.isDossier(nodeRef))
         {

            ArrayList<EtapeCircuit> circuit = (ArrayList<EtapeCircuit>) parapheurService.getCircuit(nodeRef);
            if (!circuit.isEmpty())
            {
               if (!parapheurService.isTermine(nodeRef))
               {
                  if (circuit.get(0).isApproved())
                  {
                     res = Application.getMessage(FacesContext.getCurrentInstance(),"workflow_viser");
                     if (circuit.get(circuit.size()-2).isApproved())
                     {
                        res = Application.getMessage(FacesContext.getCurrentInstance(),"workflow_signer");
                     }
                  }
               }
               else
               {
                  res = Application.getMessage(FacesContext.getCurrentInstance(),"workflow_raz");
               }
            }
         }
         if (logger.isDebugEnabled())
         {
            long endTime = System.currentTimeMillis();
            logger.debug("Resolver Step: " + (endTime - startTime) + "ms");
         }
         return res;
      }
   };

   public NodePropertyResolver resolverLu = new NodePropertyResolver()
   {
      public Object get(Node node)
      {
         return nodeService.hasAspect(node.getNodeRef(), ParapheurModel.ASPECT_LU);
      }
   };

   public NodePropertyResolver resolverVisuel = new NodePropertyResolver()
   {
      public Object get(Node node)
      {
         return nodeService.getProperty(node.getNodeRef(), ParapheurModel.PROP_VISUEL_PDF);
      }
   };

   public NodePropertyResolver resolverVisuelUrl = new NodePropertyResolver()
   {
      public Object get(Node node)
      {
	  String res = null;
	  NodeRef ref = node.getNodeRef();
	  String name = (String) nodeService.getProperty(ref, ContentModel.PROP_NAME);
	  res = DownloadContentServlet.generateBrowserURL(ref, (name != null?name:"Document")) 
	  + "?property=" + ParapheurModel.PROP_VISUEL_PDF;
	  return res;
      }
   };

   
   // ------------------------------------------------------------------------------
   // Private helpers

   /**
    * Initialise default values from client configuration
    */
   private void initFromClientConfig()
   {
      this.viewsConfig = (ViewsConfigElement)Application.getConfigService(
            FacesContext.getCurrentInstance()).getConfig("Views").
            getConfigElement(ViewsConfigElement.CONFIG_ELEMENT_ID);

      // get the defaults for the "parapheur" page
      this.parapheurViewMode = this.viewsConfig.getDefaultView(PAGE_NAME_PARAPHEUR);
      this.parapheurPageSize = this.viewsConfig.getDefaultPageSize(PAGE_NAME_PARAPHEUR,
            this.parapheurViewMode);

      // get the default for the "corbeille" page
      this.corbeilleViewMode = this.viewsConfig.getDefaultView(PAGE_NAME_CORBEILLE);
      this.corbeillePageSize = this.viewsConfig.getDefaultPageSize(PAGE_NAME_CORBEILLE, 
            this.corbeilleViewMode);

      // get the default for the "dossier" page
      this.dossierViewMode = this.viewsConfig.getDefaultView(PAGE_NAME_DOSSIER);
      this.dossierPageSize = this.viewsConfig.getDefaultPageSize(PAGE_NAME_DOSSIER, 
            this.dossierViewMode);

      if (logger.isDebugEnabled())
      {
         logger.debug("Set default \"parapheur\" view mode to: " + this.parapheurViewMode);
         logger.debug("Set default \"parapheur\" page size to: " + this.parapheurPageSize);
         logger.debug("Set default \"corbeille\" view mode to: " + this.corbeilleViewMode);
         logger.debug("Set default \"corbeille\" page size to: " + this.corbeillePageSize);
         logger.debug("Set default \"dossier\" view mode to: " + this.dossierViewMode);
         logger.debug("Set default \"dossier\" page size to: " + this.dossierPageSize);
      }
   }
   //------------------------------------------------------------------------------
   // Inner classes

   /**
    * Class to handle breadcrumb interaction for Browse pages
    */
   private class BrowseBreadcrumbHandler implements IRepoBreadcrumbHandler
   {
      private static final long serialVersionUID = 3833183653173016630L;

      /**
       * Constructor
       * 
       * @param NodeRef    The NodeRef for this browse navigation element
       * @param label      Element label
       */
      public BrowseBreadcrumbHandler(NodeRef nodeRef, String label)
      {
         this.label = label;
         this.nodeRef = nodeRef;
      }

      /**
       * @see java.lang.Object#toString()
       */
      public String toString()
      {
         return this.label;
      }

      /**
       * @see org.alfresco.web.ui.common.component.IBreadcrumbHandler#navigationOutcome(org.alfresco.web.ui.common.component.UIBreadcrumb)
       */
      @SuppressWarnings("unchecked")
      public String navigationOutcome(UIBreadcrumb breadcrumb)
      {
         // All browse breadcrumb element relate to a Node Id - when selected we
         // set the current node id
         navigator.setCurrentNodeId(this.nodeRef.getId());
         navigator.setLocation( (List)breadcrumb.getValue() );

         // setup the dispatch context
         navigator.setupDispatchContext(new Node(this.nodeRef));

         // return to browse page if required
         return (isViewCurrent() ? null : "browse"); 
      }

      public NodeRef getNodeRef()
      {
         return this.nodeRef;
      }

      private NodeRef nodeRef;
      private String label;
   }
   /**
    * @return whether the current View ID is the "browse" screen
    */
   private boolean isViewCurrent()
   {
      return (FacesContext.getCurrentInstance().getViewRoot().getViewId().equals(BrowseBean.BROWSE_VIEW_ID));
   }


	public void areaChanged()
	{
		// TODO Auto-generated method stub
		
	}


	public void spaceChanged()
	{
		// TODO Auto-generated method stub
		
	}

}
