/*
Codice per la gestione degli eventi in toscana4u

è una estensione del codice per le risorse, 
è basato (copia e incolla) su galmap e sul codice
generato dalla webpart definita in GalBaseType.

dialoga con load-events.aspx 
(che contiene una webpart che produce json
con gli eventi)
*/

RegisterScript('t4uEvents', 1, 'toscana4u events');
Require([ 'AnimeJ', { Name: 'AnimeJ', Version: 1 } ]);
Require([ 't4uStrings' ]);


var map_events = {};
var map_events_animations = {};

var EventsUpdateFunc;

// equivalente a GeoResource
function EventResource(latlong) {
  this.LatLong = latlong;
  this.Url = '';
  this.Title = '';
  this.Description = '';
  this.Icon = null;
  this.StartTime = '';
  this.EndTime = '';
           
  this.createPin = function (id) {
	var pin = new VEShape(VEShapeType.Pushpin, this.LatLong);
	if (this.Icon != null)
	    pin.SetCustomIcon(this.Icon == null ? iconurlbase + (id + 1) + iconurlext : this.Icon);
    pin.SetTitle(this.Title);
    var desc = "<div><b>" + strings['events_from'] + "</b>: " + dateFormat(this.StartTime, strings['events_dateformat']) + "</div>";
    desc += "<div><b>" + strings['events_to'] + "</b>: " + dateFormat(this.EndTime, strings['events_dateformat']) + "</div>" ;
    desc += this.Description;
    pin.SetDescription(desc);
    return pin;
  }
}

// Radius is assumed in latlong coord, use ComputeClusterRadius.
function EventCluster(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');
    pin.SetCustomIcon('/icone/eventi-cluster.png');
    if (strings && metacategories && this.length > 20 && (map.GetZoomLevel() < 14) ) {
      var groups = {};
      for (i = 0; i < this.length; i++) {
        o = data[this[i]];
        var cat = categories2metacategories[o.Category];
        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=""/>';
        d += '<a href="javascript:CenterPoints([new VELatLong('+min.Latitude+', '+min.Longitude+'), new VELatLong('+max.Latitude+', '+max.Longitude+')])">' + (strings[metacategories[cat].label]);
        d += '</a> ('+ a.length +')<br/>';
      }
    } else {
      for (i = 0; i < this.length; i++) {
        o = data[this[i]];
        // per cambiare il comportamento del click su un elemento del cluster cambia qui:
        var pinurl = o.Url
        // GetShapeByID
        //var pinurl = "javascript:map.ShowInfoBox("+o+")";
        d += '<img src="'+ o.Icon +'" alt=""/> <a href="' + pinurl + '">' + 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;
  }
}


//equivalente a ResourceSet
function EventsSet() {
  this.length = 0;
  this.filter = null;
  this.filter_utc = 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 EventCluster(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) {
    if (this.filter == null)
      return true;
    var item = this.data[idx];
    var start_utc = Date.UTC(item.StartTime.getFullYear(),item.StartTime.getMonth(),item.StartTime.getDay(),item.StartTime.getHours(),item.StartTime.getMinutes(),item.StartTime.getSeconds());
    var end_utc = Date.UTC(item.EndTime.getFullYear(),item.EndTime.getMonth(),item.EndTime.getDay(),item.EndTime.getHours(),item.EndTime.getMinutes(),item.EndTime.getSeconds());
    //Debug("item:" + this.filter_utc + " start:" + start_utc + " end:" + end_utc);
    return (start_utc < this.filter_utc) && (end_utc > this.filter_utc);
  }
  
  this.setFilter = function(map, filter) {
    this.filter = filter;
    this.filter_utc = Date.UTC(filter.getFullYear(),filter.getMonth(),filter.getDay(),filter.getHours(),filter.getMinutes(),filter.getSeconds());
    invalidate = true;
    this.updateMap(map);
  }
  
  this.clearFilter = function (map) {
    this.filter = null;
    this.filter_utc = null;
    invalidate = true;
    this.updateMap(map);
  }
  
  this.centerShapes = function (map) {
    if (cmap == null) return;
    var a = new Array(), i;
    for (i in this.data)
      a.push(this.data[i].LatLong);
    map.SetMapView(a);
    if (map.GetZoomLevel() > 17)
      map.SetZoomLevel(17);
  }
  
  this.ApplyFilter = function(map)
  {
    var events = new Array();
    for (var v in this.data)
    {
      if (this.checkFilter(v))
        events.push(this.data[v]);
    }
    return events;
  }
  
  this.updateMap = function(map) {
    if (!map.t4uEventsLayer) {
      map.t4uEventsLayer = new VEShapeLayer();
      map.AddShapeLayer(map.t4uEventsLayer);
      map.t4uEventsLayer.visible = true;
    }

    var i, obj = this;
    map.t4uEventsLayer.DeleteAllShapes();
    
   if (invalidate || cmap == null) {
      czlvl = map.GetZoomLevel();
      var factor = 1.0;
//      cmap = this.ApplyFilter(map);
      cmap = this.clusterMap(map, factor * ComputeClusterRadius(map, 16));
      invalidate = false;
    }
    
    if (first) {
      
//      var clusterOptions = new VEClusteringOptions();  
//      clusterOptions.Callback = ClusteringCallback;  
//      map.t4uEventsLayer.SetClusteringConfiguration(VEClusteringType.Grid, clusterOptions); 
//      map.t4uEventsLayer.SetClusteringConfiguration(EventClusteringFunction, clusterOptions);
	  EventsUpdateFunc = 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 {
            var t = new Timeline();
            t.SetAt(100, new FunctionCallback(t, f));
            t.Run();
          }
        }

      map.AttachEvent("onendzoom", EventsUpdateFunc );
      map.AttachEvent("onclick",
        function (e) {
          if (e.elementID)
             map.ShowInfoBox(map.GetShapeByID(e.elementID));
        }
      )
      first = false;
    }

    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));
      }
    }
    
//    for (i = 0; i < cmap.length; i++) {
//      shapes.push(cmap[i].createPin(i));
//    }
    map.t4uEventsLayer.AddShape(shapes);
//    map.t4uEventsLayer.SetClusteringConfiguration(VEClusteringType.Grid);
//    map.t4uEventsLayer.SetClusteringConfiguration(EventClusteringFunction);
    
   }
}

// NON USATA!!!
function ClusteringCallback(clusters) {  
    //The function specified in the Callback must take an array of VEClusterSpecification Class objects.  
    try {  
        if (clusters != null) {  
            for (var i = 0; i < clusters.length; i++) {  
                //VEClusterSpecification, http://msdn.microsoft.com/en-us/library/cc966730.aspx  
                //this has an array of your shapes that have been clustered .Shapes                  
                var cluster = clusters[i];  
 
                //VEClusterSpecification.GetClusterShape();  
                //returns:A VEShape Class representing the pushpin cluster.   
                //Returns null if a VEClusterSpecification object was returned from the VEShapeLayer.GetClusteredShapes Method.  
                var clusterShape = clusters[i].GetClusterShape();  
 
                var description = "";  
                for (var s = 0; s < cluster.Shapes.length; s++) {
                    var shape = cluster.Shapes[s];  
                    
                    description += "<br/><a href='javascript:ShowPin(\"" + shape.GetID() + "\")'>" + shape.Title + "</a>";  
                }  
                //add back to the cluster shape  
                clusterShape.SetDescription(description);  
            }  
        }  
    } catch (e) { alert(e.message); }  
} 

function ShowPin(pinID) {  
    var pin = map.GetShapeByID(pinID);  
    if (pin != null)  
        map.ShowInfoBox(pin);  
}

// NON USATA!!!
var EventClusteringFunction = function ( shapeLayer )
{
  var ris = new Array();
  var test1 = new VEClusterSpecification();
  for (var i = 0; i<shapeLayer.GetShapeCount(); i++)
//  for (var i = 0; i<2; i++)
  {
  	test1.Shapes.push(shapeLayer.GetShapeByIndex(i));
  }
//  test1.GetClusterShape().SetTitle("ciao");
//  var shape = test1.GetClusterShape();
  alert(shapeLayer.GetShapeCount());
  
  ris.push(test1);
  return ris;
}

// equivalente a loadmapresources
// definita nella webpart in GalBaseType
var loadmapevents = function (mapname, data, center) {
          map_events[mapname] = {};
          map_events_animations[mapname] = new EventsSet();
          var r = map_events[mapname], p = map_events_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 EventResource(item.a.LatLong);
            for (k in item.a)
              tmp[k] = item.a[k];
            p.add(v, tmp);
            len++;
          }
          p.Invalidate();
          p.updateMap(map_maps[mapname]);
          if (center)
            p.centerShapes(map);
        }

// equivalente a ContentBrowser
function EventBrowser(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';
  
  var dates = "<b>" + strings['events_from'] + "</b>: " + dateFormat(resource.StartTime, strings['events_dateformat']) + "<br/>";
  dates += "<b>" + strings['events_to'] + "</b>: " + dateFormat(resource.EndTime, strings['events_dateformat']) + "<br/>" ;
           
  desc.innerHTML = dates + 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();
}

// funzione chiamata per aggiornare gli eventi
function updateEvents(area, map, mapname, filter, center, zoom)
{
  var events_url = function() {
//    alert("/load-resources.aspx?filter=" + filter + "&mapname=" + mapname + "&from="+from+"&count="+count+"&override=no&center=no");
    var a = area != null ? "&area=" + area : "";
    var s = T4USource ? "&source=" + T4USource : "";
    return "/load-events.aspx?lang="+T4ULocale()+"&filter=" + escape(filter) + "&mapname=" + escape(mapname) + "&center=no" + a + s;
  }

  var onload = function () {  };
    
  jsonLoad(events_url(), onload);
}

// mostra/nasconde le risorse di t4u
function t4uResourcesVisible(b)
{
  map.t4uShapesLayer.visible = b;
  if (b)
  {
    var e = {
      "zoomLevel" : map.GetZoomLevel()
    }
    updateFunc(e);
    map.t4uShapesLayer.Show();
  }
  else
    map.t4uShapesLayer.Hide();  
}

// mostra/nasconde gli eventi
function t4uEventsVisible(b)
{
  map.t4uEventsLayer.visible = b;
  if (b)
  {
    var e = {
      "zoomLevel" : map.GetZoomLevel()
    }
    EventsUpdateFunc(e);
    map.t4uEventsLayer.Show();
  }
  else
    map.t4uEventsLayer.Hide();  
}

// imposta il filtro.. il filtro è una istanza di Date()
// filtro = eventi attivi in quella data e ora
function t4uEventsFilter(data)
{
  map_events_animations[mapname].setFilter(map, data);
}

// cancella il filtro
function t4uCleanEventsFilter()
{
  map_events_animations[mapname].clearFilter(map);
}

var events_loaded = false;

function SetResourcesVisible(v)
{
  var events_showResources = document.getElementById("events_showResources");
  events_showResources.checked = v;
  t4uResourcesVisible(v);
}

function SetEventsVisible(v)
{
  var events_showEvents = document.getElementById("events_showEvents");
  events_showEvents.checked = v;
  if (v)
  {
    if(events_loaded)
    {
      t4uEventsVisible(true);
    } else
    {
      updateEvents(null, map, map_name, '', true);
    }
  }
  else
  {
    t4uEventsVisible(false);
  }
}

function EventsLoad()
{
  var events_showEvents = document.getElementById("events_showEvents");
  SetEventsVisible(events_showEvents.checked);
  SetResourcesVisible(!events_showEvents.checked);
}

function EventsShowResources()
{
  var events_showResources = document.getElementById("events_showResources");
  if (events_showResources.checked)
  {
    SetResourcesVisible(true);
  } else
  {
    SetResourcesVisible(false);
    SetEventsVisible(true);
  }
}

function EventsTab()
{
  this.Render = function()
  {
    var response = "<div>";
    response += "<input type=\"checkbox\" id=\"events_showEvents\" onclick=\"EventsLoad()\"/>" + strings['events_show'];
    response += " - <input type=\"checkbox\" id=\"events_showResources\" checked=\"true\" onclick=\"EventsShowResources()\"/>" + strings['events_resources_show'];
/*	response += "<br><a href=\"javascript:t4uEventsFilter(new Date(2008,12,31,22,0,0))\">imposta filtro capodanno</a> ";
	response += "<a href=\"javascript:t4uEventsFilter(new Date(2009,8,15,15,0,0))\">imposta filtro ferragosto</a> ";
	response += "<a href=\"javascript:t4uCleanEventsFilter()\">annulla filtro</a> ";
*/
	response += "</div>";
	response += "<div>" + strings['evento_disclamer_pos'] + "</div>";

    return response;
  }
}

function lz(numero, cifre) {
	n = String(numero);
	while (n.length<cifre) { 
		n="0"+n 
	}
	return n;
}
function dateFormat(data, formato) { 
// (c) br1 - 2002 
 
	var giorni = new Array("Domenica","Lunedì","Martedì","Mercoledì","Giovedì","Venerdì","Sabato");
	var mesi = new Array("Gennaio","Febbraio","marzo","Aprile","Maggio","Giugno","Luglio","Agosto","Settembre","Ottobre","Novembre","Dicembre");
 
// preparo la data...  verificare di passarla corretta!
	var adesso = new Date(data); 
	var anno = adesso.getFullYear();
	var mese = adesso.getMonth()+1;
	var giorno = adesso.getDate();
	var settim = adesso.getDay()
	var ore = adesso.getHours()
	var minuti = adesso.getMinutes()
	var secondi = adesso.getSeconds()
 
// preparo la stringa di risposta
	var rVal = '';
 
	if (formato.length==0) { 
// assenza del secondo parametro
		return String(adesso); 
	} else {
 
	// inizio loop
		while (formato.length>0) {
 
	// verifico se c'e' qualche separatore e lo aggiungo
			while (formato.length>0 && String("ymdphnst").indexOf(formato.charAt(0).toLowerCase())<0) {
				rVal += formato.charAt(0);
				formato = formato.substr(1);
			}
 
 
	// Separo il gruppo
			if (formato.length>0) {
				ff = formato.charAt(0);
				formato = formato.substr(1);
				while (formato.length>0 && formato.charAt(0).toLowerCase()==ff.charAt(0).toLowerCase()) {
					ff += formato.charAt(0);
					formato = formato.substr(1);
				}
 
	// espando il formato nella stringa corrispondente
				ff = ff.toLowerCase();	 // operazione preliminare... tutto in minuscolo
				switch (ff) 	{ 
					case "yy" : 
						rVal += String(anno).substr(2); 
						break; 
					case "yyyy" : 
						rVal += String(anno); 
						break; 
					case "m" : 
						rVal += String(mese); 
						break; 
					case "mm" : 
						rVal += lz(mese,2);
						break; 
					case "mmm" : 
						rVal += mesi[mese-1].substr(0,3);
						break; 
					case "mmmm" : 
						rVal += mesi[mese-1];
						break; 
					case "d" : 
						rVal += String(giorno); 
						break; 
					case "dd" : 
						rVal += lz(giorno,2); 
						break; 
					case "ddd" : 
						rVal += giorni[settim].substr(0,3);
						break; 
					case "dddd" : 
						rVal += giorni[settim];
						break; 
					case "p" : 
						var inizio = new Date(anno, 0, 0); 
						rVal += Math.floor((adesso - inizio) / 86400000);
						break; 
					case "ppp" : 
						var inizio = new Date(anno, 0, 0); 
						rVal += lz(Math.floor((adesso - inizio) / 86400000),3);
						break; 
					case "h" : 
						rVal += String(ore); 
						break; 
					case "hh" : 
						rVal += lz(ore,2); 
						break; 
					case "n" : 
						rVal += String(minuti); 
						break; 
					case "nn" : 
						rVal += lz(minuti,2); 
						break; 
					case "s" : 
						rVal += String(secondi); 
						break; 
					case "ss" : 
						rVal += lz(secondi,2); 
						break; 
					case "t" : 
						rVal += lz(ore,2)+":"+lz(minuti,2)+":"+lz(secondi,2); 
						break; 
					default :  // il numero dei caratteri del formato non e' permesso
						rVal += ff.replace(/./gi,"?");
				} 
 
			}
 
		} // fine loop principale
 
		return rVal;
	}
} 