/*
 * 
 * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved.
 * 
 * The contents of this file are subject to the Sun Community Source
 * License v3.0/Jini Technology Specific Attachment v 1.0 (the
 * "License"). You may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 * http://wwws.sun.com/software/jini/licensing/SCSL3_JiniTSA1.html.
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 * the License for the specific language governing rights and limitations
 * under the License.
 * 
 * The Reference Code is Jini Technology Core Platform code, v2.0. The
 * Developer of the Reference Code is Sun Microsystems, Inc.
 * 
 * Contributor(s): Sun Microsystems, Inc.
 * 
 * The contents of this file comply with the Jini Technology Core
 * Platform Compatibility Kit, v2.0A.
 * 
 * Tester(s): Sun Microsystems, Inc.
 * 
 * Test Platform(s):
 * Java 2 SDK, Standard Edition, Version 1.4.2_03 for Solaris(TM)SPARC/x86
 * Java 2 SDK, Standard Edition, Version 1.4.2_03 for Linux (Intel x86)
 * Java 2 SDK, Standard Edition, Version 1.4.2_03 for Windows (Intel Platform)
 * 
 */
package com.sun.jini.mercury;

import net.jini.id.Uuid;
import net.jini.core.event.RemoteEvent;

import java.io.IOException;

import com.sun.jini.logging.Levels;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.NoSuchElementException;

/**
 * Class that implements the interface for an <tt>EventLog</tt>. 
 * This class encapsulates the details of reading/writing events from/to
 * some non-persistent mechanism.
 *
 * This class makes certain assumptions. First, the <tt>next</tt> and
 * <tt>remove</tt> methods are intended to be called in pairs. If 
 * <tt>remove</tt> is not called, then subsequent calls to <tt>next</tt> 
 * will attempt to return the same object. Calling <tt>remove</tt> 
 * essentially advances the read pointer to the next object, if any. 
 *
 * @author Sun Microsystems, Inc.
 *
 * @since 2.0
 */

class TransientEventLog implements EventLog {

    //
    // Class fields
    //

    /** <tt>Logger</tt> used for persistence-related debugging messages */
    private static final Logger persistenceLogger = 
	MailboxImpl.persistenceLogger;

    //
    // Object fields
    //

    /** The associated <tt>Uuid</tt> for this <tt>EventLog</tt>. */
    private Uuid uuid = null;

    /** The associated, non-persistent storage for events */
    private List entries = null;

    /** 
     * Flag that is used to determine whether or not this object 
     * has been closed. 
     */
    private boolean closed = false;

    /**
     * Simple constructor that takes a <tt>Uuid</tt> argument.
     *
     * @exception IllegalArgumentException if the argument is null
     */
    TransientEventLog(Uuid uuid) {
        if (uuid == null) 
            throw new IllegalArgumentException("Uuid cannot be null");
        this.uuid = uuid;
	entries = Collections.synchronizedList(new LinkedList());

        if (persistenceLogger.isLoggable(Level.FINEST)) {
            persistenceLogger.log(Level.FINEST, 
	        "TransientEventLog for: {0}", uuid);
        }
    }

    // Inherit documentation from supertype
    public void init() throws IOException {
	//Do nothing
    }

    // Inherit documentation from supertype
    public void add(RemoteEvent event) throws IOException {
	entries.add(event);
        printControlData(persistenceLogger, "TransientEventLog::add");
    }

    // Inherit documentation from supertype
    public RemoteEvent next() throws IOException {
        // Check if empty
	if (isEmpty()) 
	    throw new NoSuchElementException();

        printControlData(persistenceLogger, "Event::next");
        return (RemoteEvent)entries.get(0);
    }
    
    // Inherit documentation from supertype
    public boolean isEmpty() throws IOException {
        return entries.isEmpty();
    }

    // Inherit documentation from supertype
    public void remove() throws IOException {
        printControlData(persistenceLogger, "Event::remove");
	entries.remove(0);
    }

    // Inherit documentation from supertype
    public void close() throws IOException {
        closed = true;
	if (persistenceLogger.isLoggable(Level.FINEST)) {
            persistenceLogger.log(Level.FINEST, 
	        "TransientEventLog::close for {0}", uuid);
	}
	// Do nothing
    }

    // Inherit documentation from supertype
    public void delete() throws IOException {
        if (!closed)
            throw new IOException("Cannot delete log until it is closed");
	entries.clear();
	if (persistenceLogger.isLoggable(Level.FINEST)) {
            persistenceLogger.log(Level.FINEST, 
	        "TransientEventLog::destroy for {0}", uuid);
	}
    }

    /**
     * Output state information to the given <tt>Logger</tt>.
     * This is intended for debugging purposes only.
     */
    private void printControlData(Logger logger, String msg) {
	if (logger.isLoggable(Level.FINEST)) {
	    logger.log(Level.FINEST, "{0}", msg);
            logger.log(Level.FINEST, "ID: {0}", uuid);
            logger.log(Level.FINEST, "NumEvents: {0}", 
	        new Long(entries.size()));
	}
    }
}
