content: /**
   * Copyright (C) 2012 the original author or authors.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package co.jirm.mapper.jdbc;
  
  import static co.jirm.core.util.JirmPrecondition.check;
  
  import java.sql.Blob;
  import java.sql.Clob;
  import java.sql.ResultSet;
  import java.sql.ResultSetMetaData;
  import java.sql.SQLException;
  import java.util.LinkedHashMap;
  import java.util.List;
  import java.util.Map;
  
  import co.jirm.core.util.ObjectMapUtils;
  import co.jirm.mapper.definition.SqlObjectDefinition;
  
  import com.google.common.base.Splitter;
  import com.google.common.collect.Lists;
  
  
  public class JdbcResultSetMapperHelper {
  	
  	private final static Splitter splitter = Splitter.on(".");
  	
  	public Map<String, Object> mapRow(
  			SqlObjectDefinition<?> definition, 
  			ResultSet rs, int rowNum) throws SQLException {
  		ResultSetMetaData rsmd = rs.getMetaData();
  		int columnCount = rsmd.getColumnCount();
  		Map<String, Object> mapOfColValues = createColumnMap(columnCount);
  		for (int i = 1; i <= columnCount; i++) {
  			String columnName;
  			if ( (columnName = rsmd.getColumnLabel(i)) != null && columnName.contains(".")) {
  				Object value = getColumnValue(definition, rs, i);
  				List<String> names = Lists.newArrayList(splitter.split(columnName));
  				ObjectMapUtils.pushPath(mapOfColValues, names, value);
  			}
  			//else if ( (columnName = rsmd.getColumnName(i)) != null && columnName.contains(".")) {
  				//TODO make this work.
  			//}
  			else {
  				String key = getColumnKey(definition, rsmd, i);
  				Object obj = getColumnValue(definition, rs, i);
  				mapOfColValues.put(key, obj);
  			}
  		}
  		return mapOfColValues;
  	}
  
  	protected  Object getColumnValue(SqlObjectDefinition<?> definition, 
  			ResultSet rs, int index) throws SQLException {
  		return getResultSetValue(rs, index);
  	}
  
  
  	protected String getColumnKey(SqlObjectDefinition<?> definition, ResultSetMetaData rsmd, int i) throws SQLException {
  		String columnName = lookupColumnName(rsmd, i);
  		return check.notNull(definition.resolveParameter(columnName).orNull(), 
  				"The column name or label: '{}' did not match any properties " +
  				"for the object definition: {}", columnName, definition.getObjectType())
  				.getParameterName();
  	}
  	
  	protected Map<String, Object> createColumnMap(int columnCount) {
  		return new LinkedHashMap<String, Object>(columnCount);
  	}
  	
  	
  	public String lookupColumnName(ResultSetMetaData resultSetMetaData, int columnIndex) throws SQLException {
  		String name = resultSetMetaData.getColumnLabel(columnIndex);
  		if (name == null || name.length() < 1) {
  			name = resultSetMetaData.getColumnName(columnIndex);
  		}
  		return name;
  	}
  	
  	public static Object getResultSetValue(ResultSet rs, int index) throws SQLException {
  		Object obj = rs.getObject(index);
  		String className = null;
  		if (obj != null) {
  			className = obj.getClass().getName();
  		}
  		if (obj instanceof Blob) {
  			obj = rs.getBytes(index);
  		}
  		else if (obj instanceof Clob) {
  			obj = rs.getString(index);
  		}
  		else if (className != null &&
  				("oracle.sql.TIMESTAMP".equals(className) ||
  				"oracle.sql.TIMESTAMPTZ".equals(className))) {
  			obj = rs.getTimestamp(index);
  		}
  		else if (className != null && className.startsWith("oracle.sql.DATE")) {
  			String metaDataClassName = rs.getMetaData().getColumnClassName(index);
  			if ("java.sql.Timestamp".equals(metaDataClassName) ||
  					"oracle.sql.TIMESTAMP".equals(metaDataClassName)) {
  				obj = rs.getTimestamp(index);
  			}
  			else {
  				obj = rs.getDate(index);
  			}
  		}
  		else if (obj != null && obj instanceof java.sql.Date) {
  			if ("java.sql.Timestamp".equals(rs.getMetaData().getColumnClassName(index))) {
  				obj = rs.getTimestamp(index);
  			}
  		}
  		return obj;
  	}
  	
  
  }
  