package crmdna.common.contact; import crmdna.common.Utils; import crmdna.common.ValidationResultProp; import crmdna.common.api.APIException; import crmdna.common.api.APIResponse.Status; import java.util.*; import java.util.logging.Logger; import static crmdna.common.AssertUtils.ensureNotNull; public class Contact { final static String EMAIL = "email"; final static String FIRSTNAME = "firstname"; final static String LASTNAME = "lastname"; final static String NICKNAME = "nickname"; final static String HOMEPHONE = "homephone"; final static String OFFICEPHONE = "officephone"; final static String MOBILEPHONE = "mobilephone"; final static String GENDER = "gender"; final static String CITY = "city"; final static String COUNTRY = "country"; final static String HOMEADDRESS = "homeaddress"; final static String OFFICEADDRESS = "officeaddress"; final static String HOMEPOSTALCODE = "homepostalcode"; final static String OFFICEPOSTALCODE = "officepostalcode"; public static Gender getGender(String gender) { if ((null == gender) || gender.equals("")) return null; gender = gender.toUpperCase(); if (gender.equals("M") || gender.equals("MALE") || gender.equals("MAN")) return Gender.MALE; if (gender.equals("F") || gender.equals("FEMALE") || gender.equals("WOMAN")) return Gender.FEMALE; Logger logger = Logger.getLogger(Contact.class.getName()); logger.warning("Invalid gender [" + gender + "]"); return null; } public static ValidationResultProp validate(List<ContactProp> contacts) { List<String> errors = new ArrayList<>(); List<String> warnings = new ArrayList<>(); Map<String, List<Integer>> firstName3CharVsIndex = new HashMap<>(); for (int i = 0; i < contacts.size(); i++) { ContactProp c = contacts.get(i); // throw error if first name is not specified if ((c.firstName == null) || c.firstName.equals("")) { String message = "Error in line no [" + (i + 2) + "]: First name is missing"; errors.add(message); continue; } if (c.firstName.length() < 3) { String message = "Warning in line no [" + (i + 2) + "]: First name [" + c.firstName + "] is less than 3 characters"; warnings.add(message); continue; } // email and phone numbers if specified should be valid // at least email or 1 contact number should be specified boolean emailOrPhoneNoValid = false; if (c.email != null) { if (Utils.isValidEmailAddress(c.email)) { emailOrPhoneNoValid = true; } else { String message = "Error in line no [" + (i + 2) + "]: Email [" + c.email + "] is not valid"; errors.add(message); continue; } } // country should be valid when a phone number is specified if ((c.homePhone != null) || (c.mobilePhone != null) || (c.officePhone != null)) { if (c.homeAddress.country == null) { String message = "Warning in line no [" + (i + 2) + "]: Country should be specified to validate phone no(s)"; warnings.add(message); continue; } } if (c.homePhone != null) { String message = Utils.getPhoneNoErrMsgIfAnyElseNull(c.homePhone, c.homeAddress.country); if (message != null) { warnings.add("Warning in line no [" + (i + 2) + "]: " + message); continue; } emailOrPhoneNoValid = true; } if (c.mobilePhone != null) { String message = Utils.getPhoneNoErrMsgIfAnyElseNull(c.mobilePhone, c.homeAddress.country); if (message != null) { warnings.add("Warning in line no [" + (i + 2) + "]: " + message); continue; } emailOrPhoneNoValid = true; } if (c.officePhone != null) { String message = Utils.getPhoneNoErrMsgIfAnyElseNull(c.officePhone, c.homeAddress.country); if (message != null) { warnings.add("Warning in line no [" + (i + 2) + "]: " + message); continue; } emailOrPhoneNoValid = true; } if (!emailOrPhoneNoValid) { String message = "Warning in line no [" + (i + 2) + "]: No email or contact number found for [" + c.firstName + "]"; warnings.add(message); continue; } String firstName3Char = c.firstName.substring(0, 3).toLowerCase(); if (firstName3CharVsIndex.containsKey(firstName3Char)) { List<Integer> list = firstName3CharVsIndex.get(firstName3Char); for (Integer index : list) { if (isMatching(c, contacts.get(index))) { String message = "Warning in line no [" + (i + 2) + "]: Line [" + (i + 2) + "] seems to be a duplicate of line [" + (index + 2) + "]. First 3 chars of first name and atleast one phone number or email are the same"; warnings.add(message); } } list.add(i); } else { List<Integer> list = new ArrayList<>(); list.add(i); firstName3CharVsIndex.put(firstName3Char, list); } } ValidationResultProp prop = new ValidationResultProp(); prop.numEntries = contacts.size(); prop.errors = errors; prop.warnings = warnings; return prop; } public static void ensureEmailOrPhoneNumberValid(ContactProp contact) { ensureNotNull(contact); if (contact.email != null) Utils.ensureValidEmail(contact.email); if (null != contact.homePhone) Utils.ensureValidPhoneNumber(contact.homePhone); if (null != contact.mobilePhone) Utils.ensureValidPhoneNumber(contact.mobilePhone); if (null != contact.officePhone) Utils.ensureValidPhoneNumber(contact.officePhone); // email or one of the phone numbers should be specified if ((contact.email == null) && (contact.mobilePhone == null) && (contact.homePhone == null) && (contact.officePhone == null)) { throw new APIException().status(Status.ERROR_RESOURCE_INCORRECT).message( "Either email or one of the phone numbers should be specified"); } } public static void ensureFirstNameAndValidEmailSpecified(ContactProp contact) { if ((contact.firstName == null) || (contact.firstName.equals(""))) throw new APIException().status(Status.ERROR_RESOURCE_INCORRECT).message( "First name not specified"); if ((contact.email == null) || (contact.email.equals(""))) throw new APIException().status(Status.ERROR_RESOURCE_INCORRECT).message( "Email not specified"); Utils.ensureValidEmail(contact.email); } public static List<ContactProp> getContactDetailsFromListOfMap(List<Map<String, String>> listOfMap) { List<ContactProp> contactDetailProps = new ArrayList<>(); if (listOfMap == null) return contactDetailProps; boolean columnsValidated = false; for (Map<String, String> map : listOfMap) { if (!columnsValidated) { ensureValidColumns(map); columnsValidated = true; } ContactProp contactDetailProp = getContactDetailFromMap(map); contactDetailProps.add(contactDetailProp); } return contactDetailProps; } static void ensureValidColumns(Map<String, String> map) { Set<String> set = map.keySet(); ensureElementInSet(set, EMAIL); ensureElementInSet(set, FIRSTNAME); ensureElementInSet(set, LASTNAME); ensureElementInSet(set, NICKNAME); ensureElementInSet(set, HOMEPHONE); ensureElementInSet(set, OFFICEPHONE); ensureElementInSet(set, MOBILEPHONE); ensureElementInSet(set, GENDER); ensureElementInSet(set, CITY); ensureElementInSet(set, COUNTRY); ensureElementInSet(set, HOMEADDRESS); ensureElementInSet(set, OFFICEADDRESS); ensureElementInSet(set, HOMEPOSTALCODE); ensureElementInSet(set, OFFICEPOSTALCODE); } private static void ensureElementInSet(Set<String> set, String element) { if (!set.contains(element)) throw new APIException().status(Status.ERROR_RESOURCE_INCORRECT).message( "Column [" + element + "] (space and case insensitve) is missing"); } static ContactProp getContactDetailFromMap(Map<String, String> map) { if (map == null) return null; ContactProp contact = new ContactProp(); for (String key : map.keySet()) { key = key.toLowerCase(); String value = map.get(key); if (key.equals("email") || key.equals("emailid")) { value = Utils.sanitizeEmail(value); contact.email = value; } else if (key.equals("firstname")) contact.firstName = value; else if (key.equals("lastname")) contact.lastName = value; else if (key.equals("nickname")) contact.nickName = value; else if (key.equals("homephone") || key.equals("homenumber") || key.equals("homeno")) { contact.homePhone = value; } else if (key.equals("officephone") || key.equals("officenumber") || key.equals("officeno")) { contact.officePhone = value; } else if (key.equals("mobilephone") || key.equals("mobilenumber") || key.equals("mobileno")) { contact.mobilePhone = value; } else if (key.equals("gender")) contact.gender = getGender(value); else if (key.equals("city")) contact.homeAddress.city = value; else if (key.equals("country")) contact.homeAddress.country = value; else if (key.equals("homeaddress") || key.equals("address")) contact.homeAddress.address = value; else if (key.equals("officeaddress")) contact.officeAddress.address = value; else if (key.equals("occupation")) contact.occupation = value; else if (key.equals("company")) contact.company = value; // sanitize phone numbers contact.homePhone = Utils.sanitizePhoneNo(contact.homePhone, contact.homeAddress.country); contact.mobilePhone = Utils.sanitizePhoneNo(contact.mobilePhone, contact.homeAddress.country); contact.officePhone = Utils.sanitizePhoneNo(contact.officePhone, contact.homeAddress.country); } return contact; } public static String getCSV(List<ContactProp> contactDetailProps) { if (contactDetailProps == null) return null; StringBuilder builder = new StringBuilder(); builder.append("First Name,Last Name,Email,Gender,Mobile Phone,Home Phone,Office Phone,City,Country"); builder.append("\n"); for (ContactProp c : contactDetailProps) { builder.append(getCSV(c)).append("\n"); } return builder.toString(); } private static String getCSV(ContactProp c) { if (null == c) return null; String gender = null; if (c.gender != null) gender = c.gender.toString(); StringBuilder builder = new StringBuilder(); builder.append(Utils.csvEncode(c.firstName)).append(",").append(Utils.csvEncode(c.lastName)) .append(",").append(Utils.csvEncode(c.email)).append(",").append(Utils.csvEncode(gender)) .append(",").append(Utils.csvEncode(c.mobilePhone)).append(",") .append(Utils.csvEncode(c.homePhone)).append(",").append(Utils.csvEncode(c.officePhone)) .append(",").append(Utils.csvEncode(c.homeAddress.city)).append(",") .append(Utils.csvEncode(c.homeAddress.country)); return builder.toString(); } public static boolean isMatching(ContactProp c1, ContactProp c2) { ensureNotNull(c1, "c1 cannot be null"); ensureNotNull(c2, "c2 cannot be null"); // if names are not close enough return false if (!Utils.closeEnough(c1.getName(), c2.getName())) return false; // if any phone number or email matches return true Set<String> s1 = c1.getEmailAndPhoneNosAsSet(); Set<String> s2 = c2.getEmailAndPhoneNosAsSet(); s1.retainAll(s2); if (!s1.isEmpty()) return true; // if home address matches return true String c1HomeAddress = c1.homeAddress.toString(); String c2HomeAddress = c2.homeAddress.toString(); if (!c1HomeAddress.equals("") && !c2HomeAddress.equals("")) { if (c1HomeAddress.toLowerCase().equals(c2HomeAddress.toLowerCase())) return true; } // if office address matches return true String c1OfficeAddress = c1.officeAddress.toString(); String c2OfficeAddress = c2.officeAddress.toString(); if (!c1OfficeAddress.equals("") && !c2OfficeAddress.equals("")) { if (c1OfficeAddress.toLowerCase().equals(c2OfficeAddress.toLowerCase())) return true; } // None of email, phone, office address, home address match return false; } public enum Gender { MALE, FEMALE, NOT_SPECIFIED } }