/*
 *  Classe MAHSCore
 */

/* 
 * Questa classe permette di gestire gli eventi del DOM e le classi dei vari componenti del DOM.
 *
 * @author Antonio Bencivenga <a.bencivenga@mahs.it>, Marco Giammarini <m.giammarini@mahs.it>
 * @version 1.0.0
 * @copyright 2009 - MAHS di Antonio Bencivenga - www.mahs.it  
 * @package mahsJS/mahsJSBase
 */

var MAHSCore = {};

// W3C DOM 2 Events model
if (document.addEventListener)
{
  /*
   * Metodo che permette di aggiungere un listener per un determinato evento (W3C DOM 2 Events model).
   *
   * @param target L'oggetto da cui deve provenire l'evento.
   * @param type Il tipo di evento.
   * @param listener Il nome della funzione che dovrà gestire l'evento.
   */
  MAHSCore.addEventListener = function(target, type, listener)
  {
    target.addEventListener(type, listener, false);
  };

  /*
   * Metodo che permette di eliminare un listener per un determinato evento (W3C DOM 2 Events model).
   *
   * @param target L'oggetto da cui deve provenire l'evento.
   * @param type Il tipo di evento.
   * @param listener Il nome della funzione che dovrà gestire l'evento.
   */
  MAHSCore.removeEventListener = function(target, type, listener)
  {
    target.removeEventListener(type, listener, false);
  };

  /*
   * Metodo che permette di eliminare un determinato evento (W3C DOM 2 Events model).
   *
   * @param event L'evento che deve essere bloccato.
   */
  MAHSCore.preventDefault = function(event)
  {
    event.preventDefault();
  };

  /*
   * Metodo che permette di fermare la propagazione di un determinato evento (W3C DOM 2 Events model).
   *
   * @param event L'evento che deve essere bloccato.
   */
  MAHSCore.stopPropagation = function(event)
  {
    event.stopPropagation();
  };
} 
// Internet Explorer Events model
else if (document.attachEvent)
{
  /*
   * Metodo che permette di aggiungere un listener per un determinato evento (Internet Explorer Events model).
   *
   * @param target L'oggetto da cui deve provenire l'evento.
   * @param type Il tipo di evento.
   * @param listener Il nome della funzione che dovrà gestire l'evento.
   */
  MAHSCore.addEventListener = function(target, type, listener)
  {
    // Viene evitato che si aggiunga due volte lo stesso listener
    // in quanto DOM 2 Events ignora duplicati come questo.
    if (MAHSCore._findListener(target, type, listener) != -1) return;

    // Questa funzione chiama i listener come metodi dell'oggetto a cui si riferiscono
    // in uno dei due modi, dipendentemente da quale versione di IE viene supportata,
    // e gli passa l'evento globale come un argomento.
    var listener2 = function()
    {
      var event = window.event;

      if (Function.prototype.call)
      {
        listener.call(target, event);
      }
      else
      {
        target._currentListener = listener;
        target._currentListener(event);
        target._currentListener = null;
      }
    };

    // Aggiungo listener2 usando il metodo attachEvent di IE.
    target.attachEvent("on" + type, listener2);

    // Viene creato un oggetto per descrivere il listener
    // che verrà cancellato in seguito.
    var listenerRecord =
    {
      target: target,
      type: type,
      listener: listener,
      listener2: listener2
    };

    // Viene preso un riferimento all'oggetto window che contiene il target.
    var targetDocument = target.document || target;
    var targetWindow = targetDocument.parentWindow;

    // Viene creato un id univoco  per questo listener.
    var listenerId = "l" + MAHSCore._listenerCounter++;

    // Viene memorizzato l'oggetto creato prima nel window object.
    if (!targetWindow._allListeners) targetWindow._allListeners = {};
    targetWindow._allListeners[listenerId] = listenerRecord;

    // Viene memorizzato l'ID nel target.
    if (!target._listeners) target._listeners = [];
    target._listeners[target._listeners.length] = listenerId;

    // Viene settato MAHSCore._removeAllListeners per cancellare tutti i listener
    // durante l'evento onunload.
    if (!targetWindow._unloadListenerAdded)
    {
      targetWindow._unloadListenerAdded = true;
      targetWindow.attachEvent("onunload", MAHSCore._removeAllListeners);
    }
  };

  /*
   * Metodo che permette di eliminare un listener per un determinato evento (Internet Explorer Events model).
   *
   * @param target L'oggetto da cui deve provenire l'evento.
   * @param type Il tipo di evento.
   * @param listener Il nome della funzione che dovrà gestire l'evento.
   */
  MAHSCore.removeEventListener = function(target, type, listener)
  {
    // Controllo se il listener è attualmente associato al target.
    var listenerIndex = MAHSCore._findListener(target, type, listener);
    if (listenerIndex == -1) return;

    // Viene preso un riferimento all'oggetto window che contiene il target.
    var targetDocument = target.document || target;
    var targetWindow = targetDocument.parentWindow;

    // Ottengo il record del listener dalla window object.
    var listenerId = target._listeners[listenerIndex];
    var listenerRecord = targetWindow._allListeners[listenerId];

    // Rimuovo il listener e il suo id dal target.
    target.detachEvent("on" + type, listenerRecord.listener2);
    target._listeners.splice(listenerIndex, 1);

    // Rimuovo il record del listener dalla window object.
    delete targetWindow._allListeners[listenerId];
  };

  /*
   * Metodo che permette di eliminare un determinato evento (Internet Explorer Events model).
   *
   * @param event L'evento che deve essere bloccato.
   */
  MAHSCore.preventDefault = function(event)
  {
    event.returnValue = false;
  };

  /*
   * Metodo che permette di fermare la propagazione di un determinato evento (Internet Explorer Events model).
   *
   * @param event L'evento che deve essere bloccato.
   */
  MAHSCore.stopPropagation = function(event)
  {
    event.cancelBubble = true;
  };

  /*
   * Metodo privato per cercare se un evento associato ad un oggetto ha già un listener (Internet Explorer Events model).
   *
   * @param target L'oggetto da cui deve provenire l'evento.
   * @param type Il tipo di evento.
   * @param listener Il nome della funzione che dovrà gestire l'evento.
   */
  MAHSCore._findListener = function(target, type, listener)
  {
    // Viene prelevato un array contenente gli id dei listener aggiunti al target.
    var listeners = target._listeners;
    if (!listeners) return -1;

    // Viene preso un riferimento all'oggetto window che contiene il target.
    var targetDocument = target.document || target;
    var targetWindow = targetDocument.parentWindow;

    // Viene cercato all'indietro il listener.
    for (var i = listeners.length - 1; i >= 0; i--)
    {
      // Si prende l'id del listener
      var listenerId = listeners[i];

      // Viene prelevato il record del listener dalla window object
      var listenerRecord = targetWindow._allListeners[listenerId];

      // Viene comparato type e listener con il record appena prelevato.
      // Se sono uguali viene restituito l'indice del for.
      if (listenerRecord.type == type && listenerRecord.listener == listener)
      {
        return i;
      }
    }
    return -1;
  };

  /*
   * Metodo privato per rimuovere tutti i listener durante l'evento onunload (Internet Explorer Events model).
   */
  MAHSCore._removeAllListeners = function()
  {
    var targetWindow = this;

    for (id in targetWindow._allListeners)
    {
      var listenerRecord = targetWindow._allListeners[id];
      listenerRecord.target.detachEvent(
          "on" + listenerRecord.type, listenerRecord.listener2);
      delete targetWindow._allListeners[id];
    }
  };

  MAHSCore._listenerCounter = 0;
}

/*
 * Metodo che permette di trovare all'interno di documento una serie di oggetti che hanno la stessa classe.
 *
 * @param theClaass Stringa contenente il nome della classe.
 * @return L'array contenete gli elementi che hanno per classe quella cercata.
 */
MAHSCore.getElementsByClass = function(theClass)
{
  var elementArray = [];

  // Viene costruito un array con tutti gli elementi del documento.
  if (document.all)
  {
    elementArray = document.all;
  }
  else
  {
    elementArray = document.getElementsByTagName("*");
  }

  var matchedArray = [];
  // Viene creata l'espressione regolare per cercare il nome della classe.
  var pattern = new RegExp("(^| )" + theClass + "( |$)");

  // Viene applicata la regola a tutti gli elementi del documento.
  for (var i = 0; i < elementArray.length; i++)
  {
    if (pattern.test(elementArray[i].className))
    {
      // Quando la regola viene rispettata, l'elemento viene aggiunto ad un nuovo array.
      matchedArray[matchedArray.length] = elementArray[i];
    }
  }

  return matchedArray;
};

/*
 * Metodo che permette di aggiungere una classe ad un elemento.
 *
 * @param target L'oggetto a cui si vuole aggiungere la classe.
 * @param theClaass Stringa contenente il nome della classe.
 */
MAHSCore.addClass = function(target, theClass)
{
  // Viene controllato se l'oggetto ha già la classe indicata.
  if (!MAHSCore.hasClass(target, theClass))
  {
    // Si aggiunge la classe.
    if (target.className == "")
    {
      target.className = theClass;
    }
    else
    {
      target.className += " " + theClass;
    }
  }
};

/*
 * Metodo che permette di controllare se un elemento ha una classe.
 *
 * @param target L'oggetto in cui si vuole controllare la presenza della classe.
 * @param theClaass Stringa contenente il nome della classe.
 * @return true se la classe è presente.
 */
MAHSCore.hasClass = function(target, theClass)
{
  var pattern = new RegExp("(^| )" + theClass + "( |$)");

  if (pattern.test(target.className))
  {
    return true;
  }

  return false;
};

/*
 * Metodo che permette di rimuovere una classe ad un elemento.
 *
 * @param target L'oggetto a cui si vuole rimuovere la classe.
 * @param theClaass Stringa contenente il nome della classe.
 */
MAHSCore.removeClass = function(target, theClass)
{
  var pattern = new RegExp("(^| )" + theClass + "( |$)");

  target.className = target.className.replace(pattern, "$1");
  target.className = target.className.replace(/ $/, "");// ????
};

/*
 *  
 */
MAHSCore.getComputedStyle = function(element, styleProperty)
{
  var computedStyle = null;

  if (typeof element.currentStyle != "undefined")
  {
    computedStyle = element.currentStyle;
  }
  else
  {
    computedStyle = document.defaultView.getComputedStyle(element, null);
  }

  return computedStyle[styleProperty];
};

/*
 * Metodo che permette di attivare JS solo quando la pagina è stata caricata.
 *
 * @param runnable Oggetto che deve essere mandato in esecuzione.
 */
MAHSCore.start = function(runnable)
{
  MAHSCore.addEventListener(window, "load", runnable.init);
};

