package jreport.uds.javabean;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Vector;

import jreport.uds.javabean.exception.MetaDataExceptionForJavaBean;
import jreport.uds.javabean.api.JavaBeanDataProvider;
/*
 * Created on Jul 17, 2005
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */

/**
 * @author jennyw
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
public class MetaDataForJavaBean implements ResultSetMetaData {
	private Vector 	vecColumnInfoTmp = new Vector();
	private ColumnInfo[] columnsInfo = null;
	private JavaBeanDataProvider dataProvider = null;
	public MetaDataForJavaBean(JavaBeanDataProvider dataProvider) throws MetaDataExceptionForJavaBean{
		this.dataProvider = dataProvider;
		UDSForJavaBeanLogger.debug("Initialized the Metadata of the Java Bean...");
		Class clsMetadataJavaBean;
		try {
			clsMetadataJavaBean = dataProvider.getMetadataJavaBean();
			UDSForJavaBeanLogger.debug("Bean Class returned from Data Provider..."+clsMetadataJavaBean);
			addColumnInfo(null, clsMetadataJavaBean, null);
			if(vecColumnInfoTmp.size() >0 ){
				columnsInfo = new ColumnInfo[vecColumnInfoTmp.size()];
//				System.out.println("type..."+vecColumnInfoTmp.toArray());
//			    columnsInfo = (ColumnInfo [])vecColumnInfoTmp.toArray();
				vecColumnInfoTmp.copyInto(columnsInfo);
				Arrays.sort( columnsInfo, new ColumnInfoComparator());
				vecColumnInfoTmp.clear();
				vecColumnInfoTmp=null;
//				System.out.println("*** Print the metadata ***");
//				new Exception().printStackTrace();
//				for( int i =0; i < columnsInfo.length; i++){
//					System.out.println("ColumnInfo["+i+"]="+columnsInfo[i].getName());
//				}
//				System.out.println("*** end ***");
			}
			
		} catch (ClassNotFoundException e1) {
			UDSForJavaBeanLogger.debug(e1);
			throw new MetaDataExceptionForJavaBean(e1, e1.getMessage());
			
		}catch (IntrospectionException e) {
			UDSForJavaBeanLogger.debug(e);
			throw new MetaDataExceptionForJavaBean(e, e.getMessage());
		}
	}
	
	private void addColumnInfo (String prefixName, Class clsProp, Vector methods) throws IntrospectionException {
		BeanInfo 				propBeanInfo 	= Introspector.getBeanInfo(clsProp);
		PropertyDescriptor[] 	propDescriptor 	= propBeanInfo.getPropertyDescriptors();
		
		for( int i =0; i<propDescriptor.length; i++ ){
			Class clsPropType = propDescriptor[i].getPropertyType();
			if( clsPropType.equals(Class.class)){
			    continue;
			}
			if( DataTypeMapping.isDetailCollectionClass(clsPropType) && 
					(prefixName!=null || 
					!dataProvider.requireDetails(propDescriptor[i].getName()))){
				continue;
			}
			
			SQLTypeInfo info = DataTypeMapping.getSQLType(clsPropType);
			if(info != null){ // if the Java class is internal defined data type.
				ColumnInfo columnInfo = new ColumnInfo();
				columnInfo.setSqlTypeInfo(info);
				if( prefixName == null){
					columnInfo.setName(propDescriptor[i].getName());
				}else{
					columnInfo.setName(prefixName+"_"+propDescriptor[i].getName());
				}
				columnInfo.setTypeClass(clsPropType);
				UDSForJavaBeanLogger.debug("Adding property:"+columnInfo.getName()+", Cls Name:"+columnInfo.getTypeName()+", SQL Type"+info.getTypeName());
				
				Vector mymethods = new Vector();
				if( methods != null){
					mymethods= (Vector)methods.clone();
				}
			
				mymethods.addElement(propDescriptor[i].getReadMethod());
				columnInfo.setMethods(mymethods);
				
				vecColumnInfoTmp.addElement( columnInfo);
			}
			else{
				if( prefixName == null){
					Vector localmethods= new Vector();
					localmethods.addElement(propDescriptor[i].getReadMethod());
					addColumnInfo(propDescriptor[i].getName(),clsPropType,localmethods);
				}else{
					methods.addElement(propDescriptor[i].getReadMethod());
					addColumnInfo(prefixName+"_"+propDescriptor[i].getName()+"_",clsPropType, methods);
				}
			}
		}
		
	}
	
//	public ColumnInfo[] columnInfo(){
//		return columnsInfo;
//	}
	
	public ColumnInfo getColumnInfo (int index){
		try {
			if( index < getColumnCount()){
				return columnsInfo[index];
			}
		} catch (SQLException e) {
			// should not come here
		}
		
		return null;
	}
	
	public ColumnInfo getColumnInfo(String colname){
		int size=0;
		try {
			size = getColumnCount();
		} catch (SQLException e) {
			
			// shouldn't come here
		}
		for( int i = 0; i<size; i++){
			ColumnInfo info =columnsInfo[i];
			if(info.getName().equals(colname)){
				return info;
			}
		}
		
		
		return null;
	}
	
	
	/* (non-Javadoc)
	 * @see java.sql.ResultSetMetaData#getColumnCount()
	 */
	public int getColumnCount() throws SQLException {
		return (columnsInfo==null?0:columnsInfo.length);
	}

	/* (non-Javadoc)
	 * @see java.sql.ResultSetMetaData#getColumnDisplaySize(int)
	 */
	public int getColumnDisplaySize(int column) throws SQLException {
		if( column >0 && column <= getColumnCount()){
			ColumnInfo info = columnsInfo[column-1];
			return info.getDisplaySize();
		}else
			throw new SQLException("Cannot find column at index:"+column+". Total columns number is:"+getColumnCount());
			
	}

	/* (non-Javadoc)
	 * @see java.sql.ResultSetMetaData#getColumnType(int)
	 */
	public int getColumnType(int column) throws SQLException {
		if( column >0 && column <= getColumnCount()){
			ColumnInfo info = columnsInfo[column-1];
			//System.out.println("get Column type:"+info.getName()+ " type="+info.getType());
			return info.getType();
		}else
			throw new SQLException("Cannot find column at index:"+column+". Total columns number is:"+getColumnCount());
		
	}

	/* (non-Javadoc)
	 * @see java.sql.ResultSetMetaData#getPrecision(int)
	 */
	public int getPrecision(int column) throws SQLException {
		if( column >0 && column <= getColumnCount()){
			ColumnInfo info = columnsInfo[column-1];
			return info.getPrecision();
		}else
			throw new SQLException("Cannot find column at index:"+column+". Total columns number is:"+getColumnCount());
		
	}

	/* (non-Javadoc)
	 * @see java.sql.ResultSetMetaData#getScale(int)
	 */
	public int getScale(int column) throws SQLException {
		if( column >0 && column <= getColumnCount()){
			ColumnInfo info = columnsInfo[column-1];
			return info.getScale();
		}else
			throw new SQLException("Cannot find column at index:"+column+". Total columns number is:"+getColumnCount());
		
	}

	/* (non-Javadoc)
	 * @see java.sql.ResultSetMetaData#isNullable(int)
	 */
	public int isNullable(int column) throws SQLException {
		return 1;
	}

	/* (non-Javadoc)
	 * @see java.sql.ResultSetMetaData#isAutoIncrement(int)
	 */
	public boolean isAutoIncrement(int column) throws SQLException {
		// TODO Auto-generated method stub
		return false;
	}

	/* (non-Javadoc)
	 * @see java.sql.ResultSetMetaData#isCaseSensitive(int)
	 */
	public boolean isCaseSensitive(int column) throws SQLException {
		// TODO Auto-generated method stub
		return false;
	}

	/* (non-Javadoc)
	 * @see java.sql.ResultSetMetaData#isCurrency(int)
	 */
	public boolean isCurrency(int column) throws SQLException {
		// TODO Auto-generated method stub
		return false;
	}

	/* (non-Javadoc)
	 * @see java.sql.ResultSetMetaData#isDefinitelyWritable(int)
	 */
	public boolean isDefinitelyWritable(int column) throws SQLException {
		// TODO Auto-generated method stub
		return false;
	}

	/* (non-Javadoc)
	 * @see java.sql.ResultSetMetaData#isReadOnly(int)
	 */
	public boolean isReadOnly(int column) throws SQLException {
		// TODO Auto-generated method stub
		return false;
	}

	/* (non-Javadoc)
	 * @see java.sql.ResultSetMetaData#isSearchable(int)
	 */
	public boolean isSearchable(int column) throws SQLException {
		// TODO Auto-generated method stub
		return false;
	}

	/* (non-Javadoc)
	 * @see java.sql.ResultSetMetaData#isSigned(int)
	 */
	public boolean isSigned(int column) throws SQLException {
		// TODO Auto-generated method stub
		return false;
	}

	/* (non-Javadoc)
	 * @see java.sql.ResultSetMetaData#isWritable(int)
	 */
	public boolean isWritable(int column) throws SQLException {
		// TODO Auto-generated method stub
		return false;
	}

	/* (non-Javadoc)
	 * @see java.sql.ResultSetMetaData#getCatalogName(int)
	 */
	public String getCatalogName(int column) throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	/* (non-Javadoc)
	 * @see java.sql.ResultSetMetaData#getColumnClassName(int)
	 */
	public String getColumnClassName(int column) throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	/* (non-Javadoc)
	 * @see java.sql.ResultSetMetaData#getColumnLabel(int)
	 */
	public String getColumnLabel(int column) throws SQLException {
		if( column >0 && column <= getColumnCount()){
			ColumnInfo info = columnsInfo[column-1];
			//System.out.println("get Column label:"+info.getName());
			return info.getName();
		}else
			throw new SQLException("Cannot find column at index:"+column+". Total columns number is:"+getColumnCount());
	}

	/* (non-Javadoc)
	 * @see java.sql.ResultSetMetaData#getColumnName(int)
	 */
	public String getColumnName(int column) throws SQLException {
		if( column >0 && column <= getColumnCount()){
			ColumnInfo info = columnsInfo[column-1];
			//System.out.println("get Column name:"+info.getName());
			return info.getName();
		}else
			throw new SQLException("Cannot find column at index:"+column+". Total columns number is:"+getColumnCount());
	}

	/* (non-Javadoc)
	 * @see java.sql.ResultSetMetaData#getColumnTypeName(int)
	 */
	public String getColumnTypeName(int column) throws SQLException {
		if( column >0 && column <= getColumnCount()){
			ColumnInfo info = columnsInfo[column-1];
			//System.out.println("get Column type name:"+info.getTypeName());
			return info.getTypeName();
		}else
			throw new SQLException("Cannot find column at index:"+column+". Total columns number is:"+getColumnCount());
	}

	/* (non-Javadoc)
	 * @see java.sql.ResultSetMetaData#getSchemaName(int)
	 */
	public String getSchemaName(int column) throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	/* (non-Javadoc)
	 * @see java.sql.ResultSetMetaData#getTableName(int)
	 */
	public String getTableName(int column) throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	public <T> T unwrap(Class<T> iface) throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	public boolean isWrapperFor(Class<?> iface) throws SQLException {
		// TODO Auto-generated method stub
		return false;
	}

}
