OSMapWrapper = function(div, options) {
    this.div = div;
    this.options = options;
    var osMap = null;
    var UKOSVectorL = null;
    var UKOSMarkerF = null;
    var dragVector = null;
    var markerSet = false;
    var clusterControl = null;
    var markerF;
    var markerStyle = {
        fillColor: "#5AF23F",
        strokeColor: "#5AF23F",
        strokeWidth: 3,
        pointRadius: 15,
        graphicHeight: 67,
        graphicWidth: 72,
        graphicXOffset: -21,
        graphicYOffset: -63,
        externalGraphic: "/images/Pointer.png"
    };
    var markerList = null;

    var icon = null;
    this.Initalize = function() {
        if (options == null) {
            options = {};
        }
        osMap = new OpenSpace.Map('map', options);

        osMap.setCenter(new OpenSpace.MapPoint(options.centerLng, options.centerLat), options.zoomLevel);
        if (options.dragable != null && options.dragable) {
            this.makeDragable();
        }
        if (options.cluster != null && options.cluster) {
            this.clusterResults();
        }
        if (options.icon != null && options.icon != '') {
            markerStyle.externalGraphic = options.icon;
            icon = new OpenSpace.Icon(options.icon, new OpenLayers.Size(72, 67), 0, null, null);
        }
        if (options.useOverlays != null && options.useOverlays) {
            var toManySquirrelsLayer = createLayer('toMany', '<div class="mapMessageOverlay"><h3>Too Many Squirrels to Display</h3><p>There are too many squirrels to display in this area, please zoom in or move to a different area.</p></div>', false);
            osMap.addLayer(toManySquirrelsLayer);
            osMap.events.register("moveend", osMap, displayMarkers);
            osMap.events.register("move", osMap, setPositionOfOverlay);
            osMap.events.register("zoomend", osMap, setPositionOfOverlay);
        }
        markerList = options.markerList;
    }

    function setPositionOfOverlay() {
        var toManySquirrelsLayer = osMap.getLayersByName('toMany')[0];
        toManySquirrelsLayer.setPosition(new OpenSpace.Control.ControlPosition(2, new OpenLayers.Size(170, 100)));
    }

    function createLayer(name, html, visible) {
        var obj = new OpenSpace.Layer.ScreenOverlay(name);
        obj.setPosition(new OpenSpace.Control.ControlPosition(2, new OpenLayers.Size(170, 100)));
        obj.visibility = false;
        obj.setHTML(html);
        return obj;
    }

    this.clusterResults = function() {
        clusterControl = new OpenSpace.Control.ClusterManager();
        osMap.addControl(clusterControl);
        clusterControl.activate();
    }

    this.clusterOff = function() {
        clusterControl.deactivate();
    }

    this.clusterOn = function() {
        clusterControl.activate();
    }

    this.setMapCenter = function(lng, lat, zoomLevel) {
        osMap.setCenter(new OpenSpace.MapPoint(lng, lat), zoomLevel);
    }

    this.makeDragable = function() {
        UKOSVectorL = new OpenLayers.Layer.Vector("Vector Layer");
        osMap.addLayer(UKOSVectorL);
        //	Add a drag control to the vector layer
        dragVector = new OpenLayers.Control.DragFeature(UKOSVectorL,
            {
                onDrag: function(feature, pixel) {
                    var pos = osMap.getLonLatFromViewPortPx(pixel);
                    var gridRef = convertNorthingAndEastingsToGridRef(pos.lon, pos.lat, 6)
                    updatePositions(gridRef);
                }
            }
        );
        osMap.addControl(dragVector);
        dragVector.activate();
    }

    function dispayCoursePos(e) {
        var pos = osMap.getLonLatFromViewPortPx(e.xy);
        updatePositions(pos.lon, pos.lat);
    }

    function updatePositions(gridRef) {
        $('.gridRef').val(gridRef);
    }

    function showCursorPos(e) {
        var pos = osMap.getLonLatFromViewPortPx(e.xy);
        setMapCenter(pos.lon, pos.lat)
    }

    function isInbound(gridRef) {
        var extent = osMap.getExtent();
        return (gridRef[0] >= extent.left && gridRef[0] <= extent.right) && (gridRef[1] <= extent.top && gridRef[1] >= extent.bottom);
    }

    function getInboundMarkers() {
        var visableSightings = new Array();

        $.each(sightings, function() {
            if (this.GridRef) {
                var ref = this.GridRef.split(',');
                if (isInbound(ref)) {
                    if (visableSightings.length > 60) {
                        visableSightings = false;
                        return false;
                    }
                    visableSightings.push(this);
                }
            }
        });
        return visableSightings;
    }


    this.displayMarkers = function() {
        try {
            osMap.clearMarkers();
            var inboundMarkers = getInboundMarkers();
            if (!inboundMarkers) {
                var toManySquirrelsLayer = osMap.getLayersByName('toMany')[0];
                $(toManySquirrelsLayer.div).show();
                toManySquirrelsLayer.visibility = true;
                return;
            }
            if (inboundMarkers.length > 0 && inboundMarkers.length < 60) {
                var toManySquirrelsLayer = osMap.getLayersByName('toMany')[0];
                toManySquirrelsLayer.visibility = false;
                $(toManySquirrelsLayer.div).hide();
            }
            $.each(inboundMarkers, function() {
                var ref = this.GridRef.split(',');
                if (isInbound(ref)) {
                    if (this.Url != '') {
                        var html = '<span id="location">' + decode(this.Location) + "</span><br/>" +
                    '<span id="date">' + this.Date + '</span><br/><a id="sightingLink" href="' + this.Url + '">View Sighting</a>';
                        var pointerUrl = '/img/pointer' + this.Year + '.png';
                        addStaticMarker(ref[0], ref[1], html, pointerUrl);
                    }
                    else {
                        var pointerUrl = '/img/pointer' + this.Year + '.png';
                        addStaticMarker(ref[0], ref[1], '', pointerUrl);
                    }
                }
            });
            if (sightings.length == 1) {
                var ref = sightings[0].GridRef.split(',');
                this.setMapCenter(ref[0], ref[1], 8);
                var pos = convertNorthingAndEastingsToGridRef(ref[0], ref[1], 6)
                $('.gridRef').text(pos);
            }
        } catch (e) {
            var otherTab = $('#second');
            if (otherTab.length == 1) {
                otherTab.click();
            }
        }
    }

    this.addDragMarker = function(lng, lat, style) {
        var gridRef = this.ConvertNorthingAndEastingsToGridRef(lng, lat, 6);
        if (markerF != null) {
            markerF.move(new OpenLayers.LonLat(lng, lat))
            updatePositions(gridRef);
            return;
        }
        var p1 = new OpenLayers.Geometry.Point(lng, lat);
        var marker = new OpenLayers.Geometry.Collection(new Array(p1.clone()));
        markerF = new OpenLayers.Feature.Vector(marker, null, markerStyle);
        UKOSMarkerF = new Array(markerF);
        UKOSVectorL.addFeatures(UKOSMarkerF);
        updatePositions(gridRef);
    }

    function addStaticMarker(lon, lat, content, markerUrl) {
        var pos = new OpenSpace.MapPoint(lon, lat);
        var content = content;
        var popUpSize = new OpenLayers.Size(200, 150);
        //position of mapption, icon, connent of popup, size of popup
        var icone = icon.clone();
        if (markerUrl != null || markerUrl != '') {
            icone.url = markerUrl;
        }

        var marker = osMap.createMarker(pos, icone, content, popUpSize);
    }

    this.disableDraging = function() {
        dragVector.deactivate();
    }

    this.getMarkersPositions = function() {
        if (UKOSMarkerF.length == 0) {
            return new Array();
        }
        var point = UKOSMarkerF[0].geometry.components[0];
        return new Array(this.getLonLatFromScreenPoint(point.x, point.y));
    }

    this.addEvent = function(eventName, func) {
        osMap.events.register(eventName, osMap, func);
    }

    this.findPostcode = function(postcode) {
        var postcodeService = new OpenSpace.Postcode();
        postcodeService.getLonLat(postcode, postcodeSearchResult);
    }

    function postcodeSearchResult(postcodeCentre) {
        osMap.setCenter(postcodeCentre, 7, false, false);
        return postcodeCentre;
    }

    this.findTown = function(townName) {
        var gazetter = new OpenSpace.Gazetteer();
        gazetter.getLonLat(townName, postcodeSearchResult);
    }

    this.findAllTowns = function(townName, func) {
        var gazetter = new OpenSpace.Gazetteer();
        var possibles = gazetter.getLocations(townName, func);

    }

    this.getNEFromScreenPoint = function(x, y) {
        var pixel = new OpenLayers.Pixel(x, y);
        var pt = osMap.getLonLatFromViewPortPx(pixel);
        return pt;
    }

    this.getLonLatFromScreenPoint = function(x, y) {
        var pixel = new OpenLayers.Pixel(x, y);
        var pt = osMap.getLonLatFromViewPortPx(pixel);
        var latLng = new OSRef(pt.lon, pt.lat).toLatLng();
        return latLng;
    }

    this.ConvertGridRefToNorthingAndEastings = function(gridRef) {
        // get numeric values of letter references, mapping A->0, B->1, C->2, etc:
        var l1 = gridRef.toUpperCase().charCodeAt(0) - 'A'.charCodeAt(0);
        var l2 = gridRef.toUpperCase().charCodeAt(1) - 'A'.charCodeAt(0);
        // shuffle down letters after 'I' since 'I' is not used in grid:
        if (l1 > 7) l1--;
        if (l2 > 7) l2--;

        // convert grid letters into 100km-square indexes from false origin (grid square SV):
        var e = ((l1 - 2) % 5) * 5 + (l2 % 5);
        var n = (19 - Math.floor(l1 / 5) * 5) - Math.floor(l2 / 5);

        // skip grid letters to get numeric part of ref, stripping any spaces:
        gridRef = gridRef.slice(2).replace(/ /g, '');

        // append numeric part of references to grid index:
        e += gridRef.slice(0, gridRef.length / 2);
        n += gridRef.slice(gridRef.length / 2);

        // normalise to 1m grid, rounding up to centre of grid square:
        switch (gridRef.length) {
            case 6: e += '50'; n += '50'; break;
            case 8: e += '5'; n += '5'; break;
            // 10-digit refs are already 1m                                                                                     
        }
        return { northing: e, easting: n };
    }

    function convertNorthingAndEastingsToGridRef(e, n, digits) {
        var e100k = Math.floor(e / 100000), n100k = Math.floor(n / 100000);

        if (e100k < 0 || e100k > 6 || n100k < 0 || n100k > 12) return '';

        // translate those into numeric equivalents of the grid letters
        var l1 = (19 - n100k) - (19 - n100k) % 5 + Math.floor((e100k + 10) / 5);
        var l2 = (19 - n100k) * 5 % 25 + e100k % 5;

        // compensate for skipped 'I' and build grid letter-pairs
        if (l1 > 7) l1++;
        if (l2 > 7) l2++;
        var letPair = String.fromCharCode(l1 + 'A'.charCodeAt(0), l2 + 'A'.charCodeAt(0));

        // strip 100km-grid indices from easting & northing, and reduce precision
        e = Math.floor((e % 100000) / Math.pow(10, 5 - digits / 2));
        n = Math.floor((n % 100000) / Math.pow(10, 5 - digits / 2));

        var gridRef = letPair + e.padLZ(digits / 2) + n.padLZ(digits / 2);

        return gridRef;
    }
    this.ConvertNorthingAndEastingsToGridRef = function(e, n, digits) {
        var e100k = Math.floor(e / 100000), n100k = Math.floor(n / 100000);

        if (e100k < 0 || e100k > 6 || n100k < 0 || n100k > 12) return '';

        // translate those into numeric equivalents of the grid letters
        var l1 = (19 - n100k) - (19 - n100k) % 5 + Math.floor((e100k + 10) / 5);
        var l2 = (19 - n100k) * 5 % 25 + e100k % 5;

        // compensate for skipped 'I' and build grid letter-pairs
        if (l1 > 7) l1++;
        if (l2 > 7) l2++;
        var letPair = String.fromCharCode(l1 + 'A'.charCodeAt(0), l2 + 'A'.charCodeAt(0));

        // strip 100km-grid indices from easting & northing, and reduce precision
        e = Math.floor((e % 100000) / Math.pow(10, 5 - digits / 2));
        n = Math.floor((n % 100000) / Math.pow(10, 5 - digits / 2));

        var gridRef = letPair + e.padLZ(digits / 2) + n.padLZ(digits / 2);

        return gridRef;
    }
}

Number.prototype.padLZ = function(w) {
    var n = this.toString();
    for (var i = 0; i < w - n.length; i++) n = '0' + n;
    return n;
}


function decode(str) {
       var result = "";
       for (var i = 0; i < str.length; i++) {
              if (str.charAt(i) == "+") result += " ";
              else result += str.charAt(i);
       }
              return unescape(result);
}

