'Setup the Map
- not done during init() to be as Lazy as possible
- separated from xml() in order to be able to read options to put
into scripts (callback or otherwise)'

def _setup(self):

    config = GIS.get_config()
    if (not config):
        current.session.error = current.T('Map    cannot    display    without    prepop    data!')
        redirect(URL(c='default', f='index'))
    opts = self.opts
    T = current.T
    db = current.db
    auth = current.auth
    s3db = current.s3db
    request = current.request
    response = current.response
    if (not response.warning):
        response.warning = ''
    s3 = response.s3
    ctable = db.gis_config
    settings = current.deployment_settings
    MAP_ADMIN = auth.s3_has_role(current.session.s3.system_roles.MAP_ADMIN)
    get_vars = request.get_vars
    js_globals = {}
    options = {}
    i18n = {'gis_base_layers': T('Base    Layers'), 'gis_overlays': T(settings.get_gis_label_overlays()), 'gis_layers': T(settings.get_gis_layers_label()), 'gis_draft_layer': T('Draft    Features'), 'gis_cluster_multiple': T('There    are    multiple    records    at    this    location'), 'gis_loading': T('Loading'), 'gis_requires_login': T('Requires    Login'), 'gis_too_many_features': T('There    are    too    many    features,    please    Zoom    In    or    Filter'), 'gis_zoomin': T('Zoom    In')}
    height = opts.get('height', None)
    if height:
        map_height = height
    else:
        map_height = settings.get_gis_map_height()
    options['map_height'] = map_height
    width = opts.get('width', None)
    if width:
        map_width = width
    else:
        map_width = settings.get_gis_map_width()
    options['map_width'] = map_width
    zoom = get_vars.get('zoom', None)
    if (zoom is not None):
        zoom = int(zoom)
    else:
        zoom = opts.get('zoom', None)
    if (not zoom):
        zoom = config.zoom
    options['zoom'] = (zoom or 1)
    bbox = opts.get('bbox', None)
    if (bbox and ((-90) <= bbox['lat_max'] <= 90) and ((-90) <= bbox['lat_min'] <= 90) and ((-180) <= bbox['lon_max'] <= 180) and ((-180) <= bbox['lon_min'] <= 180)):
        pass
    elif (zoom is None):
        bbox = config
    else:
        bbox = None
        lat = get_vars.get('lat', None)
        if (lat is not None):
            lat = float(lat)
        else:
            lat = opts.get('lat', None)
        if ((lat is None) or (lat == '')):
            lat = config.lat
        lon = get_vars.get('lon', None)
        if (lon is not None):
            lon = float(lon)
        else:
            lon = opts.get('lon', None)
        if ((lon is None) or (lon == '')):
            lon = config.lon
    if bbox:
        options['bbox'] = [bbox['lon_min'], bbox['lat_min'], bbox['lon_max'], bbox['lat_max']]
    else:
        options['lat'] = lat
        options['lon'] = lon
    options['numZoomLevels'] = config.zoom_levels
    options['restrictedExtent'] = (config.lon_min, config.lat_min, config.lon_max, config.lat_max)
    projection = opts.get('projection', None)
    if (not projection):
        projection = config.epsg
    options['projection'] = projection
    if (projection not in (900913, 4326)):
        projpath = os.path.join(request.folder, 'static', 'scripts', 'gis', 'proj4js', 'lib', 'defs', ('EPSG%s.js' % projection))
        try:
            f = open(projpath, 'r')
            f.close()
        except:
            if projection:
                proj4js = config.proj4js
                if proj4js:
                    try:
                        f = open(projpath, 'w')
                    except IOError as e:
                        response.error = (T('Map    not    available:    Cannot    write    projection    file    -    %s') % e)
                    else:
                        f.write(('Proj4js.defs["EPSG:4326"]="%s"' % proj4js))
                        f.close()
                else:
                    response.warning = (T('Map    not    available:    Projection    %(projection)s    not    supported    -    please    add    definition    to    %(path)s') % dict(projection=("'%s'" % projection), path='/static/scripts/gis/proj4js/lib/defs'))
            else:
                response.error = T('Map    not    available:    No    Projection    configured')
            return None
        options['maxExtent'] = config.maxExtent
        options['units'] = config.units
    if config.marker_image:
        options['marker_default'] = dict(i=config.marker_image, h=config.marker_height, w=config.marker_width)
    marker_max_height = settings.get_gis_marker_max_height()
    if (marker_max_height != 35):
        options['max_h'] = marker_max_height
    marker_max_width = settings.get_gis_marker_max_width()
    if (marker_max_width != 30):
        options['max_w'] = marker_max_width
    cluster_fill = settings.get_gis_cluster_fill()
    if (cluster_fill and (cluster_fill != '8087ff')):
        options['cluster_fill'] = cluster_fill
    cluster_stroke = settings.get_gis_cluster_stroke()
    if (cluster_stroke and (cluster_stroke != '2b2f76')):
        options['cluster_stroke'] = cluster_stroke
    select_fill = settings.get_gis_select_fill()
    if (select_fill and (select_fill != 'ffdc33')):
        options['select_fill'] = select_fill
    select_stroke = settings.get_gis_select_stroke()
    if (select_stroke and (select_stroke != 'ff9933')):
        options['select_stroke'] = select_stroke
    if (not settings.get_gis_cluster_label()):
        options['cluster_label'] = False
    if (not opts.get('closable', False)):
        options['windowNotClosable'] = True
    if opts.get('window', False):
        options['window'] = True
        if opts.get('window_hide', False):
            options['windowHide'] = True
    if opts.get('maximizable', False):
        options['maximizable'] = True
    else:
        options['maximizable'] = False
    if opts.get('collapsed', False):
        options['west_collapsed'] = True
    if (not settings.get_gis_layer_tree_base()):
        options['hide_base'] = True
    if (not settings.get_gis_layer_tree_overlays()):
        options['hide_overlays'] = True
    if (not settings.get_gis_layer_tree_expanded()):
        options['folders_closed'] = True
    if settings.get_gis_layer_tree_radio():
        options['folders_radio'] = True
    if opts.get('toolbar', False):
        options['toolbar'] = True
        i18n['gis_length_message'] = T('The    length    is')
        i18n['gis_length_tooltip'] = T('Measure    Length:    Click    the    points    along    the    path    &    end    with    a    double-click')
        i18n['gis_zoomfull'] = T('Zoom    to    maximum    map    extent')
        if settings.get_gis_geolocate_control():
            i18n['gis_geoLocate'] = T('Zoom    to    Current    Location')
        if opts.get('search', False):
            geonames_username = settings.get_gis_geonames_username()
            if geonames_username:
                options['geonames'] = geonames_username
                i18n['gis_search'] = T('Search    location    in    Geonames')
        nav = opts.get('nav', None)
        if (nav is None):
            nav = settings.get_gis_nav_controls()
        if nav:
            i18n['gis_zoominbutton'] = T('Zoom    In:    click    in    the    map    or    use    the    left    mouse    button    and    drag    to    create    a    rectangle')
            i18n['gis_zoomout'] = T('Zoom    Out:    click    in    the    map    or    use    the    left    mouse    button    and    drag    to    create    a    rectangle')
            i18n['gis_pan'] = T('Pan    Map:    keep    the    left    mouse    button    pressed    and    drag    the    map')
            i18n['gis_navPrevious'] = T('Previous    View')
            i18n['gis_navNext'] = T('Next    View')
        else:
            options['nav'] = False
        if opts.get('area', False):
            options['area'] = True
            i18n['gis_area_message'] = T('The    area    is')
            i18n['gis_area_tooltip'] = T('Measure    Area:    Click    the    points    around    the    polygon    &    end    with    a    double-click')
        color_picker = opts.get('color_picker', False)
        if color_picker:
            options['color_picker'] = True
            if (color_picker is not True):
                options['draft_style'] = json.loads(color_picker)
            i18n['gis_cancelText'] = T('cancel')
            i18n['gis_chooseText'] = T('choose')
            i18n['gis_togglePaletteMoreText'] = T('more')
            i18n['gis_togglePaletteLessText'] = T('less')
            i18n['gis_clearText'] = T('Clear    Color    Selection')
            i18n['gis_noColorSelectedText'] = T('No    Color    Selected')
        print_control = ((opts.get('print_control') is not False) and settings.get_gis_print())
        if print_control:
            options['print'] = True
            i18n['gis_print'] = T('Print')
            i18n['gis_paper_size'] = T('Paper    Size')
            i18n['gis_print_tip'] = T('Take    a    screenshot    of    the    map    which    can    be    printed')
        if ((opts.get('save') is True) and auth.s3_logged_in()):
            options['save'] = True
            i18n['gis_save'] = T('Save:    Default    Lat,    Lon    &    Zoom    for    the    Viewport')
            if (MAP_ADMIN or (config.pe_id == auth.user.pe_id)):
                options['config_id'] = config.id
        pe_id = (auth.user.pe_id if auth.s3_logged_in() else None)
        if (pe_id and s3db.auth_user_options_get_osm(pe_id)):
            i18n['gis_potlatch'] = T('Edit    the    OpenStreetMap    data    for    this    area')
            i18n['gis_osm_zoom_closer'] = T('Zoom    in    closer    to    Edit    OpenStreetMap    layer')
        mgrs = opts.get('mgrs', None)
        if mgrs:
            options['mgrs_name'] = mgrs['name']
            options['mgrs_url'] = mgrs['url']
    elif (opts.get('save') is True):
        opts['save'] = 'float'
    if ((opts.get('save') == 'float') and auth.s3_logged_in()):
        permit = auth.s3_has_permission
        if permit('create', ctable):
            options['save'] = 'float'
            i18n['gis_save_map'] = T('Save    Map')
            i18n['gis_new_map'] = T('Save    as    New    Map?')
            i18n['gis_name_map'] = T('Name    of    Map')
            i18n['save'] = T('Save')
            i18n['saved'] = T('Saved')
            config_id = config.id
            _config = db((ctable.id == config_id)).select(ctable.uuid, ctable.name, limitby=(0, 1)).first()
            if MAP_ADMIN:
                i18n['gis_my_maps'] = T('Saved    Maps')
            else:
                options['pe_id'] = auth.user.pe_id
                i18n['gis_my_maps'] = T('My    Maps')
            if permit('update', ctable, record_id=config_id):
                options['config_id'] = config_id
                options['config_name'] = _config.name
            elif (_config.uuid != 'SITE_DEFAULT'):
                options['config_name'] = _config.name
    legend = opts.get('legend', False)
    if legend:
        i18n['gis_legend'] = T('Legend')
        if (legend == 'float'):
            options['legend'] = 'float'
            if settings.get_gis_layer_metadata():
                options['metadata'] = True
                if MAP_ADMIN:
                    i18n['gis_metadata_create'] = T("Create    'More    Info'")
                    i18n['gis_metadata_edit'] = T("Edit    'More    Info'")
                else:
                    i18n['gis_metadata'] = T('More    Info')
        else:
            options['legend'] = True
    if opts.get('add_feature', False):
        i18n['gis_draw_feature'] = T('Add    Point')
        if opts.get('add_feature_active', False):
            options['draw_feature'] = 'active'
        else:
            options['draw_feature'] = 'inactive'
    if opts.get('add_line', False):
        i18n['gis_draw_line'] = T('Add    Line')
        if opts.get('add_line_active', False):
            options['draw_line'] = 'active'
        else:
            options['draw_line'] = 'inactive'
    if opts.get('add_polygon', False):
        i18n['gis_draw_polygon'] = T('Add    Polygon')
        i18n['gis_draw_polygon_clear'] = T('Clear    Polygon')
        if opts.get('add_polygon_active', False):
            options['draw_polygon'] = 'active'
        else:
            options['draw_polygon'] = 'inactive'
    if opts.get('add_circle', False):
        i18n['gis_draw_circle'] = T('Add    Circle')
        if opts.get('add_circle_active', False):
            options['draw_circle'] = 'active'
        else:
            options['draw_circle'] = 'inactive'
    clear_layers = ((opts.get('clear_layers') is not False) and settings.get_gis_clear_layers())
    if clear_layers:
        options['clear_layers'] = clear_layers
        i18n['gis_clearlayers'] = T('Clear    all    Layers')
    if settings.get_gis_layer_properties():
        i18n['gis_properties'] = T('Layer    Properties')
    if settings.get_gis_geoserver_password():
        i18n['gis_uploadlayer'] = T('Upload    Shapefile')
    wms_browser = opts.get('wms_browser', None)
    if wms_browser:
        options['wms_browser_name'] = wms_browser['name']
        options['wms_browser_url'] = urllib.quote(wms_browser['url'])
    mouse_position = opts.get('mouse_position', None)
    if (mouse_position is None):
        mouse_position = settings.get_gis_mouse_position()
    if (mouse_position == 'mgrs'):
        options['mouse_position'] = 'mgrs'
        js_globals['mgrs'] = True
    elif mouse_position:
        options['mouse_position'] = True
    overview = opts.get('overview', None)
    if (overview is None):
        overview = settings.get_gis_overview()
    if (not overview):
        options['overview'] = False
    permalink = opts.get('permalink', None)
    if (permalink is None):
        permalink = settings.get_gis_permalink()
    if (not permalink):
        options['permalink'] = False
    scaleline = opts.get('scaleline', None)
    if (scaleline is None):
        scaleline = settings.get_gis_scaleline()
    if (not scaleline):
        options['scaleline'] = False
    zoomcontrol = opts.get('zoomcontrol', None)
    if (zoomcontrol is None):
        zoomcontrol = settings.get_gis_zoomcontrol()
    if (not zoomcontrol):
        options['zoomcontrol'] = False
    zoomWheelEnabled = opts.get('zoomWheelEnabled', True)
    if (not zoomWheelEnabled):
        options['no_zoom_wheel'] = True
    if settings.get_gis_duplicate_features():
        options['duplicate_features'] = True
    features = opts.get('features', None)
    if features:
        options['features'] = addFeatures(features)
    feature_queries = opts.get('feature_queries', None)
    if feature_queries:
        options['feature_queries'] = addFeatureQueries(feature_queries)
    feature_resources = opts.get('feature_resources', None)
    if feature_resources:
        options['feature_resources'] = addFeatureResources(feature_resources)
    db = current.db
    ltable = db.gis_layer_config
    etable = db.gis_layer_entity
    query = (ltable.deleted == False)
    join = [etable.on((etable.layer_id == ltable.layer_id))]
    fields = [etable.instance_type, ltable.layer_id, ltable.enabled, ltable.visible, ltable.base, ltable.dir]
    if opts.get('catalogue_layers', False):
        stable = db.gis_style
        mtable = db.gis_marker
        query &= ltable.config_id.belongs(config.ids)
        join.append(ctable.on((ctable.id == ltable.config_id)))
        fields.extend((stable.style, stable.cluster_distance, stable.cluster_threshold, stable.opacity, stable.popup_format, mtable.image, mtable.height, mtable.width, ctable.pe_type))
        left = [stable.on((((stable.layer_id == etable.layer_id) & (stable.record_id == None)) & ((stable.config_id == ctable.id) | (stable.config_id == None)))), mtable.on((mtable.id == stable.marker_id))]
        limitby = None
        if (settings.get_database_type() == 'postgres'):
            orderby = [ctable.pe_type, stable.config_id]
        else:
            orderby = [ctable.pe_type, (~ stable.config_id)]
        if settings.get_gis_layer_metadata():
            cptable = s3db.cms_post_layer
            left.append(cptable.on((cptable.layer_id == etable.layer_id)))
            fields.append(cptable.post_id)
    else:
        query &= ((ltable.base == True) & (ltable.config_id == config.id))
        left = None
        limitby = (0, 1)
        orderby = None
    layer_types = []
    lappend = layer_types.append
    layers = db(query).select(join=join, left=left, limitby=limitby, orderby=orderby, *fields)
    if (not layers):
        query = (((((etable.id == ltable.layer_id) & (ltable.config_id == ctable.id)) & (ctable.uuid == 'SITE_DEFAULT')) & (ltable.base == True)) & (ltable.enabled == True))
        layers = db(query).select(limitby=(0, 1), *fields)
        if (not layers):
            layer_types = [LayerEmpty]
    for layer in layers:
        layer_type = layer['gis_layer_entity.instance_type']
        if (layer_type == 'gis_layer_openstreetmap'):
            lappend(LayerOSM)
        elif (layer_type == 'gis_layer_google'):
            lappend(LayerGoogle)
        elif (layer_type == 'gis_layer_arcrest'):
            lappend(LayerArcREST)
        elif (layer_type == 'gis_layer_bing'):
            lappend(LayerBing)
        elif (layer_type == 'gis_layer_tms'):
            lappend(LayerTMS)
        elif (layer_type == 'gis_layer_wms'):
            lappend(LayerWMS)
        elif (layer_type == 'gis_layer_xyz'):
            lappend(LayerXYZ)
        elif (layer_type == 'gis_layer_empty'):
            lappend(LayerEmpty)
        elif (layer_type == 'gis_layer_js'):
            lappend(LayerJS)
        elif (layer_type == 'gis_layer_theme'):
            lappend(LayerTheme)
        elif (layer_type == 'gis_layer_geojson'):
            lappend(LayerGeoJSON)
        elif (layer_type == 'gis_layer_gpx'):
            lappend(LayerGPX)
        elif (layer_type == 'gis_layer_coordinate'):
            lappend(LayerCoordinate)
        elif (layer_type == 'gis_layer_georss'):
            lappend(LayerGeoRSS)
        elif (layer_type == 'gis_layer_kml'):
            lappend(LayerKML)
        elif (layer_type == 'gis_layer_openweathermap'):
            lappend(LayerOpenWeatherMap)
        elif (layer_type == 'gis_layer_shapefile'):
            lappend(LayerShapefile)
        elif (layer_type == 'gis_layer_wfs'):
            lappend(LayerWFS)
        elif (layer_type == 'gis_layer_feature'):
            lappend(LayerFeature)
    layer_types = set(layer_types)
    scripts = []
    scripts_append = scripts.append
    for LayerType in layer_types:
        try:
            layer = LayerType(layers)
            layer.as_dict(options)
            for script in layer.scripts:
                scripts_append(script)
        except Exception as exception:
            error = ('%s    not    shown:    %s' % (LayerType.__name__, exception))
            current.log.error(error)
            if s3.debug:
                raise HTTP(500, error)
            else:
                response.warning += error
    if (s3.gis.get_feature_info and settings.get_gis_getfeature_control()):
        i18n['gis_get_feature_info'] = T('Get    Feature    Info')
        i18n['gis_feature_info'] = T('Feature    Info')
    if (not self.callback):
        self.callback = opts.get('callback', 'DEFAULT')
    self.options = options
    self.globals = js_globals
    self.i18n = i18n
    self.scripts = scripts
    self.plugin_callbacks = []
    plugins = opts.get('plugins', None)
    if plugins:
        for plugin in plugins:
            plugin.extend_gis_map(self)
    self.setup = True
    return options
