/*
 * The contents of this file are subject to the terms 
 * of the Common Development and Distribution License 
 * (the License).  You may not use this file except in
 * compliance with the License.
 * 
 * You can obtain a copy of the license at 
 * https://glassfish.dev.java.net/public/CDDLv1.0.html or
 * glassfish/bootstrap/legal/CDDLv1.0.txt.
 * See the License for the specific language governing 
 * permissions and limitations under the License.
 * 
 * When distributing Covered Code, include this CDDL 
 * Header Notice in each file and include the License file 
 * at glassfish/bootstrap/legal/CDDLv1.0.txt.  
 * If applicable, add the following below the CDDL Header, 
 * with the fields enclosed by brackets [] replaced by
 * you own identifying information: 
 * "Portions Copyrighted [year] [name of copyright owner]"
 * 
 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
 */
package com.sun.appserv.management.util.misc;

import java.util.Set;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.HashMap;
import java.util.Properties;

import com.sun.appserv.management.util.stringifier.SmartStringifier;


public final class MapUtil
{
		private
	MapUtil( )
	{
		// disallow instantiation
	}
	
	    public static <K,V> V
	getWithDefault( final Map<K,V> m, final K key, V defaultValue )
	{
	    return m.containsKey( key ) ? m.get( key ) : defaultValue;
	}
	
	
		public static Object[]
	getKeyObjects( final Map<?,?> m)
	{
		return( SetUtil.toArray( m.keySet() ) );
	}
	
		public static String[]
	getKeyStrings( final Map<?,?> m)
	{
		return( GSetUtil.toSortedStringArray( m.keySet() ) );
	}
	
	/**
		Create a new Map consisting of a single key/value pair.
	 */
		public static <V> Map<String,V>
	newMap( 
		final String key,
		final V      value )
	{
		final Map<String,V>	m	= new HashMap<String,V>();
		
		m.put( key, value );
		
		return( m );
	}
	
	/**
		Create a new Map consisting of a single key/value pair.
	 */
		public static <K,V> Map<K,V>
	newMap( 
		final Map<K,V>	m1,
		final Map<K,V>	m2 )
	{
		final Map<K,V>	m	= new HashMap<K,V>();
		
		if ( m1 != null )
		{
			m.putAll( m1 );
		}
		if ( m2 != null )
		{
			m.putAll( m2 );
		}
		
		return( m );
	}
	
	/**
		Create a new Map and insert the specified mappings as found in 'mappings'.
		The even-numbered entries are the keys, and the odd-numbered entries are
		the values.
	 */
		public static <T> Map<T,T>
	newMap( final T[] mappings )
	{
		if ( (mappings.length % 2) != 0 )
		{
			throw new IllegalArgumentException( "mappings must have even length" );
		}
		
		final Map<T,T> m	= new HashMap<T,T>();
		
		for( int i = 0; i < mappings.length; i += 2 )
		{
			m.put( mappings[ i ], mappings[ i + 1 ] );
		}
		
		return( m );
	}
	
	/**
		Create a new Map and insert the specified mappings as found in 'mappings'.
		The even-numbered entries are the keys, and the odd-numbered entries are
		the values.
	 */
		public static Map<String,String>
	newMap( final String[] mappings )
	{
		if ( (mappings.length % 2) != 0 )
		{
			throw new IllegalArgumentException( "mappings must have even length" );
		}
		
		final Map<String,String>	m	= new HashMap<String,String>();
		
		for( int i = 0; i < mappings.length; i += 2 )
		{
			m.put( mappings[ i ], mappings[ i + 1 ] );
		}
		
		return( m );
	}
	
	
	/**
		Remove all entries keyed by 'keys'
	 */
		public static <T> void
	removeAll( 
		final Map<T,?>		m,
		final T[]	keys )
	{
		for( int i = 0; i < keys.length; ++i )
		{
			m.remove( keys[ i ] );
		}
	}
	
		public static boolean
	mapsEqual(
		final Map<?,?>	m1,
		final Map<?,?>	m2 )
	{
		if ( m1 == m2 )
		{
			return( true );
		}
		
		boolean	equal	= false;
		
		if ( m1.size() == m2.size() &&
			m1.keySet().equals( m2.keySet() ) )
		{
			equal	= true;
			
			for( final Object key : m1.keySet() )
			{
				final Object	value1	= m1.get( key );
				final Object	value2	= m2.get( key );
				
				if ( ! CompareUtil.objectsEqual( value1, value2 ) )
				{
					equal	= false;
					break;
				}
			}
		}
		
		return( equal );
	}
	
	
		public static <K,V> Map<K,V>
	newMapNoNullValues( final Map<K,V> m )
	{
		final Map<K,V>	result	= new HashMap<K,V>();
		
		for ( final K key : m.keySet() )
		{
			final V	value	= m.get( key );
			
			if ( value != null )
			{
				result.put( key, value );
			}
		}
		
		return( result );
	}
	
		public static String
	toString( final Map<?,?> m )
	{
		return( toString( m, "," ) );
	}
	
		public static String
	toString( final Map<?,?> m, final String separator )
	{
		if ( m == null )
		{
			return( "null" );
		}
		
		final StringBuffer	buf	= new StringBuffer();
		
		final String[]  keyStrings  = getKeyStrings( m );
		for( final String key : keyStrings )
		{
			final Object	value	= m.get( key );
			
			buf.append( key );
			buf.append( "=" );
			buf.append( SmartStringifier.toString( value ) );
			buf.append( separator );
		}
		if ( buf.length() != 0 )
		{
			// strip trailing separator
			buf.setLength( buf.length() - separator.length() );
		}
		
		return( buf.toString() );
	}
	
		public static <K> Set<K>
	getNullValueKeys( final Map<K,?> m)
	{
		final Set<K>	s	= new HashSet<K>();
		
		for( final K key : m.keySet() )
		{
			if ( m.get( key ) == null )
			{
				s.add( key );
			}
		}
		return( s );
	}
	
	
	    public static <K,V> Map<K,V>
	toMap( final Properties props, final Class<K> kClass, final Class<V> vClass)
	{
	    return TypeCast.checkMap( props, kClass, vClass );
	}
	
	    public static <K> void
	removeAll( final Map<K,?> m, final Set<K> s )
	{
	    for( final K key : s )
	    {
	        m.remove( key );
	    }
	}
	
	/**
	    @return true if non-null Map and all keys and values are of type java.lang.String
	 */
	    public static boolean
	isAllStrings( final Map<?,?> m )
	{
	    return m != null && CollectionUtil.isAllStrings( m.keySet() ) &&
	            CollectionUtil.isAllStrings( m.values() );
	}
	
	/**
	    Convert an arbitrary Map to one whose keys and values
	    are both of type String.
	 */
	    public static Map<String,String>
	toStringStringMap( final Map<?,?> m )
	{
	    if ( m == null )
	    {
	        return null;
	    }
	    
	    Map<String,String>  result  = null;
	    
	    if ( isAllStrings( m ) )
	    {
	        result  = TypeCast.asMap( m );
	    }
	    else
	    {
	        result = new HashMap<String,String>();
	        
    	    for( final Object key : m.keySet() )
    	    {
    	        final Object value = m.get( key );
    	        
    	        if ( (key instanceof String) && (value instanceof String) )
    	        {
    	            result.put( (String)key, (String)value );
    	        }
    	        else
    	        {
    	            result.put( "" + key, "" + value );
    	        }
    	    }
	    }
	    
	    return result;
	}
}





	





