'Merge form for two records
@param r: the S3Request
@param **attr: the controller attributes for the request
@note: this method can always only be POSTed, and requires
both "selected" and "mode" in post_vars, as well as
the duplicate bookmarks list in session.s3'

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

    T = current.T
    session = current.session
    response = current.response
    output = dict()
    tablename = self.tablename
    s3 = session.s3
    DEDUPLICATE = self.DEDUPLICATE
    if (DEDUPLICATE in s3):
        bookmarks = s3[DEDUPLICATE]
        if (tablename in bookmarks):
            record_ids = bookmarks[tablename]
    post_vars = r.post_vars
    mode = post_vars.get('mode')
    selected = post_vars.get('selected', '')
    selected = selected.split(',')
    if (mode == 'Inclusive'):
        ids = selected
    elif (mode == 'Exclusive'):
        ids = [i for i in record_ids if (i not in selected)]
    else:
        ids = []
    if (len(ids) != 2):
        r.error(501, T('Please    select    exactly    two    records'), next=r.url(id=0, vars={}))
    table = self.table
    query = ((table._id == ids[0]) | (table._id == ids[1]))
    orderby = (table.created_on if ('created_on' in table) else None)
    rows = current.db(query).select(orderby=orderby, limitby=(0, 2))
    if (len(rows) != 2):
        r.error(404, current.ERROR.BAD_RECORD, next=r.url(id=0, vars={}))
    original = rows[0]
    duplicate = rows[1]
    formfields = [f for f in table if (f.readable or f.writable)]
    (ORIGINAL, DUPLICATE, KEEP) = (self.ORIGINAL, self.DUPLICATE, self.KEEP)
    keep_o = ((KEEP.o in post_vars) and post_vars[KEEP.o])
    keep_d = ((KEEP.d in post_vars) and post_vars[KEEP.d])
    trs = []
    init_requires = self.init_requires
    for f in formfields:
        oid = ('%s_%s' % (ORIGINAL, f.name))
        did = ('%s_%s' % (DUPLICATE, f.name))
        sid = ('swap_%s' % f.name)
        init_requires(f, original[f], duplicate[f])
        if (keep_o or (not any((keep_o, keep_d)))):
            owidget = self.widget(f, original[f], _name=oid, _id=oid)
        else:
            try:
                owidget = s3_represent_value(f, value=original[f])
            except:
                owidget = s3_unicode(original[f])
        if (keep_d or (not any((keep_o, keep_d)))):
            dwidget = self.widget(f, duplicate[f], _name=did, _id=did)
        else:
            try:
                dwidget = s3_represent_value(f, value=duplicate[f])
            except:
                dwidget = s3_unicode(duplicate[f])
        if (not any((keep_o, keep_d))):
            swap = INPUT(_value='<-->', _class='swap-button', _id=sid, _type='button')
        else:
            swap = DIV(_class='swap-button')
        if ((owidget is None) or (dwidget is None)):
            continue
        label = f.label
        trs.append(TR(TD(label, _class='w2p_fl'), TD(), TD(label, _class='w2p_fl')))
        trs.append(TR(TD(owidget, _class='mwidget'), TD(swap), TD(dwidget, _class='mwidget')))
    if ('created_on' in table):
        original_date = original.created_on
        duplicate_date = duplicate.created_on
        if ('created_by' in table):
            represent = table.created_by.represent
            original_author = represent(original.created_by)
            duplicate_author = represent(duplicate.created_by)
            created = T('Created    on    %s    by    %s')
            original_created = (created % (original_date, original_author))
            duplicate_created = (created % (duplicate_date, duplicate_author))
        else:
            created = T('Created    on    %s')
            original_created = (created % original_date)
            duplicate_created = (created % duplicate_date)
    else:
        original_created = ''
        duplicate_created = ''
    output['title'] = T('Merge    records')
    if (keep_o or (not any((keep_o, keep_d)))):
        submit_original = INPUT(_value=T('Keep    Original'), _type='submit', _name=KEEP.o, _id=KEEP.o)
    else:
        submit_original = ''
    if (keep_d or (not any((keep_o, keep_d)))):
        submit_duplicate = INPUT(_value=T('Keep    Duplicate'), _type='submit', _name=KEEP.d, _id=KEEP.d)
    else:
        submit_duplicate = ''
    form = FORM(TABLE(THEAD(TR(TH(H3(T('Original'))), TH(), TH(H3(T('Duplicate')))), TR(TD(original_created), TD(), TD(duplicate_created), _class='authorinfo')), TBODY(trs), TFOOT(TR(TD(submit_original), TD(), TD(submit_duplicate)))), hidden={'mode': 'Inclusive', 'selected': ','.join(ids)})
    output['form'] = form
    output['reset'] = FORM(INPUT(_value=T('Reset'), _type='submit', _name='reset', _id='form-reset'), A(T('Cancel'), _href=r.url(id=0, vars={}), _class='action-lnk'), hidden={'mode': mode, 'selected': ','.join(ids)})
    formname = ('merge_%s_%s_%s' % (tablename, original[table._id], duplicate[table._id]))
    if form.accepts(post_vars, session, formname=formname, onvalidation=(lambda form: self.onvalidation(tablename, form)), keepvalues=False, hideerror=False):
        s3db = current.s3db
        if form.vars[KEEP.d]:
            prefix = ('%s_' % DUPLICATE)
            (original, duplicate) = (duplicate, original)
        else:
            prefix = ('%s_' % ORIGINAL)
        data = Storage()
        for key in form.vars:
            if key.startswith(prefix):
                fname = key.split('_', 1)[1]
                data[fname] = form.vars[key]
        search = False
        resource = s3db.resource(tablename)
        try:
            resource.merge(original[table._id], duplicate[table._id], update=data)
        except current.auth.permission.error:
            r.unauthorized()
        except KeyError:
            r.error(404, current.ERROR.BAD_RECORD)
        except:
            import sys
            r.error(424, (T('Could    not    merge    records.    (Internal    Error:    %s)') % sys.exc_info()[1]), next=r.url())
        else:
            if (mode == 'Inclusive'):
                bookmarks[tablename] = [i for i in record_ids if (i not in ids)]
                if (not bookmarks[tablename]):
                    del bookmarks[tablename]
                    search = True
            elif (mode == 'Exclusive'):
                bookmarks[tablename].extend(ids)
                if (not selected):
                    search = True
            response.confirmation = T('Records    merged    successfully.')
        if search:
            self.next = r.url(method='', id=0, vars={})
        else:
            self.next = r.url(id=0, vars={})
    response.view = self._view(r, 'merge.html')
    return output
