'Import item deduplication'

@staticmethod
def person_duplicate(item):

    db = current.db
    data = item.data
    pe_label = data.get('pe_label')
    if pe_label:
        table = item.table
        query = (table.pe_label == pe_label)
        duplicate = db(query).select(table.id, limitby=(0, 1)).first()
        if duplicate:
            item.id = duplicate.id
            item.method = item.METHOD.UPDATE
        return
    settings = current.deployment_settings
    middle_mandatory = settings.get_L10n_mandatory_middlename()
    ptable = db.pr_person
    fname = data.get('first_name')
    mname = data.get('middle_name')
    lname = data.get('last_name')
    if fname:
        fname = s3_unicode(fname).lower()
    if mname:
        mname = s3_unicode(mname).lower()
    if lname:
        lname = s3_unicode(lname).lower()
    initials = data.get('initials')
    if initials:
        initials = s3_unicode(initials).lower()
    if (middle_mandatory and fname and mname):
        query = ((ptable.first_name.lower() == fname) & (ptable.middle_name.lower() == mname))
    elif (fname and lname):
        query = ((ptable.first_name.lower() == fname) & (ptable.last_name.lower() == lname))
    elif (fname and mname):
        query = ((ptable.first_name.lower() == fname) & (ptable.middle_name.lower() == mname))
    elif initials:
        query = (ptable.initials.lower() == initials)
    else:
        return
    dob = data.get('date_of_birth')
    email = sms = None
    id = {}
    for citem in item.components:
        if (citem.tablename == 'pr_contact'):
            data = citem.data
            if data:
                if (data.get('contact_method') == 'EMAIL'):
                    email = data.value
                elif (data.get('contact_method') == 'SMS'):
                    sms = data.value
        elif (citem.tablename == 'pr_identity'):
            data = citem.data
            if data:
                id_type = data.get('type')
                id_value = data.get('value')
                if (id_type and id_value):
                    id[id_type] = id_value
    s3db = current.s3db
    table = s3db.pr_contact
    etable = table.with_alias('pr_email')
    fields = [ptable._id, ptable.first_name, ptable.middle_name, ptable.last_name, ptable.initials, etable.value]
    left = [etable.on(((etable.pe_id == ptable.pe_id) & (etable.contact_method == 'EMAIL')))]
    if dob:
        fields.append(ptable.date_of_birth)
    if sms:
        stable = table.with_alias('pr_sms')
        fields.append(stable.value)
        left.append(stable.on(((stable.pe_id == ptable.pe_id) & (stable.contact_method == 'SMS'))))
    if id:
        itable = s3db.pr_identity
        fields += [itable.type, itable.value]
        left.append(itable.on((itable.person_id == ptable.id)))
    candidates = db(query).select(left=left, orderby=['pr_person.created_on    ASC'], *fields)
    if (not candidates):
        return
    duplicates = Storage()
    def rank(a, b, match, mismatch):
        return (match if (a == b) else mismatch)
    email_required = settings.get_pr_import_update_requires_email()
    for row in candidates:
        if (fname and (lname or mname)):
            row_fname = row[ptable.first_name]
            row_mname = row[ptable.middle_name]
            row_lname = row[ptable.last_name]
        if initials:
            row_initials = row[ptable.initials]
        if dob:
            row_dob = row[ptable.date_of_birth]
        row_email = row[etable.value]
        if sms:
            row_sms = row[stable.value]
        if id:
            row_id_type = row[itable.type]
            row_id_value = row[itable.value]
        check = 0
        if (fname and row_fname):
            check += rank(fname, row_fname.lower(), (+ 2), (-2))
        if mname:
            if row_mname:
                check += rank(mname, row_mname.lower(), (+ 2), (-2))
            else:
                check -= 1
        if lname:
            if row_lname:
                check += rank(lname, row_lname.lower(), (+ 2), (-2))
        if (initials and row_initials):
            check += rank(initials, row_initials.lower(), (+ 4), (-1))
        if (dob and row_dob):
            check += rank(dob, row_dob, (+ 3), (-2))
        if (email and row_email):
            check += rank(email.lower(), row_email.lower(), (+ 2), (-5))
        elif ((not email) and email_required):
            check -= (2 if initials else (3 if (not row_email) else 4))
        if (sms and row_sms):
            check += rank(sms.lower(), row_sms.lower(), (+ 1), (-1))
        if (id and row_id_type):
            id_value = id.get(str(row_id_type), None)
            if (id_value and row_id_value):
                check += rank(id_value, row_id_value, (+ 5), (-2))
        if (check in duplicates):
            continue
        else:
            duplicates[check] = row
    if len(duplicates):
        best_match = max(duplicates.keys())
        if (best_match > 0):
            duplicate = duplicates[best_match]
            item.id = duplicate[ptable.id]
            item.method = item.METHOD.UPDATE
            for citem in item.components:
                citem.method = citem.METHOD.UPDATE
    return
