/**
 ** -----------------------------------------------------------------------------**
 ** ImagejJp4TiffMulti.java
 **
 ** Uses loci.format compatible readers for Elphel 8/16 bpp monochrome Tiff and
 ** JP4 files to read/parse camera files in a single url read operation by
 ** buffering camera data with Location.mapFile()
 **
 **
 ** Copyright (C) 2019 Elphel, Inc.
 **
 ** -----------------------------------------------------------------------------**
 **
 **  ImagejJp4TiffMulti.java 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 com.elphel.imagej.readers;

import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;

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

import ij.ImagePlus;
import loci.formats.ClassList;
import loci.formats.FormatException;

public class ImagejJp4TiffMulti {
	private static final int MAX_THREADS =   100;
	private static final Logger LOGGER =     LoggerFactory.getLogger(ClassList.class);
	private final ImagejJp4Tiff [] imagejJp4Tiff = new ImagejJp4Tiff [MAX_THREADS];


	public ImagePlus [] getMultiImages(
			final String [] urls,
			final ImagePlus [] imps,
//			final boolean telemetry,
			final boolean scale,
			final String std) throws IOException, FormatException  // std - include non-elphel properties with prefix std
	{
//		final ImagePlus [] imps = new ImagePlus [urls.length];
		LOGGER.error("Please ignore 'File has length 0 and may be corrupt' - caused by bioformat reading memory file");
   		final Thread[] threads = newThreadArray(MAX_THREADS);
   		final AtomicInteger indxAtomic = new AtomicInteger(0);
   		final AtomicInteger threadAtomic = new AtomicInteger(0);
   		for (int ithread = 0; ithread < threads.length; ithread++) {
   			threads[ithread] = new Thread() {
   				@Override
				public void run() {
   					int threadIndx = threadAtomic.getAndIncrement();
   					if (imagejJp4Tiff[threadIndx] == null ) {
   						imagejJp4Tiff[threadIndx] = new ImagejJp4Tiff();
   					}
   					for (int indx = indxAtomic.getAndIncrement(); indx < urls.length; indx = indxAtomic.getAndIncrement())
   					{
   						try {
							imps[indx] = imagejJp4Tiff[threadIndx].readTiffJp4(urls[indx], scale, std);
						} catch (IOException e) {
							LOGGER.error("getMultiImages IOException " + urls[indx]);
						} catch (FormatException e) {
							LOGGER.error("getMultiImages FormatException " + urls[indx]);
						}
   					}
   				}
   			};
   		}
   		startAndJoin(threads);
		return imps;
	}




	/* Create a Thread[] array as large as the number of processors available.
	 * From Stephan Preibisch's Multithreading.java class. See:
	 * http://repo.or.cz/w/trakem2.git?a=blob;f=mpi/fruitfly/general/MultiThreading.java;hb=HEAD
	 */
	private Thread[] newThreadArray(int maxCPUs) {
		int n_cpus = Runtime.getRuntime().availableProcessors();
		if (n_cpus>maxCPUs)n_cpus=maxCPUs;
		return new Thread[n_cpus];
	}
/* Start all given threads and wait on each of them until all are done.
	 * From Stephan Preibisch's Multithreading.java class. See:
	 * http://repo.or.cz/w/trakem2.git?a=blob;f=mpi/fruitfly/general/MultiThreading.java;hb=HEAD
	 */
	private static void startAndJoin(Thread[] threads)
	{
		for (int ithread = 0; ithread < threads.length; ++ithread)
		{
			threads[ithread].setPriority(Thread.NORM_PRIORITY);
			threads[ithread].start();
		}

		try
		{
			for (int ithread = 0; ithread < threads.length; ++ithread)
				threads[ithread].join();
		} catch (InterruptedException ie)
		{
			throw new RuntimeException(ie);
		}
	}


}