package it.mytria.portal.util;


import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.jahia.data.containers.JahiaContainer;
import org.jahia.data.containers.JahiaContainerDefinition;

import org.jahia.data.fields.JahiaFieldDefinition;

import org.jahia.exceptions.JahiaException;
import org.jahia.params.ParamBean;

import org.jahia.registries.ServicesRegistry;

import org.jahia.services.acl.JahiaBaseACL;

import org.jahia.services.fields.ContentBigTextField;
import org.jahia.services.fields.ContentPageField;
import org.jahia.services.fields.ContentSmallTextField;

import org.jahia.services.pages.ContentPage;
import org.jahia.services.pages.JahiaPage;
import org.jahia.services.pages.JahiaPageDefinition;
import org.jahia.services.pages.JahiaPageService;
import org.jahia.services.pages.PageProperty;

import org.jahia.services.version.ContentObjectEntryState;
import org.jahia.services.version.EntryLoadRequest;
import org.jahia.services.version.EntrySaveRequest;
import org.jahia.services.version.EntryStateable;
import org.jahia.services.webdav.DAVFileAccess;

import it.mytria.portal.config.VirtualSiteManager;
import it.mytria.portal.config.bo.Site;
import it.mytria.portal.wsproducer.erpwebdav.path.DirectorySelectorRules;



public class DynamicCreationUtil {
    
    
    private static final String className = DynamicCreationUtil.class.getName();

    private static final Log log = LogFactory.getLog( DynamicCreationUtil.class );    
    
    
        
    /** Create a page field with the default language passed as parameter, than translate its title using the ones stored in
     *  parameterer localizedValuesMap. Accept no null parameters.
     * @param paramBean  
     * @param jahiaPage the page that owns the containerList wrapping the container where the jahiaPage will be created
     * @param site tria view on a specific virtual site
     * @param container the container where the jahiaPageField will be added
     * @param templateName the name of the template that will be used by the page wrapped in jahiaPageField
     * @param fieldName the name of the jahiaPageField
     * @param localizedValuesMap a map storing page title translations
     * @param defaultLanguage the default language; see java.util.Locale for knowing which values to use
     * @return a ContentPageField wrapping a jahiaPage
     * @throws JahiaException for every possible exception while using jahia core functionalities 
     */
    public static ContentPageField createPageField(ParamBean paramBean, JahiaPage jahiaPage, Site site, JahiaContainer container,
            																			 String templateName, String fieldName, Map localizedValuesMap, String defaultLanguage)
            throws JahiaException {

        log.debug(className + ".createPageField, entered");

        JahiaContainerDefinition ctnDef = container.getDefinition();
        JahiaFieldDefinition fieldDef = ctnDef.findFieldInStructure(fieldName, paramBean.getPage().getPageTemplateID());

        JahiaPageDefinition theTemplate = ServicesRegistry.getInstance().getJahiaPageTemplateService()
                                                                        .lookupPageTemplateByName( templateName, paramBean.getSiteID() );

        log.debug(className + ".createPageField, template found is [" + theTemplate.getName() + "]");

        Collection languages = site.getLanguagesMap().values();

        // TODO Manage inexistence of default language, bring in it siteconfig.xml
        String defaultValue = (String) localizedValuesMap.get( defaultLanguage );

        log.debug(className + ".createPageField, default value is [" + defaultValue + "]");

        // we need a defautl locale for page creation
        Locale defaultLocale = new Locale ( defaultLanguage );
        
        // stores temporary original paramBean locale
        Locale paramBeanOriginalLocale = paramBean.getLocale();
        // a try just for using a finally where we set back the original locale of the paramBean
        try{
            paramBean.changeLanguage( defaultLocale );
        
            JahiaBaseACL acl = new JahiaBaseACL();
            acl.create( container.getAclID() );
            
            log.debug(className + " - createPageField, entryLoadRequest is [" + paramBean.getEntryLoadRequest() + "]");

            // this field will be created as a child of the argument 'jahiaPage' and will use as template the argument 'templateName'
            ContentPageField contentPageField = ContentPageField.createNewPage( site.getId(), 
                                                                            		jahiaPage.getID(), 
                                                                            		container.getID(), 
                                                                            		fieldDef.getID(), 
                                                                            		container.getAclID(), 
                                                                            		acl.getID(), 
                                                                            		defaultValue, 
                                                                            		theTemplate.getID(), 
                                                                            		paramBean.getUser().getUserKey(), 
                                                                            		paramBean);

            // only for debug purpose
            // need to change locale on paramBean as pageField are always shared
            if (log.isDebugEnabled()) {

                paramBean.changeLanguage( VirtualSiteManager.SHARED_LOCALE );

                log.debug(className + ".createPageField, created contentPageField [" + contentPageField.getID() + "] with value ["
                    		        	+ contentPageField.getValue( paramBean ) + "]");

                paramBean.changeLanguage( defaultLocale );

            }
            // end debug purpose

            ContentPage contentPage = contentPageField.getContentPage( paramBean, true );

            EntryStateable defaultEntryStateable = new ContentObjectEntryState( 2, 0, defaultLanguage );

            // title translation part
            // cycle on every language setting descriptions except for default language ( the one used when page was created, see above )
            Iterator siteLanguageIterator = languages.iterator();
            String localeString;
            String tmpValue;
            EntryStateable localizedEntryStateable;

            ArrayList localizedList = new ArrayList( 1 );

            EntryLoadRequest entryLoadRequest = EntryLoadRequest.STAGED;

          		while (siteLanguageIterator.hasNext()) {

          		    localeString = (String) siteLanguageIterator.next();

          		    log.debug(className + ".createPageField, start copy page for language [" + localeString + "]");

          		    if ( localeString.equals( defaultLanguage )) {
          		        // the field is created by default in defaultLanguage, so we silently continue as we already have this translation
          		        continue;
          		    }

          		    tmpValue = (String) localizedValuesMap.get( localeString );

          		    // so we don't have an erp translation in our erpCategory, rollback to default english value
          		    if (tmpValue == null) {
          		        tmpValue = defaultValue;
          		        log.debug(className + ".createPageField, no translation for site language [" + localeString + "], using default value [" + tmpValue + "]");
          		    }

          		    log.debug(className + ".createPageField, translated title is [" + tmpValue + "]");

          		    localizedEntryStateable = new ContentObjectEntryState( 2, 0, localeString );

          		    contentPage.copyEntry( defaultEntryStateable, localizedEntryStateable );

          		    localizedList.clear();

          		    localizedList.add( new Locale( localeString ) );

          		    entryLoadRequest.setLocales( localizedList );

          		    contentPage.setTitle( localeString, tmpValue, entryLoadRequest );

          		}

          	// commit all changes to db
          	contentPage.commitChanges( true );

          	log.debug(className + ".createPageField, end");

            return contentPageField;

        
        }finally{
          
            paramBean.changeLanguage( paramBeanOriginalLocale );
          
        }
    
 
  }
    
    
    
    
    /** Create a small text with field with the default language passed as parameter, than translatesa its value using the ones stored in
     *  parameterer localizedValuesMap. Accept no null parameters.
     * @param paramBean  
     * @param jahiaPage the page that owns the containerList wrapping the container where this field will be created
     * @param site tria view on a specific virtual site
     * @param container the container where the jahiaSmalltextField will be added
     * @param fieldName the name of the smnallTextField
     * @param localizedValuesMap a map storing page title translations
     * @param defaultLanguage the default language; see java.util.Locale for knowing which values to use
     * @throws JahiaException for every possible exception while using jahia core functionalities 
     */
    public static ContentSmallTextField createSmallTextField( ParamBean paramBean, JahiaPage jahiaPage, Site site, JahiaContainer container,
            																									String fieldName, Map localizedValuesMap, String defaultLanguage)
            throws JahiaException {

        JahiaContainerDefinition ctnDef = container.getDefinition();
        JahiaFieldDefinition fieldDef = ctnDef.findFieldInStructure( fieldName, jahiaPage.getPageTemplateID() );

        log.debug(className + ".createSmallTextSharedFieldCode, field definition is [" + fieldDef.getName() + "]");

        EntrySaveRequest entrySaveRequest = new EntrySaveRequest( paramBean.getUser() );

        Collection languages = site.getLanguagesMap().values();

        String defaultValue = (String) localizedValuesMap.get( defaultLanguage );        
        
        // stores temporary original paramBean locale
        Locale paramBeanOriginalLocale = paramBean.getLocale();
        // a try just for using a finally where we set back the original locale of the paramBean        
        try{
        
            paramBean.changeLanguage( new Locale ( defaultLanguage ) );

            // start creating field with the default locale, which is always english
            ContentSmallTextField contentSmallTextField = ContentSmallTextField.createSmallText( paramBean.getSiteID(), 
                                                                                             		 jahiaPage.getID(),
                                                                                             		 container.getID(), 
                                                                                             		 fieldDef.getID(), 
                                                                                             		 container.getAclID(), 
                                                                                             		 0, 
                                                                                             		 defaultValue, 
                                                                                             		 paramBean
                                                                                            		);

            // cycle on every language setting descriptions except english
            Iterator siteLanguageIterator = languages.iterator();
            String localeString;
            String tmpValue;
            while ( siteLanguageIterator.hasNext() ) {

                localeString = (String) siteLanguageIterator.next();

            		if ( localeString.equals( defaultLanguage ) ) {
            		    // the field is created by default in english, so we silently
            		    // continue
            		    continue;
            		}

            		entrySaveRequest.setLanguageCode( localeString );

            		tmpValue = (String) localizedValuesMap.get(localeString);

            		// so we don't have a transaltion in our erpCategory, rollback to
            		// the value of the default language
            		if (tmpValue == null) {
            		    tmpValue = defaultValue;
            		}

            		contentSmallTextField.setText( tmpValue, entrySaveRequest );

            		log.debug(className + ".setSmallTextSharedFieldCode() called | field [" + contentSmallTextField.getID() + "] | added value ["
                                		+ tmpValue + "] for locale [" + localeString + "]");
            		// here we modify the text only in edit mode, it is not committed to
            		// live mode
            		// use field activation if you want to go live

            }

          return contentSmallTextField;
            
        }finally{
            
          paramBean.changeLanguage( paramBeanOriginalLocale );    
            
        }

    }
    
    
  	// save in webdav filesystem
  	// here we return a davResponse because in some occasions it can be null, another Jahia way for saying exception
  	/** Create a DAVFile in jahia webdav fileSystem.
  	 *  Jahia implementation of DAVFileAccess requires, as parameter, a java.io.File (everything is conceived for
  	 *  being used from web console, so that the java.io.File is provided via <FORM ENCTYPE="multipart/form-data">).
  	 *  Our case is difefrent as we don't come from web interface.
  	 *  So, as a workaround, we create a file in the machine filesystem (not webdav), pointing to this file
  	 *  in this method implementation. This file will be created in a directory whose path is:
  	 *  $webdav_file_path$/tmp_ws
  	 * 
  	 * @param path
  	 * @param filename
  	 * @param paramBean
  	 * @return
  	 * @throws Exception
  	 */
  	public static String davSave (String path, String filename, ParamBean paramBean) throws Exception{
  	    
  	    
  	  log.debug(className + ".davSave | user is [" + paramBean.getUser().getUserKey() + "]");
  	  log.debug(className + ".davSave | site is [" + paramBean.getSiteKey() + "]");
  	    		
  	  // TODO check if this lowercase is necessary
  		String davFileAccessPath = ( path.substring( path.indexOf("shared") - 1, path.lastIndexOf( DirectorySelectorRules.TMP_WS_SAVE_DIRECTORY ) - 1  ) ).toLowerCase();	
  		
  		davFileAccessPath = davFileAccessPath.replace('\\', '/');
  		
  		log.debug(className + ".davSave() | path for DavFileAccess is [" + davFileAccessPath + "]");
  		
  		DAVFileAccess access = new DAVFileAccess( paramBean,  davFileAccessPath );
  		
  		File file = new File(path, filename);	
  		
  		String davResponse = null;
  		
  		// start dav transaction
  		access.beginTransaction();			
  			
  		// for now always text/xml contentType and false for versioning (not yet managed in Jahia)
  		davResponse = access.uploadFile(filename, file, "text/xml", false);			
  			
  		log.debug(className + ".davSave [" + davResponse + "]" );			
  						
  		
  		if(davResponse == null){
  		  access.rollbackTransaction();
  		  if(access.getException() != null){
  		    throw access.getException();
  		  }else{
  		    throw new Exception ( "Impossible to create davFile for path [" + path + "] and filename [" + filename + "]" );    
  		  }
  		}else{
  		  access.commitTransaction();    
  		}
  		
  		return davResponse;
  	
  	}    
    
    

  	// save simply to filesystem, no webdav interaction
  	// if ko throws Exception
  	public static void simpleFileSave (String message, String path, String filename) throws IOException{
  		
  		FileWriter fileWriter = null;
  		
  	  try {					  
  	  	fileWriter = new FileWriter ( new File (path, filename), false);		  							
  	  	fileWriter.write (message, 0, message.length());
  	  	fileWriter.flush();																		 
  		}finally{		
  			if(fileWriter != null){
  	      fileWriter.close();
  			}			
  		}			
  	}
  	//  	
  	
  	
  	public static JahiaPage findPageByPropertyKeyAndUniqueValue(String key, String value, ParamBean paramBean) throws JahiaException{
  	    
  	    log.debug(className + " - findPageBypropertyKeyAndUniqueValue, entered with key [" + key + "] value [" + value + "]");
  	    
  	    JahiaPageService jahiaPageService = (JahiaPageService) ServicesRegistry.getInstance().getJahiaPageService();  	    
  	    
        List pagePropertiesList = jahiaPageService.getPagePropertiesByValue( value );
        log.debug(className + " - findPageBypropertyKeyAndUniqueValue | pagePropertyList is null [" + ( pagePropertiesList == null ) + "]");
        log.debug(className + " - findPageBypropertyKeyAndUniqueValue | pagePropertyList size [" + pagePropertiesList.size() + "]");
        Iterator pagePropertiesListIterator = pagePropertiesList.iterator();
        PageProperty pageProperty; 
        ContentPage uniqueContentPage = null;
        String pagePropertyName;
        JahiaPage jahiaPage = null;
        int pageId;
        
        // cycle on every PageProperty, we should have only one of them here for the given value
        // if more than one is found, we get the one with name.equals( key )
        while( pagePropertiesListIterator.hasNext() && jahiaPage == null){
            pageProperty = (PageProperty)pagePropertiesListIterator.next();
            pagePropertyName = pageProperty.getName();
            log.debug(className + " - findPageBypropertyKeyAndUniqueValue | pageProperties name is [" + pagePropertyName + "]");
            	if( pagePropertyName.equals( key ) ){                	                    	    
            	  pageId = pageProperty.getPageID();
            	  log.debug(className + " - findPageBypropertyKeyAndUniqueValue | pageId name is [" + pageId + "]");                	              	              	              	  
            	  uniqueContentPage = ContentPage.getPage( pageId, true );
            	  
            	  jahiaPage = uniqueContentPage.getPage( paramBean );
            	  
            	  log.debug(className + " - findPageBypropertyKeyAndUniqueValue | jahiapage is null [" + ( jahiaPage == null ) + "]");
            	  
            	}                                            
        }// end while
       
        if( jahiaPage == null ){
            log.debug(className + " - findPageBypropertyKeyAndUniqueValue | returning a null page reference for key [" + key + "] value [" + value + "]");  
        }else{
            log.debug(className + " - findPageBypropertyKeyAndUniqueValue | returning page [" + jahiaPage.getID() + "] for key [" + key + "] value [" + value + "]");            
        }
        
        
        return jahiaPage;
  	
  	
  	}
  	
  	
    /** Update a page title for every site's language if new titles are different from old ones.
     * Every possible upfate exception is caught and properly logged
     * @param jahiaPage the page with the title to be updated in multiple languages
     * @param site tria view on a specific virtual site
     * @param localizedValuesMap a map storing page title translations
     */  	
    public static void updatePageField( JahiaPage jahiaPage, Site site, Map localizedValuesMap ){
        
        
        ContentPage contentPage = jahiaPage.getContentPage();
        
        Collection languages = site.getLanguagesMap().values();
        Iterator languageIterator = languages.iterator();
        String language;
        EntryLoadRequest entryLoadRequest;
        // list for locale that will be passed to entryLoadRequest
        ArrayList languageList = new ArrayList( 1 );
        String title;
        String newTitle;

        	while ( languageIterator.hasNext() ){

        	    language = (String)languageIterator.next();
        	    log.debug(className + " - updateSinglePage, working with language [" + language + "]");
        	    languageList.clear();
        	    languageList.add( new Locale( language ) );
        	    entryLoadRequest = new EntryLoadRequest( EntryLoadRequest.STAGING_WORKFLOW_STATE, 0, languageList );

        	    try{
        	    
        	        title = contentPage.getTitle( entryLoadRequest );

        	        log.debug(className + " - updateSinglePage, working with language [" + language + "] title [" + title + "]");            

        	        newTitle = (String) localizedValuesMap.get( language );

        	        log.debug(className + " - updateSinglePage, working with language [" + language + "] newtitle [" + newTitle + "]");

        	        // do we really need to update existing title for this language, case sensitive
        	        if( title.equals( newTitle ) ){
        	            // evaluate nect title 
        	            continue;
        	        }else{
        	            contentPage.setTitle(language, newTitle, entryLoadRequest);
        	            contentPage.commitChanges( true );
        	        }
        	    // catehc everyExcetion possible exception, not only JahiaException    
        	    }catch(Throwable everyException){
        	        
        	        log.error( className + " - updatePageField, impossible update for page [" + jahiaPage.getID() + "] with language [" + language + "]", everyException);
        	         
        	    }   
        	} // end while
 
    }
    
    
    
    
    
    /** Create a small text with field with the default language passed as parameter, than translatesa its value using the ones stored in
     *  parameterer localizedValuesMap. Accept no null parameters.
     * @param paramBean  
     * @param jahiaPage the page that owns the containerList wrapping the container where this field will be created
     * @param site tria view on a specific virtual site
     * @param container the container where the jahiaSmalltextField will be added
     * @param fieldName the name of the smnallTextField
     * @param localizedValuesMap a map storing page title translations
     * @param defaultLanguage the default language; see java.util.Locale for knowing which values to use
     * @throws JahiaException for every possible exception while using jahia core functionalities 
     */
    public static ContentBigTextField createBigTextField( ParamBean paramBean, JahiaPage jahiaPage, Site site, JahiaContainer container,
            																							String fieldName, Map localizedValuesMap, String defaultLanguage )
            throws JahiaException {

        JahiaContainerDefinition ctnDef = container.getDefinition();
        JahiaFieldDefinition fieldDef = ctnDef.findFieldInStructure( fieldName, jahiaPage.getPageTemplateID() );

        log.debug(className + " - createBigTextField, field definition is [" + fieldDef.getName() + "]");

        EntrySaveRequest entrySaveRequest = new EntrySaveRequest( paramBean.getUser() );

        Collection languages = site.getLanguagesMap().values();

        String defaultValue = (String) localizedValuesMap.get( defaultLanguage );        
        
        // stores temporary original paramBean locale
        Locale paramBeanOriginalLocale = paramBean.getLocale();
        // a try just for using a finally where we set back the original locale of the paramBean        
        try{
        
            paramBean.changeLanguage( new Locale ( defaultLanguage ) );

            // start creating field with the default locale, which is always english
            ContentBigTextField contentBigTextField = ContentBigTextField.createBigText( paramBean.getSiteID(), 
                                                                                         jahiaPage.getID(),
                                                                                         container.getID(), 
                                                                                         fieldDef.getID(), 
                                                                                         container.getAclID(), 
                                                                                         0, 
                                                                                         defaultValue, 
                                                                                         paramBean
                                                                                         );

            // cycle on every language setting descriptions except english
            Iterator siteLanguageIterator = languages.iterator();
            String localeString;
            String tmpValue;
            while ( siteLanguageIterator.hasNext() ) {

                localeString = (String) siteLanguageIterator.next();

            		if ( localeString.equals( defaultLanguage ) ) {
            		    // the field is created by default in english, so we silently
            		    // continue
            		    continue;
            		}

            		entrySaveRequest.setLanguageCode( localeString );

            		tmpValue = (String) localizedValuesMap.get(localeString);

            		// so we don't have a transaltion in our erpCategory, rollback to
            		// the value of the default language
            		if (tmpValue == null) {
            		    tmpValue = defaultValue;
            		}

            		contentBigTextField.setText( tmpValue, entrySaveRequest );

            		log.debug(className + " - createBigTextField | field [" + contentBigTextField.getID() + "] | added value ["
                                		+ tmpValue + "] for locale [" + localeString + "]");
            		// here we modify the text only in edit mode, it is not committed to
            		// live mode
            		// use field activation if you want to go live

            }

          return contentBigTextField;
            
        }finally{
            
          paramBean.changeLanguage( paramBeanOriginalLocale );    
            
        }

    }    
    
    
    
    
    
 
 
 
}
        