/*
 ************************************************************************
 *
 * Copyright (c) 2003-2004, C&C Research Laboratories, NEC Europe Ltd.
 *
 * Copyright in this software belongs to C&C Research Laboratories,
 * Rathausallee 10, 53757 Sankt Augustin, Germany.
 *
 * This software may not be used, sold, licensed, transferred, copied
 * or reproduced in whole or in part in any manner or form or in or
 * on any media by any person other than in accordance with the terms
 * of the Licence Agreement supplied with the software, or otherwise
 * without the prior written consent of the copyright owners.
 *
 * This software is distributed WITHOUT ANY WARRANTY, without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE, except where stated in the Licence Agreement supplied with
 * the software.
 *
 *  Created By :           G.A. Kohring
 *  Created for Project :  GEMSS (IST-2001-37153)
 *
 ************************************************************************
 *
 */

package de.nece.ccrle.util;

import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;

/**
 * Provides synchronized and immutable registries.
 *
 * @author Greg Kohring
 */
public final class Registries {

    // Make sure nobody tries to instantiate this class
    private Registries() {
    }

    /**
     * Returns a synchronized (thread-safe) register backed by the specified
     * register.
     * <P>
     * NOTE: The following comments are taken from the Java documention 
     * for the <tt>Collections</tt> class.
     * <P>
     * In order to guarantee serial access, it is critical that
     * <strong>all</strong> access to the backing registry is accomplished
     * through the returned register.<p>
     *
     * It is imperative that the user manually synchronize on the returned
     * register when iterating over it:
     * <pre>
     *  Register r = Registries.synchronizedRegister( myRegister );
     *     ...
     *  synchronized(r) {
     *      Iterator i = r.iterator(); // Must be in the synchronized block
     *      while (i.hasNext())
     *         foo(i.next());
     *  }
     * </pre>
     * Failure to follow this advice may result in non-deterministic behavior.
     *
     * @param  r the register to be "wrapped" in a synchronized register.
     * @return a synchronized view of the specified register.
     */

    public static Register synchronizedRegister( Register r ) {
    return new SynchronizedRegister( r );
    }

    static Register synchronizedRegister( Register r, Object mutex ) {
    return new SynchronizedRegister( r, mutex );
    }

    /**
     * @serial include
     */
    static class SynchronizedRegister implements Register, Serializable {

        Register r;      // Backing Registry
        Object   mutex;  // Object on which to synchronize

        SynchronizedRegister( Register r ) {
            if ( r == null ){
                throw new NullPointerException();
            }
            this.r = r;
            mutex = this;
        }

        SynchronizedRegister( Register r, Object mutex ) {
            this.r = r;
            this.mutex = mutex;
        }

        public int size() {
            synchronized(mutex) {
                return r.size();
            }
        }

        public boolean isEmpty() {
            synchronized(mutex) {
                return r.isEmpty();
            }
        }

        public boolean contains( Object o ) {
            synchronized(mutex) {
                return r.contains(o);
            }
        }

        public Object[] toArray() {
            synchronized(mutex) {
                return r.toArray();
            }
        }

        public Object[] toArray( Object[] a ) {
            synchronized(mutex) {
                return r.toArray(a);
            }
        }

        //NOTE: The user must manually synchronize the Iterator!
        public Iterator iterator() {
            return r.iterator();
        }

        public boolean add( Object o ) {
            synchronized(mutex) {
                return r.add(o);
            }
        }

        public boolean remove( Object o ) {
            synchronized(mutex) {
                return r.remove(o);
            }
        }

        public boolean containsAll( Collection c ) {
            synchronized(mutex) {
                return r.containsAll( c );
            }
        }

        public boolean addAll( Collection c ) {
            synchronized(mutex) {
                return r.addAll( c );
            }
        }

        public boolean removeAll( Collection c ) {
            synchronized(mutex) {
                return r.removeAll( c );
            }
        }

        public boolean retainAll( Collection c ) {
            synchronized(mutex) {
                return r.retainAll( c );
            }
        }

        public void clear() {
            synchronized(mutex) {
                r.clear();
            }
        }

        public String toString() {
            synchronized(mutex) {
                return r.toString();
            }
        }

        public boolean equals( Object o ) {
            synchronized(mutex) {
                return r.equals( o );
            }
        }

        public int hashCode() {
            synchronized(mutex) {
                return r.hashCode();
            }
        }

        public void setRegisterID( String id ){
            synchronized(mutex) {
                r.setRegisterID( id );
            }
        }

        public String getRegisterID(){
            synchronized(mutex) {
                return r.getRegisterID();
            }
        }


    }
}
