/*
 * 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.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;

import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.search.LimitBy;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.ResultSetRow;
import org.alfresco.service.cmr.search.SearchParameters;
import org.alfresco.service.cmr.search.SearchService;
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.ui.common.Utils;
import org.alfresco.web.ui.common.component.data.UIRichList;
import org.alfresco.web.ui.repo.component.UISimpleSearch;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.atolcd.parapheur.model.ParapheurModel;
import com.atolcd.parapheur.repo.ParapheurService;
import org.alfresco.web.bean.search.SearchContext;

public class ParapheurSearchBean implements IContextListener
{
   private static Log logger = LogFactory.getLog(ParapheurSearchBean.class);
   
   private NavigationBean navigator;
   private BrowseBean browseBean;
   private ParapheurBean parapheurBean;
   private SearchService searchService;
   private NodeService nodeService;
   private ParapheurService parapheurService;
   private ContentService contentService;
   
   private List<Node> dossiersAccessibles;
   private List<Node> dossiersVisibles;
   private List<Node> dossiersArchives;
   
   protected UIRichList dossiersAccessiblesRichList;
   protected UIRichList dossiersVisiblesRichList;
   protected UIRichList dossiersArchivesRichList;

   
   public ParapheurSearchBean()
   {
      UIContextService.getInstance(FacesContext.getCurrentInstance()).registerBean(this);
   }
   
   /**
    * @param navigator The navigator to set.
    */
   public void setNavigator(NavigationBean navigator)
   {
      this.navigator = navigator;
   }
   /**
    * @param browseBean The browseBean to set.
    */
   public void setBrowseBean(BrowseBean browseBean)
   {
      this.browseBean = browseBean;
   }

   /**
    * @param parapheurBean The parapheurBean to set.
    */
   public void setParapheurBean(ParapheurBean parapheurBean)
   {
      this.parapheurBean = parapheurBean;
   }
   /**
    * @param searchService The searchService to set.
    */
   public void setSearchService(SearchService searchService)
   {
      this.searchService = searchService;
   }

   /**
    * @param nodeService The nodeService to set.
    */
   public void setNodeService(NodeService nodeService)
   {
      this.nodeService = nodeService;
   }
   /**
    * @param parapheurService The parapheurService to set.
    */
   public void setParapheurService(ParapheurService parapheurService)
   {
      this.parapheurService = parapheurService;
   }
   /**
    * @param contentService The contentService to set.
    */
   public void setContentService(ContentService contentService)
   {
      this.contentService = contentService;
   }

   /**
    * @return Returns the dossiersAccessiblesRichList.
    */
   public UIRichList getDossiersAccessiblesRichList()
   {
      return dossiersAccessiblesRichList;
   }

   /**
    * @param dossiersAccessiblesRichList The dossiersAccessiblesRichList to set.
    */
   public void setDossiersAccessiblesRichList(
         UIRichList dossiersAccessiblesRichList)
   {
      this.dossiersAccessiblesRichList = dossiersAccessiblesRichList;
   }

   /**
    * @return Returns the dossiersArchivesRichList.
    */
   public UIRichList getDossiersArchivesRichList()
   {
      return dossiersArchivesRichList;
   }

   /**
    * @param dossiersArchivesRichList The dossiersArchivesRichList to set.
    */
   public void setDossiersArchivesRichList(UIRichList dossiersArchivesRichList)
   {
      this.dossiersArchivesRichList = dossiersArchivesRichList;
   }

   /**
    * @return Returns the dossiersVisiblesRichList.
    */
   public UIRichList getDossiersVisiblesRichList()
   {
      return dossiersVisiblesRichList;
   }

   /**
    * @param dossiersVisiblesRichList The dossiersVisiblesRichList to set.
    */
   public void setDossiersVisiblesRichList(UIRichList dossiersVisiblesRichList)
   {
      this.dossiersVisiblesRichList = dossiersVisiblesRichList;
   }

   /**
    * @return Returns the dossiersAccessibles.
    */
   public List<Node> getDossiersAccessibles()
   {
      if (dossiersAccessibles == null)
         getNodes();
      
      return dossiersAccessibles;
   }

   /**
    * @return Returns the dossiersArchives.
    */
   public List<Node> getDossiersArchives()
   {
      if (dossiersArchives == null)
         getNodes();
      return dossiersArchives;
   }

   /**
    * @return Returns the dossiersVisibles.
    */
   public List<Node> getDossiersVisibles()
   {
      if (dossiersVisibles == null)
         getNodes();
      return dossiersVisibles;
   }

   private void getNodes()
   {
      this.dossiersAccessibles = Collections.<Node>emptyList();
      this.dossiersArchives = Collections.<Node>emptyList();
      this.dossiersVisibles = Collections.<Node>emptyList();
      
      if (this.navigator.getSearchContext() != null)
      {
         SearchContext searchContext = navigator.getSearchContext();
         
         // get the searcher object to build the query
         String query = searchContext.buildQuery(browseBean.getMinimumSearchLength());
         if (query == null)
         {
            // failed to build a valid query, the user probably did not enter the
            // minimum text required to construct a valid search
            Utils.addErrorMessage(MessageFormat.format(Application.getMessage(FacesContext.getCurrentInstance(), "search_minimum"),
                  new Object[] {browseBean.getMinimumSearchLength()}));
            return;
         }
         
         // Limit search to the first 100 matches
         SearchParameters sp = new SearchParameters();
         sp.setLanguage(SearchService.LANGUAGE_LUCENE);
         sp.setQuery(query);
         sp.addStore(Repository.getStoreRef());
         
         int searchLimit = Application.getClientConfig(FacesContext.getCurrentInstance()).getSearchMaxResults();
         if(searchLimit > 0)
         {
            sp.setLimitBy(LimitBy.FINAL_SIZE);
            sp.setLimit(searchLimit);
         }
         
         ResultSet results = searchService.query(sp);
         if (logger.isDebugEnabled())
            logger.debug("Search results returned: " + results.length());
         
         this.dossiersAccessibles = new ArrayList<Node>(results.length());
         this.dossiersArchives = new ArrayList<Node>(results.length());
         this.dossiersVisibles = new ArrayList<Node>(results.length());
         String userName = navigator.getCurrentUser().getUserName();
         
         if (results.length() != 0)
         {
            for (ResultSetRow row: results)
            {
               NodeRef nodeRef = row.getNodeRef();
               
               if (nodeService.exists(nodeRef))
               {
                  MapNode node = new MapNode(nodeRef, nodeService, true);
                  
                  node.addPropertyResolver("url", browseBean.resolverUrl);
                  node.addPropertyResolver("webdavUrl", browseBean.resolverWebdavUrl);
                  node.addPropertyResolver("cifsPath", browseBean.resolverCifsPath);
                  node.addPropertyResolver("fileType16", browseBean.resolverFileType16);
                  node.addPropertyResolver("fileType32", browseBean.resolverFileType32);
                  node.addPropertyResolver("size", browseBean.resolverSize);
                  
                  node.addPropertyResolver("icon", browseBean.resolverSpaceIcon);
                  node.addPropertyResolver("smallIcon", browseBean.resolverSmallIcon);
                  node.addPropertyResolver("late",parapheurBean.resolverLate);
                  node.addPropertyResolver("notLate",parapheurBean.resolverNotLate);
                  node.addPropertyResolver("step",parapheurBean.resolverStep);
                  
                  if (parapheurService.isDossier(nodeRef))
                  {
                     if (! parapheurService.isTermine(nodeRef))
                     {
                        if (parapheurService.isActeurCourant(nodeRef, userName))
                           if (!nodeExistInList(this.dossiersAccessibles, node))
                               this.dossiersAccessibles.add(node);
                        else
                           if (!nodeExistInList(this.dossiersVisibles, node))
                      	       this.dossiersVisibles.add(node);
                     }
                     else
                     {
                        if (parapheurService.getEmetteur(nodeRef).equals(parapheurBean.getParapheurCourant()))
                           if (!nodeExistInList(this.dossiersAccessibles, node))
                               this.dossiersAccessibles.add(node);
                        else
                           if (!nodeExistInList(this.dossiersVisibles, node))
                      	       this.dossiersVisibles.add(node);
                     }
                  }
                  else if (ContentModel.TYPE_CONTENT.equals(nodeService.getType(nodeRef)))
                  {
                     NodeRef parentRef = nodeService.getPrimaryParent(nodeRef).getParentRef();  // attention ça claque si pas autorisé!?!?
                     String parentName = (String)nodeService.getProperty(parentRef, ContentModel.PROP_NAME);
                     
                     if (parentName != null && parentName.equals("Archives"))
                     {
                        ContentReader reader = contentService.getReader(node.getNodeRef(), ContentModel.PROP_CONTENT);
                        if (MimetypeMap.MIMETYPE_PDF.equals(reader.getMimetype()))
                        {
                           node.addPropertyResolver("signed", this.resolverSigned);
                           if (this.nodeService.hasAspect(nodeRef, ParapheurModel.ASPECT_SIGNED))
                           {
                              node.addPropertyResolver("mainDoc", this.resolverMainDoc);
                              node.addPropertyResolver("sig", this.resolverSig);
                           }
                           this.dossiersArchives.add(node);
                        }
                     }
                     else if (ParapheurModel.TYPE_DOSSIER.equals(nodeService.getType(parentRef)))
                     {
                        node = new MapNode(parentRef, nodeService, true);
                        
                        node.addPropertyResolver("url", browseBean.resolverUrl);
                        node.addPropertyResolver("webdavUrl", browseBean.resolverWebdavUrl);
                        node.addPropertyResolver("cifsPath", browseBean.resolverCifsPath);
                        node.addPropertyResolver("fileType16", browseBean.resolverFileType16);
                        node.addPropertyResolver("fileType32", browseBean.resolverFileType32);
                        node.addPropertyResolver("size", browseBean.resolverSize);
                        
                        node.addPropertyResolver("icon", browseBean.resolverSpaceIcon);
                        node.addPropertyResolver("smallIcon", browseBean.resolverSmallIcon);
                        node.addPropertyResolver("late",parapheurBean.resolverLate);
                        node.addPropertyResolver("notLate",parapheurBean.resolverNotLate);
                        node.addPropertyResolver("step",parapheurBean.resolverStep);
                        
                        if (! parapheurService.isTermine(parentRef))
                        {
                           if (parapheurService.isActeurCourant(parentRef, userName))
                              if (!nodeExistInList(this.dossiersAccessibles, node))
                           	  this.dossiersAccessibles.add(node);
                           else
                           {
                              if (!nodeExistInList(this.dossiersVisibles, node))
                        	  this.dossiersVisibles.add(node);
                           }
                        }
                        else
                        {
                           if (parapheurService.getEmetteur(parentRef).equals(parapheurBean.getParapheurCourant()))
                              if (!nodeExistInList(this.dossiersAccessibles, node))
                          	  this.dossiersAccessibles.add(node);
                           else
                              if (!nodeExistInList(this.dossiersVisibles, node))
                         	  this.dossiersVisibles.add(node);
                        }
                        
                     }
                  }
               }
               else
               {
                  if (logger.isWarnEnabled())
                     logger.warn("Missing object returned from search indexes: id = " + nodeRef + " search query: " + query);
               }
            }
            
            results.close();
         }
      }
   }
   
   private boolean nodeExistInList(List<Node> list, Node node)
   {
       Iterator<Node> it = list.iterator();
       String id = node.getId();
       for (Iterator<Node> ie=it; ie.hasNext();)
       {
	   Node lnode = ie.next();
	   if (lnode.getId().equalsIgnoreCase(id))
	   {
	       if (logger.isDebugEnabled())
		   logger.debug("SearchEngine: node '"+id+"' already exists in list!");
	       return true;
	   }
       }
       return false;
   }
   
   public void search(ActionEvent event)
   {
      UISimpleSearch search = (UISimpleSearch)event.getComponent();
      this.navigator.setSearchContext(search.getSearchContext());
      
      FacesContext fc = FacesContext.getCurrentInstance();
      fc.getApplication().getNavigationHandler().handleNavigation(fc, null, "search");
   }
   
   public void contextUpdated()
   {
      if (logger.isDebugEnabled())
         logger.debug("Invalidating \"parapheur search\" components...");
     
      if (this.dossiersAccessiblesRichList != null)
      {
         this.dossiersAccessiblesRichList.setValue(null);
      }
      if (this.dossiersVisiblesRichList != null)
      {
         this.dossiersVisiblesRichList.setValue(null);
      }
      if (this.dossiersArchivesRichList != null)
      {
         this.dossiersArchivesRichList.setValue(null);
      }
      
      // reset the lists
      this.dossiersAccessibles = null;
      this.dossiersVisibles = null;
      this.dossiersArchives = null;
   }
   
   public NodePropertyResolver resolverMainDoc = new NodePropertyResolver()
   {
      public Object get(Node node)
      {
         String res = null;
         if (node.hasAspect(ParapheurModel.ASPECT_SIGNED))
         {
            NodeRef ref = node.getNodeRef();
            String name = (String) nodeService.getProperty(ref, ParapheurModel.PROP_ORIGINAL_NAME);
            res = DownloadContentServlet.generateBrowserURL(ref, (name != null?name:"Document")) 
                  + "?property=" + ParapheurModel.PROP_ORIGINAL;
         }
         return res;
         /*
         String docName = node.getName() + ".old";
         NodeRef docRef = null;
         NodeRef parentRef = nodeService.getPrimaryParent(node.getNodeRef()).getParentRef();
         List<ChildAssociationRef> children = nodeService.getChildAssocs(parentRef);
         
         for (ChildAssociationRef child : children)
         {
            NodeRef childRef = child.getChildRef();
            String name = (String)nodeService.getProperty(childRef, ContentModel.PROP_NAME);
            if (docName.equals(name))
            {
               docRef = childRef;
               break;
            }
         }
         
         String res = null;
         if (docRef != null)
         {
            res = DownloadContentServlet.generateBrowserURL(docRef, docName);
         }
         return res;
         */
      }
   };
   
   public NodePropertyResolver resolverSig = new NodePropertyResolver()
   {
      public Object get(Node node)
      {
         String res = null;
         if (node.hasAspect(ParapheurModel.ASPECT_SIGNED))
         {
            NodeRef ref = node.getNodeRef();
            String name = (String) nodeService.getProperty(ref, ParapheurModel.PROP_ORIGINAL_NAME);
            res = DownloadContentServlet.generateBrowserURL(ref, (name != null?name + ".p7s":"Signature")) 
                  + "?property=" + ParapheurModel.PROP_SIG;
         }
         return res;
         /*
         String docName = node.getName() + ".p7s";
         NodeRef docRef = null;
         NodeRef parentRef = nodeService.getPrimaryParent(node.getNodeRef()).getParentRef();
         List<ChildAssociationRef> children = nodeService.getChildAssocs(parentRef);
         
         for (ChildAssociationRef child : children)
         {
            NodeRef childRef = child.getChildRef();
            String name = (String)nodeService.getProperty(childRef, ContentModel.PROP_NAME);
            if (docName.equals(name))
            {
               docRef = childRef;
               break;
            }
         }
         
         String res = null;
         if (docRef != null)
         {
            res = DownloadContentServlet.generateBrowserURL(docRef, "Signature.p7s");
         }
         
         return res;
         */
      }
   };
   
   public NodePropertyResolver resolverSigned = new NodePropertyResolver()
   {
      public Object get(Node node)
      {
         return node.hasAspect(ParapheurModel.ASPECT_SIGNED);
      }
   };


	public void areaChanged()
	{
		// TODO Auto-generated method stub
		
	}

	public void spaceChanged()
	{
		// TODO Auto-generated method stub
		
	}
}
