RegisterScript('t4uGalMap', 1, 'toscana4u main script');
Require([ 'AnimeJ', { Name: 'AnimeJ', Version: 1 } ]);


var resourcesBase = '/resources/';
var iconurlbase = '/images/editor/';
var iconurlext = '.png';
var animation = null;
var map = null;
var editorEnabled = false;

function T4ULocale() {
  var k = new Cookies();
  if (k['_t4u_lang']) return k['_t4u_lang'];
  var lang = navigator.language? navigator.language : navigator.userLanguage;
  if (!lang) return "en";
  lang = lang.substring(0, 2);
  return lang.toLowerCase();
}

var t4u_lang = T4ULocale();

function T4USetLocale(locale) {
  if (t4u_lang == locale) return;
  var k = new Cookies();
  var year = (new Date()).getYear();
  if (year < 2000) year += 1900;
  var expireDate = new Date(year + 10, 11, 31);
  k.Set('_t4u_lang', locale, expireDate);
  history.go(0);
}

// Utilities
function ConfigureStyle(d, props) {
  var v;
  for (v in props)
    d.style[v] = props[v];
}

function AbsBox(l, t, w, h) {
  var d = document.createElement('div');
  d.style.position = 'absolute';
  d.style.left = l;
  d.style.top = t;
  d.style.width = w;
  d.style.height = h;
  return d;
}

// Tick must be true if the string is delimited by '
function QuoteText(tick, txt) {
  txt = txt.replace('\\', '\\\\');
  return txt.replace(tick ? "'" : '"', tick ? "\\'" : '\\"');
}

// Scroller
var StripScrollerScrollers = { 'id': 0 };
var StripScrollerLeftImg = resourcesBase + "scroll_left.png";
var StripScrollerRightImg = resourcesBase + "scroll_right.png";
var StripScrollerUpImg = resourcesBase + "scroll_up.png";
var StripScrollerDownImg = resourcesBase + "scroll_down.png";

function StripScrollerMove(name, up) {
  var s = StripScrollerScrollers[name];
  if (s) {
    if (up)
      s.ScrollUp();
    else
      s.ScrollDown();
    
    setTimeout("StripScrollerMove('" + name + "' , "+ up+ ')', 100);
  }
}

// Transforms a double nested div into a scrollable div
// Structure must be:
// <div></div>
function StripScroller(div, vertical) {
  var id = 0;
  var arrow_fst = vertical ? StripScrollerUpImg : StripScrollerLeftImg;
  var arrow_snd = vertical ? StripScrollerDownImg : StripScrollerRightImg;
  div.innerHTML = '<span style="position: absolute; '+(vertical ? 'top' : 'left')+': 0px;'+(vertical ? '' : 'top: 14px')+'" onmousedown="this.parentNode.StartScroll(true)" onmouseup="this.parentNode.StopScroll()"><img src="'+arrow_fst+'" /></span><span>' + div.innerHTML + '</span><span style="position: absolute; '+(vertical ? 'left' : 'top')+':0px; '+(vertical ? 'bottom' : 'right')+': 0px;'+(vertical ? '' : 'top: 14px')+'" onmousedown="this.parentNode.StartScroll(false)" onmouseup="this.parentNode.StopScroll()"><img src="'+arrow_snd+'" /></span>';
  div.style.overflow = 'hidden';
  var content = div.childNodes[1];
  content.style.position = 'absolute';
  content.style[vertical ? 'top' : 'left'] = '10px';
  content.style[vertical ? 'height' : 'width'] = Math.max(0, (div[vertical ? 'clientHeight' : 'clientWidth'] - (2*10))) + 'px';
  content.style.overflow = 'hidden';

  div.onresize = function () {
    content.style[vertical ? 'height' : 'width'] = Math.max(0, (div[vertical ? 'clientHeight' : 'clientWidth'] - (2*10))) + 'px';
  }

  div.ScrollContent = function () {
    return content;
  }

  div.ScrollUp = function () {
    content[vertical ? 'scrollTop' : 'scrollLeft'] -= 5;
  }

  div.ScrollDown = function () {
    content[vertical ? 'scrollTop' : 'scrollLeft'] += 5;
  }
  
  div.StartScroll = function(up) {
    id = StripScrollerScrollers.count++;
    StripScrollerScrollers[id] = div;
    StripScrollerMove(id, up);
  }
  
  div.StopScroll = function() {
    StripScrollerScrollers[id] = null;
  }
  
}

// Interpolators

function LinearInterpolator(from, to) {
  this.From = from;
  this.To = to;
  this.Get = function (v) {
    return this.From + (this.To - this.From)*v;
  }
}

function DiscreteLinearInterpolator(from, to) {
  this.From = from;
  this.To = to;
  this.Get = function (v) {
    return Math.floor(this.From + (this.To - this.From)*v);
  }
}

function ComputeClusterRadius(map, radius) {
  var origin = map.PixelToLatLong(new VEPixel(0, 0));
  var px = map.PixelToLatLong(new VEPixel(radius, 0));
  return Math.abs(px.Longitude - origin.Longitude);
}

// Radius is assumed in latlong coord, use ComputeClusterRadius.
function Cluster(map, radius) {
  this.length = 0;
  this.origin = null;
  this.end = null;
  this.map = map;
  this.Radius = radius;
  
  
  this.AddElement = function (latlong, obj) {
    if (this.length == 0) {
      this.origin = latlong;
      this.end = new VELatLong(latlong.Latitude + this.Radius, latlong.Longitude + this.Radius);
      this[this.length++] = obj;
    } else {
      var min = function (a, b) { return a < b ? a : b };
      var max = function (a, b) { return a < b ? a : b };

      this.origin = new VELatLong(
        min(this.origin.Latitude, latlong.Latitude),
        min(this.origin.Longitude, latlong.Longitude));
      this.end = new VELatLong(
        max(this.end.Latitude, latlong.Latitude + this.Radius),
        max(this.end.Longitude, latlong.Longitude + this.Radius));
      this[this.length++] = obj;
    }
  }
  
  this.Merge = function (c) {
    var i;
    for (i = 0; i < c.length; i++)
      this[this.length++] = c[i];
    
    var min = function (a, b) { return a < b ? a : b };
    var max = function (a, b) { return a < b ? a : b };

    this.origin = new VELatLong(
        min(this.origin.Latitude, c.origin.Latitude),
        min(this.origin.Longitude, c.origin.Longitude));
    this.end = new VELatLong(
        max(this.end.Latitude, c.end.Latitude),
        max(this.end.Longitude, c.end.Longitude));
  }
  
  this.Location = function () {
    return new VELatLong((this.origin.Latitude + this.end.Latitude) / 2, (this.origin.Longitude + this.end.Longitude) / 2);
  }
  
  this.createPin = function (data) {
    var pin = new VEShape(VEShapeType.Pushpin, this.Location()), i, d = "", o;
    pin.SetTitle(strings['clustering_risorse_disponibili'] + ': ' + this.length);
    pin.SetCustomIcon(this.length > 5 ? (this.length > 10 ? '/icone/clusterlarge.png' : '/icone/cluster.png') : '/icone/clustersmall.png');
    if (strings && metacategories && this.length > 20) {
      var groups = {};
      for (i = 0; i < this.length; i++) {
        o = data[this[i]];
        var cat = categories2metacategories[o.Category];
        if (!cat) 
          cat = "altro"
        if (!groups[cat]) {
          groups[cat] = new Array();
        }
        var l = groups[cat];
        l.push(o);
      }
      for (cat in groups) {
        var i, a = groups[cat];
        var min = a[0].LatLong;
        var max = a[0].LatLong;
        
        for (i = 1; i < a.length; i++) {
          min = new VELatLong(Math.min(min.Latitude, a[i].LatLong.Latitude), Math.min(min.Longitude, a[i].LatLong.Longitude));
          max = new VELatLong(Math.max(max.Latitude, a[i].LatLong.Latitude), Math.max(max.Longitude, a[i].LatLong.Longitude));
        }
        
        var minLatDist = 0.0010756035475362562; // Empirical

        if ((max.Latitude - min.Latitude) < minLatDist) {
          min = new VELatLong(min.Latitude - minLatDist, min.Longitude);
          max = new VELatLong(max.Latitude + minLatDist, max.Longitude);
        }
        
        
        d += '<img src="' + (metacategories[cat].icon) + '" alt=""/> <a href="javascript:CenterPoints([new VELatLong('+min.Latitude+', '+min.Longitude+'), new VELatLong('+max.Latitude+', '+max.Longitude+')])">' + (strings[metacategories[cat].label]) + '</a> ('+ a.length +')<br/>';
      }
    } else {
      for (i = 0; i < this.length; i++) {
        o = data[this[i]];
        d += '<img src="'+ o.Icon +'" alt=""/> <a href="' + o.Url + '">' + o.Title + '</a><br/>';
      }
    }
    pin.SetDescription(d);
    return pin;
  }
  
  this.Contains = function(latlong) {
    if (this.length == 0)
      return false;
      
    return (latlong.Latitude > this.origin.Latitude   &&
             latlong.Longitude > this.origin.Longitude &&
             latlong.Latitude < this.end.Latitude  &&
             latlong.Longitude < this.end.Longitude);
  }
  
  this.IntersectsWith = function (c) {
    if (this.origin.Latitude > c.end.Latitude)
      return false;
    if (this.end.Latitude < c.origin.Latitude)
      return false;
    if (this.origin.Longitude > c.end.Longitude)
      return false;
    if (this.end.Longitude < c.origin.Longitude)
      return false;
    return true;
  }
}

var updateFunc;

function ResourceSet() {
  this.length = 0;
  this.filter = null;
  this.epoqueFilter = null;
  this.data = {};

  this.add = function (id, step) {
    this.data[id] = step;
    this.length++;
  }

  this.remove = function (id) {
    if (this.data[id]) {
      this.data[id] = null;
      this.length--;
    }
  }
  
  this.mergeClusters = function (clusters) {
      var merged, a;
      do {
        merged = false;
        a = new Array();
        for (i = 0; i < clusters.length; i++) {
          for (j = 0; j < a.length; j++)
            if (a[j].IntersectsWith(clusters[i])) {
              a[j].Merge(clusters[i]);
              merged = true;
              break;
            }
          if (j == a.length) a.push(clusters[i]);
        }
        //if (merged) alert(clusters.length + ' -> ' + a.length);
        clusters = a;
      } while (merged);
      
      return clusters;
  }
  
  // dir: < 0: zoomin > 0: zoomout
  this.clusterMap = function(map, rad, dir) {
    var clusters = new Array();
    var i, j, k, h;
    var tocluster = new Array();
    
    if (!dir) {
      for (i in this.data)
        tocluster.push(i);
    } else if (dir < 0) { //zoomin
      for (k = 0; k < cmap.length; k++)
        if (cmap[k].length == 1) {
          cmap[k].end.Latitude  += rad - cmap[k].Radius;
          cmap[k].end.Longitude += rad - cmap[k].Radius;
          cmap[k].Radius = rad;
          clusters.push(cmap[k]);
        } else for (h = 0; h < cmap[k].length; h++) tocluster.push(cmap[k][h]);
    } else { // zoomout
      for (k = 0; k < cmap.length; k++)
        if (cmap[k].length > 1) {
          cmap[k].end.Latitude  += rad - cmap[k].Radius;
          cmap[k].end.Longitude += rad - cmap[k].Radius;
          cmap[k].Radius = rad;
          clusters.push(cmap[k]);
        } else tocluster.push(cmap[k][0]);
    }

    for (k = 0; k < tocluster.length; k++) {
      i = tocluster[k];
      if (!this.checkFilter(i)) // Skip filtererd
        continue;
      var pos = this.data[i].LatLong;
      for (j = 0; j < clusters.length; j++) {
        var c = clusters[j];
        
        if (c.Contains(pos)) {
          c.AddElement(pos, i);
          pos = null;
          break;
        }
      }
      
      if (pos != null) {
        var c = new Cluster(map, rad);
        c.AddElement(pos, i);
        clusters.push(c);
      }
    }
    if (this.length > clusters.length)
      clusters = this.mergeClusters(clusters);
    
    return clusters;
  }

  var first = true;
  var invalidate = false;
  var cmap = null;
  var czlvl = -1;
  
  this.Invalidate = function () {
    invalidate = true;
  }
  
  this.checkFilter = function (idx) {
    var i;
    if ((!this.filter && !this.epoqueFilter) || this.data[idx].Icon == null)
      return true;
      
    var ret = this.filter ? false : true;
    
    if (this.filter)
      for (i = 0; i < this.filter.length; i++)
        if (this.data[idx].Icon.indexOf(this.filter[i]) != -1) {
          ret = true;
          break;
        }

    if (!ret)
      return false;

    if (this.epoqueFilter)
      for (i = 0; i < this.epoqueFilter.length; i++)
        if (this.data[idx].Icon.indexOf(this.epoqueFilter[i]) != -1)
          return true;

    return (this.epoqueFilter ? false : true);
  }
  
  // A filter on the resource type. Actually performed on icon names.
  // filter: a string array
  this.setTypeFilter = function(map, filter) {
    this.filter = filter;
    invalidate = true;
    this.updateMap(map);
  }
  
  this.setEpoqueFilter = function(map, filter) {
    this.epoqueFilter = filter;
    invalidate = true;
    this.updateMap(map);
  }
  
  this.clearTypeFilter = function(map) {
    this.filter = null;
    invalidate = true;
    this.updateMap(map);
  }
  
  this.clearEpoqueFilter = function (map) {
    this.epoqueFilter = null;
    invalidate = true;
    this.updateMap(map);
  }
  
  this.centerShapes = function (map) {
    if (cmap == null) return;
    var a = new Array(), i;
//    for (i = 0; i < cmap.length; i++)
//      a.push(cmap[i].origin);
    for (i in this.data)
      a.push(this.data[i].LatLong);
    map.SetMapView(a);
    if (map.GetZoomLevel() > 17)
      map.SetZoomLevel(17);
  }
  
  this.updateMap = function(map) {
    if (!map.t4uShapesLayer) {
      map.t4uShapesLayer = new VEShapeLayer();
      map.AddShapeLayer(map.t4uShapesLayer);
      map.t4uShapesLayer.visible = true;
    }
    
    if (!map.t4uShapesLayer.visible)
      return;
    
    var i, obj = this;
    map.t4uShapesLayer.DeleteAllShapes();
    
   if (invalidate || cmap == null) {
      czlvl = map.GetZoomLevel();
      var factor = 1.0;
//      var factor = (czlvl > 6 && czlvl < 11) ? 0.1*(10 - czlvl) + 1.0 : 1.0;
      cmap = this.clusterMap(map, factor * ComputeClusterRadius(map, 16));
      invalidate = false;
    }
    
    if (first) {
      updateFunc  = function (e) {
          var f = function (d) {
            if (e.zoomLevel != czlvl) {
              cmap = obj.clusterMap(map, ComputeClusterRadius(map, 16), czlvl - e.zoomLevel);
              czlvl = e.zoomLevel;
            }
            obj.updateMap(map);
          };
          if (e.zoomLevel - czlvl < 2) f(0);
          else {
            f(0);
            //var t = new Timeline();
            //t.SetAt(100, new FunctionCallback(t, f));
            //t.Run();
          }
        }
      map.AttachEvent("onendzoom", updateFunc )
      map.AttachEvent("onclick",
        function (e) {
          if (e.elementID)
             map.ShowInfoBox(map.GetShapeByID(e.elementID));
        }
      )
      first = false;
    }
    if (this._Regions) {
      var reg;
      for (reg in this._Regions)
        if (reg != 'length') {
          var d = this._Regions[reg].data;
          var p = new VEShape(VEShapeType.Polygon, d);
          p.HideIcon();
          map.t4uShapesLayer.AddShape(p);
        }
    }
    
    if (this._Paths) {
      var path;
      for (path in this._Paths) 
        if (path != 'length') {
          var d = this._Paths[path].data;
          var p = new VEShape(VEShapeType.Polyline, d);
          p.HideIcon();
          map.t4uShapesLayer.AddShape(p);
        }
    }
    
    var shapes = new Array();
    for (i = 0; i < cmap.length; i++) {
      if (cmap[i].length > 1) {
        shapes.push(cmap[i].createPin(this.data));
      } else {
        var idx = cmap[i][0];
        shapes.push(this.data[idx].createPin(idx));
      }
    }
    map.t4uShapesLayer.AddShape(shapes);
  }
}

function GeoResource(latlong) {
  this.LatLong = latlong;
           
  this.Url = '';
  this.Title = '';
  this.Description = '';
  this.Icon = null;
  this.Category = null;
           
  this.createPin = function (id) {
	var pin = new VEShape(VEShapeType.Pushpin, this.LatLong);
    pin.SetCustomIcon(this.Icon == null ? iconurlbase + (id + 1) + iconurlext : this.Icon);
    pin.SetTitle(this.Title);
    pin.SetDescription(this.Description);	 
    return pin;
  }
}

function AnimationSteps() {
  this.length = 0;
  this.drawLines = 1;
  this.drawRegion = 0;
  this.ResourceSet = new ResourceSet();
  var timeline = new Timeline();

  this.add = function (step) {
    this.ResourceSet.add(this.length, step.GeoResource);
    this[this.length++] = step;
  }

  this.remove = function (id) {
    if (id < 0 || id >= this.length)
    return;

    var i;
    this.length--;
    for (i = id; i < this.length; i++) {
      this[i] = this[i + 1];
    }
    this[this.length] = null;
    this.ResourceSet.remove(id);
  }
  this.move = function (from, to) {
    if (from < 0 || from >= this.length)
    return;
    if (to < 0 || to >= this.length)
    return;
    if (from == to)
    return;

    var dir = from < to ? 1 : -1, tmp, j = from;

    while (j != to) {
      tmp = this[j + dir];
      this[j + dir] = this[j];
      this[j] = tmp;
      j += dir;
    }
  }
      
  this.updateMap = function(map) {
    if (!map.t4uShapesLayer) {
      map.t4uShapesLayer = new VEShapeLayer();
      map.AddShapeLayer(map.t4uShapesLayer);
    }

    var i, obj = this;
    map.t4uShapesLayer.DeleteAllShapes();
    for (i = 0; i < this.length; i++)
      map.t4uShapesLayer.AddShape(this[i].createPin(i, this.length));

    var a = new Array();
    for (id in this.ResourceSet.data)
      a.push(this[id].GeoResource.LatLong);
    
    if (this.length > 1 && this.drawLines && !this.drawRegion) {
      var l = new VEShape(VEShapeType.Polyline, a);
      l.HideIcon();
      map.t4uShapesLayer.AddShape(l);
    }
    if (this.length > 2 && this.drawRegion) {
      var p = new VEShape(VEShapeType.Polygon, a);
      p.HideIcon();
      map.t4uShapesLayer.AddShape(p);
    }
  }
  
  this.Play = function () {
    var animation = this;
    var i, time = 0;
    if (timeline.IsRunning())
      timeline.Stop();
    timeline = new Timeline();
    map.SetMapStyle(animation[0].MapStyle);
    map.SetZoomLevel(animation[0].ZoomLevel);
    for (i = 0; i < animation.length - 1; i++) {
      var step = animation[i];
      var next = animation[i + 1];
      var llfrom = step.GeoResource.LatLong;
      var llto = next.GeoResource.LatLong;
      var t = step.Span * 1000;
      var styleset = function (from, to, action) { // Trick to close the actual values of style
        return function (v) { 
          
          if (v == 0 && from != to) map.SetMapStyle(from);
          if (v == 1) {
            if (from != to) map.SetMapStyle(to);
            if (action)
              eval(action);
          }
        }
      };
      timeline.SetAt(time, AnimeJInterp.ffa(t, 100, function (v) { map.SetCenter(new VELatLong(v[0], v[1])); }, [ llfrom.Latitude, llfrom.Longitude ], [llto.Latitude, llto.Longitude]));
      if (next.MapStyle != VEMapStyle.Birdseye && next.MapStyle != VEMapStyle.BirdseyeHybrid)
        timeline.SetAt(time, AnimeJInterp.fiv(t, 300, function (v) { map.SetZoomLevel(v); }, step.ZoomLevel, next.ZoomLevel));
      timeline.SetAt(time, AnimeJInterp.fiv(t, t, styleset(step.MapStyle, next.MapStyle, next.Action), 0, 1));
      time += t;
    }
    timeline.Run();
  }

  this.Pause = function () {
    if (timeline.IsRunning())
      if (!timeline.IsPaused()) timeline.Pause();
      else timeline.Resume();
  }
  
  this.Stop = function () {
    timeline.Stop();
  }
}

function FlightPlay(mapname, res) {
  var d = document.createElement('div');
  var mp = document.getElementById('primaryContent');
  var map = document.getElementById(mapname);
  d.style.position = 'absolute';
  d.style.background = 'url(/resources/playerbg.png) no-repeat';
  d.style.width = '124px';
  d.style.height = '69px';
  d.style.paddingTop = '18px';
  d.style.left = ((parseInt(map.offsetWidth) - 124) / 2 + 64) + 'px';
  d.style.top = (90 - 69 + parseInt(map.offsetHeight) + 30) + 'px';
  d.style.textAlign = 'center';
  
  var play = document.createElement('img');
  var pause = document.createElement('img');
  var stop = document.createElement('img');
  
  play.src = '/images/editor/play.png';
  pause.src = '/images/editor/pause.png';
  stop.src = '/images/editor/stop.png';
  
  play.style.display = 'none';
  play.style.marginRight = '10px';
  pause.style.marginRight = '10px';
  stop.style.marginLeft = '10px';
  
  d.appendChild(play);
  d.appendChild(pause);
  d.appendChild(stop);

  var anim = map_animations[mapname]._Animations[res];
  
  play.onclick = function () {
  	anim.Pause();
  	play.style.display = 'none';
  	pause.style.display = 'inline';
  };

  pause.onclick = function() {
    anim.Pause();
  	pause.style.display = 'none';
  	play.style.display = 'inline';
  };
  
  stop.onclick = function() {
  	anim.Stop();
    map_maps[mapname].ShowMiniMap();
    map_maps[mapname].ShowDashboard();
  	document.body.removeChild(d);
  };
  
  document.body.appendChild(d);
  map_maps[mapname].HideMiniMap();
  map_maps[mapname].HideDashboard();
  anim.Play();
}

// FIXME: This should depend on GeoResource only!
function AnimationStep(georesource, zoomlvl, style) {
  this.GeoResource = georesource;
  
  // Used for editing points
  this.Altitude = 0;
  this.Span = 10;
  this.Action = "";
  this.MapStyle = style;
  this.ZoomLevel = zoomlvl;
                      
  if (editorEnabled)
    this.createPin = function(id, max) {
      // Generates the move step
      var s = 'Step: <select onchange="moveStep('+id+', this.value);true">';
      var i;
      for (i = 0; i < max; i++)
      s += '<option value="' + i + '"'+ (i == id ? ' selected' : '') +'>'+(i+1)+'</option>';
      s += '</select><br/>';
               
      // Generates the intepolation
//      s += 'Interpolator: <select onchange="selectInterpolator('+id+', this.value);true">';
//      for (i = 0; i < interpolators.length; i++)
//      s += '<option value="' + i + '"'+ (i == this.Interpolator ? ' selected' : '') +'>'+interpolators[i].desc+'</option>';
//      s += '</select><br/>';
               
      // Generates the interval
      s += 'Time span: <input onchange="var v=parseInt(this.value); if (!isNaN(v)) setSpan('+id+', v); else this.style.color=\'Red\';true" type="text" size="8" value="'+this.Span+'"/><br/>';
  
      // Generates the interval
      s += 'Action: <input onchange="var v=this.value; setAction('+id+', v); true" type="text" size="8" value="'+this.Action+'"/><br/>';
               
      // Generates the Map Style options
      s += 'Map style: <select onchange="setMapStyle('+id+', this.value);true">';
      for (i in VEMapStyle)
      s += '<option value="' + VEMapStyle[i] + '"'+ (VEMapStyle[i] == this.MapStyle ? ' selected' : '') +'>'+i+'</option>';
      s += '</select><br/>';
               
  
      // Generates the Map Style options
      s += 'Zoom level: <select onchange="setZoomLevel('+id+', this.value);true">';
      for (i = 0; i < 20; i++)
      s += '<option value="' + i + '"'+ (i == this.ZoomLevel ? ' selected' : '') +'>'+i+'</option>';
      s += '</select><br/>';

	  var pin = new VEShape(VEShapeType.Pushpin, this.GeoResource.LatLong);
      pin.SetCustomIcon(iconurlbase + (id + 1) + iconurlext);
      pin.SetTitle('Step number ' + (id + 1));
      pin.SetDescription(s +'<br/><a href="javascript:removePushpin(' + id + ')">Delete</a>');	    
      return pin;
    }
  else
    this.createPin = function (id) {
      return this.GeoResource.createPin(id);
    }
}

function GetMap(name)
{
  var map = null;
  try {
    map = new VEMap(name);
    map.LoadMap();
  } catch(ex) {
    var s = "";
    for (vv in ex)
      s += vv + ', ' + ex[vv];
    alert(s);
  }
  return map;
}

function MoveMap() {
  //map.Pan(-1, 0);
  //setTimeout("MoveMap()", 100);
}

function ismark() {
  return document.getElementById("addPin").innerHTML != "Marca";
}

function moveStep(f, t) {
  animation.move(f, t);
  animation.updateMap(map);
}

function removePushpin(id) {
  animation.remove(id);
  animation.updateMap(map);
}

function selectInterpolator(id, i) {
  animation[id].Interpolator = i;
  animation.updateMap(map);
}

function centerPath(map, animation) {
  var a = new Array(animation.length), i, j = 0;
  for (i in animation.data)
    a[j++] = animation.data[i].LatLong;
  map.SetMapView(a);
}
         
function setSpan(id, v) {
  animation[id].Span = v;
  animation.updateMap(map);
}

function setAction(id, v) {
  animation[id].Action = v;
  animation.updateMap(map);
}

function setMapStyle(id, i) {
  animation[id].MapStyle = i;
  animation.updateMap(map);
}

function setZoomLevel(id, i) {
  animation[id].ZoomLevel = i;
  animation.updateMap(map);
}

function mark() {
  document.getElementById("addPin").innerHTML = "";
}
         
function nextCenter(start, end, steps) {
  return new VELatLong(start.Latitude + (end.Latitude - start.Latitude) / (steps * 1.0), start.Longitude + (end.Longitude - start.Longitude) / (steps * 1.0)) ;
}
         
function find(map) {
  var t = document.getElementById("findlocation");
  map.Find("", t.value);
}
         
function resizeMap(map, name, large) {
  var m = document.getElementById(name);
  if (large) {
    m.style.width = '100%';
    m.style.height = '85%';             
  } else {
    m.style.width = '50%';
    m.style.height = '35%';
  }
  map.Resize(m.offsetWidth, m.offsetHeight);
}

function freshName(base) {
  var d = document.getElementById(base);
  while (d) {
    base = base + '_';
    d = document.getElementById(base);
  }
  return base;
}


function editPositionSwitchMode(lbl, img) {
  var lbldiv = document.getElementById(lbl);
  if (img.src.indexOf('nomark.png') != -1)
  {
    img.src = resourcesBase+'mark.png';
    lbldiv.innerHTML = '<strong>Modalit&agrave; inserimento posizione. </strong><br/>Clicca sulla mappa per inserire la posizione. Clicca sull\'icona per tornare in modalit&agrave; navigazione';
  } else
  {
    img.src = resourcesBase+'nomark.png';
    lbldiv.innerHTML = '<strong>Modalit&agrave; navigazione. </strong><br/>Clicca sull\'icona per andare in modalit&agrave; inserimento posizione';
  }
}

function editPosition(savefun, lat, lon, altitude, readonly) {
  var popup = new ModalOverlay(0.7, 50);
  var d =  AbsBox('0px', '0px', '100%', '100%');
           
  var n = freshName('positionEditor');
  var lbl = freshName('editorLabel');
  var findn = freshName('findPosition');
  // la toolbar per edit/pan
  var toolbar = '<div style="position: absolute; top: 10px; left: 10px;">';
  toolbar += '<div style="float: left">';
  toolbar += '<img id="_gal__tool_mark" src="'+resourcesBase+'nomark.png" ';
  toolbar += 'onclick="editPositionSwitchMode(\'' + lbl + '\',this);"';
  toolbar += 'width="32" border="0">';
  toolbar += '</div>';
  toolbar += '<div id="'+lbl+'" style="color:#fff;font-family:"Courier New", Courier, mono; font-size:1.0em; line-height:1.1">'
  toolbar += '<strong>Modalit&agrave; navigazione. </strong><br/>Clicca sull\'icona per andare in modalit&agrave; inserimento posizione';
  toolbar += '</div>';
  toolbar += '</div>';
  
  // la mappa
  var mappa = '<div id="'+n+'" style="position: absolute; top: 10%; left: 10%; width: 80%; height: 80%"></div>';           
  // il tool di ricerca
  var cerca = '<div style="position: absolute; top: 90%; left: 10%; padding: 5px"><input type="text" id="'+findn+'"><input type="button" onclick="map.Find(\'\', document.getElementById(\''+findn+'\').value)" value="Cerca"></div>';

  if (readonly)           
    d.innerHTML = mappa;
  else
    d.innerHTML = toolbar + mappa + cerca;
           
  var ismarked = function () {
    var im = document.getElementById('_gal__tool_mark');
    return (im && im.src.indexOf('nomark.png') == -1);
  }
           
  popup.setContent(d);
  popup.show();
           
  var point = new AnimationSteps();
  animation = point;

  var altname = freshName('tbaltitude');
                      
  if (!readonly)
    popup.setOnClose(function () {
      var a = document.getElementById(altname);
      savefun(point.length ? (new Number(point.ResourceSet.data[0].LatLong.Latitude)).toExponential() + ";" + (new Number(point.ResourceSet.data[0].LatLong.Longitude)).toExponential() + ";" + (a && a.value ? a.value : "0") : "0;0;0");
    });

      var localmap = GetMap(n);
  map = localmap;           
           
  var setPoint = function (latlong) {
    var step = new AnimationStep(new GeoResource(latlong));
    step.GeoResource.Title = 'Information';
    // Maybe undefined as it is optional...
    if (!altitude) altitude = 0;
    step.Altitude = altitude;
    if (readonly)
      step.GeoResource.Description = 'Altitude: <i>'+altitude+'</i><p/>';
    else
      step.GeoResource.Description = 'Altitude: <input type="text" name="'+altname+'" value="'+altitude+'"><p/><a href="javascript:removePushpin(0)">Delete</a>';
    point.add(step);
    point.updateMap(localmap);
  }
         
  localmap.AttachEvent('onclick',
		       function (e) {
    if (!ismarked()) return;
               
    if (point.length)
      point.remove(0);
    
    setPoint(localmap.PixelToLatLong(new VEPixel(e.mapX, e.mapY)));
  }
		       );  
           
  map.SetMapStyle(VEMapStyle.Hybrid);
//  map.HideDashboard();
           
  if (lat && lon) {
    setPoint(new VELatLong(lat, lon));
    map.SetCenterAndZoom(new VELatLong(lat, lon), 7);
  } else
  {
      map.SetCenterAndZoom(new VELatLong(43.397774813294625, 10.909970998764043), 7);
  }
           
  //map.Find('', 'Italy, Europe');

}
/*                  
function editPosition(savefun, lat, lon, altitude, readonly) {
  var popup = new ModalOverlay(0.7, 100);
  var d =  AbsBox('0px', '0px', '100%', '100%');
           
  var n = freshName('positionEditor');
  var findn = freshName('findPosition');
           
  if (readonly)           
    d.innerHTML = '<div id="'+n+'" style="position: absolute; top: 10%; left: 10%; width: 80%; height: 80%"></div>';
  else
    d.innerHTML = '<div style="position: absolute; top: 10px; left: 10px;"><img id="_gal__tool_mark" src="'+resourcesBase+'nomark.png" onclick="this.src = (this.src.indexOf(\'nomark.png\') != -1) ? \''+resourcesBase+'mark.png\' : \''+resourcesBase+'nomark.png\'; " width="32" border="0"></div><div id="'+n+'" style="position: absolute; top: 10%; left: 10%; width: 80%; height: 80%"></div><div style="position: absolute; top: 90%; left: 10%; padding: 5px"><input type="text" id="'+findn+'"><input type="button" onclick="map.Find(\'\', document.getElementById(\''+findn+'\').value)" value="Cerca"></div>';
           
  var ismarked = function () {
    var im = document.getElementById('_gal__tool_mark');
    return (im && im.src.indexOf('nomark.png') == -1);
  }
           
  popup.setContent(d);
  popup.show();
           
  var point = new AnimationSteps();
  animation = point;

  var altname = freshName('tbaltitude');
                      
  if (!readonly)
    popup.setOnClose(function () {
      var a = document.getElementById(altname);
      savefun(point.length ? (new Number(point.ResourceSet.data[0].LatLong.Latitude)).toExponential() + ";" + (new Number(point.ResourceSet.data[0].LatLong.Longitude)).toExponential() + ";" + (a && a.value ? a.value : "0") : "0;0;0");
    })

      var localmap = GetMap(n);
  map = localmap;           
           
  var setPoint = function (latlong) {
    var step = new AnimationStep(new GeoResource(latlong));
    step.GeoResource.Title = 'Information';
    // Maybe undefined as it is optional...
    if (!altitude) altitude = 0;
    step.Altitude = altitude;
    if (readonly)
      step.GeoResource.Description = 'Altitude: <i>'+altitude+'</i><p/>';
    else
      step.GeoResource.Description = 'Altitude: <input type="text" name="'+altname+'" value="'+altitude+'"><p/><a href="javascript:removePushpin(0)">Delete</a>';
    point.add(step);
    point.updateMap(localmap);
  }
         
  localmap.AttachEvent('onclick',
		       function (e) {
    if (!ismarked()) return;
               
    if (point.length)
      point.remove(0);
    
    setPoint(localmap.PixelToLatLong(new VEPixel(e.mapX, e.mapY)));
  }
		       );  
           
  map.SetMapStyle(VEMapStyle.Hybrid);
//  map.HideDashboard();
           
  if (lat && lon) {
    setPoint(new VELatLong(lat, lon));
  }
           
  map.Find('', 'Italy, Europe');

}
*/      

function closeMapPopup() {
  var d = document.getElementById('_gal_mapchooser');
  if (d.onclose)
    d.onclose();
  document.body.removeChild(d);
}
         
function serializePath(p) {
  if (!p.length) return "0;0;0";
  var i;
  var ret = "";
  for (i = 0; i < p.length; i++) {
    if (i) ret += "|";
    ret += (new Number(p[i].GeoResource.LatLong.Latitude)).toExponential() + ";" + (new Number(p[i].GeoResource.LatLong.Longitude)).toExponential() + ";" + p[i].Altitude;
  }
           
  return ret;
}
         
function deserializePath(inp, path, map, altname, ispath, readonly) {
  var pts = inp.split('|');
  var i;
           
  for (i = 0; i < pts.length; i++) {
    var pt = pts[i].split(';');

    var step = new AnimationStep(new GeoResource(new VELatLong(parseFloat(pt[0]), parseFloat(pt[1]))));
    step.GeoResource.Title = 'Information'
      var id = i;

    // Generates the move step
    var s = "";
    s = 'Step: <select onchange="moveStep('+id+', this.value);true">';
    if (ispath) {
      var j;
      for (j = 0; j < 10; j++) // FIXME: How to show the exact num?
	s += '<option value="' + j + '"'+ (j == id ? ' selected' : '') +'>'+(j+1)+'</option>';
      s += '</select><br/>';
    }

    step.Altitude = parseInt(pt[2]);
    if (readonly)
      step.GeoResource.Description = s + 'Altitude: <i>'+"0"+'</i><p/>';
    else
      step.GeoResource.Description = s + 'Altitude: <input type="text" name="'+altname+'" value="'+"0"+'"><p/><a href="javascript:removePushpin('+i+')">Delete</a>';
    path.add(step);
  }
  path.updateMap(map);
}

function serializeAnimation(p) {
  if (!p.length) return "0;0;0;;0;0;0";
  var i;
  var ret = "";
  for (i = 0; i < p.length; i++) {
    if (i) ret += "|";
    ret += (new Number(p[i].GeoResource.LatLong.Latitude)).toExponential() + ";" + (new Number(p[i].GeoResource.LatLong.Longitude)).toExponential() + ";" + p[i].Altitude + ";" + p[i].Action + ";" + p[i].MapStyle + ";" + p[i].ZoomLevel + ";" + p[i].Span;
  }
  return ret;
}
         
function deserializeAnimation(inp, path, map, altname, ispath, readonly) {
  var pts = inp.split('|');
  var i;
           
  for (i = 0; i < pts.length; i++) {
    var pt = pts[i].split(';');

    var step = new AnimationStep(new GeoResource(new VELatLong(parseFloat(pt[0]), parseFloat(pt[1]))));
    step.Altitude = parseInt(pt[2]);
    step.Action = pt[3];
    step.MapStyle = pt[4];
    step.ZoomLevel = parseInt(pt[5]);
    step.Span = parseInt(pt[6]);
    step.GeoResource.Title = 'Information'
      var id = i;

    // Generates the move step
    var s = "";
    s = 'Step: <select onchange="moveStep('+id+', this.value);true">';
    if (ispath) {
      var j;
      for (j = 0; j < 10; j++) // FIXME: How to show the exact num?
	s += '<option value="' + j + '"'+ (j == id ? ' selected' : '') +'>'+(j+1)+'</option>';
      s += '</select><br/>';
    }

    step.Altitude = parseInt(pt[2]);
    if (readonly)
      step.GeoResource.Description = s + 'Altitude: <i>'+"0"+'</i><p/>';
    else
      step.GeoResource.Description = s + 'Altitude: <input type="text" name="'+altname+'" value="'+"0"+'"><p/><a href="javascript:removePushpin('+i+')">Delete</a>';
    path.add(step);
  }
  path.updateMap(map);
}
         
function editPath(isregion, savefun, serpath, readonly) {
  var popup = new ModalOverlay(0.7, 100);
  var d = AbsBox('0px', '0px', '100%', '100%');
           
  var n = freshName('pathEditor');
  var findn = freshName('findPosition');
           
  if (readonly)           
    d.innerHTML = '<div id="'+n+'" style="position: absolute; top: 10%; left: 10%; width: 80%; height: 80%"></div>';
  else
    d.innerHTML = '<div style="position: absolute; top: 10px; left: 10px;"><img id="_gal__tool_mark" src="'+resourcesBase+'nomark.png" onclick="this.src = (this.src.indexOf(\'nomark.png\') != -1) ? \''+resourcesBase+'mark.png\' : \''+resourcesBase+'nomark.png\'; " width="32" border="0"></div><div id="'+n+'" style="position: absolute; top: 10%; left: 10%; width: 80%; height: 80%"></div><div style="position: absolute; top: 90%; left: 10%; padding: 5px"><input type="text" id="'+findn+'"><input type="button" onclick="map.Find(\'\', document.getElementById(\''+findn+'\').value)" value="Cerca"></div>';
           
  var ismarked = function () {
    var im = document.getElementById('_gal__tool_mark');
    return (im && im.src.indexOf('nomark.png') == -1);
  }
                                
  popup.setContent(d);
  popup.show();
           
  var point = new AnimationSteps();
  point.drawRegion = isregion ? 1 : 0;
  animation = point;

  var altname = freshName('tbaltitude');
                      
  if (!readonly)
    popup.setOnClose(function () {
      // FIXME: Deal with altitude
      //var a = document.getElementById(altname);
      savefun(serializePath(point));
    });

  var localmap = GetMap(n);
  map = localmap;           
                      
  var setPoint = function (latlong) {
    var step = new AnimationStep(new GeoResource(latlong));
    step.GeoResource.Title = 'Information';
    // Maybe undefined as it is optional...
    //               if (!altitude) altitude = 0;
    //               step.Altitude = altitude;
    // Generates the move step
    var s = 'Step: <select onchange="moveStep('+point.length+', this.value);true">';
    var j;
    for (j = 0; j < 10; j++) // FIXME: How to show the exact num?
    s += '<option value="' + j + '"'+ (j == point.length ? ' selected' : '') +'>'+(j+1)+'</option>';
    s += '</select><br/>';

    if (readonly)
      step.GeoResource.Description = s + 'Altitude: <i>'+"0"+'</i><p/>';
    else
      step.GeoResource.Description = s + 'Altitude: <input type="text" name="'+altname+'" value="'+"0"+'"><p/><a href="javascript:removePushpin('+point.length+')">Delete</a>';
    point.add(step);
    point.updateMap(localmap);
  }

  localmap.AttachEvent('onclick',
		       function (e) {
    if (!ismarked()) return;
               
    setPoint(localmap.PixelToLatLong(new VEPixel(e.mapX, e.mapY)));
  }
		       );
           
  map.SetMapStyle(VEMapStyle.Hybrid);
  //map.HideDashboard();
  //map.ShowDashboard();
         
  if (serpath)
    deserializePath(serpath, point, map, altname, true, readonly);
                      
  map.Find('', 'Italy, Europe');

}

function editPath2(isregion, savefun, serpath, readonly) {
  editorEnabled = true;  
  var popup = new ModalOverlay(0.7, 100);
  var d = AbsBox('0px', '0px', '100%', '100%');
           
  var n = freshName('pathEditor');
  var findn = freshName('findPosition');
           
  if (readonly)           
    d.innerHTML = '<div id="'+n+'" style="position: absolute; top: 10%; left: 10%; width: 80%; height: 80%"></div>';
  else
    d.innerHTML = '<div style="position: absolute; top: 10px; left: 10px;"><img id="_gal__tool_mark" src="'+resourcesBase+'nomark.png" onclick="this.src = (this.src.indexOf(\'nomark.png\') != -1) ? \''+resourcesBase+'mark.png\' : \''+resourcesBase+'nomark.png\'; " width="32" border="0"><br/><br/><img src="/images/editor/play.png" onclick="this.parentNode.parentNode.Play()" /><br/><br/><img src="/images/editor/pause.png" onclick="this.parentNode.parentNode.Pause()" /><br/><br/><img src="/images/editor/stop.png" onclick="this.parentNode.parentNode.Stop()" /></div><div id="'+n+'" style="position: absolute; top: 10%; left: 10%; width: 80%; height: 80%"></div><div style="position: absolute; top: 90%; left: 10%; padding: 5px"><input type="text" id="'+findn+'"><input type="button" onclick="map.Find(\'\', document.getElementById(\''+findn+'\').value)" value="Cerca"></div>';
           
  var ismarked = function () {
    var im = document.getElementById('_gal__tool_mark');
    return (im && im.src.indexOf('nomark.png') == -1);
  }
                                
  popup.setContent(d);
  popup.show();
           
  var point = new AnimationSteps();
  point.drawRegion = isregion ? 1 : 0;
  animation = point;

  var altname = freshName('tbaltitude');
                      
  var timeline = new Timeline();

  if (!readonly)
    popup.setOnClose(function () {
      // FIXME: Deal with altitude
      //var a = document.getElementById(altname);
      editorEnabled = false;
      timeline.Stop();
      savefun(serializeAnimation(point));
    });

  var localmap = GetMap(n);
  map = localmap;           
                      
  var setPoint = function (latlong) {
    var step = new AnimationStep(new GeoResource(latlong));
    step.ZoomLevel = localmap.GetZoomLevel();
    step.MapStyle = localmap.GetMapStyle();
    step.GeoResource.Title = 'Information';
    // Maybe undefined as it is optional...
    //               if (!altitude) altitude = 0;
    //               step.Altitude = altitude;
    // Generates the move step
    var s = 'Step: <select onchange="moveStep('+point.length+', this.value);true">';
    var j;
    for (j = 0; j < 10; j++) // FIXME: How to show the exact num?
    s += '<option value="' + j + '"'+ (j == point.length ? ' selected' : '') +'>'+(j+1)+'</option>';
    s += '</select><br/>';

    if (readonly)
      step.GeoResource.Description = s + 'Altitude: <i>'+"0"+'</i><p/>';
    else
      step.GeoResource.Description = s + 'Altitude: <input type="text" name="'+altname+'" value="'+"0"+'"><p/><a href="javascript:removePushpin('+point.length+')">Delete</a>';
    point.add(step);
    point.updateMap(localmap);
  }

  localmap.AttachEvent('onclick',
		       function (e) {
    if (!ismarked()) return;
               
    setPoint(localmap.PixelToLatLong(new VEPixel(e.mapX, e.mapY)));
  }
		       );

  // Player
  var styles2int = {}, int2styles = new Array(), stylename;
  i = 0;
  for (stylename in VEMapStyle) {
    styles2int[stylename] = i++;
    int2styles.push(VEMapStyle[stylename]);
  }
  
  d.Play = function () {
    point.Play();
/*
    var i, time = 0;
    if (timeline.IsRunning())
      timeline.Stop();
    timeline = new Timeline();
    map.SetMapStyle(animation[0].MapStyle);
    map.SetZoomLevel(animation[0].ZoomLevel);
    for (i = 0; i < animation.length - 1; i++) {
      var step = animation[i];
      var next = animation[i + 1];
      var llfrom = step.GeoResource.LatLong;
      var llto = next.GeoResource.LatLong;
      var t = step.Span * 1000;
      var styleset = function (from, to, action) { // Trick to close the actual values of style
        return function (v) { 
          
          if (v == 0 && from != to) map.SetMapStyle(from);
          if (v == 1) {
            if (from != to) map.SetMapStyle(to);
            if (action)
              eval(action);
          }
        }
      };
      timeline.SetAt(time, AnimeJInterp.ffa(t, 100, function (v) { map.SetCenter(new VELatLong(v[0], v[1])); }, [ llfrom.Latitude, llfrom.Longitude ], [llto.Latitude, llto.Longitude]));
      if (next.MapStyle != VEMapStyle.Birdseye && next.MapStyle != VEMapStyle.BirdseyeHybrid)
        timeline.SetAt(time, AnimeJInterp.fiv(t, 300, function (v) { map.SetZoomLevel(v); }, step.ZoomLevel, next.ZoomLevel));
      timeline.SetAt(time, AnimeJInterp.fiv(t, t, styleset(step.MapStyle, next.MapStyle, next.Action), 0, 1));
      time += t;
    }
    timeline.Run();
    */
  };
  
  d.Pause = function () {
    point.Pause();
    /*
    if (timeline.IsRunning())
      if (!timeline.IsPaused()) timeline.Pause();
      else timeline.Resume();
    */
  }
  
  d.Stop = function () {
    point.Stop();
    //timeline.Stop();
  }
           
  map.SetMapStyle(VEMapStyle.Hybrid);
//  map.HideDashboard();
           
  if (serpath)
    deserializeAnimation(serpath, point, map, altname, true, readonly);
                      
  map.Find('', 'Italy, Europe');

}
         
function closeMapPopup() {
  var d = document.getElementById('_gal_mapchooser');
  if (d.onclose)
    d.onclose();
  document.body.removeChild(d);
}
                  
function ModalOverlay(op, zidx) {
  if (!op) op = 0.8;
  var bg = AbsBox('0px', '0px', '100%', '100%');
  // FIXME: This is a workaround...
  bg.style.zIndex = zidx ? zidx : 1000;

  var d = AbsBox('0px', '0px', '100%', '100%');
  d.style.backgroundColor= '#000000';
  d.style.visibility='visible';
  AnimeSetOpacity(d, op);

  var cont = AbsBox('0px', '0px', '100%', '100%');
                      
  var fade = 400;
  var speed = 70;

  var close = document.createElement('div');
  ConfigureStyle(close, { 'position': 'absolute', 'top': '0px', 'right': '0px' });

  close.ModalOverlayClose =  function () {
    var tm = new Timeline();
    tm.SetAt(0, AnimeJInterp.alpha(fade, speed, bg, 1.0, 0.0));
    tm.OnEnd = function (d) { 
      document.body.removeChild(bg);
      var docscroll = AnimeIEVer >= 7 ? document.documentElement : document.body;
      docscroll.ModalOverlayCount--;
      if (!docscroll.ModalOverlayCount) {
        if (bg.oncloseoverlay) bg.oncloseoverlay();
        docscroll.style.overflow = bg.OriginalPosition.originaloverflow;
        docscroll.scrollTop = bg.OriginalPosition.scrollTop;
      }
    };
    tm.Run()
  }

  close.innerHTML = '<img src="'+resourcesBase+'close.png" width="32" alt="Close" border="0" onclick="this.parentNode.ModalOverlayClose()">';
           
  bg.appendChild(d);
  bg.appendChild(cont);
  bg.appendChild(close);

  var tm = new Timeline();
  tm.SetAt(0, AnimeJInterp.alpha(fade, speed, bg, 0.0, 1.0));
  tm.SetAt(0, AnimeJInterp.alpha(fade, speed, d, 0.0, op));
  tm.SetAt(0, AnimeJInterp.alpha(fade, speed, cont, 0.0, 1.0));
  tm.SetAt(0, AnimeJInterp.alpha(fade, speed, close, 0.0, 1.0));
           
  this.show = function () {
    // Workaround for IE7
    var docscroll = AnimeIEVer >= 7 ? document.documentElement : document.body;
    if (!docscroll.ModalOverlayCount) {
      bg.OriginalPosition = {};
      bg.OriginalPosition.scrollTop = docscroll.scrollTop;
      bg.OriginalPosition.originaloverflow = docscroll.style.overflow;
      docscroll.style.overflow = 'hidden';
      docscroll.scrollTop = 0;
      docscroll.ModalOverlayCount = 0;
    }
    docscroll.ModalOverlayCount++;
    AnimeSetOpacity(bg, 0);
    
    // Work around on IE7 that when adding a div first display
    // and after opacity is applied.
    bg.style.visibility = 'hidden';
    document.body.appendChild(bg);
    bg.style.visibility = 'visible';
    var puppa = d;
    tm.OnEnd = function (d) {
      if (bg.onloadoverlay) bg.onloadoverlay();
    }
    tm.Run();
  }
           
  this.setContent = function (content) {
    if (typeof(content) == 'string')
    cont.innerHTML = content;
    else {
      while (cont.hasChildNodes())
        cont.removeChild(this.cont.firstChild);
      cont.appendChild(content);
    }
  }
  
  this.close = function () {
    close.ModalOverlayClose();
  }
           
  this.setOnClose = function (func) {
    bg.oncloseoverlay = func;
  }
  
  this.setOnLoad = function (func) {
    bg.onloadoverlay = func;
  }
}
         
function playVideo(id) {
  var m = new ModalOverlay();
  var html = '<object width="425" height="350"><param name="movie" value="http://www.youtube.com/v/'+id+'&autoplay=1"></param><param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/'+id+'&autoplay=1" type="application/x-shockwave-flash" wmode="transparent" width="425" height="350"></embed></object>';
  m.setContent(html);
  m.show();
}
         
function IconList() {
  this.List_Name = freshName('IconList');
  this.List = document.createElement('div');
  this.List.setAttribute('id', this.List_Name);
  ConfigureStyle(this.List, { 'height': '90%', 'overflow': 'auto', 'top': '5px', 'position': 'relative' });
  
  StripScroller(this.List, true);

  this.List.ScrollContent().style.background = 'url(/resources/moviestrip.png) repeat-y scroll left top'

  this.add = function (urlicon, link) {
    var s = document.createElement('div');
    s.style.padding = '2px 18px';
    s.innerHTML = '<a href="'+link+'"><img src="'+urlicon+'" width="100"></a>';
    this.List.appendChild(s);
    this.List.ScrollContent().appendChild(s);
  }
}
         
function SelectTab(nm, tab) {
  var v = document.getElementById(nm);
  v.State.select(tab);
}
         
function TabPanel() {
  this.TabPanel_Name = freshName('TabPanel');
  this.PhotoIcon_Name = freshName('TabPanel_tb_photo_icon');
  this.VideoIcon_Name = freshName('TabPanel_tb_video_icon');
  this.MeshIcon_Name = freshName('TabPanel_tb_mesh_icon');
  this.TabPanel = document.createElement('div');
  this.TabPanel.setAttribute('id', this.TabPanel_Name);
  this.TabPanel.State = this;
           
  this.Video = new IconList();
  this.Photo = new IconList();
  this.Mesh = new IconList();
           
  var tb = document.createElement('div');
  tb.innerHTML = '<img id="'+this.PhotoIcon_Name+'" src="'+resourcesBase+'photo.png" width="32" border="0" alt="Foto" onclick="SelectTab(\''+this.TabPanel_Name+'\', \'photo\')"><img id="'+this.VideoIcon_Name+'" src="'+resourcesBase+'video_small.png" width="24" border="0" alt="Video" onclick="SelectTab(\''+this.TabPanel_Name+'\', \'video\')"><img id="'+this.MeshIcon_Name+'" src="'+resourcesBase+'3d_small.png" width="24" border="0" alt="3D" onclick="SelectTab(\''+this.TabPanel_Name+'\', \'mesh\')">';
  this.TabPanel.appendChild(tb);
  
  var selectedTab = this.Photo;
  this.TabPanel.appendChild(this.Photo.List);
  
  this.Visible = { 'photo': true, 'video': true, 'mesh': true };

  this.onresize = function() {
    selectedTab.List.onresize();
  }

  this.hide = function (tab) {
    this.Visible[tab] = false;
    if (tab == "video") {
      var img = document.getElementById(this.VideoIcon_Name);
      img.src = resourcesBase+"video_disabled.png";
      img.style.width = '24px';
      img.onclick = null;
    }
    if (tab == "photo") {
      var img = document.getElementById(this.PhotoIcon_Name);
      img.src = resourcesBase+"photo_disabled.png";
      img.style.width = '24px';
      img.onclick = null;
    }
    if (tab == "mesh") {
      var img = document.getElementById(this.MeshIcon_Name);
      img.src = resourcesBase+"3d_disabled.png";
      img.style.width = '24px';
      img.onclick = null;
    }
  }
           
  this.select = function (tab) {
    if (tab == "video") {
      var img = document.getElementById(this.PhotoIcon_Name);
      img.style.width = "24px";
      if (this.Visible['photo'])
        img.src = resourcesBase+'photo_small.png';
      img = document.getElementById(this.VideoIcon_Name);
      img.src = resourcesBase+'video.png';
      img.style.width = "32px";
      img = document.getElementById(this.MeshIcon_Name);
      img.style.width = "24px";
      if (this.Visible['mesh'])
        img.src = resourcesBase+'3d_small.png';
      this.TabPanel.removeChild(this.TabPanel.lastChild);
      this.TabPanel.appendChild(this.Video.List);
      selectedTab = this.Video;
    }
    if (tab == "photo") {
      var img = document.getElementById(this.PhotoIcon_Name);
      img.style.width = "32px";
      img.src = resourcesBase+'photo.png';
      img = document.getElementById(this.VideoIcon_Name);
      img.style.width = "24px";
      if (this.Visible['video'])
        img.src = resourcesBase+'video_small.png';
      img = document.getElementById(this.MeshIcon_Name);
      img.style.width = "24px";
      if (this.Visible['mesh'])
        img.src = resourcesBase+'3d_small.png';
      this.TabPanel.removeChild(this.TabPanel.lastChild);
      this.TabPanel.appendChild(this.Photo.List);
      selectedTab = this.Photo;
    }
    if (tab == "mesh") {
      var img = document.getElementById(this.PhotoIcon_Name);
      img.style.width = "24px";
      if (this.Visible['photo'])
        img.src = resourcesBase+'photo_small.png';
      img = document.getElementById(this.VideoIcon_Name);
      img.style.width = "24px";
      if (this.Visible['video'])
        img.src = resourcesBase+'video_small.png';
      img = document.getElementById(this.MeshIcon_Name);
      img.style.width = "32px";
      img.src = resourcesBase+'3d.png';
      this.TabPanel.removeChild(this.TabPanel.lastChild);
      this.TabPanel.appendChild(this.Mesh.List);
      selectedTab = this.Mesh;
    }
    
    this.onresize();
  }
}
         
function Resource() {
  this.Video = new Array();
  this.Photo = new Array();
  this.Mesh = new Array();
  this.Text = new Array();
           
  this.Title ="";
  this.Description = "";
}
         
function VideoPlayer(id, res, desc) {
  this.Player = document.createElement('div');
  this.Player.style.position = 'relative';
  this.Player.style.top = '10%';
  this.Player.style.left = '0px';
  this.Player.style.width = '100%';
           
  this.selectVideo = function (vid) {
    this.Player.innerHTML = '<p align="center"><object width="425" height="350"><param name="movie" value="http://www.youtube.com/v/'+vid+'&autoplay=1"></param><param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/'+vid+'&autoplay=1" type="application/x-shockwave-flash" wmode="transparent" width="425" height="350"></embed></object></p>';
  }
           
  this.selectVideo(id);
}

function PhotoPlayer(url, res, desc) {
  this.Player = document.createElement('div');
  this.Player.style.position = 'relative';
  this.Player.style.top = '10%';
  this.Player.style.left = '0px';
  this.Player.style.width = '100%';
           
  this.selectPhoto = function (purl, desc) {
    this.Player.innerHTML = '<a onclick="this.parentNode.SlideShow()" style="color: #FF9900">Play</a><p align="center"><img src="'+purl+'" class="ContentPlayerImage"><div style="color: #cccccc; width: 500px; margin: auto; text-align: left">'+desc+'</div></p>';
  }
   
  this.Player.SlideShow = function () {
    var photos = new Array(), i;
    for (i = 1; i < res.Photo.length; i+=3)
      photos.push(res.Photo[i]);
    var s = new ModalOverlay(AnimeIEVer >= 7 ? 0.85 : 1.0);
    var d = document.createElement('div');
    d.style.position = 'absolute';
    d.style.top = '20px';
    d.style.height = '100%';
    d.style.width = '100%';
    var show = Sld_MakeShow(d, photos);
    s.setOnClose(function () { show.Stop(); });
    s.setContent(d);
    s.show();
    show.Play();
  }
           
  this.selectPhoto(url, desc);
}
         
function MeshPlayer(url, res, desc) {
  this.Player = document.createElement('div');
  this.Player.style.position = 'relative';
  this.Player.style.top = '10%';
  this.Player.style.left = '0px';
  this.Player.style.width = '100%';
  
  if (url.indexOf("photosynth") != -1) {
    this.Player.innerHTML = '<p align="center"><iframe frameborder=0 src="'+url+'" width="600" height="450"></iframe></p>';    
  } else {
    this.Player.innerHTML = '<p align="center"><object id="UnityObject" classid="clsid:444785F1-DE89-4295-863A-D46C3A781394" width="600" height="450" codebase="http://webplayer.unity3d.com/download_webplayer-2.x/UnityWebPlayer.cab#version=2,0,0,0"><param name="src" value="'+url+'" /><embed id="UnityEmbed" src="'+url+'" width="600" height="450" type="application/vnd.unity" pluginspage="http://www.unity3d.com/unity-web-player-2.x" /><noembed><div align="center">This content requires the Unity Web Player<br /><br /><a href="http://www.unity3d.com/unity-web-player-2.x">Install the Unity Web Player today!</a></div></noembed></object></p>';
  }
}

function PlayContent(nm, type, id, desc) {
  var d = document.getElementById(nm);

  if (d.CompanyBrowser) {
    var dd = document.getElementById(d.CompanyBrowser);
    dd.style.display = 'none';
    dd = document.getElementById(d.CompanyBrowserTabs);
    dd.style.display = 'none';
    dd = document.getElementById(d.CompanyBrowser + "_showText");
    dd.style.display = 'inline';
  }
  
  var p;
  if (type == 'video')
    p = new VideoPlayer(id, d.Resource, desc);
  else if (type == 'photo')
    p = new PhotoPlayer(id, d.Resource, desc);
  else if (type == 'mesh')
    p = new MeshPlayer(id, d.Resource, desc);
             
  while (d.Player.hasChildNodes()) d.Player.removeChild(d.Player.firstChild);
  d.Player.appendChild(p.Player);  
}

function RestoreCompanyText(nm) {
  var d = document.getElementById(nm);

  while (d.Player.hasChildNodes()) d.Player.removeChild(d.Player.firstChild);

  var dd = document.getElementById(d.CompanyBrowser);
  dd.style.display = 'inline';
  dd = document.getElementById(d.CompanyBrowserTabs);
  dd.style.display = 'inline';
  dd = document.getElementById(d.CompanyBrowser + "_showText");
  dd.style.display = 'none';
}

function ShowElement(name, visible) {
  var el = document.getElementById(name);
  el.style.display = visible ? 'inline' : 'none';
}
                  
function ContentBrowser(resource) {
  var m = new ModalOverlay();
           
  var pagnm = freshName('ContentPlayer');
  var pag = AbsBox('0px', '0px', '100%', '100%');
  pag.setAttribute('id', pagnm);           
  pag.CompanyBrowser = false;
  
  pag.Resource = resource;
           
  var tab = new TabPanel();
  ConfigureStyle(tab.TabPanel, { 'position': 'absolute', 'right': '0px', 'top': '32px', 'width': '120px', 'height': '95%' });
  
  var pagePlayer = document.createElement('div');
  ConfigureStyle(pagePlayer, { 'position': 'absolute', 'left': '10px', 'right': '120px', 'top': '10px', 'height': '90%', 'textAlign': 'center' });
  
  var title = document.createElement('div');
  title.style.width = '100%';
  title.innerHTML = '<p align="center" class="ContentBrowserTitle">'+resource.Title+'</p><p align="center" class="ContentBrowserSubTitle">'+(resource.Description.replace(/<.*?>/g, ""))+'</p>';
  
  pagePlayer.appendChild(title);
   
  var player = document.createElement('div');
  player.style.width = '100%';
                      
  pagePlayer.appendChild(player);
  
  pag.appendChild(pagePlayer);
  
  pag.Player = player;
           
  var i;
           
  for (i = 0; i < resource.Video.length; i+=2) {
    tab.Video.add(resource.Video[i], "javascript:PlayContent('" + pagnm + "', 'video', '" + resource.Video[i + 1] + "', '')");
  }
  for (i = 0; i < resource.Photo.length; i+=3)
    tab.Photo.add(resource.Photo[i], "javascript:PlayContent('" + pagnm + "', 'photo', '" + resource.Photo[i + 1] + "', '" + QuoteText(true, resource.Photo[i + 2]) +"')");

  for (i = 0; i < resource.Mesh.length; i+=2)
    tab.Mesh.add(resource.Mesh[i], "javascript:PlayContent('" + pagnm + "', 'mesh', '" + resource.Mesh[i + 1] + "', '')");
           
  pag.appendChild(tab.TabPanel);
           
  var desc_name = freshName('ContentBrowser_Text');
  var showText = document.createElement('div');
  ConfigureStyle(showText, { 'position': 'absolute', 'left': '10px', 'bottom': '10px' });           
  showText.innerHTML = '<a href="javascript:ShowElement(\''+desc_name+'\', true)"><img src="'+resourcesBase+'Notepad.png" alt="Mostra testo"></a>';
           
  if ((resource.Video.length || resource.Photo.length || resource.Mesh.length) && resource.Text.length)
    pag.appendChild(showText);

  var innerText = "";
  var idx = 0;
  var desc_common = ((resource.Video.length || resource.Photo.length || resource.Mesh.length) ? '<div style="position: relative; right: 0px; top: 0px;"><a href="javascript:ShowElement(\''+desc_name+'\', false)"><img src="'+resourcesBase+'close.png" alt="Close"></a></div>' : '');

  var txtload = function (txt) {
    innerText += txt;
    if (resource.Text.length == idx)
      document.getElementById(desc_name).innerHTML = desc_common + innerText;
    else
      resourceTextLoadHTML(resource.Text[idx++], txtload);
  }

  if (resource.Text.length > 0)
    resourceTextLoadHTML(resource.Text[idx++], txtload);

  var desc = document.createElement('div');
  desc.setAttribute('id', desc_name);
  ConfigureStyle(desc, { 'position': 'absolute', 'left': '30px', 'top': '30px',
    'right': '120px', 'height': '90%', 'overflow': 'auto', 'padding': '25px', 'fontSize': '10pt',
    'fontFamily': 'Verdana, Arial, Helvetica, sans-serif',
    'backgroundColor': '#ffffff', 'borderWidth': 'thin', 'borderColor': '#000000', 'borderStyle': 'solid' });

  if (resource.Video.length || resource.Photo.length || resource.Mesh.length)
    desc.style.display = 'none';
           
           
  desc.innerHTML = desc_common + resource.Description;
           
  pag.appendChild(desc);
                      
  m.setContent(pag);
  m.show();
           
  // Handling of visible tabs
  if (!resource.Photo.length) {
    tab.hide('photo');
  }
  if (!resource.Video.length) {
    tab.hide('video');
  }
  if (!resource.Mesh.length) {
    tab.hide('mesh');
  }

  // Select content
  if (resource.Photo.length)
    PlayContent(pagnm, 'photo', resource.Photo[1], resource.Photo[2]);
  else if (resource.Video.length) {
    PlayContent(pagnm, 'video', resource.Video[1], '');
    tab.select('video');
  } else if (resource.Mesh.length) {
    PlayContent(pagnm, 'mesh', resource.Mesh[1], '');
    tab.select('mesh');
  }

  tab.onresize();
}

function ajaxLoad(url, response_fn) {
  var __http_request = false;
  if (window.XMLHttpRequest) { // Mozilla, Safari,...
	 __http_request = new XMLHttpRequest();
	 if (__http_request.overrideMimeType) {
		__http_request.overrideMimeType('text/xml');
	 }
  } else if (window.ActiveXObject) { // IE
	 try {
		__http_request = new ActiveXObject("Msxml2.XMLHTTP");
	 } catch (e) {
		try {
		   __http_request = new ActiveXObject("Microsoft.XMLHTTP");
		} catch (e) {}
	 }
  }
  if (!__http_request) {
	 alert('Cannot create XMLHTTP instance');
	 return false;
  }
  __http_request.onreadystatechange = function () {
    if (__http_request.readyState == 4) {
       response_fn(__http_request);
    }
  }
  __http_request.open('GET', url, true);
  __http_request.send(null);
}

function jsonLoad(url, response_fun) {
  var js = document.createElement("script");
  js.onload = function () {
    response_fun();
    var hd = document.getElementsByTagName("head").item(0);
    hd.removeChild(js);
  }
  js.onreadystatechange = function () {
    if (js.readyState=="loaded" || js.readyState=="complete") {
      response_fun();
      var hd = document.getElementsByTagName("head").item(0);
      hd.removeChild(js);
    }
  }
  js.setAttribute("type", "text/javascript");
  js.setAttribute("src", url);
  var hd = document.getElementsByTagName("head").item(0);
  hd.appendChild(js);
  return js;
}

function updateMapView(area, map, mapname, filter, center, zoom) {
  var throbber = document.getElementById("throbber4u");
  var finish = false;
  if (throbber) {
    var throbberanim = new Timeline();
    throbberanim.SetAt(0, AnimeJInterp.alpha(1000, 100, throbber, 1.0, 0.0));
    throbberanim.SetAt(1000, AnimeJInterp.alpha(1000, 100, throbber, 0.0, 1.0));
    throbberanim.OnEnd = function (d) { if (!finish) throbberanim.Run(); }
    throbberanim.Run();
  }
  map_loadcb[mapname] = function () {
    finish = true;
    if (center)
      map_animations[mapname].centerShapes(map);
    map_loadcb[mapname] = null;
  }
  var from = 0, count = 70;  
  map_animations[mapname] = new ResourceSet();
  map_resources[mapname] = {};

  if (typeof(center) != "boolean") {
    map.SetCenterAndZoom(center, zoom);
    map_animations[mapname].Invalidate();
    map_animations[mapname].updateMap(map);
  }
  
  var url = function() {
    var a = area != null ? "&area=" + area : "";
    var s = T4USource ? "&source=" + T4USource : "";
//    alert("/load-resources-ex.aspx?lang="+T4ULocale()+"&filter=" + escape(filter) + "&mapname=" + escape(mapname) + "&from="+from+"&count="+count+"&override=no&center=no" + a + s);
    return "/load-resources-ex.aspx?lang="+T4ULocale()+"&filter=" + escape(filter) + "&mapname=" + escape(mapname) + "&from="+from+"&count="+count+"&override=no&center=no" + a + s;
  }

  var onload = function () { from += count; if (!finish) jsonLoad(url(), onload); };
    
  jsonLoad(url(), onload);
}

function resourceTextLoadHTML(url, loaded, iscompany) {
    // Hack: when accessed from https IE for security reasons blocks http requests.
    // I assume that text is available at the same URL
    if ((/^https:/).test(document.location)) {
      url = url.replace(/^http:\//, "https:/");
    }
	ajaxLoad(
	  url, 
	  function (r) { 
		if (r.status == 200) {
		  var re_b = /<body[^>]*>([\s\S]*)<\/body>/i;
		  var re_t = /<title[^>]*>([\s\S]*)<\/title>[\s\S]*<\/body>/i;
		  var txt = r.responseText;
		  var a = txt.match(re_t);
		  var title = "";
		  if (a.length)
		    title = a[1];
		  a = txt.match(re_b);
		  if (a.length) {
			txt = a[1];
			if (iscompany)
  			  txt = txt.replace(/(<[^>]+)(?:style)=(?:[^\s>]+|'[^']*'|"[^"]*")([^>]*>)/gi, "$1$2");
  			else
  			  txt = txt.replace(/(<[^>]+)(?:style|class)=(?:[^\s>]+|'[^']*'|"[^"]*")([^>]*>)/gi, "$1$2");
			txt = txt.replace(/(<a\s)/gi, '$1target="_blank" ');
			txt = txt.replace(/<\/?span[^>]*>/gi, "");
			txt = txt.replace(/<\/?[\d\w]+:[\d\w][^>]*>/gi, "");
			loaded(txt, title);
		  }              
		}
	  });
}

function SelectCompanyTab(desc_name, tabs_name, idx) {
  var d = document.getElementById(desc_name);
  document.getElementById(tabs_name + '_' + d.SelectedTab).style.backgroundColor = "#ffffff";
  d.SelectedTab = idx;
  document.getElementById(tabs_name + '_' + d.SelectedTab).style.backgroundColor = "#AAAAAA";
  d.innerHTML = d.TextTabs[idx];
}

function CompanyBrowser(resource) {
  var m = new ModalOverlay();
           
  var pagnm = freshName('ContentPlayer');
  var pag = AbsBox('0px', '0px', '100%', '100%');
  pag.setAttribute('id', pagnm);           
           
  pag.Resource = resource;

  var tab = new TabPanel();
  ConfigureStyle(tab.TabPanel, { 'position': 'absolute', 'right': '0px', 'top': '32px', 'width': '120px', 'height': '95%' });
  
  var pagePlayer = document.createElement('div');
  ConfigureStyle(pagePlayer, { 'position': 'absolute', 'left': '10px', 'right': '120px', 'top': '10px', 'height': '90%', 'textAlign': 'center' });
  
  var title = document.createElement('div');
  title.style.width = '100%';
  title.innerHTML = '<p align="center" class="ContentBrowserTitle">'+resource.Title+'</p><p align="center" class="ContentBrowserSubTitle">'+(resource.Description.replace(/<.*?>/g, ""))+'</p>';
  
  pagePlayer.appendChild(title);
     
  var player = document.createElement('div');
  player.style.width = '100%';
                      
  pagePlayer.appendChild(player);
  
  pag.appendChild(pagePlayer);
  
  pag.Player = player;

  var i;
           
  for (i = 0; i < resource.Video.length; i+=2) {
    tab.Video.add(resource.Video[i], "javascript:PlayContent('" + pagnm + "', 'video', '" + resource.Video[i + 1] + "', '')");
  }
  for (i = 0; i < resource.Photo.length; i+=3)
    tab.Photo.add(resource.Photo[i], "javascript:PlayContent('" + pagnm + "', 'photo', '" + resource.Photo[i + 1] + "', '"+QuoteText(true, resource.Photo[i + 2])+"')");

  for (i = 0; i < resource.Mesh.length; i+=2)
    tab.Mesh.add(resource.Mesh[i], "javascript:PlayContent('" + pagnm + "', 'mesh', '" + resource.Mesh[i + 1] + "', '')");
           
  pag.appendChild(tab.TabPanel);
           
  var desc_name = freshName('ContentBrowser_Text');
  pag.CompanyBrowser = desc_name;

  var showText = document.createElement('div');
  showText.setAttribute('id', desc_name + "_showText");
  ConfigureStyle(showText, { 'position': 'absolute', 'left': '10px', 'bottom': '10px', 'display': 'none' });
  showText.innerHTML = '<a href="javascript:RestoreCompanyText(\''+pagnm+'\')"><img src="'+resourcesBase+'Notepad.png" alt="Mostra testo"></a>';

  pag.appendChild(showText);

  var tabsText = "|";
  var idx = 0;
  
  var tabs_name = freshName('ContentBrowser_TextTabs');
  var tabs = document.createElement('div');
  tabs.setAttribute('id', tabs_name);
  ConfigureStyle(tabs, { 'position': 'absolute', 'left': '30px', 'top': '60px', 'height': '22px',
     'padding': '0px', 'fontSize': '12pt', 'fontFamily': 'Palatino Linotype, Book Antiqua3, Palatino6, serif',
     'backgroundColor': '#ffffff', 'borderWidth': 'thin',
     'borderColor': '#000000', 'borderStyle': 'solid', 'borderBottomStyle': 'none' });
                      
  pag.CompanyBrowserTabs = tabs_name;
  pag.appendChild(tabs);
  

  var txtload = function (txt, title) {
    document.getElementById(desc_name).TextTabs[idx] = txt;
    tabsText += '<span id="'+(tabs_name + '_' + idx)+'"><a href="javascript:SelectCompanyTab(\''+desc_name+'\', \''+ tabs_name +'\', '+idx+')" style="text-decoration: none;">&nbsp;' + title + '&nbsp;</a></span>|';
    if (resource.Text.length == idx) {
      document.getElementById(tabs_name).innerHTML = tabsText;
      SelectCompanyTab(desc_name, tabs_name, 1);
    } else
      resourceTextLoadHTML(resource.Text[idx++], txtload, true);
  }

  if (resource.Text.length > 0)
    resourceTextLoadHTML(resource.Text[idx++], txtload, true);

  var desc = document.createElement('div');
  desc.setAttribute('id', desc_name);
  ConfigureStyle(desc, {
    'position': 'absolute',
  	'left': '30px', 'top': '82px', 'right': '120px', 'height': '80%',
    'overflow': 'auto', 'padding': '25px',
    'fontSize': '10pt', 'fontFamily': 'Verdana, Arial, Helvetica, sans-serif',
    'backgroundColor': '#ffffff',
    'borderWidth': 'thin', 'borderColor': '#000000', 'borderStyle': 'solid'
    });
  desc.TextTabs = {};
  desc.SelectedTab = 1;
           
  desc.innerHTML = resource.Description;
  
  if (!resource.Text.length)
    desc.style.display = 'none';

           
  pag.appendChild(desc);
                      
  m.setContent(pag);
  m.show();
           
  // Handling of visible tabs
  if (!resource.Photo.length) {
    tab.hide('photo');
  }
  if (!resource.Video.length) {
    tab.hide('video');
  }
  if (!resource.Mesh.length) {
    tab.hide('mesh');
  }
  tab.onresize();
}

// centra e zooma la mappa in base all'array di VELatLong passato come parametro
function CenterPoints(points)
{
  map.SetMapView(points);
}


// preso da MapWebPart.cs
        var bodyonload = window.onload;
        var map_maps = {};
        var map_inits = {};
        var map_animations = {};
        var map_resources = {};
        var map_loadcb = {};
        var loadmapdata = function (mapname, data, regions, paths, animations, override, center, notify) {
          if (override) {
            map_animations[mapname] = new ResourceSet();
            map_resources[mapname] = {};
          }
          var r = map_resources[mapname], p = map_animations[mapname], v, len = 0;
          for (v in data) {
            var item = data[v], k, tmp = new Resource();
            for (k in item.r)
              tmp[k] = item.r[k];
            r[v] = tmp;
            tmp = new GeoResource(item.a.LatLong);
            for (k in item.a)
              tmp[k] = item.a[k];
            p.add(v, tmp);
            len++;
          }
          if (animations && animations.length) {
            p._Animations = {};
            for (v in animations) {
              var d = animations[v].data, i;
              var an = new AnimationSteps();
              for (i in d) {
                var step = new AnimationStep(new GeoResource(d[i].loc), d[i].zoom, d[i].view);
                step.Span = d[i].timespan;
                step.Action = d[i].action;
                an.add(step);
              }
              p._Animations[v] = an;
            }
          }
          p._Regions = regions.length ? regions : p._Regions;
          p._Paths = paths.length ? paths : p._Paths;
          p.Invalidate();
          p.updateMap(map_maps[mapname]);
          if (center)
            p.centerShapes(map);
          if (notify && map_loadcb[mapname]) (map_loadcb[mapname])();
        }
        // meant for fixing the map
        var fixmap = false;
        var fixmapcback = function(mapname, before) {}
        window.onload = function () {
          for (mapname in map_inits) {
            if (fixmap || (navigator.userAgent+'').indexOf("MSIE") == -1) {
              document.getElementById(mapname).style.position = 'relative';
              //document.getElementById(mapname).parentNode.style.padding = '5px';
            }
            fixmapcback(mapname, true);
            map_maps[mapname] = GetMap(mapname);
            map_inits[mapname](map_maps[mapname]);
            fixmapcback(mapname, false);
          }
          bodyonload();
        }
