/***************************************************************************
    File                 : AbstractFilter.cpp
    Project              : SciDAVis
    --------------------------------------------------------------------
    Copyright            : (C) 2007 by Knut Franke, Tilman Benkert
    Email (use @ for *)  : knut.franke*gmx.de, thzs*gmx.net
    Description          : Base class for all analysis operations.

 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *  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 2 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, write to the Free Software           *
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor,                    *
 *   Boston, MA  02110-1301  USA                                           *
 *                                                                         *
 ***************************************************************************/
#include "AbstractFilter.h"

bool AbstractFilter::input(int port, const AbstractColumn* source)
{
	if (port<0 || (inputCount()>=0 && port>=inputCount())) return false;
	if (source && !inputAcceptable(port, source)) return false;
	if (port >= d_inputs.size()) d_inputs.resize(port+1);
	const AbstractColumn* old_input = d_inputs.value(port);
	if (source == old_input) return true;
	if (old_input) 
	{
		disconnect(old_input, 0, this, 0);
		// replace input, notifying the filter implementation of the changes
		inputDescriptionAboutToChange(old_input);
		inputPlotDesignationAboutToChange(old_input);
		inputMaskingAboutToChange(old_input);
		inputDataAboutToChange(old_input);
		if(source && source->columnMode() != old_input->columnMode())
			inputModeAboutToChange(old_input);
	}
	if (!source)
		inputAboutToBeDisconnected(old_input);
	d_inputs[port] = source;
	if (source) { // we have a new source
		if(old_input && source->columnMode() != old_input->columnMode())
			inputModeAboutToChange(source);
		inputDataChanged(source);
		inputMaskingChanged(source);
		inputPlotDesignationChanged(source);
		inputDescriptionChanged(source);
		// connect the source's signals
		QObject::connect(source, SIGNAL(aspectDescriptionAboutToChange(const AbstractAspect *)),
				this, SLOT(inputDescriptionAboutToChange(const AbstractAspect *)));
		QObject::connect(source, SIGNAL(aspectDescriptionChanged(const AbstractAspect *)),
				this, SLOT(inputDescriptionChanged(const AbstractAspect *)));
		QObject::connect(source, SIGNAL(plotDesignationAboutToChange(const AbstractColumn *)),
				this, SLOT(inputPlotDesignationAboutToChange(const AbstractColumn *)));
		QObject::connect(source, SIGNAL(plotDesignationChanged(const AbstractColumn *)),
				this, SLOT(inputPlotDesignationChanged(const AbstractColumn *)));
		QObject::connect(source, SIGNAL(modeAboutToChange(const AbstractColumn *)),
				this, SLOT(inputModeAboutToChange(const AbstractColumn *)));
		QObject::connect(source, SIGNAL(modeChanged(const AbstractColumn *)),
				this, SLOT(inputModeChanged(const AbstractColumn *)));
		QObject::connect(source, SIGNAL(dataAboutToChange(const AbstractColumn *)),
				this, SLOT(inputDataAboutToChange(const AbstractColumn *)));
		QObject::connect(source, SIGNAL(dataChanged(const AbstractColumn *)),
				this, SLOT(inputDataChanged(const AbstractColumn *)));
		QObject::connect(source, SIGNAL(aboutToBeReplaced(const AbstractColumn *,const AbstractColumn*)),
				this, SLOT(inputAboutToBeReplaced(const AbstractColumn *,const AbstractColumn*)));
		QObject::connect(source, 
			SIGNAL(rowsAboutToBeInserted(const AbstractColumn *,int,int)),
			this, SLOT(inputRowsAboutToBeInserted(const AbstractColumn *,int,int)));
		QObject::connect(source, 
			SIGNAL(rowsInserted(const AbstractColumn *,int,int)),
			this, SLOT(inputRowsInserted(const AbstractColumn *,int,int)));
		QObject::connect(source, 
			SIGNAL(rowsAboutToBeRemoved(const AbstractColumn *,int,int)),
			this, SLOT(inputRowsAboutToBeRemoved(const AbstractColumn *,int,int)));
		QObject::connect(source, 
			SIGNAL(rowsRemoved(const AbstractColumn *, int, int)),
			this, SLOT(inputRowsRemoved(const AbstractColumn *,int,int)));
		QObject::connect(source, SIGNAL(maskingAboutToChange(const AbstractColumn *)),
				this, SLOT(inputMaskingAboutToChange(const AbstractColumn *)));
		QObject::connect(source, SIGNAL(maskingChanged(const AbstractColumn *)),
				this, SLOT(inputMaskingChanged(const AbstractColumn *)));
		QObject::connect(source, SIGNAL(aboutToBeDestroyed(const AbstractColumn *)),
				this, SLOT(inputAboutToBeDestroyed(const AbstractColumn *)));
	} else { // source==0, that is, the input port has been disconnected
		// try to shrink d_inputs
		int num_connected_inputs = d_inputs.size();
		while ( d_inputs.at(num_connected_inputs-1) == 0 )
		{
			num_connected_inputs--;
			if(!num_connected_inputs) break;
		}
		d_inputs.resize(num_connected_inputs);
	}
	return true;
}

bool AbstractFilter::input(const AbstractFilter* sources)
{
	if (!sources) return false;
	bool result = true;
	for (int i=0; i<sources->outputCount(); i++)
		if (!input(i, sources->output(i)))
			result = false;
	return result;
}

QString AbstractFilter::inputLabel(int port) const
{
	return QObject::tr("In%1").arg(port + 1);
}

void AbstractFilter::inputAboutToBeReplaced(const AbstractColumn * source, const AbstractColumn* replacement)
{
	input(portIndexOf(source), replacement);
}

