package lu.tudor.santec.gecamed.patient.gui.administrative;

import java.util.LinkedList;
import java.util.List;

import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;

import lu.tudor.santec.gecamed.patient.gui.PatientManagerModule;
import lu.tudor.santec.gecamed.patient.utils.SettingConstants;

import org.apache.commons.lang3.text.WordUtils;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;

/**
 * @author jens.ferring(at)tudor.lu
 * 
 * @version
 * <br>$Log: PatientNameDocument.java,v $
 * <br>Revision 1.3  2013-12-27 18:07:56  donak
 * <br>Cleanup of imports
 * <br>
 * <br>Revision 1.2  2013-07-15 06:18:34  ferring
 * <br>logging changed
 * <br>
 * <br>Revision 1.1  2013-03-26 10:25:49  ferring
 * <br>Option added in admin settings, to format the patient names
 * <br>
 */

public class PatientNameDocument extends PlainDocument
{
	/* ======================================== */
	// 		CONSTANTS
	/* ======================================== */
	
	private static final long	serialVersionUID	= 1L;
	
	private static final char[]	CAPITALIZE_DELIMITER	= new char[] {
		' ', '-', '_', '\'', '/', '\\', '|', '.', ',', ';', ':', '\t', '\n', '\r'};
	
	
	
	/* ======================================== */
	// 		MEMBERS
	/* ======================================== */
	
	/** the logger Object for this class */
	private static Logger logger = Logger.getLogger(PatientNameDocument.class.getName());
	
	private static List<PatientNameDocument>	firstNameDocuments	= new LinkedList<PatientNameDocument>();
	
	private static List<PatientNameDocument>	lastNameDocuments	= new LinkedList<PatientNameDocument>();
	
	
	private int		limit;
	
	private boolean	limited;
	
	private int		mode;
	
	
	
	/* ======================================== */
	// 		CONSTRUCTORS
	/* ======================================== */
	
	private PatientNameDocument(int patientNameMode, int limit)
	{
		this.limit		= limit;
		this.limited	= limit > 0;
		setPatientNameMode(patientNameMode);
	}
	
	
	
	/* ======================================== */
	// 		CLASS BODY
	/* ======================================== */
	
	@Override
	public void insertString(int offs, String str, AttributeSet a) throws BadLocationException
	{
		if (limited && str != null)
		{
			int toCut = (getLength() + str.length()) - limit;
			
			if (toCut > 0)
			{
				// text is too long, write until the limit is reached
				str	= str.substring(0, str.length() - toCut);
			}
		}
		
		if (str == null || str.length() == 0)
			return;
		
		str = changeText(str, getText(0, offs));
		super.insertString(offs, str, a);
//		change();
	}
	
	public int getMode()
	{
		return this.mode;
	}
	
	@Override
	public void remove (int offs, int len) throws BadLocationException
	{
		super.remove(offs, len);
//		change();
	}
	
	
	@Override
	public void replace(int offset, int length, String text, AttributeSet attrs) throws BadLocationException
	{
		if (limited && text != null && length < text.length())
		{
			int toCut = (getLength() + text.length() - length) - limit;
			
			if (toCut > 0)
			{
				// text is too long, write until the limit is reached
				text	= text.substring(0, text.length() - toCut);
			}
		}
		
		if ((text == null || text.length() == 0) && length == 0)
			return;
		
		text = changeText(text, getText(0, offset));
		super.replace(offset, length, text, attrs);
//		change();
	}
	
	
	public void setPatientNameMode (int mode)
	{
		String	text;
		
		if (this.mode != mode)
		{
			this.mode	= mode;
			
			try
			{
				text	= getText(0, getLength());
				replace(0, text.length(), text, null);
			}
			catch (BadLocationException e)
			{
				// Should be impossable to happen
				logger.log(Level.ERROR, e.getMessage(), e);
			}
		}
	}
	
	
	public static PatientNameDocument getFirstNameDocument (int limit)
	{
		PatientNameDocument	doc	= new PatientNameDocument(getFirstNameMode(), limit);
		
		
		firstNameDocuments.add(doc);
		
		return doc;
	}
	
	
	public static PatientNameDocument getLastNameDocument (int limit)
	{
		PatientNameDocument	doc	= new PatientNameDocument(getLastNameMode(), limit);
		
		
		lastNameDocuments.add(doc);
		
		return doc;
	}
	
	
	public static void updateMode ()
	{
		for (PatientNameDocument doc : firstNameDocuments)
		{
			doc.setPatientNameMode(getFirstNameMode());
		}
		
		for (PatientNameDocument doc : lastNameDocuments)
		{
			doc.setPatientNameMode(getLastNameMode());
		}
	}
	
	
	
	/* ======================================== */
	// 		HELP METHODS
	/* ======================================== */
	
	private static int getFirstNameMode ()
	{
		return getMode(SettingConstants.PATIENT_FIRST_NAME_MODE);
	}
	
	
	private static int getLastNameMode ()
	{
		return getMode(SettingConstants.PATIENT_LAST_NAME_MODE);
	}
	
	
	private static int getMode (String key)
	{
		Integer	mode	= (Integer) PatientManagerModule.getInstance().administrativeElementsPlugin.getValue(key);
		
		if (mode == null)
			return SettingConstants.PATIENT_NAME_DEFAULT;
		else
			return mode.intValue();
	}
	
	public String changeText (String text, String charsBefore) throws BadLocationException
	{
		if (text == null) text = "";
		if (charsBefore == null) charsBefore = "";
		
		if (mode == SettingConstants.PATIENT_NAME_AS_ENTERED) {
			return text;
		}else if (mode == SettingConstants.PATIENT_NAME_UPPER_CASE) {
			return text.toUpperCase();
		} else if (mode == SettingConstants.PATIENT_NAME_CAPITALIZED) {
			text = WordUtils.capitalizeFully(charsBefore + text, CAPITALIZE_DELIMITER).substring(charsBefore.length());
			return text;
		}
		
		return text;
	}
	
	public void change () throws BadLocationException 
	{
		if (mode == SettingConstants.PATIENT_NAME_AS_ENTERED)
			return;
		 
		String		text	= getText(0, getLength());
		String		changedText;
		
		
		if (mode == SettingConstants.PATIENT_NAME_CAPITALIZED)
		{
			changedText	= WordUtils.capitalizeFully(text, CAPITALIZE_DELIMITER);
			
			if (changedText.equals(text))
				return;
		}
		else if (mode == SettingConstants.PATIENT_NAME_UPPER_CASE)
		{
			changedText	= text.toUpperCase();
			
			if (changedText.equals(text))
				return;
		}
		else
		{
			logger.warn("Invalid option for patient name checking: " + mode);
			return;
		}
		writeLock();
		try {
			remove(0, getLength());
			insertString(0, changedText, null);			
		} catch (Exception e) {
			// TODO: handle exception
		} finally {
			writeUnlock();
		}
	}
	
}
