package cz.muni.fi.jboss.migration.actions;

import cz.muni.fi.jboss.migration.conf.Configuration;
import cz.muni.fi.jboss.migration.ex.ActionException;
import cz.muni.fi.jboss.migration.ex.MigrationException;
import cz.muni.fi.jboss.migration.spi.IMigrator;
import cz.muni.fi.jboss.migration.utils.AS7ModuleUtils;
import cz.muni.fi.jboss.migration.utils.Utils;
import org.apache.commons.io.FileUtils;

import javax.xml.transform.TransformerException;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;

/**
 * @author Ondrej Zizka, ozizka at redhat.com
 */
public class ModuleCreationAction extends AbstractStatefulAction {
    private static final Logger log = LoggerFactory.getLogger(ModuleCreationAction.class);
    
    private static final String MODULE_XML_FNAME = "module.xml";

    // Action data
    File jarFile;
    String moduleName;
    String[] deps;
    Configuration.IfExists ifExists;
    
    // Backup
    private File moduleDir;
    private File backupDir;


    public ModuleCreationAction( Class<? extends IMigrator> fromMigrator, 
            String moduleName, String[] deps, File jar, Configuration.IfExists ifExists)
    {
        super(fromMigrator);
        this.jarFile = jar;
        this.moduleName = moduleName;
        this.deps = deps;
        this.ifExists = ifExists;
    }


    @Override
    public String toDescription() {
        return "Create an AS 7 module '"+moduleName+"' from .jar " + this.jarFile.getPath() + ", deps: " + StringUtils.join(deps, " ");
    }
    

    @Override
    public void preValidate() throws MigrationException {
        if( ! jarFile.exists() )
            throw new ActionException(this, "Module source jar doesn't exist: " + jarFile.getPath());
        
        File dir = getModuleDir();
        if( dir.exists() ){
            switch( this.ifExists ){
                case FAIL:
                    throw new ActionException(this, "Module dir already exists in AS 7, overwrite not allowed: " + dir.getAbsolutePath());
                case ASK:
                case MERGE:
                    throw new UnsupportedOperationException("ASK and MERGE are not supported for " + getClass().getSimpleName());
                case WARN:
                    log.warn("Module directory for "+this.moduleName+" already exists: " + this.moduleDir);
                    break;
                case SKIP:
                    log.debug("Module directory for "+this.moduleName+" already exists, skipping: " + this.moduleDir);
                    break;
            }
        }
    }


    @Override
    public void perform() throws MigrationException {
        // Create a module.
        try {
            // Copy jar file
            File dir = getModuleDir();
            FileUtils.copyFileToDirectory(this.jarFile, dir);
            //File dest = new File(dir, this.jarFile.getName());
            //FileUtils.copyFile( jarFile, dest );
            
            // XML doc
            File moduleXmlFile = new File(dir, MODULE_XML_FNAME);
            if( moduleXmlFile.exists() && this.ifExists != Configuration.IfExists.OVERWRITE )
                throw new ActionException(this, MODULE_XML_FNAME + " already exists: " + moduleXmlFile.getPath() );
            
            Document doc = AS7ModuleUtils.createModuleXML( moduleName, jarFile.getName(), deps );
            Utils.transformDocToFile( doc, moduleXmlFile );

            // Backup
            this.moduleDir = dir;
        }
        catch( IOException ex ) {
            throw new ActionException(this, "Copying failed: " + ex.getMessage(), ex);
        }
        catch( TransformerException ex ) {
            throw new ActionException(this, "Creation of " + MODULE_XML_FNAME + " failed: " + ex.getMessage(), ex);
        }
        catch( ParserConfigurationException ex ) {
            throw new ActionException(this, "Creation of " + MODULE_XML_FNAME + " failed: " + ex.getMessage(), ex);
        }

        setState(State.DONE);
    }


    @Override
    public void rollback() throws MigrationException {
        if( this.isAfterPerform() ) {
            FileUtils.deleteQuietly( this.moduleDir );
        }
        setState(State.ROLLED_BACK);
    }


    @Override
    public void postValidate() throws MigrationException {
    }


    @Override
    public void backup() throws MigrationException {
        Path tmpDir;
        try {
            tmpDir = Files.createTempDirectory( "JBossAS-migr-backup-"+moduleName );
        } catch( IOException ex ) {
            throw new ActionException( this, "Failed creating a backup dir. " + ex.getMessage(), ex);
        }
        try {
            FileUtils.copyDirectory( getModuleDir(), tmpDir.toFile() );
        } catch( IOException ex ) {
            throw new ActionException( this, "Failed copying to the backup dir " + tmpDir + " : " + ex.getMessage(), ex);
        }
        this.backupDir = tmpDir.toFile();
        setState(State.BACKED_UP);
    }


    @Override
    public void cleanBackup() {
        setState(State.FINISHED);
    }


    private File getModuleDir() {
        return new File( getMigrationContext().getAs7Config().getModulesDir(), this.moduleName.replace('.', '/') + "/main" );
    }

}// class

@@ -549,16 +549,48 @@
 e.Path;%0A
+import java.util.logging.Level;%0A
 import j
@@ -4393,32 +4393,326 @@
 ir );%0A        %7D%0A
+        if( this.backupDir != null )%7B%0A            try %7B%0A                FileUtils.moveDirectory( this.backupDir, this.moduleDir );%0A            %7D catch( IOException ex ) %7B%0A                throw new ActionException( this, %22Can't move %22 + backupDir + %22 to %22 + moduleDir );%0A            %7D%0A        %7D%0A
         setState
@@ -4732,16 +4732,16 @@
 _BACK);%0A
-
     %7D%0A%0A%0A
@@ -5148,32 +5148,75 @@
  ex);%0A        %7D%0A
+        if( getModuleDir().exists() )%7B%0A    
         try %7B%0A  
@@ -5205,32 +5205,36 @@
           try %7B%0A
+    
             File
@@ -5289,32 +5289,36 @@
 le() );%0A        
+    
 %7D catch( IOExcep
@@ -5333,32 +5333,36 @@
 ) %7B%0A            
+ 
+   
 throw new Action
@@ -5447,32 +5447,46 @@
 Message(), ex);%0A
+            %7D%0A
         %7D%0A      

Use IfExists; handle backup & restore.