//
//  KVCSupport.java
//  Dvis
//
//  Created by Florijan Stamenkovic on 08/12/06.
//  Copyright 2006 CNG Havaso Ltd. All rights reserved.
//
package com.havaso.util.eof;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;



/**
*	Provides a way to translate model defined entity and property names into
*	user presentable (understandable) names. Does so in most cases by simply parsing
*	the model defined names into something more readable. However, it is possible to load
*	data from an <tt>InputStream</tt>, written in the convention of Java properties,
*	containing name "translations" for cases where model defined names are simply
*	not usable for GUI presentation. If there is an entry in the properties,
*	that value is returned, otherwise standard parsing is used.
*
	@author	Florijan Stamenkovic (flor285@mac.com)
	@version	1.0, 12/08/06
*/
public final class KVCSupport {
	
	//	used for String construction
	private static StringBuffer buff = new StringBuffer(1024);
	
	//	storage for loaded entity and property name files
	private static final Properties
		entityNames		= new Properties(),
		propertyNames	= new Properties();
	
	/**
	*	Tries to parse the data found in the given stream into the Java properties
	*	form of keys and values. Uses the loaded pairs to override standard entity name
	*	parsing.
	*
		@param	ins	The input stream to load data from
	*/
	public static void loadEntityNames(InputStream ins) throws IOException{
		entityNames.load(ins);
	}
	
	/**
	*	Tries to parse the data found in the given stream into the Java properties
	*	form of keys and values. Uses the loaded pairs to override standard property name
	*	parsing.
	*
		@param	ins	The input stream to load data from
	*/
	public static void loadPropertyNames(InputStream ins) throws IOException{
		propertyNames.load(ins);
	}
	
	
	/**
	*	Disallow instantiation, as the class is intended for static calls only.
	*/
	private KVCSupport(){}

	/**
	*	Returns a more readable entity name then the one defined in the model,
	*	possibliy even a different one (based on a lookup in the black-list
	*	file.
	*
		@param	entityNameInModel	Name of the entity as it is declared in the
			EOModel.
		@return	The visually more appealing entity name, for GUI display.
	*/
	public static String entityName(String entityNameInModel){
		
		//	first check if the props file defines a value, if so, return it
		String entityName = entityNames.getProperty(entityNameInModel);
		if(entityName != null)	return entityName;
		
		return processKey(entityNameInModel);
	}
	
	/**
	*	Returns a more readable property name then the one defined in the model,
	*	possibliy even a different one (based on a lookup in the black-list
	*	file.
	*
		@param	propertyNameInModel	Name of the property as it is declared in the
			EOModel.
		@return	The visually more appealing property name, for GUI display.
	*/
	public static String propertyName(String propertyNameInModel){
	
		//	first check if the props file defines a value, if so, return it
		String propertyName = propertyNames.getProperty(propertyNameInModel);
		if(propertyName != null)	return propertyName;
		
		return processKey(propertyNameInModel);
	}
	
	/**
	*	Returns the same string with the first letter of the first word
	*	switched to uppercase or lowercase, depending on the boolean param.
	*
		@param	name	The name to modify
		@param	uppercase	Indicates if the first word should start with
			an uppercase letter, or a lowercase letter
	*/
	public static String firstCharCaseChange(String name, boolean uppercase){
		if(name == null || name.length() == 0) return null;
		
		if(uppercase && Character.isLowerCase(name.charAt(0))){
			buff.append(Character.toUpperCase(name.charAt(0)));
			buff.append(name.substring(1));
			String rVal = buff.toString();
			buff.delete(0, buff.length());

			return rVal;
		}
		
		if(!uppercase && Character.isUpperCase(name.charAt(0))){
			buff.append(Character.toLowerCase(name.charAt(0)));
			buff.append(name.substring(1));
			String rVal = buff.toString();
			buff.delete(0, buff.length());

			return rVal;
		}

		return name;
	}
	
	
	/**
	*	Translates variable names into a more readable form, by breaking them
	*	down into individual words. For example "firstName" is translated to
	*	"first name", "free4All" is translated to "free 4 all".
	*
		@param	name	The name to convert to split into words
		@return	The parameter, broken down into words separated with a single
			space character.
	*/
	public static String nameWordSplit(String name){
		if(name == null || name.length() == 0) return null;
		
		//	break down the string on upper case letters and numbers
		for(int i = 0 ; i < name.length() ; i++){
			char c = name.charAt(i);
			if(Character.isUpperCase(c)){
				buff.append(' ');
				buff.append(Character.toLowerCase(c));
			}else if(Character.isDigit(c)){
				buff.append(' ');
				buff.append(c);
				buff.append(' ');
			}else
				buff.append(c);
		}
		
		String rVal = buff.toString();
		buff.delete(0, buff.length());

		return rVal;
	}
	
	/**
	*	Processes an EOF key path into a user presentable string of text.
	*	Path separators are replaced with " - ", and every path component
	*	is split over words and numbers, and capitalized. Example:
	*	"project.punchItems.free4all" is translated into
	*	"Project - Punch items - Free 4 all"
	*
		@param	keypath	The keypath to translate
		@return	User presentable version of the keypath parameter
	*/
	public static String processKey(String keypath){
		if(keypath == null || keypath.length() == 0) return null;
		
		//	can't use the buff on this one, coz it is used by other methods in the meanwhile
		//	use raw String concatenation
		String rVal = "";
		
		//	split the keypath on key separator
		String[] keys = keypath.split("\\.");

		//	generate user presentable key path
		for(int i = 0 ; i < keys.length ; i++){
			if(i > 0)
				rVal += " - ";
			
			rVal += firstCharCaseChange(nameWordSplit(keys[i]), true);
		}
		
		return rVal;
	}
}
