/**
 * License Agreement.
 *
 * Rich Faces - Natural Ajax for Java Server Faces (JSF)
 *
 * Copyright (C) 2007 Exadel, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 */
package org.ajax4jsf.portlet.context;

import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Iterator;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * 
 * @author shura
 * 
 * 
 * 
 * Base class for All maps in <code>ExternalContextCocoonImpl</code> get from
 * 
 * Sun Jsf-ri
 * 
 * 
 * 
 */
abstract class ContextMap extends AbstractMap {
    private transient volatile Set keySet;

    /*
         * 
         * (non-Javadoc)
         * 
         * 
         * 
         * @see java.util.Map#entrySet()
         * 
         */
    public Set entrySet() {
	Set entries = new HashSet();
	for (Enumeration e = getEnumeration(); e.hasMoreElements();) {
	    String paramName = (String) e.nextElement();
	    if (isValidParameter(paramName)) {
		entries.add(new Entry(paramName, get(paramName)));
	    }
	}
	return entries;
    }

    protected boolean isValidParameter(String paramName) {
	return true;
    }

    public Set keySet() {
	if (this.keySet == null) {
	    this.keySet = new AbstractSet() {
		public Iterator iterator() {
		    return new EnumerationIterator(getEnumeration());
		}

		public int size() {
		    Enumeration enumeration = getEnumeration();
		    int size = 0;
		    while (enumeration.hasMoreElements()) {
			size++;
		    }
		    ;
		    return size;
		}
	    };
	}
	return this.keySet;
    }

    public Collection values() {
	return super.values();
    }

    /**
         * 
         * 
         * 
         * Template metod - all maps in ExternalFacesContext creates Set from
         * 
         * parameters <code>Enumeration</code>
         * 
         * 
         * 
         * @return enumeration for current map.
         * 
         */
    protected abstract Enumeration getEnumeration();

    // Unsupported by all Maps.
    public void clear() {
	throw new UnsupportedOperationException();
    }

    // Unsupported by all Maps.
    public void putAll(Map t) {
	throw new UnsupportedOperationException();
    }

    // Supported by maps if overridden
    public Object remove(Object key) {
	throw new UnsupportedOperationException();
    }

    static class Entry implements Map.Entry {
	// immutable Entry
	private final Object key;

	private final Object value;

	Entry(Object key, Object value) {
	    this.key = key;
	    this.value = value;
	}

	public Object getKey() {
	    return this.key;
	}

	public Object getValue() {
	    return this.value;
	}

	// No support of setting the value
	public Object setValue(Object value) {
	    throw new UnsupportedOperationException();
	}

	public int hashCode() {
	    return ((this.key == null ? 0 : this.key.hashCode()) ^ (this.value == null ? 0
		    : this.value.hashCode()));
	}

	public boolean equals(Object obj) {
	    if ((obj == null) || !(obj instanceof Map.Entry)) {
		return false;
	    }
	    Map.Entry input = (Map.Entry) obj;
	    Object inputKey = input.getKey();
	    Object inputValue = input.getValue();
	    if ((inputKey == this.key) || ((inputKey != null) && inputKey.equals(this.key))) {
		if ((inputValue == this.value)
			|| ((inputValue != null) && inputValue.equals(this.value))) {
		    return true;
		}
	    }
	    return false;
	}
    }

    public boolean equals(Object obj) {
	if ((obj == null) || !(obj instanceof ContextMap)) {
	    return false;
	}
	return super.equals(obj);
    }
}