/*
 * Copyright 2013 Netherlands eScience Center
 *
 * 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 nl.esciencecenter.amuse.distributed.workers;

import ibis.ipl.Ibis;
import ibis.ipl.IbisIdentifier;
import ibis.ipl.SendPort;
import ibis.ipl.WriteMessage;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;

import nl.esciencecenter.amuse.distributed.DistributedAmuse;

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

/**
 * Forwards output of a worker to the "master" Ibis process.
 * 
 * @author Niels Drost
 * 
 */
public class OutputForwarder extends Thread {

    private static final Logger logger = LoggerFactory.getLogger(OutputForwarder.class);

    private final InputStream input;

    private final String file;

    private final Ibis ibis;

    public OutputForwarder(InputStream input, String file, Ibis ibis) throws IOException {
        this.input = new BufferedInputStream(input);
        this.file = file;
        this.ibis = ibis;

        setDaemon(true);
        setName("output forwarder");
        start();
    }
    
    public void waitFor(long timeout) {
        try {
            this.join(timeout);
        } catch (InterruptedException e) {
            //IGNORE
        }
    }

    /**
     * Forwards input stream to given output stream.
     */
    public void run() {
        byte[] buffer = new byte[WorkerOutputManager.MAX_MESSAGE_SIZE];
        SendPort sendPort = null;

        logger.debug("Forwarding output to " + file);

        try {

            if (file.equalsIgnoreCase("/dev/null")) {
                sendPort = null;
                logger.info("Discarding code output");
            } else {
                logger.debug("Creating sendport");
                sendPort = ibis.createSendPort(DistributedAmuse.MANY_TO_ONE_PORT_TYPE);
                logger.debug("getting daemon IbisIdentifier");
                IbisIdentifier daemon = ibis.registry().getElectionResult("amuse");
                logger.debug("Connecting to output manager port");
                sendPort.connect(daemon, "output");
            }

            logger.debug("Starting with forwarding output");

            while (true) {
                int count = input.read(buffer);

                if (count == -1) {
                    // we're done (final block will close sendport)
                    return;
                }

                if (sendPort != null) {
                    logger.trace("Sending message with {} bytes", count);
                    WriteMessage message = sendPort.newMessage();
                    message.writeString(file);
                    message.writeInt(count);
                    message.writeArray(buffer, 0, count);
                    message.finish();
                }
            }
        } catch (IOException error) {
            if (error.getMessage() == null || !error.getMessage().equals("Stream closed")) {
                logger.error("Error on forwarding code output", error);
            }
        } finally {
            if (sendPort != null) {
                try {
                    sendPort.close();
                } catch (IOException e) {
                    // IGNORE
                }
            }
        }

    }

}
