/*******************************************************************************

 * Copyright (c) 2006 IONA Technologies PLC

 * All rights reserved. This program and the accompanying materials

 * are made available under the terms of the Eclipse Public License v1.0

 * which accompanies this distribution, and is available at

 * http://www.eclipse.org/legal/epl-v10.html

 * 

 * Contributors:

 *     IONA Technologies PLC - initial API and implementation

 *******************************************************************************/
package org.eclipse.stp.sc.xmlvalidator.classbuilder;

import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.stp.common.logging.LoggingProxy;


/**
 * @author jma
 * Holding glabal constant pool for the class
 * 
 */
class JConstantPool  {

	private static final LoggingProxy LOG = LoggingProxy.getlogger(JConstantPool.class);
	
	public final Map<List<?>, Integer> poolMap = new LinkedHashMap<List<?>, Integer>();

	public int poolIndex = 1;
        

	public JConstantPool() {
	}


    public void accept(JVisitor v) throws Exception {
    	v.visitConstantPool(this);
    }

	public int stringUTFConstant(String s) {
		LOG.debug("stringUTFConstant:" + s);
		return constant(JConstants.UTF8, s);
	}

        public int stringConstant(String s) {
            /*
            CONSTANT_String_info {
    	       u1 tag;
    	       u2 string_index;
             } */
	     int index = stringUTFConstant(s);	
	     return constant(JConstants.String, index);	
            
        }

	
	public int nameAndTypeConstant(JField field) {
		/*
		CONSTANT_NameAndType_info {
	    	u1 tag;
	    	u2 name_index;
	    	u2 descriptor_index;
	    }
	    */
		int nameIndex = stringUTFConstant(field.name);
		String desc = ByteCodeUtils.getFieldDescriptor(field.type);
		LOG.debug("field desc:" + desc);
		int descIndex = stringUTFConstant(desc);	
		return constant(JConstants.NameAndType, nameIndex, descIndex);	
	}
	
	public int nameAndTypeConstant(JMethod method) {
		/*
		CONSTANT_NameAndType_info {
	    	u1 tag;
	    	u2 name_index;
	    	u2 descriptor_index;
	    }
	    */
		int nameIndex = stringUTFConstant(method.name);
		String desc = ByteCodeUtils.getMethodDescriptor(method);
		int descIndex = stringUTFConstant(desc);		
		return constant(JConstants.NameAndType, nameIndex, descIndex);	
	}
	
	public int fieldConstant(String className, JField field) {
		/*
		CONSTANT_Fieldref_info {
	    	u1 tag;
	    	u2 class_index;
	    	u2 name_and_type_index;
	    }
	    */
		int classNameIndex = classConstant(className);
		int nameTypeIndex = nameAndTypeConstant(field);	
		return constant(JConstants.FIELDREF, classNameIndex, nameTypeIndex);
	}
	
	public int methodConstant(String className, JMethod method) {
		/*
		CONSTANT_Methodref_info {
	    	u1 tag;
	    	u2 class_index;
	    	u2 name_and_type_index;
	    }
	    */
		int classNameIndex = classConstant(className);
		int nameTypeIndex = nameAndTypeConstant(method);
		return constant(JConstants.Methodref, classNameIndex, nameTypeIndex);
	}

	public int classConstant(String s) {
		int classNameIndex = stringUTFConstant(s.replace('.', '/'));
		LOG.debug("classConstant:" + s + " index:" + classNameIndex);
		return constant(JConstants.CLASS, classNameIndex);
	}

	public int constant(Object... data) {
		List<?> dataList = Arrays.asList(data);
		if (poolMap.containsKey(dataList))
			return poolMap.get(dataList);
		poolMap.put(dataList, poolIndex);
		return poolIndex++;
	}

}
