/**
 * \brief Dark image construction function for arbitrary image sequences
 */
ImagePtr DarkFrameFactory::operator()(const ImageSequence& images) const {
	debug(LOG_DEBUG, DEBUG_LOG, 0, "processing %d images into dark frame",
		images.size());
	// make sure we have at least one image
	if (images.size() == 0) {
		debug(LOG_ERR, DEBUG_LOG, 0, "cannot create dark from no images");
		throw std::runtime_error("no images in sequence");
	}

	// find out whether these are Bayer images, by looking at the first
	// image
	ImagePtr	firstimage = *images.begin();
	bool	gridded = firstimage->getMosaicType().isMosaic();
	debug(LOG_DEBUG, DEBUG_LOG, 0, "first image is %sgridded",
		(gridded) ? "" : "not ");
	
	// based on the bit size of the first image, decide whether to work
	// with floats or with doubles
	unsigned int	floatlimit = std::numeric_limits<float>::digits;
	debug(LOG_DEBUG, DEBUG_LOG, 0, "float limit is %u", floatlimit);
	ImagePtr	result;
	if (firstimage->bitsPerPlane() <= floatlimit) {
		result = dark<float>(images, gridded);
	} else {
		result = dark<double>(images, gridded);
	}
	if (firstimage->hasMetadata("INSTRUME")) {
		result->setMetadata(firstimage->getMetadata("INSTRUME"));
	}
	if (firstimage->hasMetadata("PROJECT")) {
		result->setMetadata(firstimage->getMetadata("PROJECT"));
	}
	result->setMosaicType(firstimage->getMosaicType());
	return result;
}
/**
 * \brief Check that the image sequence is consistent 
 *
 * Only a if all the images are of the same size we can actually compute
 * a calibration image.
 * \param images
 */
bool	consistent(const ImageSequence& images) {
	// make sure all images in the sequence are of the same size
	ImageSequence::const_iterator	i = images.begin();
	for (i++; i != images.end(); i++) {
		if ((*images.begin())->size() != (*i)->size()) {
			debug(LOG_DEBUG, DEBUG_LOG, 0, "image size mismatch");
			return false;
		}
	}

	// make sure all the images are monochrome images. There is now way
	// to calibrate color image,
	for (i = images.begin(); i != images.end(); i++) {
		if (isColorImage(*i)) {
			return false;
		}
	}
	return true;
}
void	ImageMean<T>::setup_images(const ImageSequence& images) {
	// create an image of appropriate size
	size = (*images.begin())->size();
	image = new Image<T>(size);
	if (enableVariance) {
		// prepare the variance image
		var = new Image<T>(size);
	} else {
		var = NULL;
	}
}
void	ImageMean<T>::setup_pv(const ImageSequence& images) {
	// the image sequence must be consistent, or we cannot do 
	// anything about it
	if (!consistent(images)) {
		throw std::runtime_error("images not consistent");
	}

	// we need access to the pixels, but we want to avoid all the
	// time consuming dynamic casts, so we create a vector of
	// PixelValue objects, which already do the dynamic casts
	// in the constructor
	ImageSequence::const_iterator i;
	for (i = images.begin(); i != images.end(); i++) {
		pvs.push_back(PV(*i));
	}
}