package gov.va.med.esr.common.model.person;

// Java Classes
import java.util.Iterator;
import java.util.Locale;
import java.util.Set;

// Library Classes
import org.apache.commons.lang.Validate;
import org.apache.commons.lang.builder.ToStringBuilder;

// Framework Classes
import gov.va.med.fw.model.AbstractEntity;
import gov.va.med.fw.model.lookup.AbstractCode;
import gov.va.med.fw.util.StringUtils;

// ESR Classes
import gov.va.med.esr.common.model.lookup.NameType;

public class Name extends AbstractEntity implements Comparable
{
    private static final long serialVersionUID = 6236325865733264677L;
    
    public static final StandardFormat NAME_FORMAT_FIRST_SPACE_LAST = new StandardFormat("1");
    public static final StandardFormat NAME_FORMAT_LAST_COMMA_FIRST = new StandardFormat("2");

    public static class StandardFormat extends AbstractCode
    {
        private static final long serialVersionUID = -8139709996478085470L;

        private StandardFormat(String code)
        {
            super(code);
        }
    }

    private String prefix = null;
    private String givenName = null;
    private String middleName = null;
    private String familyName = null;
    private String suffix = null;
    private NameType type = null;

    /**
     * Creates a new Name object.
     */
    public Name()
    {
        super();
    }

    public String getPrefix()
    {
        return this.prefix;
    }

    public void setPrefix(String prefix)
    {
        this.prefix = prefix;
    }

    public String getGivenName()
    {
        return this.givenName;
    }

    public void setGivenName(String givenName)
    {
        this.givenName = givenName;
    }

    public String getMiddleName()
    {
        return this.middleName;
    }

    public void setMiddleName(String middleName)
    {
        this.middleName = middleName;
    }

    public String getFamilyName()
    {
        return this.familyName;
    }

    public void setFamilyName(String familyName)
    {
        this.familyName = familyName;
    }

    public String getSuffix()
    {
        return this.suffix;
    }

    public void setSuffix(String suffix)
    {
        this.suffix = suffix;
    }

    public NameType getType()
    {
        return this.type;
    }

    public void setType(NameType type)
    {
        this.type = type;
    }

    /**
     * @see gov.va.med.fw.model.AbstractKeyedEntity#buildToString(org.apache.commons.lang.builder.ToStringBuilder)
     */
    protected void buildToString(ToStringBuilder builder)
    {
        builder.append("prefix", this.prefix);
        builder.append("givenName", this.givenName);
        builder.append("middleName", this.middleName);
        builder.append("familyName", this.familyName);
        builder.append("suffix", this.suffix);
        builder.append("type", this.type);
    }

    /**
     * Helper method to get the Name of a given type code. This method iterates the collection of Names and return the
     * Name of give type code or null if no Name for a given type code exists.
     *
     * @param names
     * @param typeCode
     *
     * @return Name if found or null if no phone with a given type found.
     */
    public static Name getNameOfType(Set names, String typeCode)
    {
        Validate.notNull(names, "The set of Name's must not be null");
        Validate.notNull(typeCode, "Name type's code must not be null");
        for (Iterator iter = names.iterator(); iter.hasNext();)
        {
            Name name = (Name)iter.next();
            NameType nameType = name.getType();
            if (nameType != null && nameType.getCode().equals(typeCode))
            {
                return name;
            }
        }
        return null;
    }

    /**
     * Compares this name to the specified name object. The comparrison is based on the getFormattedName method.
     *
     * @param nameObject the name object.
     *
     * @return the comparrision result.
     */
    public int compareTo(Object nameObject)
    {
        Name otherName = (Name)nameObject;
        String str1 = getFormattedName();
        String str2 = otherName.getFormattedName();
        return StringUtils.compareTo(((str1 != null) ? str1.toUpperCase(Locale.ENGLISH) : ""), ((str2 != null) ? str2.toUpperCase(Locale.ENGLISH) : ""));
    }

    /**
     * Gets the formatted version of the name using the NAME_FORMAT_LAST_COMMA_FIRST format type.
     *
     * @return the formatted name.
     */
    public String getFormattedName()
    {
        return getFormattedName(NAME_FORMAT_LAST_COMMA_FIRST);
    }

    /**
     * Gets the formatted version of the name using the specified format.  The NAME_FORMAT_LAST_COMMA_FIRST
     * format will be used if no format is specified.
     *
     * @param format the format to use.
     *
     * @return the formatted name.
     */
    public String getFormattedName(Name.StandardFormat format)
    {
        StringBuffer buf = new StringBuffer();
        if (format != null)
        {
            if ((format != null) && (Name.NAME_FORMAT_FIRST_SPACE_LAST.getCode().equals(format.getCode())))
            {
                if (StringUtils.isNotBlank(givenName))
                {
                    buf.append(givenName);
                }
                if (StringUtils.isNotBlank(familyName))
                {
                    buf.append(" ").append(familyName);
                }
            }
            else
            {
                // Default format
                if (StringUtils.isNotBlank(familyName))
                {
                    buf.append(familyName);
                }
                if (StringUtils.isNotBlank(givenName))
                {
                    if (buf.length() > 0)
                    {
                        buf.append(", ");
                    }
                    buf.append(givenName);
                }
            }
        }
        return buf.toString().toUpperCase();
    }
}
