OpenLayers.ProxyHost = ServerVars.serverPath+"/prox.html?url=";

Map.Markers = { // for compatibility with Markers/GMaps
    getLayer: function() {
        var markerStyle = {externalGraphic: Utils.imageLocation+"bluearrow.png", graphicWidth: 16, graphicHeight: 16, graphicYOffset: -16};
        var addMark = function(lonlat, imgTitle) {
            var point = new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat);
            var feature = new OpenLayers.Feature.Vector(point, {title: imgTitle, clickable: 'off'});
            this.addFeatures([feature]);
        };
        return new OpenLayers.Layer.Vector('Search markers', {style: markerStyle, addMark: addMark});
    },

    addMarker: function(lng, lat) {
        Map.addMarker(lng, lat);
    },

    add: function(lat, lng, name) {
        Map.addMarker(lng, lat, name);
    },

    clearMarkers: function() { // 'this' is button control
        this.map.getLayersByName('Search markers')[0].destroyFeatures();
    }
};

Map.doVectors = function(mapProjs, inputDone) {
// add callback functions needed by vector layers in general to map object
// along with variables used by them
    var defaultInputDone = function() { // check after loading each vector input whether that was the last one
        // 'this' is map
        if (this.feedCount == this.feedsRead) {
            StatusLog.logMsg('mapsetup');
            if (this.zoomToFeatures === true) {//if zoom etc, pass thru
                if (ServerVars.bbox) {// if bbox param, zoom to it
                    var bounds = OpenLayers.Bounds.fromString(ServerVars.bbox);
                    if (this.projection != "EPSG:4326") {
                        bounds.transform(this.displayProjection, this.baseLayer.projection);
                    }
                    this.zoomToExtent(bounds);
                } else {// else zoom to features extent (unless no features)
                    if (this.featureExtent.bottom !== null) {
                        this.zoomToExtent(this.featureExtent);
                    }
                    else {
                        this.setCenter(this.defaultLonglat, this.defaultZoom);
                    }
                }
            }
            StatusLog.endMsg();
        }
    };
    this.addTooltipDiv = function() {
       jQuery('body').append('<div class="popup" id="tooltip" style="visibility: hidden"></div>');
    };
    OpenLayers.Util.extend(this.map, {
        feedsRead: 0, // added to by vector layer loadEnd
        feedCount: 0, // set by addSpecifics()
        featureExtent: new OpenLayers.Bounds(), // cumulative data extent to zoom to
        inputDone: inputDone || defaultInputDone,
        featureOver: function(feature) {
            var fname = feature.attributes.name || feature.attributes.title || feature.attributes.id || feature.fid;
            if (feature.geometry.CLASS_NAME == "OpenLayers.Geometry.LineString" && feature.layer.calcKm) {
                fname += ' '+ this.map.getLength(feature);
            }
            var xy = this.map.getControl('ll_mouse').lastXy || new OpenLayers.Pixel(0,0);
            Utils.showTooltip(fname, xy.x, xy.y);
        },
        getLength: function(feature) {
            return Math.round(feature.geometry.getGeodesicLength(feature.layer.map.baseLayer.projection) * 0.1) / 100 + 'km';
        }
    });

// logic specific to page
// tilecache layer
    if (this.specifics.addTc) {
        this.addTc(this.specifics.addTc);
    }

// create vector layer(s) - function first (as declared function brought error)
    var mapThis = this;
    var createVectorLayer = function(layerName, inOptions) {
// takes options array containing strategyTypes, format, protocolOptions (other than format) and other layer options
// creates strategies from strategyTypes
// creates format obj from format and adds to protocolOptions
// creates protocol based on options
        var options;
        if (inOptions.passThrough) {
            options = inOptions.passThrough;
        }
        else {
            options = {};
        }
        var otherOptions = { };
// create strategies
        if (inOptions.strategyTypes) {
            options.strategies = [];
            for (var i = 0; i < inOptions.strategyTypes.length; i++) {
                options.strategies.push(new OpenLayers.Strategy[inOptions.strategyTypes[i]]);
            }
        }
// create protocol
        if (inOptions.type == 'FS') { // featureserver
            options.serverLocation = window.location.hostname == "localhost" ? "/test/fs/featureserver.cgi/" : "/cgi-bin/fs/";
            inOptions.format = 'geo';
            inOptions.protocolOptions = {url: options.serverLocation+inOptions.fsFile};
        }
        if (inOptions.type == 'GMD') { // Google Maps Data js client lib
            inOptions.format = 'kml';
            inOptions.protocolOptions = {url: ServerVars.featureFeed};
            inOptions.protocolType = 'GoogleMapsData';
            if (!ServerVars.gstyle || ServerVars.gstyle != 'n') {
                inOptions.extractStyles = true;
            }
        }
        options.protocolOptions = inOptions.protocolOptions || {};
        options.protocolOptions.format = inOptions.protocolOptions.format || createFormat(inOptions.format, inOptions.extractStyles, inOptions.mapProjs);
        var protocolType = inOptions.protocolType || 'HTTP';
        options.protocol = new OpenLayers.Protocol[protocolType](options.protocolOptions);
// create stylemap
        if (inOptions.defaultStyle) {
            options.styleMap = mapThis.Styles.createStyleMap(inOptions.defaultStyle, inOptions.rulesArray, inOptions.poiStyleWanted);
        }
        if (inOptions.includeInInitialZoom) {
            otherOptions.includeInInitialZoom = inOptions.includeInInitialZoom;
        }
        if (inOptions.featureAdded) {
            otherOptions.featureAdded = inOptions.featureAdded;
        }
        var layer = new Map.OberVector(layerName, options, otherOptions);
        if (layer.strategies) {
            for (i = 0; i < layer.strategies.length; i++) {
                if (layer.strategies[i].CLASS_NAME == "OpenLayers.Strategy.Save") {
                    layer.saveSuccess = function(event) {
                        alert('Changes saved');
                    };
                    layer.saveFail = function(event) {
                        alert('Error! Changes not saved');
                    };
                    layer.strategies[i].events.on({'success': layer.saveSuccess, 'fail': layer.saveFail, scope: layer});
                }
            }
        }
        return layer;
    };

// set up vector layers
    this.specifics.setupVectorOptions();
    var layerOptions = this.specifics.layerOptions;
    var layers = Array();
    for (var layerName in layerOptions) {
        layerOptions[layerName].mapProjs = mapProjs;
        var layer = createVectorLayer(layerName, layerOptions[layerName]);
        if (this.specifics.afterAdd) {
            this.specifics.afterAdd(layer);
        }
        layers.push(layer);
        if (layerOptions[layerName].lineLayer) {
            this.map.lineLayerId = layer.id;
        }
        if (layerOptions[layerName].addSelect) {
            layer.featureSelect = this.Controls.selects[layerOptions[layerName].addSelect];
        }
    }
// if POI layers, add
    if (this.specifics.poi === true) {
        layerOptions = this.getPoiLayerOptions();
        for (layerName in layerOptions) {
            layerOptions[layerName].mapProjs = mapProjs;
            layers.push(createVectorLayer(layerName, layerOptions[layerName]));
        }
        this.specifics.switcher = true;
    }
// and places layer
    if (this.specifics.placesLayer) {
        layerOptions = this.getPlacesLayerOptions(this.specifics.placesLayer);
        layerOptions.mapProjs = mapProjs;
        layers.push(createVectorLayer('Places', layerOptions));
    }
    this.map.addLayers(layers);
// other page-specific settings
    OpenLayers.Util.extend(this.map, this.specifics.mapOptions);
    if (this.specifics.switcher === true) {
        this.Controls.switcher = true;
    }
    if (this.specifics.features == 'n') {
        this.features = false;
    }
    else {
        this.features = true;
    }

    function createFormat(format, extractStyles, mapProjs) {
// creates format obj from format, setting internal/external projection and extractStyles if needed
        var formats = {
            gml: OpenLayers.Format.GML,
            kml: OpenLayers.Format.KML,
            wkt: OpenLayers.Format.WKT,
            geo: OpenLayers.Format.GeoJSON,
            atom: OpenLayers.Format.Atom
        };
        var options = {};
        if (mapProjs) {
            options.internalProjection = mapProjs.int;
            options.externalProjection = mapProjs.ext;
        }
        if (extractStyles) {
            if (format == 'kml' || format == 'atom') {
                options.extractStyles = true;
            }
        }
        if (format == 'atom') {
            options.kmlContent = true;
            options.georssContent = false;
        }
        if (format == 'geo') {
            options.ignoreExtraDims = true;
        }
        return new formats[format](options);
    }
};

Map.getVectorControls = function(vectorControls) {
    var controls = Array();
    for (var i = 0; i < vectorControls.length; i++) {
        if (vectorControls[i] == 'selectFeature') {
            var options = this.specifics.selectFeature;
            if (typeof options.selectFunction == "string") {
                options.selectFunction = this.Controls.selects[options.selectFunction];
            }
            this.addTooltipDiv();
            if (options.dialog == 'feature') {
                Dialogs.setups.wiki();
            }
            if (Dialogs.setups[options.dialog]) {
                Dialogs.setups[options.dialog]();
            }
            var controlOptions = {
                callbacks: { over: this.map.featureOver, out: Utils.hideTooltip },
                onSelect: options.selectFunction
            };
            if (options.geometryTypes) {
                controlOptions.geometryTypes = options.geometryTypes;
            }
            // selectFeature applies to all vector layers
            var layers = this.map.getLayersByClass('OpenLayers.Layer.Vector');
            var selectControl = new OpenLayers.Control.SelectFeature(layers, controlOptions);
            this.map.addControl(selectControl);
            selectControl.activate();
        }
        if (vectorControls[i] == 'baselayerChange') {
            controls.push(this.Controls.getBaselayerChange(this.map));
            this.map.getOtherMap = this.Controls.getOtherMap;
        }
        if (vectorControls[i] == 'palette') {
            controls.push(this.Controls.getPalette(this.map));
            this.map.changeColour = this.Controls.changeColour;
        }
        if (vectorControls[i] == 'print') {
            this.map.print = function() {
                var perma = this.map.getControl('thisPerma');
                var params = perma.createParams();
                var base = perma.base.split('?')[0];
                base += ServerVars.bbox ? '?bbox='+ServerVars.bbox+'&' : '?';
                var url = base+'zoom='+params.zoom+'&lat='+params.lat+'&lon='+params.lon+'&layers='+params.layers+'&print=y';
                var w = window.open(url, "MapPrint");
                w.focus();
            };
            var func = this.Controls.getPrintButton();
            func.trigger = this.map.print; 
            controls.push(func);
        }
        if (vectorControls[i] == 'editToolbar') {
            this.addTooltipDiv();
            var layerName = 'Vectors';
            var noAdd;
            if (this.specifics.editToolbar) {
                options = this.specifics.editToolbar;
                if (options.layerName) {
                    layerName = options.layerName;
                }
                if (options.noAdd) {
                    noAdd = options.noAdd;
                }
            }
            var layer = this.map.getLayersByName(layerName)[0];
            layer.newAttribute = this.Controls.newAttribute;
            layer.enterAttributes = this.Controls.enterAttributes;
            layer.editAttributes = this.Controls.editAttributes;
            layer.freshAttributes = this.Controls.freshAttributes;
            this.map.addControl(this.Controls.getEditToolbar(layer, this.Styles.styles.edit, noAdd));
        }
    }
    return controls;
};

Map.OberVector = OpenLayers.Class(OpenLayers.Layer.Vector, { // super vector class
// status msgs are printed on layer loadstart/loadend
// on loadend, inputDone() is called to do end procedure if last layer
    calcKm: false,

    initialize: function(name, options, otherOptions) {
        OpenLayers.Layer.Vector.prototype.initialize.apply(this, [name, options]);
        otherOptions = otherOptions || {};
        if (otherOptions.includeInInitialZoom) {
            this.events.register('loadstart', this, function() {StatusLog.logMsg('fetch', name);});
            this.events.register('loadend', this, this.loaded);
        }
        if (otherOptions.featureAdded) {
            this.events.register('featureadded', this, otherOptions.featureAdded);
        }
    },

    loaded: function(event) {
        StatusLog.logMsg('loaded', event.object.name);
        this.map.featureExtent.extend(this.getDataExtent());
        this.map.feedsRead++;
        this.map.inputDone();
    },

    getTemplate: function(feature) {
        var atts = feature.attributes;
        // id in entry if GMD else use fid
        var featureId = this.protocol.entries ? this.protocol.entries[feature.fid].link[0].href.substr(this.protocol.entries[feature.fid].link[0].href.lastIndexOf('/')+1) : feature.fid;
        var template = '<i>featureId</i>: '+featureId;
        for (var att in atts) {
            if (atts[att] != '') {
                if (atts[att].substring(0, 7) == 'http://') {
                    template += '<br /><i>'+att+'</i>: <a target="linktab" href="'+atts[att]+'">'+atts[att]+'</a>';
                }
                else {
                    template += '<br /><i>'+att+'</i>: '+atts[att];
                }
            }
        }
        if (feature.geometry.CLASS_NAME == "OpenLayers.Geometry.LineString") {
            template += '<br />' + this.map.getLength(feature) + ' (calculated from map)';
            if (ServerVars.routeProfile) {
                feature.coords = Array();
                var clone = feature.geometry.clone();
                if (this.map.projection != "EPSG:4326") {
                    clone.transform(feature.layer.projection, this.map.displayProjection);
                }
                var vertices = clone.getVertices();
                for (var i = 0; i < vertices.length; i++) {
                    feature.coords[i] = [vertices[i].y, vertices[i].x];
                }
                template += '<br /><a id="profile" href="#">Show height profile</a>';
                template += '<div id="profile"></div>';
            }
        }
        return template;
    }
});

Map.Styles = {
    styles: {
        select: {strokeColor: "red", fillColor: "red"}
    },
    filters: { // style filters
        type_ne_null: {
            type: OpenLayers.Filter.Comparison.NOT_EQUAL_TO, property: "type", value: null
        }
    },
    rules: { // style rules
        elseFilter: {
            elseFilter: true
        }
    },

    createStyleMap: function(defaultStyle, rulesArray, poiStyleWanted) {
        if (typeof defaultStyle ==  "string") {
            defaultStyle = this.styles[defaultStyle];
        }
        if (poiStyleWanted) { // won't work if have 2 layers with same style but only 1 with poi;
            OpenLayers.Util.extend(defaultStyle, this.styles.poi);
        }
        var sty = OpenLayers.Util.applyDefaults(defaultStyle, OpenLayers.Feature.Vector.style["default"]);
        var sm = new OpenLayers.StyleMap({'default': sty, 'select': this.styles.select});
        if (rulesArray) {
            var rules = Array();
            var mvr = this.rules;
            for (i=0; i < rulesArray.length; i++) {
                var ruleParams = {};
                if (mvr[rulesArray[i]].filter) {
                    ruleParams.filter = new OpenLayers.Filter.Comparison(this.filters[mvr[rulesArray[i]].filter]);
                }
                if (mvr[rulesArray[i]].elseFilter) {
                    ruleParams.elseFilter = true;
                }
                if (mvr[rulesArray[i]].minScaleDenominator) {
                    ruleParams.minScaleDenominator = mvr[rulesArray[i]].minScaleDenominator;
                }
                if (mvr[rulesArray[i]].symbolizer) {
                    ruleParams.symbolizer = this.styles[mvr[rulesArray[i]].symbolizer];
                }
                var rule =  new OpenLayers.Rule(ruleParams);
                rules.push(rule);
            }
            sm.styles['default'].addRules(rules);
        }
        return sm;
    }
};

Dialogs.setups.feature = function() {
    Dialogs.divs.feature = '<div id="feature" title="Feature details" style="font-size: 10px"></div>';
    Dialogs.params.feature = { position: 'top', autoOpen: false };
    Dialogs.setup('feature');
};

Dialogs.setups.wiki = function() {
    Dialogs.divs.wiki = '<div id="wiki" title="Wiki Entry"></div>';
    Dialogs.params.wiki = { position: 'top', width: 600, maxHeight: 300, autoOpen: false };
    Dialogs.functions.wiki = function() {
        appendCSS('#p-logo, .generated-sidebar, #p-lang, #p-tb, #p-search, #p-cactions, #p-personal, #footer {display:none;} #mw_content {margin: 0 0 .6em 0;}');
    };
    Dialogs.setup('wiki');
};

Map.Controls.selects = { // select feature functions
    feature: function(feature) {
        if (feature.attributes.clickable == 'off') {
            return;
        }
        if (feature.attributes.wiki) {
            Dialogs.urls.wiki = ServerVars.wiki+feature.attributes.wiki+'?printable=yes';
            Dialogs.open('wiki', true);
        } else {
            var html = feature.layer.getTemplate(feature);
            jQuery('#feature').html(html);
            jQuery('#feature').dialog('open');
            jQuery('#profile').click(jQuery.proxy(function(){topoDrawGraph( $('profile'), this.coords, 600, 250);return false;}, feature));
        }
    }
};
