'Build initial location dict (to populate Lx dropdowns)
@param levels: the exposed levels
@param values: the current values
@param default_bounds: the default bounds (if already known, e.g.
single-country deployment)
@param lowest_lx: the lowest un-selectable Lx level (to determine
default bounds if not passed in)
@param config: the current GIS config
@return: dict of location data, ready for JSON output
@ToDo: DRY with controllers/gis.py ldata()'

def _locations(self, levels, values, default_bounds=None, lowest_lx=None, config=None):

    db = current.db
    s3db = current.s3db
    settings = current.deployment_settings
    L0 = values.get('L0')
    L1 = values.get('L1')
    L2 = values.get('L2')
    L3 = values.get('L3')
    L4 = values.get('L4')
    gtable = s3db.gis_location
    if ('L0' in levels):
        query = (gtable.level == 'L0')
        countries = settings.get_gis_countries()
        if len(countries):
            ttable = s3db.gis_location_tag
            query &= (((ttable.tag == 'ISO2') & ttable.value.belongs(countries)) & (ttable.location_id == gtable.id))
        if (L0 and ('L1' in levels)):
            query |= ((gtable.level != None) & (gtable.parent == L0))
        if (L1 and ('L2' in levels)):
            query |= ((gtable.level != None) & (gtable.parent == L1))
        if (L2 and ('L3' in levels)):
            query |= ((gtable.level != None) & (gtable.parent == L2))
        if (L3 and ('L4' in levels)):
            query |= ((gtable.level != None) & (gtable.parent == L3))
        if (L4 and ('L5' in levels)):
            query |= ((gtable.level != None) & (gtable.parent == L4))
    elif (L0 and ('L1' in levels)):
        query = ((gtable.level != None) & (gtable.parent == L0))
        if (L1 and ('L2' in levels)):
            query |= ((gtable.level != None) & (gtable.parent == L1))
        if (L2 and ('L3' in levels)):
            query |= ((gtable.level != None) & (gtable.parent == L2))
        if (L3 and ('L4' in levels)):
            query |= ((gtable.level != None) & (gtable.parent == L3))
        if (L4 and ('L5' in levels)):
            query |= ((gtable.level != None) & (gtable.parent == L4))
    elif (L1 and ('L2' in levels)):
        query = ((gtable.level != None) & (gtable.parent == L1))
        if (L2 and ('L3' in levels)):
            query |= ((gtable.level != None) & (gtable.parent == L2))
        if (L3 and ('L4' in levels)):
            query |= ((gtable.level != None) & (gtable.parent == L3))
        if (L4 and ('L5' in levels)):
            query |= ((gtable.level != None) & (gtable.parent == L4))
    elif (L2 and ('L3' in levels)):
        query = ((gtable.level != None) & (gtable.parent == L2))
        if (L3 and ('L4' in levels)):
            query |= ((gtable.level != None) & (gtable.parent == L3))
        if (L4 and ('L5' in levels)):
            query |= ((gtable.level != None) & (gtable.parent == L4))
    elif (L3 and ('L4' in levels)):
        query = ((gtable.level != None) & (gtable.parent == L3))
        if (L4 and ('L5' in levels)):
            query |= ((gtable.level != None) & (gtable.parent == L4))
    elif (L4 and ('L5' in levels)):
        query = ((gtable.level != None) & (gtable.parent == L4))
    else:
        query = None
    language = current.session.s3.language
    if (language in ('en', 'en-gb')):
        translate = False
    else:
        translate = settings.get_L10n_translate_gis_location()
    if (query is not None):
        query &= ((gtable.deleted == False) & (gtable.end_date == None))
        fields = [gtable.id, gtable.name, gtable.level, gtable.parent, gtable.inherited, gtable.lat_min, gtable.lon_min, gtable.lat_max, gtable.lon_max]
        if translate:
            ntable = s3db.gis_location_name
            fields.append(ntable.name_l10n)
            left = ntable.on((((ntable.deleted == False) & (ntable.language == language)) & (ntable.location_id == gtable.id)))
        else:
            left = None
        locations = db(query).select(left=left, *fields)
    else:
        current.log.warning('S3LocationSelector:    no    default    for    hidden    Lx    level?')
        locations = []
    location_dict = {}
    if default_bounds:
        location_dict['d'] = dict(id=L0, b=default_bounds)
        location_dict[L0] = dict(b=default_bounds, l=0)
    elif lowest_lx:
        lx = values.get(lowest_lx)
        record = db((gtable.id == lx)).select(gtable.lat_min, gtable.lon_min, gtable.lat_max, gtable.lon_max, cache=s3db.cache, limitby=(0, 1)).first()
        try:
            bounds = [record.lon_min, record.lat_min, record.lon_max, record.lat_max]
        except:
            raise ValueError
        location_dict['d'] = dict(id=lx, b=bounds)
        location_dict[lx] = dict(b=bounds, l=int(lowest_lx[1:]))
    else:
        fallback = None
        default_location = config.default_location_id
        if default_location:
            query = (gtable.id == default_location)
            record = db(query).select(gtable.level, gtable.lat_min, gtable.lon_min, gtable.lat_max, gtable.lon_max, cache=s3db.cache, limitby=(0, 1)).first()
            if (record and record.level):
                bounds = [record.lon_min, record.lat_min, record.lon_max, record.lat_max]
                if any(bounds):
                    fallback = {'id': default_location, 'b': bounds}
        if (fallback is None):
            fallback = {'b': [config.lon_min, config.lat_min, config.lon_max, config.lat_max]}
        location_dict['d'] = fallback
    if translate:
        for location in locations:
            l = location['gis_location']
            name = (location['gis_location_name.name_l10n'] or l.name)
            data = dict(n=name, l=int(l.level[1]))
            if l.parent:
                data['f'] = int(l.parent)
            if (not l.inherited):
                data['b'] = [l.lon_min, l.lat_min, l.lon_max, l.lat_max]
            location_dict[int(l.id)] = data
    else:
        for l in locations:
            level = l.level
            if level:
                level = int(level[1])
            else:
                current.log.warning('S3LocationSelector', 'Location    Hierarchy    not    setup    properly')
                continue
            data = dict(n=l.name, l=level)
            if l.parent:
                data['f'] = int(l.parent)
            if (not l.inherited):
                data['b'] = [l.lon_min, l.lat_min, l.lon_max, l.lat_max]
            location_dict[int(l.id)] = data
    return location_dict
