function patchLayer(layer) {

  var oldMoveTo = layer.moveTo;
  layer.moveTo = function(bounds, zoomChanged, dragging) {

      var layer = this.layers[this.map.zoom];
      // for TileCache or TMS
      this.layername = layer;
      // for WMS
      this.params.LAYERS = layer;

      return oldMoveTo.apply(this, arguments);
  };
}

function repeat(value, n) {
    var array = [];
    while (n--) {
        array.push(value);
    }
    return array;
}

OpenLayers.DOTS_PER_INCH = 96;
OpenLayers.IMAGE_RELOAD_ATTEMPTS = 5;
OpenLayers.ImgPath = "../carto/ol/img/";

var gMap;

function init() {

    var BLANK_URL = "images/blank.gif";

    var scaleControl;
    if (gDebug) {
        scaleControl = new ResolutionControl();
    } else {
        scaleControl = new OpenLayers.Control.Scale();

        var oldUpdateScale = OpenLayers.Control.Scale.prototype.updateScale;
        OpenLayers.Control.Scale.prototype.updateScale = function() {
            oldUpdateScale.apply(this, arguments);
            this.element.innerHTML = this.element.innerHTML.replace("Scale", gTranslations["scale"]);
        }
    }
    var layerSwitcher = new OpenLayers.Control.LayerSwitcher({activeColor: "black"});

    if (gDebug)
        document.title += " [DEBUG MODE]";

    var map = new OpenLayers.Map("map",  {
        maxExtent: new OpenLayers.Bounds(531000,146000,544000,162000),
        restrictedExtent: new OpenLayers.Bounds(531000,146000,544000,162000),
        units: "m",
        projection: "EPSG:21781",
        resolutions: [26.458333509513746, 19.843750132135305, 13.229166490486257, 10.583327618336419,
                      6.614583245243129, 5.291666578529876, 2.645833289264938,
                      1.3229167327517914, 0.6614582947785876, 0.3307291473892938],
        controls: [
                new OpenLayers.Control.Navigation(),
                new OpenLayers.Control.PanZoomBar(),
                layerSwitcher,
                new OpenLayers.Control.MousePosition({numdigits:0}),
                scaleControl,
                new OpenLayers.Control.ArgParser(),
                new OpenLayers.Control.Attribution()
                ]
    });

    var layerConfigs = [
        {name: gTranslations["orthos"], opts: {isBaseLayer: true}, format: "image/jpeg",
         layers: ["mosaique_2m2m", "mosaique_2m2m", "mosaique_2m2m", "mosaique_2m2m",
                  "mosaique_2m2m", "mosaique_2m2m", "orthophotos_lausanne", 
                  "orthophotos_lausanne", "orthophotos_lausanne", "orthophotos_lausanne"]},

        {name: gTranslations["cs"], opts: {isBaseLayer: true}, format: "image/png",
         layers: ["cs_100k_96", "cs_100k_192", "cs_50k_96", "cs_50k_192", "cs_50k_192", 
                  "cs_20k_96", "cs_20k_192", "cs_5k_96", "cs_5k_192", "cs_5k_192"]}
    ];

    var histMaps = [["plan_histo_Mh115", gTranslations["plan_histo_Mh115"]],
                    ["plan_histo_110-1", gTranslations["plan_histo_110-1"]],
                    ["plan_histo_096-1", gTranslations["plan_histo_096-1"]],
                    ["plan_histo_095-1", gTranslations["plan_histo_095-1"]],
                    ["plan_histo_094-1", gTranslations["plan_histo_094-1"]],
                    ["plan_histo_092-3", gTranslations["plan_histo_092-3"]],
                    ["plan_histo_092-1", gTranslations["plan_histo_092-1"]],
                    ["plan_histo_091-1", gTranslations["plan_histo_091-1"]],
                    ["plan_histo_090-1", gTranslations["plan_histo_090-1"]]];

    for (var i = 0; i < histMaps.length; i++) {
        var histMap = histMaps[i];
        layerConfigs.push(
          {name: histMap[1], opts: {isBaseLayer: false,
                                    maxExtent: new OpenLayers.Bounds(533500, 149300, 542200, 157200),
                                    visibility: false, 
                                    alpha: true}, 
           format: "image/png", layers: repeat(histMap[0], 10)}
        );
    }

    layerConfigs.push(
        {name: "boucles", opts: {displayInLayerSwitcher: false,
                                 maxExtent: new OpenLayers.Bounds(537300, 150500, 540700, 155160),
                                 isBaseLayer: false, 
                                 alpha: true},
         format: "image/png", layers: repeat("boucles", 10)}
    );

    // useful for debugging
    gMap = map;

    if (gDebug) {
        if (location.search.indexOf("seeding") > 0) {
            document.title = "Seeding commands";
            var tcUrl = location.search.split("=")[1];
            generateSeedingCommands(map, layerConfigs, tcUrl);
            return;
        }
        if (location.search.indexOf("tilecache") > 0) {
            document.title = "Tilecache configuration";
            var url = location.search.split("=")[1];
            generateTilecacheConfig(map, layerConfigs, url);
            return;
        }
    }

    var layerType = "TMS";
    //var layerType = "TileCache";

//    var TILECACHE_URL = CACHE_URL = "/tc-lj2009/";
    var TILECACHE_URL = CACHE_URL = ['http://t0.lausannejardins.cache-camptocamp.com/tc-lj2009/', 
                                     'http://t1.lausannejardins.cache-camptocamp.com/tc-lj2009/', 
                                     'http://t2.lausannejardins.cache-camptocamp.com/tc-lj2009/'];

    for (var i = 0; i < layerConfigs.length; i++) {
        var lc = layerConfigs[i];
        if (!lc) {
            continue;
        }
        
        var opts = lc.opts || {};
        opts.layers = lc.layers;

        if (layerType == "TileCache") {
            var layer = new OpenLayers.Layer.TileCache(lc.name,
                CACHE_URL,
                lc.layers[0],
                OpenLayers.Util.extend(opts, {
                    format: lc.format
                }));
        } else if (layerType == "WMS") {
            var layer = new OpenLayers.Layer.WMS(lc.name,
                TILECACHE_URL,
                { layers: [lc.layers[0]] },
                OpenLayers.Util.extend(opts, {
                    format: lc.format
                }));
        } else if (layerType == "TMS") {
            var layer = new OpenLayers.Layer.TMS(lc.name,
                TILECACHE_URL,
                OpenLayers.Util.extend(opts, {
                    buffer: 0,
                    layername: lc.layers[0],
                    type: lc.format.split('/')[1].toLowerCase()
                }));
        } else {
            alert("error: invalid layerType " + layerType);
            return;
        }
        patchLayer(layer);
        map.addLayer(layer);
    }
    
    // add the mask layer
    map.addLayer(new OpenLayers.Layer.Image(gTranslations["mask"], 
                                            '../carto/images/white.png',
                                            map.maxExtent,
                                            new OpenLayers.Size(1, 1)));

    // markers:
    var markers = new OpenLayers.Layer.Markers(gTranslations["photos"]);

    function buildURL(cells) {
        // XXX construct this from the Joomla/gallery URL
        return "/carto/photos_csv/cache/boucle_" + cells[0] + "/" + cells[1] + "-" + cells[2] + ".JPG";
    }

    function addClass(n, c, b) {
        var o = removeClass(n, c);
        n.className = b ? c + (o != '' ? (' ' + o) : '') : (o != '' ? (o + ' ') : '') + c;
    }

    function removeClass(n, c) {
        c = n.className.replace(new RegExp("(^|\\s+)" + c + "(\\s+|$)"), ' ');
        return n.className = c != ' ' ? c : '';
    }

    function showImage(url) {
        removeClass($("loading"), "hidden");

        $("imageDiv").className = "showImage";
        $("image").src = url;

        displayHelp();

        // XXX safari does not fire onload if image in cache!
    }

    function hideImage() {
        displayHelp(true);
        $("image").src = BLANK_URL;
        $("imageDiv").className = "showHelp";
    }

    function displayHelp(state) {
      var help = $("help");
      if (state) {
        help.style.display = 'block';
      } else {
        help.style.display = 'none';
      }
    }

    OpenLayers.loadURL("../carto/photos_csv/photos.csv", null, this, function(ajaxRequest) {

        var calculateOffset =  function(size) {
            return new OpenLayers.Pixel(-(size.w / 2), -(size.h / 2));
        };
        var iconSmall = new OpenLayers.Icon('../carto/images/camera-photo-16x13.png', new OpenLayers.Size(16, 13), null, calculateOffset);
        var iconLarge = new OpenLayers.Icon('../carto/images/camera-photo-32x26.png', new OpenLayers.Size(32, 26), null, calculateOffset);
    
        // preload images
        var cacheSmall = new Image(iconSmall.size.w, iconSmall.size.h);
        cacheSmall.src = iconSmall.url;
        var cacheLarge = new Image(iconLarge.size.w, iconLarge.size.h);
        cacheLarge.src = iconLarge.url;

        var response = ajaxRequest.responseText;
        var lines = response.split("\n");
        for (var i = 0; i < lines.length; i++) {
            var line = lines[i];
            var cells = line.split(",");
            if (cells.length != 5)
                continue;

            var pos = new OpenLayers.LonLat(parseFloat(cells[3]), parseFloat(cells[4]));
            var marker = new OpenLayers.Marker(pos, iconSmall.clone());
            marker.imageURL = buildURL(cells);

            marker.events.register('mouseover', marker, function(event) {
                if (markers.selectedMarker) {
                    markers.selectedMarker.icon.url = iconSmall.url;
                    markers.selectedMarker.icon.setSize(iconSmall.size);
                    hideImage();
                }

                this.icon.url = iconLarge.url;
                this.icon.setSize(iconLarge.size);
                showImage(this.imageURL);

                markers.selectedMarker = this;
            });
            marker.events.register('mouseout', marker, function(event) {
                markers.selectedMarker.icon.url = iconSmall.url;
                markers.selectedMarker.icon.setSize(iconSmall.size);
                hideImage();

                delete markers.selectedMarker;
            });
            markers.addMarker(marker);
        }
    });

    OpenLayers.Event.observe($("image"), "load", function() {
        addClass($("loading"), "hidden");
    });

    OpenLayers.Event.observe($("image"), "error", function(evt) {
      var helpState = $('imageDiv').className;
      if (helpState != 'showHelp') {
        $("imageDiv").className = "showNoImage";
        addClass($("loading"), "hidden");
      }
    });

    map.addLayer(markers);

    //map.zoomToExtent(new OpenLayers.Bounds(536797, 151172, 541189, 154569));
    map.zoomToExtent(new OpenLayers.Bounds(538179, 150754, 540740, 155654));

    // layer switcher translation
    layerSwitcher.baseLbl.innerHTML = "<u>" + gTranslations["layers"] + "</u>";
    layerSwitcher.dataLbl.innerHTML = "";

    document.body.className += " presentation";
    var hist_txt = document.getElementById('OpenLayers_Control_MaximizeDiv');
    var hist_img = document.getElementById('OpenLayers_Control_MaximizeDiv_innerImage');
    hist_img.style.cursor = "pointer";
    hist_txt.style.cursor = "pointer";

    var hist_img_min = document.getElementById('OpenLayers_Control_MinimizeDiv_innerImage');
    hist_img_min.style.cursor = "pointer";

    hist_txt.style.width = 'auto';
    hist_img.style.width = 'auto';

    layerSwitcher.layersDiv.style.paddingRight = "0px";
    $('OpenLayers_Control_PanZoomBar_SliderOpenLayers.Map_9_innerImage').style.cursor = 'pointer';
}

window.onload = init;

