/*
 ************************************************************************
 *
 * 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.ObjectOutputStream;
import java.net.InetAddress;
import java.util.Date;
import java.util.Set;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Collection;

import eu.gemss.components.providers.Registrable;

/**
 * This class implements the <tt>Register</tt> interface, backed by a 
 * hash table (actually a <tt>HashMap</tt> instance).
 *
 * @author Greg Kohring
 *
 */
public class HashRegister extends HashSet implements Register {

    // A string identifying this registry
    private String registryID;

    /**
     * Constructs a new, empty registry; the backing <tt>HashMap</tt> instance
     * has default initial capacity (16) and load factor (0.75).
     */
    public HashRegister() {
        super();
    }

    /**
     * Constructs a new, empty registry; the backing <tt>HashMap</tt> instance
     * has the specified initial capacity and default load factor, which is
     * <tt>0.75</tt>.
     *
     * @param      initialCapacity  the initial capacity of the hash table.
     * @throws     IllegalArgumentException if the initial capacity is less
     *             than zero.
     */
    public HashRegister( int initialCapacity ) {
        super( initialCapacity );
        initializeID();
    }

    /**
     * Constructs a new, empty registry; the backing <tt>HashMap</tt> instance
     * has the specified initial capacity and the specified load factor.
     *
     * @param      initialCapacity   the initial capacity of the hash map.
     * @param      loadFactor        the load factor of the hash map.
     * @throws     IllegalArgumentException if the initial capacity is less
     *             than zero, or if the load factor is nonpositive.
     */
    public HashRegister( int initialCapacity, float loadFactor ) {
        super( initialCapacity, loadFactor  );
        initializeID();
    }

    /**
     * Constructs a new registry containing the elements in the specified
     * registry.  The <tt>HashMap</tt> is created with default load factor
     * (0.75) and an initial capacity sufficient to contain the elements in
     * the specified registry.
     *
     * @param r the registry whose elements are to be placed into this
     *        registry.
     * @throws NullPointerException  if the specified registry is null.
     */
    public HashRegister( Register r ) {
        super( r );
        initializeID();
    }

    // Sets the registryID for this registry

    public boolean add( Object o ){
        if ( o instanceof Registrable ){
            Registrable ro = (Registrable) o;
            if ( ro.onRegistration( getRegisterID () ) ){
                super.add( o );
                return true;
            } else {
                return false;
            }
        } else {
            super.add( o );
            return true;
        }
    }

    public boolean addAll(Collection c) {
        boolean changed = false;
        Iterator ic = c.iterator();
        while ( ic.hasNext() ){
            changed |= add( ic.next() );
        }
        return changed;
    }

    public boolean remove( Object o ){
        if ( super.remove( o ) ) {
            if ( o instanceof Registrable ){
                Registrable ro = (Registrable) o;
                ro.onDeregistration( getRegisterID () );
            } 
            return true;
        } else {
            return false;
        }
    }

    public boolean removeAll( Collection c ) {
        boolean changed = false;
        Iterator ic = c.iterator();
        while ( ic.hasNext() ){
            changed |= remove( ic.next() );
        }
        return changed;
    }
                                                                                
    public void clear(){
        Iterator items = iterator();
        while ( items.hasNext() ){
            Object o = items.next();
            items.remove();
        }
    }

    private Iterator hashSetIterator(){
        return super.iterator();
    }

    public Iterator iterator(){
        return new Iterator() {
            private Iterator i = HashRegister.this.hashSetIterator();
            private Object current = null;

            public boolean hasNext(){
                return i.hasNext();
            }

            public Object next(){
                current = i.next();
                return current;
            }

            public void remove(){
                if ( current != null ){
                    if ( current instanceof Registrable ){
                        Registrable cr = (Registrable) current;
                        cr.onDeregistration( 
                                       HashRegister.this.getRegisterID() );
                    }
                }
                i.remove();
            }
        };
    }

    public String getRegisterID() {
        	return registryID;
    }

    public void setRegisterID( String id ) {
        	if ( id != null ) {
                registryID = registryID.concat( ":" ).concat( id );
            }
    }

    private void initializeID(){
        String hostName;
        try{
            hostName = InetAddress.getLocalHost().getHostName();
        } catch ( Exception e) {
            hostName = "unknown";
        }

        String user = System.getProperty( "user.name" );

        Date date = new Date();

        String now = Long.toString( date.getTime() );

        registryID = "urn:registry:" + hostName + ":" + user + ":" + now;
    }

    /**
     * Clones this instance of the <tt>HashRegisty</tt>.
     * The elements themselves are not cloned, their references are
     * simply copied to the new registry.
     *
     * @return a shallow copy of this registry.
     */
    public Object clone(){
        Object obj = super.clone();
        return obj;
    }

    public int hashCode(){
        return super.hashCode();
    }

    public boolean equals( Object o){
        if ( o == this ){
            return true;
        }

        if ( !( o instanceof HashRegister)  ){
            return false;
        }

        return super.equals( o );
    }


    /** @link dependency */
    /*# Registrable lnkRegistrable; */
}
