/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package fi.csc.emrex.smp.model; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Value; /** * * @author salum */ public class Person { @Value("${smp.verification.threshold}") private double threshold ; private String firstName; private String lastName; /** * Format: 0 Not known 1 Male 2 Female 9 Not specified */ private int gender; private LocalDate birthDate; private DateTimeFormatter dateFormatter; public Person() { } public double getThreshold() { return threshold; } public void setThreshold(double threshold) { this.threshold = threshold; } public String getFullName() { if (firstName != null || lastName != null) { return firstName + " " + lastName; } else { return null; } } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public int getGender() { return gender; } public void setGender(int gender) { this.gender = gender; } public void setGender(String gender) { Integer temp = Integer.getInteger(gender); if (temp == null) { this.gender = 9; } else { this.gender = temp; } } public LocalDate getBirthDate() { return birthDate; } public void setBirthDate(LocalDate birthDate) { this.birthDate = birthDate; } public void setBirthDate(String birthDate, String dateFormat) { dateFormatter = DateTimeFormatter.ofPattern(dateFormat); if (birthDate == null || dateFormat == null) { this.birthDate = null; } else { this.birthDate = LocalDate.parse(birthDate, dateFormatter); } } public VerificationReply verifiy(Person otherPerson) { //TODO implement verification algorithm; VerificationReply r = new VerificationReply(); r.setFullNameFromHomeInstitute(this.getFullName()); r.setFullNameInElmo(otherPerson.getFullName()); boolean bdMatch = false; boolean nameMatch = false; int match = 0; LocalDate vbd = this.birthDate; LocalDate ebd = otherPerson.getBirthDate(); if (ebd == null || vbd == null) { r.addMessage("Birth date not set for " + (ebd == null ? "elmo" : "local") + " person."); } else if (!ebd.equals(vbd)) { r.addMessage("Birth date does not match."); } else { bdMatch = true; } double score = 0; score += levenshteinDistance(this.getLastName(), otherPerson.getLastName()); score += levenshteinDistance(this.getFirstName(), otherPerson.getFirstName()); double ratio = StringUtils.isNotBlank(this.getFullName()) ? score / this.getFullName().length() : 0.0; r.addMessage("Error ratio " + ratio + " based on Levenshtein check on name."); if (ratio > this.threshold) { r.addMessage("Ratio over threshold "+threshold); } else { nameMatch = true; } r.setVerified(bdMatch && nameMatch); return r; } private static int levenshteinDistance(String s, String t) { if (s == null && t == null) { return 0; } if (s == null || s.length() == 0) { return t.length(); } if (t == null || t.length() == 0) { return s.length(); } int[] v0 = new int[t.length() + 1]; int[] v1 = new int[t.length() + 1]; for (int i = 0; i < v0.length; i++) { v0[i] = i; } for (int i = 0; i < s.length(); i++) { // calculate v1 (current row distances) from the previous row v0 // first element of v1 is A[i+1][0] // edit distance is delete (i+1) chars from s to match empty t v1[0] = i + 1; // use formula to fill in the rest of the row for (int j = 0; j < t.length(); j++) { int cost = (s.charAt(i) == t.charAt(j)) ? 0 : 1; v1[j + 1] = Math.min(Math.min(v1[j] + 1, v0[j + 1] + 1), v0[j] + cost); } // copy v1 (current row) to v0 (previous row) for next iteration for (int j = 0; j < v0.length; j++) { v0[j] = v1[j]; } } return v1[t.length()]; } }