'Widget renderer
@param field: the Field
@param value: the current value(s)
@param attr: additional HTML attributes for the widget'

def __call__(self, field, value, **attributes):

    T = current.T
    db = current.db
    s3db = current.s3db
    request = current.request
    s3 = current.response.s3
    requires = field.requires
    if requires:
        required = (not hasattr(requires, 'other'))
    else:
        required = False
    if (request.controller == 'appadmin'):
        attr = FormWidget._attributes(field, {}, **attributes)
        if required:
            requires = IS_LOCATION()
        else:
            requires = IS_EMPTY_OR(IS_LOCATION())
        return TAG[''](INPUT(**attr), requires=requires)
    settings = current.deployment_settings
    countries = settings.get_gis_countries()
    gis = current.gis
    config = gis.get_config()
    values = self.parse(value)
    location_id = values.get('id')
    gtable = s3db.gis_location
    default = field.default
    default_bounds = None
    if (not default):
        default = config.default_location_id
    if (not default):
        if (len(countries) == 1):
            ttable = s3db.gis_location_tag
            query = (((ttable.tag == 'ISO2') & (ttable.value == countries[0])) & (ttable.location_id == gtable.id))
            country = db(query).select(gtable.id, gtable.lat_min, gtable.lon_min, gtable.lat_max, gtable.lon_max, cache=s3db.cache, limitby=(0, 1)).first()
            try:
                default = country.id
                default_bounds = [country.lon_min, country.lat_min, country.lon_max, country.lat_max]
            except AttributeError:
                error = 'Default    country    data    not    in    database    (incorrect    prepop    setting?)'
                current.log.critical(error)
                if s3.debug:
                    raise RuntimeError(error)
    if ((not location_id) and (values.keys() == ['id'])):
        location_id = values['id'] = default
    values = self.extract(location_id, values=values)
    levels = self.levels
    load_levels = self.load_levels
    lowest_lx = None
    for level in load_levels[::(-1)]:
        if ((level not in levels) and values.get(level)):
            lowest_lx = level
            break
    fieldname = attributes.get('_name')
    if (not fieldname):
        fieldname = str(field).replace('.', '_')
    (labels, labels_compact) = self._labels(levels, country=values.get('L0'))
    location_dict = self._locations(levels, values, default_bounds=default_bounds, lowest_lx=lowest_lx, config=config)
    components = {}
    manual_input = self._input
    show_address = self.show_address
    if show_address:
        address = values.get('address')
        if (show_address is True):
            label = gtable.addr_street.label
        else:
            label = show_address
        components['address'] = manual_input(fieldname, 'address', address, label, hidden=(not address))
    show_postcode = self.show_postcode
    if (show_postcode is None):
        show_postcode = settings.get_gis_postcode_selector()
    if show_postcode:
        postcode = values.get('postcode')
        components['postcode'] = manual_input(fieldname, 'postcode', postcode, settings.get_ui_label_postcode(), hidden=(not postcode))
    lat = values.get('lat')
    lon = values.get('lon')
    if self.show_latlon:
        hidden = ((not lat) and (not lon))
        components['lat'] = manual_input(fieldname, 'lat', lat, T('Latitude'), hidden=hidden, _class='double')
        components['lon'] = manual_input(fieldname, 'lon', lon, T('Longitude'), hidden=hidden, _class='double')
    multiselect = settings.get_ui_multiselect_widget()
    lx_rows = self._lx_selectors(fieldname, levels, labels, required=required, multiselect=multiselect)
    components.update(lx_rows)
    if self.latlon_mode_toggle:
        latlon_labels = {'decimal': T('Use    decimal'), 'dms': T('Use    deg,    min,    sec')}
        if (self.latlon_mode == 'dms'):
            latlon_label = latlon_labels['decimal']
        else:
            latlon_label = latlon_labels['dms']
        toggle_id = (fieldname + '_latlon_toggle')
        components['latlon_toggle'] = ('', A(latlon_label, _id=toggle_id, _class='action-lnk'), toggle_id, False)
    else:
        latlon_labels = None
    location_selector_loaded = s3.gis.location_selector_loaded
    if (not location_selector_loaded):
        global_append = s3.js_global.append
        global_append(('i18n.select="%s"' % T('Select')))
        if (multiselect == 'search'):
            global_append(('i18n.search="%s"' % T('Search')))
        if latlon_labels:
            global_append(('i18n.latlon_mode={decimal:"%(decimal)s",dms:"%(dms)s"}' % latlon_labels))
            global_append(('i18n.latlon_error={lat:"%s",lon:"%s",min:"%s",sec:"%s",format:"%s"}' % (T('Latitude    must    be    -90..90'), T('Longitude    must    be    -180..180'), T('Minutes    must    be    0..59'), T('Seconds    must    be    0..59'), T('Unrecognized    format'))))
    wkt = values.get('wkt')
    radius = values.get('radius')
    if ((lat is not None) or (lon is not None) or (wkt is not None)):
        use_callback = True
    else:
        use_callback = False
    options = {'hideLx': self.hide_lx, 'reverseLx': self.reverse_lx, 'locations': location_dict, 'labels': labels_compact, 'showLabels': self.labels, 'featureRequired': self.feature_required, 'latlonMode': self.latlon_mode, 'latlonModeToggle': self.latlon_mode_toggle}
    if self.min_bbox:
        options['minBBOX'] = self.min_bbox
    if self.open_map_on_load:
        options['openMapOnLoad'] = True
    script = ("$('#%s').locationselector(%s)" % (fieldname, json.dumps(options, separators=SEPARATORS)))
    show_map = self.show_map
    callback = None
    if (show_map and use_callback):
        callback = script
    elif ((not location_selector_loaded) or (not location_selector_loaded.get(fieldname))):
        s3.jquery_ready.append(script)
    if s3.debug:
        script = 's3.ui.locationselector.js'
    else:
        script = 's3.ui.locationselector.min.js'
    script = ('/%s/static/scripts/S3/%s' % (request.application, script))
    scripts = s3.scripts
    if (script not in scripts):
        scripts.append(script)
    geocoder = (config.geocoder and show_address)
    if show_map:
        map_icon = self._map(field, fieldname, lat, lon, wkt, radius, callback=callback, geocoder=geocoder, tablename=field.tablename)
    else:
        map_icon = None
    if location_selector_loaded:
        location_selector_loaded[fieldname] = True
    else:
        s3.gis.location_selector_loaded = {fieldname: True}
    classes = ['location-selector']
    if fieldname.startswith('sub_'):
        is_inline = True
        classes.append('inline-locationselector-widget')
    else:
        is_inline = False
    real_input = self.inputfield(field, values, classes, **attributes)
    visible_components = self._layout(components, map_icon=map_icon, inline=is_inline)
    return TAG[''](DIV(_class='throbber'), real_input, visible_components)
