/*******************************************************************************
 * Copyright 2006 - 2014 Vienna University of Technology,
 * Department of Software Technology and Interactive Systems, IFS
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/
package eu.scape_project.planning.services.pa.taverna;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import eu.scape_project.planning.manager.CriteriaManager;
import eu.scape_project.planning.model.Alternative;
import eu.scape_project.planning.model.DigitalObject;
import eu.scape_project.planning.model.PlatoException;
import eu.scape_project.planning.model.SampleObject;
import eu.scape_project.planning.model.beans.MigrationResult;
import eu.scape_project.planning.model.interfaces.actions.IMigrationAction;
import eu.scape_project.planning.model.measurement.Measure;
import eu.scape_project.planning.model.measurement.Measurement;
import eu.scape_project.planning.model.values.Value;
import eu.scape_project.planning.services.taverna.executor.SSHInMemoryTempFile;
import eu.scape_project.planning.services.taverna.executor.SSHTavernaExecutor;
import eu.scape_project.planning.services.taverna.executor.TavernaExecutorException;
import eu.scape_project.planning.services.taverna.generator.T2FlowExecutablePlanGenerator;

/**
 * Migration action that executes generated Taverna executable plans.
 * 
 * @see T2FlowExecutablePlanGenerator
 */
public class SSHGeneratedTavernaMigrationService implements IMigrationAction {
    private static Logger log = LoggerFactory.getLogger(SSHGeneratedTavernaMigrationService.class);

    private CriteriaManager cm;

    /**
     * Constructs a new migration service.
     */
    public SSHGeneratedTavernaMigrationService() {
        cm = new CriteriaManager();
        cm.init();
    }

    @Override
    public boolean perform(Alternative alternative, SampleObject sampleObject) throws PlatoException {
        MigrationResult result = migrate(alternative, sampleObject);
        return result.isSuccessful();
    }

    @Override
    public MigrationResult migrate(Alternative alternative, DigitalObject digitalObject) throws PlatoException {
        DigitalObject workflow = alternative.getExperiment().getWorkflow();
        MigrationResult result = new MigrationResult();
        result.setSourceFormat(digitalObject.getFormatInfo());
        result.setSuccessful(false);

        // Prepare executor
        SSHTavernaExecutor tavernaExecutor = new SSHTavernaExecutor();
        tavernaExecutor.init();
        SSHTavernaExecutor.ByteArraySourceFile workflowFile = tavernaExecutor.new ByteArraySourceFile(
            workflow.getFullname(), workflow.getData().getData());
        tavernaExecutor.setWorkflow(workflowFile);

        // Input
        HashMap<String, Object> inputData = new HashMap<String, Object>();
        SSHTavernaExecutor.ByteArraySourceFile sourceFile = tavernaExecutor.new ByteArraySourceFile(
            digitalObject.getFullname(), digitalObject.getData().getData());
        inputData.put("source", sourceFile);
        tavernaExecutor.setInputData(inputData);

        // Outputs
        tavernaExecutor.setOutputPorts(null);
        HashMap<String, SSHInMemoryTempFile> requestedFiles = new HashMap<String, SSHInMemoryTempFile>(1);
        SSHInMemoryTempFile tempFile = new SSHInMemoryTempFile();
        requestedFiles.put("target", tempFile);
        tavernaExecutor.setOutputFiles(requestedFiles);

        // Execute
        try {
            tavernaExecutor.execute();
            result.setReport(tavernaExecutor.getOutputDoc());

            // Migrated file
            Map<String, ?> outputFiles = tavernaExecutor.getOutputFiles();

            DigitalObject migrated = new DigitalObject();
            for (Entry<String, ?> entry : outputFiles.entrySet()) {
                SSHInMemoryTempFile resultFile = (SSHInMemoryTempFile) entry.getValue();
                migrated.getData().setData(resultFile.getData());
                migrated.setFullname("migrated-" + digitalObject.getFullname());
            }
            result.setMigratedObject(migrated);
            result.setTargetFormat(migrated.getFormatInfo());
            result.setSuccessful(migrated.isDataExistent());

            // Measures
            Map<String, ?> outputData = tavernaExecutor.getOutputData();
            Map<String, Measurement> measurements = new HashMap<String, Measurement>();
            for (Entry<String, ?> outputEntry : outputData.entrySet()) {
                Measurement measurement = createMeasurement(outputEntry.getKey(), outputEntry.getValue());
                if (measurement != null) {
                    measurements.put(measurement.getMeasureId(), measurement);
                }
            }
            result.setMeasurements(measurements);
        } catch (IOException e) {
            throw new PlatoException("Error communicating with the server.", e);
        } catch (TavernaExecutorException e) {
            throw new PlatoException("Error executing taverna workflow", e);
        }
        return result;
    }

    /**
     * Creates a measurement from the provided ID and value.
     * 
     * If a {@link Measure} can be created, uses the value from the measure.
     * Otherwise the string representation of the {@code value} is used.
     * 
     * @param measureId
     *            the ID of the measure
     * @param value
     *            the measured value
     * @return a measurement
     */
    private Measurement createMeasurement(String measureId, Object value) {
        Measurement measurement = null;
        String measureUri = T2FlowExecutablePlanGenerator.guessMeasureUrl(measureId);
        if (measureUri != null) {
            Measure measure = cm.getMeasure(measureUri);
            if (measure != null) {
                Value v = measure.getScale().createValue();
                try {
                    v.parse(value.toString());
                    // The measurement value does not need a scale
                    v.setScale(null);
                    measurement = new Measurement();
                    measurement.setMeasureId(measureUri);
                    measurement.setValue(v);
                } catch (Exception e) {
                    // Catch parsing exceptions
                    log.debug("Error parsing measure value", e);
                }
            }
        }

        if (measurement == null) {
            if (!"target".equals(measureId)) {
                measurement = new Measurement(measureId, value.toString());
            }
        }
        return measurement;
    }
}

@@ -1978,16 +1978,66 @@
 nerator;
+%0Aimport eu.scape_project.planning.utils.FileUtils;
 %0A%0A/**%0A *
@@ -3372,16 +3372,39 @@
         
+FileUtils.makeFilename(
 workflow
@@ -3417,16 +3417,17 @@
 llname()
+)
 , workfl
@@ -3708,16 +3708,39 @@
         
+FileUtils.makeFilename(
 digitalO
@@ -3758,16 +3758,17 @@
 llname()
+)
 , digita
@@ -4797,18 +4797,53 @@
 ame(
-%22migrated-
+alternative.getAction().getShortname() + %22 - 
 %22 + 

Normalize input filenames for experiment execution for #232