'Links user accounts to person registry entries
@param user: the user record
@param organisation_id: the user\'s organisation_id
to get the person\'s realm_entity
Policy for linking to pre-existing person records:
If this user is already linked to a person record with a different
first_name, last_name, email or realm_entity these will be
updated to those of the user.
If a person record with exactly the same first name and
last name exists, which has a contact information record
with exactly the same email address as used in the user
account, and is not linked to another user account, then
this person record will be linked to this user account.
Otherwise, a new person record is created, and a new email
contact record with the email address from the user record
is registered for that person.'

def s3_link_to_person(self, user=None, organisation_id=None):

    db = current.db
    s3db = current.s3db
    utable = self.settings.table_user
    ttable = s3db.auth_user_temp
    ptable = s3db.pr_person
    ctable = s3db.pr_contact
    atable = s3db.pr_address
    gctable = s3db.gis_config
    ltable = s3db.pr_person_user
    if organisation_id:
        org_pe_id = s3db.pr_get_pe_id('org_organisation', organisation_id)
    else:
        org_pe_id = None
    left = [ltable.on((ltable.user_id == utable.id)), ptable.on((ptable.pe_id == ltable.pe_id)), ttable.on((utable.id == ttable.user_id))]
    if (user is not None):
        if (not isinstance(user, (list, tuple))):
            user = [user]
        user_ids = [u.id for u in user]
        query = utable.id.belongs(user_ids)
    else:
        query = (utable.id != None)
    fields = [utable.id, utable.first_name, utable.last_name, utable.email, ltable.pe_id, ptable.id, ptable.first_name, ttable.home, ttable.mobile, ttable.image]
    middle_name = current.deployment_settings.get_L10n_mandatory_middlename()
    if middle_name:
        fields.append(ptable.middle_name)
    else:
        fields.append(ptable.last_name)
    rows = db(query).select(left=left, distinct=True, *fields)
    person_ids = []
    if current.request.vars.get('opt_in', None):
        opt_in = current.deployment_settings.get_auth_opt_in_team_list()
    else:
        opt_in = []
    for row in rows:
        user = row.auth_user
        tuser = row.auth_user_temp
        person = row.pr_person
        link = row.pr_person_user
        pe_id = link.pe_id
        if (pe_id is not None):
            if ((user.first_name != person.first_name) or ((not middle_name) and (user.last_name != person.last_name)) or (middle_name and (user.last_name != person.middle_name))):
                query = (ptable.pe_id == pe_id)
                if middle_name:
                    db(query).update(first_name=user.first_name, middle_name=user.last_name)
                else:
                    db(query).update(first_name=user.first_name, last_name=user.last_name)
            query = (((ctable.pe_id == pe_id) & (ctable.contact_method == 'EMAIL')) & (ctable.value == user.email))
            item = db(query).select(ctable.id, limitby=(0, 1)).first()
            if (item is None):
                ctable.insert(pe_id=pe_id, contact_method='EMAIL', value=user.email)
            if tuser.mobile:
                query = (((ctable.pe_id == pe_id) & (ctable.contact_method == 'SMS')) & (ctable.value == tuser.mobile))
                item = db(query).select(ctable.id, limitby=(0, 1)).first()
                if (item is None):
                    ctable.insert(pe_id=pe_id, contact_method='SMS', value=tuser.mobile)
            person_ids.append(person.id)
        else:
            first_name = user.first_name
            last_name = user.last_name
            email = user.email.lower()
            if email:
                if middle_name:
                    mquery = (ptable.middle_name == last_name)
                else:
                    mquery = (ptable.last_name == last_name)
                query = (((((ptable.first_name == first_name) & mquery) & (ctable.pe_id == ptable.pe_id)) & (ctable.contact_method == 'EMAIL')) & (ctable.value.lower() == email))
                person = db(query).select(ptable.id, ptable.pe_id, limitby=(0, 1)).first()
            else:
                person = None
            owner = Storage(owned_by_user=user.id)
            if person:
                other = db((ltable.pe_id == person.pe_id)).select(ltable.id, limitby=(0, 1)).first()
            if (person and (not other)):
                pe_id = person.pe_id
                realm_entity = self.get_realm_entity(ptable, person)
                if (not realm_entity):
                    realm_entity = org_pe_id
                owner.realm_entity = realm_entity
                ltable.insert(user_id=user.id, pe_id=pe_id)
                person.update_record(**owner)
                db((ctable.pe_id == pe_id)).update(**owner)
                db((atable.pe_id == pe_id)).update(**owner)
                db((gctable.pe_id == pe_id)).update(**owner)
                if (self.user and (self.user.id == user.id)):
                    self.user.pe_id = pe_id
                person_ids.append(person.id)
            else:
                if middle_name:
                    person_id = ptable.insert(first_name=first_name, middle_name=last_name, opt_in=opt_in, modified_by=user.id, **owner)
                else:
                    person_id = ptable.insert(first_name=first_name, last_name=last_name, opt_in=opt_in, modified_by=user.id, **owner)
                if person_id:
                    person = Storage(id=person_id)
                    s3db.update_super(ptable, person)
                    pe_id = person.pe_id
                    realm_entity = self.get_realm_entity(ptable, person)
                    if (not realm_entity):
                        realm_entity = org_pe_id
                    self.set_realm_entity(ptable, person, entity=realm_entity)
                    owner.realm_entity = realm_entity
                    ltable.insert(user_id=user.id, pe_id=pe_id)
                    ctable.insert(pe_id=pe_id, contact_method='EMAIL', priority=1, value=email, **owner)
                    gtable = s3db.pr_group
                    mtable = s3db.pr_group_membership
                    for team in opt_in:
                        team_rec = db((gtable.name == team)).select(gtable.id, limitby=(0, 1)).first()
                        if (team_rec == None):
                            team_id = gtable.insert(name=team, group_type=5)
                        else:
                            team_id = team_rec.id
                        mtable.insert(group_id=team_id, person_id=person_id)
                    person_ids.append(person_id)
                else:
                    pe_id = None
            if (pe_id is not None):
                tuser = row.auth_user_temp
                mobile = tuser.mobile
                if mobile:
                    ctable.insert(pe_id=pe_id, contact_method='SMS', priority=2, value=mobile, **owner)
                home = tuser.home
                if home:
                    ctable.insert(pe_id=pe_id, contact_method='HOME_PHONE', priority=3, value=home, **owner)
                image = tuser.image
                if image:
                    itable = s3db.pr_image
                    url = URL(c='default', f='download', args=image)
                    itable.insert(pe_id=pe_id, profile=True, image=image, url=url, description=current.T('Profile    Picture'))
                if (self.user and (self.user.id == user.id)):
                    self.user.pe_id = pe_id
    if (len(person_ids) == 1):
        return person_ids[0]
    else:
        return person_ids
