package trail.transaction;

import trail.entity.beans.*;
import javax.ejb.*;
import javax.persistence.*;
import javax.annotation.Resource;
import java.util.*;

@Stateless
public class TransCalculator implements Calculator {

  @PersistenceContext
  protected EntityManager em;

  public Collection <TimedRecord> getRecords () {
    return em.createQuery("from TimedRecord r order by r.id desc").getResultList();
  }

  @TransactionAttribute(TransactionAttributeType.REQUIRED)
  public void updateExchangeRate (double newrate) throws Exception {
    Collection <TimedRecord> rc = em.createQuery("from TimedRecord r").getResultList();
    int size = rc.size();

    for (Iterator iter = rc.iterator(); iter.hasNext();) {
      TimedRecord r = (TimedRecord) iter.next();
      r.setSaving(r.getSaving() * newrate);
      r.setResult(r.getResult() * newrate);

      // Emulate a failure

      // Calculate failure probability for each loop
      // in order for the overall failure probability
      // to be 50%
      double prob = Math.pow (0.5, 1./size);
      if (Math.random() > prob) {
        // Emulated failure causes rollback
        throw new TransException ();

        // Or throw a RuntimeException to trigger rollback
      }
    }
  }

  @TransactionAttribute(TransactionAttributeType.REQUIRED)
  public void updateExchangeRate2 (double newrate) throws Exception {
    Collection <TimedRecord> rc = em.createQuery("from TimedRecord r").getResultList();
    for (Iterator iter = rc.iterator(); iter.hasNext();) {
      TimedRecord r = (TimedRecord) iter.next();
      r.setSaving(r.getSaving() * newrate);
      r.setResult(r.getResult() * newrate);

      // Emulate a database failure
      int status = (int) (Math.random () * 4.);
      System.err.println("status is " + status);
      if (status == 3) {
        throw new RuntimeException ("Emulated database failure");
      }
      // Synchronize the persistence context to the DB
      // All flushed updates will be removed from the DB
      // if the transaction is rolled back
      em.flush();
    }
    // em.flush();
  }
}
