'Ajax response method, expects a JSON input like:
{l: the PE label (from the input field),
c: boolean to indicate whether to just check
the PE label or to register payments
t: the event type code
x: [array of PE labels,
only when registering for multiple persons
@param r: the S3Request instance
@param attr: controller parameters
@return: JSON response, structure:
{l: the actual PE label (to update the input field),
p: the person details,
d: the family details,
f: [{n: the flag name
i: the flag instructions
b: profile picture URL,
i: {<event_code>: [<msg>, <blocked_until_datetime>]},
x: [{l: the family member PE label,
n: the family member full name,
d: the family member date of birth,
p: the family member profile picture URL,
r: {<event_code>: [<msg>, <blocked_until_datetime>]},
s: whether the action is permitted or not
e: form error (for label field)
a: error message
w: warning message
m: success message'

def registration_ajax(self, r, **attr):

    T = current.T
    s3db = current.s3db
    s = r.body
    s.seek(0)
    try:
        data = json.load(s)
    except (ValueError, TypeError):
        r.error(400, current.ERROR.BAD_REQUEST)
    output = {}
    error = None
    alert = None
    message = None
    warning = None
    permitted = False
    flags = []
    pe_label = data.get('l')
    person = self.get_person(pe_label)
    if (person is None):
        error = s3_str(T('No    person    found    with    this    ID    number'))
    else:
        flag_info = s3db.dvr_get_flag_instructions(person.id, action='id-check')
        permitted = flag_info['permitted']
        check = data.get('c')
        if check:
            output['l'] = person.pe_label
            person_details = self.person_details(person)
            output['p'] = s3_str(person_details)
            profile_picture = self.profile_picture(person)
            output['b'] = profile_picture
            details = s3db.dvr_get_household_size(person.id, dob=person.date_of_birth)
            if details:
                output['d'] = {'d': details}
            family_members = self.get_family_members(person)
            if family_members:
                output['x'] = family_members
            info = flag_info['info']
            for (flagname, instructions) in info:
                flags.append({'n': s3_str(T(flagname)), 'i': s3_str(T(instructions))})
            event_types = self.get_event_types()
            blocked = self.get_blocked_events(person.id)
            intervals = {}
            for (type_id, info) in blocked.items():
                event_type = event_types.get(type_id)
                if (not event_type):
                    continue
                code = event_type.code
                (msg, dt) = info
                intervals[code] = (s3_str(msg), ('%sZ' % s3_encode_iso_datetime(dt)))
            output['i'] = intervals
        else:
            type_id = None
            event_code = data.get('t')
            if (not event_code):
                alert = T('No    event    type    specified')
            elif (not permitted):
                alert = T('Event    registration    not    permitted')
            else:
                event_type = self.get_event_type(event_code)
                if (not event_type):
                    alert = (T('Invalid    event    type:    %s') % event_code)
                else:
                    type_id = event_type.id
            if type_id:
                family_labels = data.get('x')
                if family_labels:
                    family_members = self.get_family_members(person, include_ids=True)
                    family_members = dict(((m['l'], m) for m in family_members))
                    registered = 0
                    alerts = []
                    for label in family_labels:
                        member = family_members.get(label)
                        if (not member):
                            continue
                        member_id = member.get('id')
                        rules = member.get('r')
                        if (rules and (event_code in rules)):
                            alerts.append(':    '.join((s3_str(member['n']), s3_str(rules[event_code][0]))))
                        else:
                            self.register_event(member_id, type_id)
                            registered += 1
                    if alerts:
                        alert = ',    '.join(alerts)
                    if registered:
                        message = (T('%(number)s    registrations    successful') % {'number': registered})
                    elif (not alerts):
                        alert = T('Could    not    register    event')
                else:
                    person_id = person.id
                    blocked = self.get_blocked_events(person_id, type_id=type_id)
                    if (type_id in blocked):
                        alert = blocked[type_id][0]
                    else:
                        success = self.register_event(person.id, type_id)
                        if success:
                            message = T('Event    registered')
                        else:
                            alert = T('Could    not    register    event')
    if alert:
        output['a'] = s3_str(alert)
    if error:
        output['e'] = s3_str(error)
    if message:
        output['m'] = s3_str(message)
    if warning:
        output['w'] = s3_str(warning)
    output['s'] = permitted
    output['f'] = flags
    current.response.headers['Content-Type'] = 'application/json'
    return json.dumps(output)
