package net.sourceforge.fenixedu.util;

import java.util.HashSet;
import java.util.Set;

import net.sourceforge.fenixedu.domain.KnownGivenName;
import net.sourceforge.fenixedu.domain.RootDomainObject;
import net.sourceforge.fenixedu.domain.person.Gender;

public abstract class PersonNamesHandler {

    private static Set<KnownGivenName> knownGivenNames;

    private static Set<String> namesParticules = new HashSet<String>();

    static {
	knownGivenNames = RootDomainObject.getInstance().getKnownGivenNamesSet();

	namesParticules.add("da");
	namesParticules.add("ds");
	namesParticules.add("de");
	namesParticules.add("do");
	namesParticules.add("dos");
	namesParticules.add("e");
	namesParticules.add("del");
	namesParticules.add("der");
	namesParticules.add("la");
	namesParticules.add("los");
	namesParticules.add("van");
    }

    public static String getGivenNamesFromFullName(final String fullName, final Gender gender) {
	final String[] names = fullName.split(" ");
	final StringBuilder givenNames = new StringBuilder();
	final StringBuilder particules = new StringBuilder();
	int i = 0;
	boolean wasParticule = false;
	int numberOfGivenNames = 0;
	if (hasOnlyTwoNames(names)) {
	    givenNames.append(names[0]);
	} else {
	    for (final String n : names) {
		boolean foundGivenName = false;
		for (final KnownGivenName knownGivenName : knownGivenNames) {
		    if (knownGivenName.getName().equalsIgnoreCase(n.trim())) {
			foundGivenName = true;
			numberOfGivenNames++;
		    }
		}
		if (!foundGivenName && fullName.startsWith(n)) {
		    new KnownGivenName(n, gender);
		    foundGivenName = true;
		}
		if (foundGivenName && numberOfGivenNames <= 2) {
		    if (wasParticule) {
			givenNames.append(particules);
			particules.delete(0, particules.length());
		    }
		    givenNames.append(n.trim()).append(" ");
		    wasParticule = false;
		} else {
		    if (namesParticules.contains(n)) {
			particules.append(n.trim()).append(" ");
			wasParticule = true;
		    } else {
			break;
		    }
		}
	    }
	    i++;
	}
	return givenNames.toString().trim();
    }

    private static boolean hasOnlyTwoNames(final String[] names) {
	int numberOfNames = 0;
	for (final String name : names) {
	    if (!namesParticules.contains(name))
		numberOfNames++;
	}
	return numberOfNames == 2;
    }

    private static boolean isFemaleName(final String name) {
	final String[] names = name.split(" ");
	for (final String n : names) {
	    for (final KnownGivenName knownGivenName : knownGivenNames) {
		if (knownGivenName.getName().equalsIgnoreCase(n)
			&& knownGivenName.getGender() == Gender.FEMALE)
		    return true;
	    }
	}
	return false;
    }

    public static String computeUsedGivenName(final String givenName) {
	final String[] givenNames = givenName.split(" ");
	final StringBuilder usedGivenName = new StringBuilder();
	String specialNameFound = "";
	for (final String n : givenNames) {
	    if (n.equalsIgnoreCase("Maria")) {
		specialNameFound = "Maria";
		if (givenNames.length == 1)
		    return specialNameFound;
		continue;
	    }
	    if (specialNameFound.length() > 0) {
		if (namesParticules.contains(n.trim())) {
		    specialNameFound += " " + n;
		    continue;
		} else {
		    if (!isFemaleName(n)) {
			usedGivenName.append(specialNameFound).append(" ").append(n);
		    } else {
			usedGivenName.append(n).append(" ");
		    }
		    specialNameFound = "";
		    continue;
		}
	    }
	    if (usedGivenName.length() > 0) {
		if (specialNameFound.length() > 0) { // Maria appears after another given name.
		    // Example: João Maria
		    if (!isFemaleName(usedGivenName.toString())) {
			usedGivenName.append(specialNameFound).append(" ");
			continue;
		    }
		}
	    }
	    usedGivenName.append(n).append(" ");
	}
	return usedGivenName.toString().trim();
    }

    public static String computeUsedFamilyName(final String familyName) {
	final String[] familyNames = familyName.split(" ");
	final StringBuilder usedFamilyName = new StringBuilder();
	for (int i = (familyNames.length - 1); i >= 0; i--) {
	    final String name = familyNames[i];
	    if (usedFamilyName.length() > 0) {
		if (namesParticules.contains(name)) {
		    usedFamilyName.insert(0, " ").insert(0, name);
		    if (name.equals("e")) {
			if ((i - 1) >= 0)
			    usedFamilyName.insert(0, " ").insert(0, familyNames[i - 1]);
		    }
		    continue;
		} else
		    break;
	    }
	    usedFamilyName.append(name);
	}
	return usedFamilyName.toString();
    }
}