package org.basex.core;

import java.util.LinkedList;
import org.basex.util.Util;

/**
 * Management of executing read/write processes.
 * Supports multiple readers, limited by {@link MainProp#PARALLEL},
 * and a single writer (readers/writer lock).
 *
 * @author BaseX Team 2005-11, BSD License
 * @author Christian Gruen
 */
final class Lock {
  /** Queue for all waiting processes. */
  private final LinkedList<Object> queue = new LinkedList<Object>();
  /** Mutex object. */
  private final Object mutex = new Object();
  /** Database context. */
  private final Context ctx;

  /** Number of active readers. */
  private int readers;
  /** Writer flag. */
  private boolean writer;

  /**
   * Default constructor.
   * @param c context
   */
  Lock(final Context c) {
    ctx = c;
  }

  /**
   * Modifications before executing a command.
   * @param w writing flag
   */
  void lock(final boolean w) {
    final Object o = new Object();

    synchronized(mutex) {
      queue.add(o);

      while(true) {
        if(!writer && o == queue.get(0)) {
          if(w) {
            if(readers == 0) {
              writer = true;
              break;
            }
          } else if(readers < Math.max(ctx.mprop.num(MainProp.PARALLEL), 1)) {
            ++readers;
            break;
          }
        }
        try {
          mutex.wait();
        } catch(final InterruptedException ex) {
          Util.stack(ex);
        }
      }

      queue.remove(0);
    }
  }

  /**
   * Modifications after executing a command.
   * @param w writing flag
   */
  void unlock(final boolean w) {
    synchronized(mutex) {
      if(w) {
        writer = false;
      } else {
        --readers;
      }
      mutex.notifyAll();
    }
  }
}
