package lu.tudor.santec.gecamed.patient.utils;

import java.util.regex.Pattern;

import lu.tudor.santec.gecamed.core.utils.BaseFormatter;
import lu.tudor.santec.gecamed.core.utils.StringUtilities;
import lu.tudor.santec.gecamed.core.utils.Translator;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.Patient;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.PatientContact;
import lu.tudor.santec.i18n.Translatrix;

public class PatientNameFormatter extends BaseFormatter
	{
	private static final long serialVersionUID = 1L;

	private Translator m_Translator;
	
	private boolean m_MaidenNameIsMarriedName = Boolean.FALSE;
	
//---------------------------------------------------------------------------
//***************************************************************************
//* Constants	                                                            *
//***************************************************************************
//---------------------------------------------------------------------------

	private static final int c_Title			= 0;
	private static final int c_FirstName		= 1;
	private static final int c_FamilyName		= 2;
	private static final int c_BirthName		= 3;

	// needs at least Java 6
//	private	static Pattern			accentPattern	= Pattern.compile("\\p{InCombiningDiacriticalMarks}+");
	public	static ReplacePattern[]	unaccentPattern	= new ReplacePattern[]
//	{
//		new ReplacePattern("Æ", "A"), 
//		new ReplacePattern("æ", "a"), 
//		new ReplacePattern("Đ", "D"), 
//		new ReplacePattern("đ", "d"), 
//		new ReplacePattern("ØŒ", "O"), 
//		new ReplacePattern("øœ", "o")
//	};
	{
		new ReplacePattern("[ÀÁÂÃÄÅĀÆĂ]",	"A"),
		new ReplacePattern("[àáâãäåæāă]",	"a"),
		new ReplacePattern("[ÇČĆ]",			"C"),
		new ReplacePattern("[çčć]",			"c"),
		new ReplacePattern("[ĐĎ]",			"D"),
		new ReplacePattern("[đ]",			"d"),
		new ReplacePattern("[ÈÉÊËĒ]",		"E"),
		new ReplacePattern("[èéêëē]",		"e"),
		new ReplacePattern("[Ğ]",			"G"),
		new ReplacePattern("[ğ]",			"g"),
		new ReplacePattern("[ÌÍÎÏĪ]",		"I"),
		new ReplacePattern("[ìíîïī]",		"i"),
		new ReplacePattern("[ÑŇ]",			"N"),
		new ReplacePattern("[ñň]",			"n"),
		new ReplacePattern("[ÒÓÔÕÖØŌŒ]",	"O"),
		new ReplacePattern("[òóôõöøōœ]",	"o"),
		new ReplacePattern("[Ř]",			"R"),
		new ReplacePattern("[ř]",			"r"),
		new ReplacePattern("[Š]",			"S"),
		new ReplacePattern("[š]",			"s"),
		new ReplacePattern("[Ť]",			"T"),
		new ReplacePattern("[ÙÚÛŨÜŪ]",		"U"),
		new ReplacePattern("[ùúûũüū]",		"u"),
		new ReplacePattern("[ŸÝ]",			"Y"),
		new ReplacePattern("[ÿý]",			"y"),
		new ReplacePattern("[ŽŹŻ]",			"Z"),
		new ReplacePattern("[žźż]",			"z")
	};

    static 
		{
    	Translatrix.addBundle("lu.tudor.santec.gecamed.patient.utils.resources.ServerResources");
		}

//---------------------------------------------------------------------------
//***************************************************************************
//* Constructor	                                                            *
//***************************************************************************
//---------------------------------------------------------------------------

public PatientNameFormatter ()	
	{
	super(ORIGINAL);
	}

//---------------------------------------------------------------------------

public PatientNameFormatter (Integer p_PrintMode)	
	{
	super(p_PrintMode);
	}
	
//---------------------------------------------------------------------------
//***************************************************************************
//* Primitives	                                                            *
//***************************************************************************
//---------------------------------------------------------------------------
/**
  * applies the currently applicable print mode to the specified Name.
  * @param p_NameType specifies the type of the name to apply print mode to.
  * Possible values are:
  * <ul>
  * <li>c_Title      : Courtesy title of the patient
  * <li>c_FirstName  : First or Christian Name of the patient
  * <li>c_FamilyName : Name of the patient
  * <li>c_BirthName  : Birth name of patient if married
  * <ul>
  * @param p_Name specifies the name to apply print mode to.
  * @return a copy of the specified original name formatted according to
  * the currently applicable print mode and the specified name type.
  */
//---------------------------------------------------------------------------

private String applyPrintMode (int p_NameType, String p_Name) 
	{
	if ((p_Name == null) || (p_Name.length() == 0)) return p_Name;		

	switch (printMode) 
		{
		case ORIGINAL		   : return p_Name;
						  
		case CAPITALIZE_WORDS  : if (   (p_NameType == c_FamilyName)  
									 || (p_NameType == c_BirthName))
									  return p_Name.toUpperCase();
								 else return StringUtilities.capitalizeWords(p_Name);
		
		case ALL_UPPERCASE	   : return p_Name.toUpperCase();
	
		default                : return p_Name;
		}
	}

//---------------------------------------------------------------------------

private String formatNameBlock (String[] p_Names, int[] p_Types, boolean p_WithComma)
	{
	StringBuffer l_NameBlock = new StringBuffer ();
	String		 l_Name;
	String		 l_Blank = "";
	int			 l_Position;
	
	for (l_Position = 0; l_Position < p_Names.length; l_Position++)
		{
		l_Name = p_Names [l_Position];
		if ((l_Name != null) && (l_Name.trim().length() > 0))
			{
			if (p_Types[l_Position] == c_FirstName 
					&& l_Position > 0 
					&& (p_Types[l_Position-1] == c_BirthName
					||  p_Types[l_Position-1] == c_FamilyName))
				l_Blank = p_WithComma ? ", " : " ";
			l_NameBlock.append(l_Blank);
			l_NameBlock.append(this.applyPrintMode(p_Types[l_Position], l_Name));
			l_Blank = " ";
			}
		}
	
	return l_NameBlock.toString();
	}

//---------------------------------------------------------------------------

private String formatNames (String p_Title, String p_FirstName, String p_MaidenName, String p_Name, boolean p_FirstNameLast, boolean p_WithComma)
	{
	String			l_FamilyName 	= "";
	String  		l_FirstName 	= "";
	String 			l_BirthName 	= "";

	StringBuffer 	l_PatientName;
	String[]		l_Names;
	int[]			l_Types;
	
	l_PatientName = new StringBuffer();	
	
	if (p_FirstName != null) l_FirstName = p_FirstName;

	if (m_MaidenNameIsMarriedName)
		{
		if (p_Name != null)    l_BirthName  = p_Name;
		if (p_MaidenName != null) l_FamilyName = p_MaidenName;
		}
	else
		{
		if (p_Name != null)       l_FamilyName = p_Name;
		if (p_MaidenName != null) l_BirthName  = p_MaidenName;
		}
			
	if ((l_FamilyName == null) || (l_FamilyName.length() == 0))
		{
		l_FamilyName = l_BirthName;
		l_BirthName  = null;
		}
	
	if (p_FirstNameLast)
		{
		l_Names = new String [] { p_Title, l_FamilyName, l_BirthName, l_FirstName };
		l_Types = new int []    { c_Title, c_FamilyName, c_BirthName, c_FirstName }; 
		
		l_PatientName.append(this.formatNameBlock (l_Names,l_Types,p_WithComma));
		}
	else
		{
		l_Names = new String [] { p_Title, l_FirstName, l_FamilyName, l_BirthName };
		l_Types = new int []    { c_Title, c_FirstName, c_FamilyName, c_BirthName }; 
		
		l_PatientName.append(this.formatNameBlock (l_Names,l_Types,p_WithComma));
		}
	
	return l_PatientName.toString();
	}

//---------------------------------------------------------------------------
//***************************************************************************
//* Class Body                                                              *
//***************************************************************************
//---------------------------------------------------------------------------

public void setMaidenNameIsMarriedName (Boolean p_MaidenNameIsMarriedName)
	{
	m_MaidenNameIsMarriedName = p_MaidenNameIsMarriedName;
	}

//---------------------------------------------------------------------------
/**
 * returns the full name of the patient by concatenating its name and its
 * first name.
 * @param p_FirstName first name of patient.
 * @param p_MaidenName maiden name or married name, depending on system
 * configuration, of patient. Interpretation of maiden name is governed
 * by maidenNameIsMarried name property. If property is set to <code>true
 * </code>, method will interpreted maiden name as married name.
 * @param p_Name married name or birth name of patient, depending on
 * state of maidenNameIsMarried property. If property is set to <code>true
 * </code>, method will interpreted name as birth name.
 * @return full name of patient.
 */
//---------------------------------------------------------------------------

public String getPatientFullName (String p_FirstName, String p_MaidenName, String p_Name) 
	{
	return this.formatNames (null, p_FirstName, p_MaidenName, p_Name, true, true);
	}

//---------------------------------------------------------------------------
/**
 * 
 * formats the patient name to surname + " " + ucase(firstname)
 * n/a if null
 * 
 * @param p_Patient the patient 
 * @return the formated name
 */
//---------------------------------------------------------------------------

public String formatPatientName (Patient p_Patient, boolean p_WithTitle, boolean p_FirstNameLast, boolean p_WithComma)
	{
	String	l_Title	= "";

	if (p_Patient == null) return "";

	if (p_WithTitle && (p_Patient.getTitle() != null)) 
		l_Title = m_Translator.translate("Title."+p_Patient.getTitle()); //Title.translate (p_Patient.getTitle());
		
	return this.formatNames (l_Title, 
							 p_Patient.getFirstName(), 
							 p_Patient.getMaidenName(), 
							 p_Patient.getSurName(),
							 p_FirstNameLast,
							 p_WithComma);
	}

//---------------------------------------------------------------------------
/**
 * Returns a printable representation of guarantor for specified patient.
 * Guarantor is the person who takes over the costs charged to the patient.
 * A typical case of a guarantor / patient relationship are children.
 * Whereas the child is the patient, one of the parents is the guarantor. If
 * no guarantor is defined for patient, the patient will be used as its own
 * guarantor.
 * 
 * @param p_Patient specifies patient to get printable representation of 
 * guarantor for.
 * @return a printable representation of specified patient's guarantor.
 * Method returns <code>Unknown</code> if an invalid (<code>null</code>)
 * patient was specified.
 */
//---------------------------------------------------------------------------

public String formatGuarantorName (Patient p_Patient, boolean p_WithTitle, boolean p_FirstNameLast) 
    {
	String 		   l_Name;
	PatientContact l_Guarantor = null;

	if (p_Patient == null) return m_Translator.translate("PatientNameFormatter.Unknown");
 
	l_Guarantor = p_Patient.getPatientContact();

	if ((l_Guarantor != null) && (l_Guarantor.getName() != null)) 
	     l_Name = l_Guarantor.getName();
	else l_Name = this.formatPatientName (p_Patient, p_WithTitle, p_FirstNameLast, p_FirstNameLast);

	return l_Name;
    }


public void setTranslator (Translator p_Translator)
	{
	m_Translator = p_Translator;
	}


public static String unaccent (String text)
{
	if (text == null)
		return "";
	
	
//	// normalising will make two chars out of the accented letters - the letter and the accent
//	// example: "é" becomes "e´" 
//	text = Normalizer.normalize(text, Normalizer.Form.NFD);
//	// removes all accents
//	text = accentPattern.matcher(text).replaceAll("");
	
	for (ReplacePattern p : unaccentPattern)
		text = p.replace(text);
	
	return text;
}


private static class ReplacePattern 
{
	private Pattern	pattern;
	private String	replacement;
	
	
	public ReplacePattern (String regex, String replacement)
	{
		this.pattern		= Pattern.compile(regex);
		this.replacement	= replacement;
	}
	
	
	public String replace (String text)
	{
		return pattern.matcher(text).replaceAll(replacement);
	}
}


public static void main(String[] args)
{
	String	text = "ÀÁÂÃÄÅĀÆĂàáâãäåæāăÇČĆçčćĐĎđÈÉÊËĒèéêëēĞğÌÍÎÏĪìíîïīÑŇñňÒÓÔÕÖØŌŒòóôõöøōœŘřŠšŤÙÚÛŨÜŪùúûũüūŸÝÿýŽŹŻ";
	System.out.println(unaccent(text));
	
//	long	time;
//	
//	
//	unaccent("");
//	time	= System.currentTimeMillis();
//	for (int i = 0; i < 100000; i++)
//	{
//		unaccent(text);
//	}
//	time	= System.currentTimeMillis() - time;
//	System.out.println(time+"ms");
}

//---------------------------------------------------------------------------
//***************************************************************************
//* End of Class                                                            *
//***************************************************************************
//---------------------------------------------------------------------------

}
