'Contact Information Subform
@param r: the S3Request
@param pe_id: the pe_id
@param allow_create: allow adding of new contacts
@param method: the request method ("contacts", "private_contacts"
or "public_contacts")'

def contacts(self, r, pe_id, allow_create=False, method='contacts'):

    T = current.T
    s3db = current.s3db
    tablename = 'pr_contact'
    resource = s3db.resource(tablename, filter=(FS('pe_id') == pe_id))
    if (method != 'contacts'):
        if (method == 'private_contacts'):
            access = (FS('access') == 1)
        else:
            access = (FS('access') == 2)
        resource.add_filter(access)
    fields = ['id', 'priority', 'contact_description', 'value', 'contact_method', 'comments']
    rows = resource.select(fields, orderby='pr_contact.priority').rows
    from itertools import groupby
    groups = []
    gappend = groups.append
    method = (lambda row: row['pr_contact.contact_method'])
    for (key, group) in groupby(rows, method):
        gappend((key, list(group)))
    PRIORITY = self.PRIORITY
    groups.sort(key=(lambda item: PRIORITY.get(item[0], 99)))
    form = DIV(H2(T('Contacts')), _class='pr-contacts')
    table = resource.table
    if (allow_create and current.auth.s3_has_permission('create', table)):
        add_btn = DIV(A(T('Add'), _class='contact-add-btn    action-btn'), DIV(_class='throbber    hide'))
        form.append(add_btn)
    r.customise_resource(tablename)
    if table.comments.readable:
        comments_readable = True
    else:
        comments_readable = False
    if table.contact_description.readable:
        description_readable = True
    else:
        description_readable = False
    if table.priority.readable:
        priority_readable = True
    else:
        priority_readable = False
    opts = current.msg.CONTACT_OPTS
    action_buttons = self.action_buttons
    inline_edit_hint = T('Click    to    edit')
    for (method, contacts) in groups:
        form.append(H3(opts[method]))
        for contact in contacts:
            contact_id = contact['pr_contact.id']
            value = contact['pr_contact.value']
            data = {'id': contact_id, 'value': value}
            if priority_readable:
                priority = contact['pr_contact.priority']
                if priority:
                    data['priority'] = priority
                    priority_title = ('%s    -    %s' % (T('Priority'), inline_edit_hint))
                    priority_field = SPAN(priority, _class='pr-contact-priority', _title=priority_title)
                else:
                    priority_field = ''
            else:
                priority_field = ''
            title = SPAN(value, _title=inline_edit_hint, _class='pr-contact-value')
            if description_readable:
                description = (contact['pr_contact.contact_description'] or '')
                if description:
                    data['description'] = description
                    title = TAG[''](SPAN(description, _title=inline_edit_hint, _class='pr-contact-description'), ',    ', title)
            if comments_readable:
                comments = (contact['pr_contact.comments'] or '')
                data['comments'] = comments
                comments = DIV(SPAN(comments, _title=inline_edit_hint, _class='pr-contact-comments'), _class='pr-contact-subtitle')
            else:
                comments = DIV()
            actions = action_buttons(table, contact_id)
            form.append(DIV(DIV(priority_field, DIV(DIV(title, _class='pr-contact-title'), comments, _class='pr-contact-details'), _class='pr-contact-data    medium-9    columns'), actions, data=data, _class='pr-contact    row'))
    return form
