package Samples;

/*Generated by MPS */

import java.util.List;
import jetbrains.mps.internal.collections.runtime.ListSequence;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CopyOnWriteArrayList;
import utils.ParallelLoopException;

public class ThreadSafeSample {
  private static final String fixedFieldValue = "Fixed value for ever";
  public ThreadSafeSample() {
  }
  public static void main(String[] args) throws InterruptedException {
    // This sample shows that classes marked thread-safe will not be reported
    //  as inproperly used from within parallel for loops

    // This is a thread safe class to exchange a single value between a producer and a consumer
    // Open the DropBox class definition and notice the "@thread safe" annotation for the class
    final DropBox<String> box = new DropBox<String>();

    // A consumer thread reading and printing values exchanged through the drop box
    Thread thread = new Thread(new Runnable() {
      @Override
      public void run() {
        try {
          while (true) {
            System.out.println("Received: " + box.retrieve());
          }
        } catch (InterruptedException e) {
          System.out.println("Interrupted");
        }
      }
    });
    thread.start();

    final List<String> names = ListSequence.fromListAndArray(new ArrayList<String>(), "Joe", "Dave", "Alice");

    {
      final CountDownLatch latch_n0c = new CountDownLatch(ListSequence.fromList(names).count());
      final List<Exception> exceptions_n0c = new CopyOnWriteArrayList<Exception>();

      for (final String name : names) {

        final String localA = name;
        final Runnable runnable = () -> {
          try {
            try {
              // Notice no warning nor error reported
              box.store(localA);
              // If the DropBox class was annotated as "@non thread safe", we would get an error reported
              // No annotation on the class would result in a warning
            } catch (InterruptedException e) {
              throw new RuntimeException(e);
            }
          } catch (RuntimeException e) {
            ListSequence.fromList(exceptions_n0c).addElement(e);
          } finally {
            latch_n0c.countDown();
          }
        };

        new Thread(runnable).start();

      }
      try {
        latch_n0c.await();
      } catch (InterruptedException e) {
        ListSequence.fromList(exceptions_n0c).addElement(e);
      }
      if (ListSequence.fromList(exceptions_n0c).isNotEmpty()) {
        throw new ParallelLoopException("Some parallel calculations failed", exceptions_n0c);
      }

    }

    // By annotating a local variable, field or parameter declaration as thread safe you indicate that calling methods
    // on the object is thread-safe
    // Alt + Enter on variable declarations will let you mark and unmark them as thread-safe
    final String fixedValue = " fixed value ";

    {
      final CountDownLatch latch_u0c = new CountDownLatch(ListSequence.fromList(names).count());
      final List<Exception> exceptions_u0c = new CopyOnWriteArrayList<Exception>();

      for (final String name : names) {

        final String localA = name;
        final Runnable runnable = () -> {
          try {
            String finalString = localA + fixedValue.toUpperCase() + fixedFieldValue;
            log("Result: " + finalString);
          } catch (RuntimeException e) {
            ListSequence.fromList(exceptions_u0c).addElement(e);
          } finally {
            latch_u0c.countDown();
          }
        };

        new Thread(runnable).start();

      }
      try {
        latch_u0c.await();
      } catch (InterruptedException e) {
        ListSequence.fromList(exceptions_u0c).addElement(e);
      }
      if (ListSequence.fromList(exceptions_u0c).isNotEmpty()) {
        throw new ParallelLoopException("Some parallel calculations failed", exceptions_u0c);
      }

    }
    thread.interrupt();
  }
  private static void log(String message) {
    System.out.println(message);
  }
}
