package eu.dnetlib.espas.data.harvest;

import static org.junit.Assert.assertEquals;

import java.util.Iterator;

import org.apache.log4j.Logger;
import org.junit.Test;

public class TestCSWTransImplConcurrency
{
   {  // Class initialization.
      logger = Logger.getLogger(TestCSWTransImplConcurrency.class);
   }
   private static Logger logger = null;

   public void testProducerConsumerConcurrency(final int numOfRecordsToProduce, final int timeToSleepBeforeCheckingHarvestingStatus, final int producersMaxTimeToSleep, final int consumersMaxTimeToSleep)
   {
      RecordsHarvester recordsHarvester = new RecordsHarvesterTransImpl(null);
      Producer producer = new Producer();
      producer.setNumOfRecordsToProduce(numOfRecordsToProduce);
      producer.setMaxTimeToSleep(producersMaxTimeToSleep);
      producer.setRecordsHarvester(recordsHarvester);
      Consumer consumer = new Consumer();
      consumer.setMaxTimeToSleep(consumersMaxTimeToSleep);
      consumer.setRecordsHarvester(recordsHarvester);
      CSWHarvester cswHarvester = new CSWHarvester();
      cswHarvester.getExecutorService().execute(consumer);
      cswHarvester.getExecutorService().execute(producer);

      try
      {
         while(!(recordsHarvester.isHarvestingCompleted() && recordsHarvester.size() == 0))
         {
            Thread.sleep(timeToSleepBeforeCheckingHarvestingStatus);
            logger.info("Harvesting has not completed yet!");
         }
         logger.info("Harvesting has been completed yet!");
         assertEquals("Different sums between the producer and the cosnumer", producer.getSum(), consumer.getSum());
      }
      catch(InterruptedException e)
      {
         logger.error("Interrupted exception", e);
      }
      cswHarvester.shutdownAndWaitTermination();
   }

   // Both the producer and the consumer, act in the same speed.
   @Test
   public void testRecordsHarvesterTransImplConcurrency1()
   {
      this.testProducerConsumerConcurrency(10, 100, 100, 100);
   }

   // The consumer consumes much faster than the producer produces.
   @Test
   public void testRecordsHarvesterTransImplConcurrency2()
   {
      this.testProducerConsumerConcurrency(10, 100, 100, 1);
   }

   // The producer produces much faster than the comsumer consumes.
   @Test
   public void testRecordsHarvesterTransImplConcurrency3()
   {
      this.testProducerConsumerConcurrency(10, 100, 1, 100);
   }

   public void testIterator(final int numOfRecordsToProduce, int producersMaxTimeToSleep, int consumersMaxTimeToSleep)
   {
      int actualSum = 0;
      RecordsHarvester recordsHarvester = new MockRecordsHarvesterTransImpl();
      ((MockRecordsHarvesterTransImpl)recordsHarvester).setNumOfRecordsToProduce(numOfRecordsToProduce);
      ((MockRecordsHarvesterTransImpl)recordsHarvester).setMaxTimeToSleep(producersMaxTimeToSleep);
      CSWHarvester cswHarvester = new CSWHarvester();
      cswHarvester.execute(recordsHarvester);

      try
      {
         String value = null;
         Iterator<String> it = recordsHarvester.iterator();
         while(it.hasNext())
         {
            Thread.sleep(consumersMaxTimeToSleep);
            value = it.next();
            actualSum += Integer.parseInt(null != value ? value : "0");
         }
         assertEquals("Different sums between the producer and the cosnumer", ((MockRecordsHarvesterTransImpl)recordsHarvester).getSum(), actualSum);
      }
      catch(InterruptedException e)
      {
         logger.error("Interrupted exception", e);
      }
      cswHarvester.shutdownAndWaitTermination();
   }

   // Both the producer and the consumer, act in the same speed.
   @Test
   public void testRecordsHarvesterTransImplConcurrencyIterator4()
   {
      this.testIterator(10, 100, 100);
   }

   // The consumer consumes much faster than the producer produces.
   @Test
   public void testRecordsHarvesterTransImplConcurrencyIterator5()
   {
      this.testIterator(10, 100, 1);
   }

   // The producer produces much faster than the comsumer consumes.
   @Test
   public void testRecordsHarvesterTransImplConcurrencyIterator6()
   {
      this.testIterator(10, 1, 100);
   }

   public void testIterable(final int numOfRecordsToProduce, final int producersMaxTimeToSleep, final int consumersMaxTimeToSleep)
   {
      int actualSum = 0;
      RecordsHarvester recordsHarvester = new MockRecordsHarvesterTransImpl();
      ((MockRecordsHarvesterTransImpl)recordsHarvester).setNumOfRecordsToProduce(numOfRecordsToProduce);
      ((MockRecordsHarvesterTransImpl)recordsHarvester).setMaxTimeToSleep(producersMaxTimeToSleep);
      CSWHarvester cswHarvester = new CSWHarvester();
      cswHarvester.execute(recordsHarvester);

      try
      {
         for(String value : (MockRecordsHarvesterTransImpl)recordsHarvester)
         {
            Thread.sleep(consumersMaxTimeToSleep);
            actualSum += Integer.parseInt(null != value ? value : "0");
         }
         assertEquals("Different sums between the producer and the cosnumer", ((MockRecordsHarvesterTransImpl)recordsHarvester).getSum(), actualSum);
      }
      catch(InterruptedException e)
      {
         logger.error("Interrupted exception", e);
      }
      cswHarvester.shutdownAndWaitTermination();
   }

   // Both the producer and the consumer, act in the same speed.
   @Test
   public void testRecordsHarvesterTransImplConcurrencyIterable7()
   {
      this.testIterable(10, 100, 100);
   }

   // The consumer consumes much faster than the producer produces.
   @Test
   public void testRecordsHarvesterTransImplConcurrencyIterable8()
   {
      this.testIterable(10, 100, 1);
   }

   // The producer produces much faster than the comsumer consumes.
   @Test
   public void testRecordsHarvesterTransImplConcurrencyIterable9()
   {
      this.testIterable(10, 1, 100);
   }
}
