'Report generator
@param r: the S3Request instance
@param attr: controller attributes'

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

    T = current.T
    output = {}
    resource = self.resource
    tablename = resource.tablename
    get_config = resource.get_config
    representation = r.representation
    show_filter_form = False
    if (representation in ('html', 'iframe')):
        filter_widgets = get_config('filter_widgets', None)
        if (filter_widgets and (not self.hide_filter)):
            show_filter_form = True
            from s3filter import S3FilterForm
            S3FilterForm.apply_filter_defaults(r, resource)
    report_config = self.get_report_config()
    fields = self.resolve(report_config)
    extract = report_config.get('extract')
    if (not callable(extract)):
        extract = self.extract
    selectors = [s for s in fields if (fields[s] is not None)]
    orderby = report_config.get('orderby_cols')
    items = extract(self.resource, selectors, orderby)
    groupby = report_config.get('groupby_cols')
    aggregate = report_config.get('aggregate_cols')
    gi = S3GroupedItems(items, groupby=groupby, aggregate=aggregate)
    title = report_config.get('title')
    if (title is None):
        title = self.crud_string(tablename, 'title_report')
    display_cols = report_config.get('display_cols')
    labels = report_config.get('labels')
    represent = report_config.get('groupby_represent')
    if (representation in ('pdf', 'xls')):
        as_dict = True
    else:
        as_dict = False
    data = gi.json(fields=display_cols, labels=labels, represent=represent, as_dict=as_dict)
    group_headers = report_config.get('group_headers', False)
    widget_id = 'groupeditems'
    if (representation in ('html', 'iframe')):
        output['report_type'] = 'groupeditems'
        output['widget_id'] = widget_id
        output['title'] = title
        if show_filter_form:
            settings = current.deployment_settings
            filter_formstyle = get_config('filter_formstyle', None)
            filter_clear = get_config('filter_clear', settings.get_ui_filter_clear())
            filter_submit = get_config('filter_submit', True)
            filter_form = S3FilterForm(filter_widgets, formstyle=filter_formstyle, submit=filter_submit, clear=filter_clear, ajax=True, _class='filter-form', _id=('%s-filter-form' % widget_id))
            fresource = current.s3db.resource(tablename)
            alias = (resource.alias if resource.parent else None)
            output['filter_form'] = filter_form.html(fresource, r.get_vars, target=widget_id, alias=alias)
        items = INPUT(_type='hidden', _id=('%s-data' % widget_id), _class='gi-data', _value=data)
        output['items'] = items
        output['empty'] = T('No    data    available')
        output['formats'] = self.export_links(r)
        ajaxurl = attr.get('ajaxurl', r.url(method='grouped', representation='json', vars=r.get_vars))
        totals_label = report_config.get('totals_label', T('Total'))
        options = {'ajaxURL': ajaxurl, 'totalsLabel': str(totals_label).upper(), 'renderGroupHeaders': group_headers}
        self.inject_script(widget_id, options=options)
        self._view(r, 'grouped.html')
        response = current.response
        response.view = self._view(r, 'report.html')
    elif (representation == 'json'):
        output = data
    elif (representation == 'pdf'):
        totals_label = report_config.get('totals_label', T('Total'))
        pdf_header = report_config.get('pdf_header', DEFAULT)
        gi_table = S3GroupedItemsTable(resource, title=title, data=data, group_headers=group_headers, totals_label=totals_label, pdf_header=pdf_header)
        return gi_table.pdf(r)
    elif (representation == 'xls'):
        field_types = report_config.get('ftypes')
        totals_label = report_config.get('totals_label', T('Total'))
        gi_table = S3GroupedItemsTable(resource, title=title, data=data, field_types=field_types, aggregate=aggregate, group_headers=group_headers, totals_label=totals_label)
        return gi_table.xls(r)
    else:
        r.error(415, current.ERROR.BAD_FORMAT)
    return output
