/********************************************************************
 * Copyright © 2004 VHA. All rights reserved
 ********************************************************************/
package gov.va.med.esr.common.model.person;

import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.apache.commons.lang.Validate;
import org.apache.commons.lang.builder.ToStringBuilder;

import gov.va.med.fw.model.AbstractKeyedEntity;
import gov.va.med.fw.util.StringUtils;

import gov.va.med.esr.common.model.lookup.PseudoSSNReason;
import gov.va.med.esr.common.model.lookup.SSAMessage;
import gov.va.med.esr.common.model.lookup.SSAVerificationStatus;
import gov.va.med.esr.common.model.lookup.SSNChangeSource;
import gov.va.med.esr.common.model.lookup.SSNType;

/**
 * Person/Relation SSN BOM.
 * This SSN is associated to a Relation.
 * 
 * @author DNS   MANSOG
 * @date Jun 13, 2005 3:53:31 PM
 */
public class SSN
    extends AbstractKeyedEntity {
    private static final long serialVersionUID = 4376951375392165841L;
    
    private Relation relation = null;
    private String ssnText = null;

    private SSNType type = null;
    private PseudoSSNReason pseudoSSNReason;

    private SSAMessage ssaMessage = null;
    private Date ssaSentDate = null;
    private Date ssaReceivedDate = null;
    private Date ssaVerificationDate = null;
    private SSAVerificationStatus ssaVerificationStatus = null;
    private SSNChangeSource sourceOfChange = null;

    public SSN() {
        super();
    }
    
	protected void buildToString(ToStringBuilder builder) {
		builder.append("ssnText", this.ssnText);
		builder.append("ssaVerificationStatus", this.ssaVerificationStatus);
		builder.append("sourceOfChange", this.sourceOfChange);
		builder.append("ssaSentDate", this.ssaSentDate);
		builder.append("ssaReceivedDate", this.ssaReceivedDate);
		builder.append("ssaVerificationDate", this.ssaVerificationDate);
		
		super.buildToString(builder);
	}    

    public Relation getRelation() {
        return relation;
    }

    public void setRelation(Relation relation) {
        validateOwner(this.relation, relation);
        this.relation = relation;
    }

    public String getSsnText() {
        return ssnText;
    }

    public void setSsnText(String ssnText) {
        this.ssnText = ssnText;
    }

    public String getFormattedSsnText() {
    	return formatSSN(ssnText);
    }

    public static String formatSSN(String unformattedSSN) {
    	// remove whitespace and dashes
    	String temp = unformattedSSN != null ? StringUtils.remove(unformattedSSN, '-') : null;
    	temp = temp != null ? StringUtils.remove(temp, ' ') : null;
    	
        return temp;    	
    }
    
    public SSNType getType() {
        return type;
    }

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

    public SSAMessage getSsaMessage() {
        return ssaMessage;
    }

    public void setSsaMessage(SSAMessage message) {
        this.ssaMessage = message;
    }

    public PseudoSSNReason getPseudoSSNReason() {
        return pseudoSSNReason;
    }

    public void setPseudoSSNReason(PseudoSSNReason pseudoSSNReason) {
        this.pseudoSSNReason = pseudoSSNReason;
    }

    public Date getSsaVerificationDate() {
        return ssaVerificationDate;
    }

    public void setSsaVerificationDate(Date ssaSentDate) {
        this.ssaVerificationDate = ssaSentDate;
    }

    public Date getSsaReceivedDate() {
        return ssaReceivedDate;
    }

    public void setSsaReceivedDate(Date ssaReceivedDate) {
        this.ssaReceivedDate = ssaReceivedDate;
    }

    public Date getSsaSentDate() {
        return ssaSentDate;
    }

    public void setSsaSentDate(Date ssaSentDate) {
        this.ssaSentDate = ssaSentDate;
    }

    public SSAVerificationStatus getSsaVerificationStatus() {
        return ssaVerificationStatus;
    }

    public void setSsaVerificationStatus(
            SSAVerificationStatus ssaVerificationStatus) {
        this.ssaVerificationStatus = ssaVerificationStatus;
    }

    public SSNChangeSource getSourceOfChange() {
        return sourceOfChange;
    }

    public void setSourceOfChange(SSNChangeSource sourceOfChange) {
        this.sourceOfChange = sourceOfChange;
    }

    public boolean isSsaVerificationStatusVerified() {
        return ssaVerificationStatus != null 
                &&  SSAVerificationStatus.VERIFIED.getCode().equals(ssaVerificationStatus.getCode());
    }

    /**
     * Helper method to get the SSN of a given type code.
     * This method iterates the collection of ssns and return 
     * the SSN of give type code or null if no SSN for a given 
     * type code exists.
     * 
     * @param ssns
     * @param typeCode
     * @return SSN if found or null if no SSN with a given type found.
     */
    public static SSN getSSNOfType(Set ssns, String typeCode) {
        Validate.notNull(typeCode, "Ssn type code can not be null.");
        for (Iterator iter = ssns.iterator(); iter.hasNext();) {
            SSN ssn = (SSN) iter.next();
            if (isTypeEqual(ssn, typeCode)) {
                return ssn;
            }
        }
        return null;
    }

    /**
     * Helper method to get collections the SSN with a given type code.
     * This method iterates the collection of ssns and return the Set 
     * of SSN that have given type code
     * 
     * @param ssns
     * @param typeCode
     * @return Set - Set of type SSN, never null
     */
    public static Set getSSNsOfType(Set ssns, String typeCode) {
        Validate.notNull(typeCode, "Ssn type code can not be null.");
        Set typeSsns = new HashSet();
	    for (Iterator iter = ssns.iterator(); iter.hasNext();) {
            SSN ssn = (SSN) iter.next();
            if (isTypeEqual(ssn, typeCode)) {
                typeSsns.add(ssn);
            }
        }
	    return typeSsns;
    }

    private static boolean isTypeEqual(SSN ssn, String typeCode) {
        return ssn != null 
                && ssn.getType() != null 
                && typeCode.equals(ssn.getType().getCode());
    }
    
    public static boolean isValidSSN(String ssnStr) {
        if (ssnStr == null) {
            return false;
        }
        ssnStr = ssnStr.replaceAll("-", "");
        String[] startWiths = new String[] {"000", "00000"};
        if (ssnStr.length() != 9
                || !StringUtils.isNumeric(ssnStr)
                || StringUtils.isSameCharString(ssnStr)
                || StringUtils.startsWith(ssnStr, startWiths) 
                || ssnStr.startsWith("00", 3)
                || ssnStr.endsWith("0000")
                || "123456789".equals(ssnStr)) {
            return false;
        }
        return true;        
    }
}