/*
 * 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.repo.patch;

import java.util.List;
import java.util.Properties;

import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
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.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.namespace.NamespaceService;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;

import com.atolcd.parapheur.model.ParapheurModel;

public class ParapheurPatch implements InitializingBean
{
   private static Logger logger = Logger.getLogger(ParapheurPatch.class);
   
   private static NodeService internalNodeService;
   private static SearchService internalSearchService;
   private static NamespaceService internalNamespaceService;
   private static PermissionService internalPermissionService;
   private static ContentService internalContentService;
   private static PersonService internalPersonService;
   private static Properties configuration;
   
   /**
    * @param internalSearchService The internalSearchService to set.
    */
   public void setInternalSearchService(SearchService aSearchService)
   {
      internalSearchService = aSearchService;
   }

   /**
    * @param internalNodeService The internalNodeService to set.
    */
   public void setInternalNodeService(NodeService aNodeService)
   {
      internalNodeService = aNodeService;
   }

   /**
    * @param internalNamespaceService The internalNamespaceService to set.
    */
   public void setInternalNamespaceService(
         NamespaceService aNamespaceService)
   {
      internalNamespaceService = aNamespaceService;
   }

   /**
    * @param internalPermissionService The internalPermissionService to set.
    */
   public void setInternalPermissionService(
         PermissionService aPermissionService)
   {
      internalPermissionService = aPermissionService;
   }

   /**
    * @param internalContentService The internalContentService to set.
    */
   public void setInternalContentService(ContentService aContentService)
   {
      internalContentService = aContentService;
   }
   
   /**
    * @param internalPersonService The internalPersonService to set.
    */
   public void setInternalPersonService(PersonService aPersonService)
	{
   	internalPersonService = aPersonService;
	}

	/**
    * @param configuration The configuration to set.
    */
   public void setConfiguration(Properties aConfiguration)
   {
      configuration = aConfiguration;
   }

   public void afterPropertiesSet() throws Exception
   {
      Assert.notNull(internalNodeService, "There must be a node service");
      Assert.notNull(internalSearchService, "There must be a search service");
      Assert.notNull(internalNamespaceService, "There must be a namespace service");
      Assert.notNull(internalPermissionService, "There must be a permission service");
      Assert.notNull(internalContentService, "There must be a content service");
      Assert.notNull(internalPersonService, "There must be a person service");
      Assert.notNull(configuration, "There must be a configuration");

      RunAsWork<Object> patchWork = new RunAsWork<Object>()
      {
         public Object doWork()
         {
            patchArchivesFolderPermissions();
            patchArchivesFormat();
            patchArchivesPermissions();
            patchAdminHomeFolder();
            return null;
         }
      };
      
      AuthenticationUtil.runAs(patchWork, "System");
   }
   
   private static NodeRef getArchivesFolder()
   {
      List<NodeRef> results = null;
      String xpath = configuration.getProperty("spaces.company_home.childname") + "/" +
                     configuration.getProperty("spaces.archives.childname");
      
      // Récupération du répertoire des archives
      results = internalSearchService.selectNodes(
                internalNodeService.getRootNode(new StoreRef(configuration.getProperty("spaces.store"))),
                xpath,
                null,
                internalNamespaceService,
                false);
      
      if (results == null || results.size() != 1)
      {
         throw new RuntimeException("Il n'y a pas de dossier \"Archives\"");
      }
      
      return results.get(0);
   }
   
   private static NodeRef getParapheursFolder()
   {
      List<NodeRef> results = null;
      String xpath = configuration.getProperty("spaces.company_home.childname") + "/" +
                     configuration.getProperty("spaces.parapheurs.childname");
      
      // Récupération du répertoire des archives
      results = internalSearchService.selectNodes(
                internalNodeService.getRootNode(new StoreRef(configuration.getProperty("spaces.store"))),
                xpath,
                null,
                internalNamespaceService,
                false);
      
      if (results == null || results.size() != 1)
      {
         throw new RuntimeException("Il n'y a pas de dossier \"Parapheurs\"");
      }
      
      return results.get(0);
   }
   
   private static void patchArchivesFolderPermissions()
   {
      logger.info("Applying parapheur patch 1 : archives folder permissions");
      
      NodeRef archivesRef = getArchivesFolder();
      internalPermissionService.setInheritParentPermissions(archivesRef, false);
      internalPermissionService.setPermission(archivesRef, "GROUP_EVERYONE", PermissionService.CONTRIBUTOR,true);
      
      logger.info("Applying parapheur patch 1 : done");
   }
   
   private static void patchArchivesFormat()
   {
      logger.info("Applying parapheur patch 2 : archives format");
      
      NodeRef archivesRef = getArchivesFolder();
      List<ChildAssociationRef> children = internalNodeService.getChildAssocs(archivesRef);
      for (ChildAssociationRef child : children)
      {
         NodeRef archive = child.getChildRef();
         if (internalNodeService.exists(archive)
          && ContentModel.TYPE_CONTENT.equals(internalNodeService.getType(archive))
          && !internalNodeService.hasAspect(archive, ParapheurModel.ASPECT_SIGNED))
         {
            ContentReader reader = internalContentService.getReader(archive, ContentModel.PROP_CONTENT);
            if (MimetypeMap.MIMETYPE_PDF.equals(reader.getMimetype()))
            {
               String name = (String)internalNodeService.getProperty(archive, ContentModel.PROP_NAME);
               NodeRef docRef = null,
                       sigRef = null;
               for (ChildAssociationRef tmpChild : children)
               {
                  if (docRef != null && sigRef != null)
                     break;
                  else
                  {
                     NodeRef tmpChildRef = tmpChild.getChildRef();
                     if (internalNodeService.exists(tmpChildRef))
                     {
                        String tmpName = (String) internalNodeService.getProperty(tmpChildRef, ContentModel.PROP_NAME);
                        if (tmpName.equals(name+".old"))
                        {
                           docRef = tmpChildRef;
                        }
                        else if (tmpName.equals(name+".p7s"))
                        {
                           sigRef = tmpChildRef;
                        }
                     }
                  }
               }
               if (docRef != null && sigRef != null)
               {
                  internalNodeService.addAspect(archive, ParapheurModel.ASPECT_SIGNED, null);
                  
                  String originalName = "Document original";
                  internalNodeService.setProperty(archive, ParapheurModel.PROP_ORIGINAL_NAME, originalName);
                  
                  ContentReader tmpReader = internalContentService.getReader(docRef, ContentModel.PROP_CONTENT);
                  ContentWriter tmpWriter = internalContentService.getWriter(archive, ParapheurModel.PROP_ORIGINAL, true);
                  tmpWriter.setEncoding(tmpReader.getEncoding());
                  tmpWriter.setMimetype(tmpReader.getMimetype());
                  tmpWriter.putContent(tmpReader);
                  
                  tmpReader = internalContentService.getReader(sigRef, ContentModel.PROP_CONTENT);
                  tmpWriter = internalContentService.getWriter(archive, ParapheurModel.PROP_SIG, true);
                  tmpWriter.setEncoding(tmpReader.getEncoding());
                  tmpWriter.setMimetype(tmpReader.getMimetype());
                  tmpWriter.putContent(tmpReader);
                  
                  internalNodeService.deleteNode(docRef);
                  internalNodeService.deleteNode(sigRef);
               }
            }
         }
      }
      
      logger.info("Applying parapheur patch 2 : done");
   }
   
   private static void patchArchivesPermissions()
   {
      logger.info("Applying parapheur patch 3 : archives permissions");
      
      NodeRef archivesRef = getArchivesFolder();
      List<ChildAssociationRef> children = internalNodeService.getChildAssocs(archivesRef);
      for (ChildAssociationRef child : children)
      {
         NodeRef archive = child.getChildRef();
         if (internalNodeService.exists(archive)
          && internalPermissionService.getAllSetPermissions(archive).isEmpty())
         {
            String creator = (String)internalNodeService.getProperty(archive, ContentModel.PROP_CREATOR);
            internalPermissionService.setPermission(archivesRef, creator, PermissionService.READ, true);
         }
      }
      
      logger.info("Applying parapheur patch 3 : done");
   }

   private static void patchAdminHomeFolder()
   {
      logger.info("Applying parapheur patch 4 : Admin homefolder");
      
      NodeRef parapheursRef = getParapheursFolder();
      NodeRef adminRef = internalPersonService.getPerson("admin");
      internalNodeService.setProperty(adminRef, ContentModel.PROP_HOMEFOLDER, parapheursRef);
      
      logger.info("Applying parapheur patch 4 : done");
   }

}
