void AMExternalScanDataSourceAB::copyValues(int dataSourceIndex)
{
	AMDataSource* ds = scan_->dataSourceAt(dataSourceIndex);
	const AMnDIndex size = ds->size();

	switch(ds->rank()) {
	case 0:
		values_.clear();
		values_ << ds->value(AMnDIndex());
		break;

	case 1: {
		values_.resize(size.i());
		for(int i=0; i<size.i(); i++)
			values_[i] = ds->value(i);
		break;
	}
	case 2: {
		values_.resize(size.i()*size.j());
		for(int i=0; i<size.i(); i++)
			for(int j=0; j<size.j(); j++)
				values_[i*size.j() + j] = ds->value(AMnDIndex(i,j));
		break;
	}
	case 3: {
		values_.resize(size.i()*size.j()*size.k());
		for(int i=0; i<size.i(); i++)
			for(int j=0; j<size.j(); j++)
				for(int k=0; k<size.k(); k++)
					values_[i*size.j()*size.k() + j*size.k() + k] = ds->value(AMnDIndex(i,j,k));
		break;
	}
	case 4: {
		values_.resize(size.i()*size.j()*size.k()*size.l());
		for(int i=0; i<size.i(); i++)
			for(int j=0; j<size.j(); j++)
				for(int k=0; k<size.k(); k++)
					for(int l=0; l<size.l(); l++)
						values_[i*size.j()*size.k()*size.l() + j*size.k()*size.l() + k*size.l() + l] = ds->value(AMnDIndex(i,j,k,l));
		break;
	}
	case 5: {
		values_.resize(size.i()*size.j()*size.k()*size.l()*size.m());
		for(int i=0; i<size.i(); i++)
			for(int j=0; j<size.j(); j++)
				for(int k=0; k<size.k(); k++)
					for(int l=0; l<size.l(); l++)
						for(int m=0; m<size.m(); m++)
							values_[i*size.j()*size.k()*size.l()*size.m() + j*size.k()*size.l()*size.m() + k*size.l()*size.m() + l*size.m() + m] = ds->value(AMnDIndex(i,j,k,l,m));
		/// \todo oh god, we really need a block copy or a multi-dimensional iterator for AMDataSource::value()...
		break;
	}
	}
}
AMNumber AMExternalScanDataSourceAB::value(const AMnDIndex &indexes) const
{
	if(!isValid())
		return AMNumber::InvalidError;

	if(indexes.rank() != axes_.count())
		return AMNumber::DimensionError;

	switch(axes_.count()) {
	case 0:
		return values_.at(0);

	case 1:
#ifdef AM_ENABLE_BOUNDS_CHECKING
		if((unsigned)indexes.i() >= (unsigned)axes_.at(0).size)
				return AMNumber::OutOfBoundsError;
#endif
		return values_.at(indexes.i());

	case 2:
#ifdef AM_ENABLE_BOUNDS_CHECKING
		if(((unsigned)indexes.i() >= (unsigned)axes_.at(0).size ||
				(unsigned)indexes.j() >= (unsigned)axes_.at(1).size))
			return AMNumber::OutOfBoundsError;
#endif
		return values_.at(indexes.i()*axes_.at(1).size
						  + indexes.j());

	case 3: {
#ifdef AM_ENABLE_BOUNDS_CHECKING
		if(((unsigned)indexes.i() >= (unsigned)axes_.at(0).size ||
				(unsigned)indexes.j() >= (unsigned)axes_.at(1).size ||
				(unsigned)indexes.k() >= (unsigned)axes_.at(2).size))
			return AMNumber::OutOfBoundsError;
#endif

		int flatIndex = indexes.k();
		int stride = axes_.at(2).size;
		flatIndex += indexes.j()*stride;
		stride *= axes_.at(1).size;
		flatIndex += indexes.i()*stride;
		return values_.at(flatIndex);
	}

	case 4: {
#ifdef AM_ENABLE_BOUNDS_CHECKING
		if(((unsigned)indexes.i() >= (unsigned)axes_.at(0).size ||
				(unsigned)indexes.j() >= (unsigned)axes_.at(1).size ||
				(unsigned)indexes.k() >= (unsigned)axes_.at(2).size ||
				(unsigned)indexes.l() >= (unsigned)axes_.at(3).size))
			return AMNumber::OutOfBoundsError;
#endif

		int flatIndex = indexes.l();
		int stride = axes_.at(3).size;
		flatIndex += indexes.k()*stride;
		stride *= axes_.at(2).size;
		flatIndex += indexes.j()*stride;
		stride *= axes_.at(1).size;
		flatIndex += indexes.i();
		return values_.at(flatIndex);
	}

	case 5: {
#ifdef AM_ENABLE_BOUNDS_CHECKING
		if(((unsigned)indexes.i() >= (unsigned)axes_.at(0).size ||
				(unsigned)indexes.j() >= (unsigned)axes_.at(1).size ||
				(unsigned)indexes.k() >= (unsigned)axes_.at(2).size ||
				(unsigned)indexes.l() >= (unsigned)axes_.at(3).size ||
				(unsigned)indexes.m() >= (unsigned)axes_.at(4).size))
			return AMNumber::OutOfBoundsError;
#endif

		int flatIndex = indexes.m();
		int stride = axes_.at(4).size;
		flatIndex += indexes.l()*stride;
		stride *= axes_.at(3).size;
		flatIndex += indexes.k()*stride;
		stride *= axes_.at(2).size;
		flatIndex += indexes.j()*stride;
		stride *= axes_.at(1).size;
		flatIndex += indexes.i()*stride;

		return values_.at(flatIndex);
	}
	default:
		return AMNumber::InvalidError;
	}
}