/*
 * cc.redberry.pipe: java library for implementation of concurrent pipelines
 * Copyright (c) 2010-2012
 * Bolotin Dmitriy <bolotin.dmitriy@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package cc.redberry.pipe.blocks;

import cc.redberry.pipe.InputPort;
import cc.redberry.pipe.OutputPort;
import cc.redberry.pipe.PInterruptedException;
import cc.redberry.pipe.util.ExceptionHandler;

/**
 * Output to input transmitter.
 *
 * @param <T> type of transmitted objects
 * @author Bolotin Dmitriy
 * @author Mikhail Shugay
 */
public final class O2ITransmitter<T> implements Runnable {
    public final ExceptionHandler handler;
    public final OutputPort<? extends T> oPort;
    public final InputPort<T> iPort;
    public volatile boolean stopped = false;

    public O2ITransmitter(OutputPort<? extends T> output, InputPort<T> input,
                          ExceptionHandler<O2ITransmitter> exceptionHandler) {
        this.handler = exceptionHandler;
        this.oPort = output;
        this.iPort = input;
    }

    public O2ITransmitter(OutputPort<T> output, InputPort<T> input) {
        this(output, input, null);
    }

    public OutputPort<? extends T> getInput() {
        return oPort;
    }

    public InputPort<T> getOutput() {
        return iPort;
    }

    public void stop() {
        stopped = true;
    }

    @Override
    public void run() {
        try {
            T element;
            while (!stopped && (element = oPort.take()) != null)
                iPort.put(element);
        } catch (PInterruptedException ex) {
        } catch (RuntimeException re) {
            if (handler != null)
                handler.handle(re, this);
        } finally {
            iPort.put(null); //close upstream input port any way
        }
    }
}
