/* EFFETTO DI SELEZIONE DI UNA IMMAGINE TRAMITE CLICK SU ELENCO

  Questo effetto quando si ha una lista di immagini e si vuole che ne sia visibile solo una per volta in funzione della scelta fatta clickando su un insieme di oggetti
  
  Per utilizzarlo è necessario includere nello head del documento html l'istruzione
  
  <script type="text/javascript" src="click-and-view.js"></script>
<script type="text/javascript">
  // costruisce la relazione fra scelte del menu e immagini da visualizzare
  window.addEvent('load', function(){
    matches = [{'choice': 'choice1', 'viewable': 'images/img-home.jpg'}, 
                    {'choice': 'choice2', 'viewable': 'images/img-home2.jpg'}]; 
    cvm = new clickAndViewManager({'matches':matches, 'id_imageDiv1':'divImmagineSfondo'});
    cvm.exec();
  });
</script>

  nell'istruzione
    matches = [{'choice': 'choice1', 'viewable': 'img1'}, 
                    {'choice': 'choice2', 'viewable': 'img2'},
                    ...]; 
  le stringhe 'choiche1', 'choice2'... sono gli identificatori assegnati agli elementi che rappresentano le scelte, e le stringhe 'choiche1', 'choice2'... sono i nomi delle immagini da associare alle scelte; questa istruzione costruisce un array di coppie che collegano le scelte con le immagini da mostrare in base alla scelta effettuata
  
  nell'istruzione
    cvm = new clickAndViewManager({'matches':matches, 'id_imageDiv1':'divImmagineSfondo'});
  la stringa 'divImmagine' è l'identificatore assegnato al div destinato a contenere le immagini da visualizzare; se si vuole cambiare l'evento su cui cambiare l'immagine allora bisogno aggiungere una coppia del tipo 'event':'mouseover' alle opzioni passate al costruttore del clickAndViewManager

  Inoltre il codice HTML deve essere strutturato come segue perchè questo effetto funzioni:
  - gli elementi che rappresentano le scelte devono avere un id che viene utilizzato per costruire l'array che li associa alle rispettive immagini
  - deve essere presente un div
    <div id="divImmagineSfondo">
      <img src="img1">
    </div>
    tale che 'img1' è il nome della prima immagine da mostrare
*/

var clickAndViewManager = new Class({
  initialize: function(options){
    this.options = Object.extend({
      duration: 2000,
      event: 'click',
      transitionType: 'fadeInOut',
      z1: 100,
      z2: 99
      }, options ||  {});
    if (!$defined(this.options.id_imageDiv1)) {alert("clickAndVieManager::initialize - missing value for id_imageDiv1"); return(0);};
    if (!$defined(this.options.matches)) {alert("clickAndVieManager::initialize - missing value for matches"); return(0);};
    if (!$defined(this.options.fadeValue)) {this.options.fadeValue = 0.4;};
    if (!$defined(this.options.highlightSelected)) {this.options.highlightSelected = true};
    
    this.options.choiceElements = new Array();
    this.options.matches.each((function(match){
      this.options.choiceElements.include(match.choice);
    }).bind(this));
    this.options.currChoice = $(this.options.choiceElements['0']);
    this.options.prevChoice = this.options.currChoice;
  },
  
  initializeTransition: function(options) {
    if (options.transitionType == 'fadeInOut') return this.initializeFadeInOut(options);
    if (options.transitionType == 'horizontalSlide') return this.initializeHorizontalSlide(options);
  },
  
  initializeFadeInOut: function(options) { 
    if (!$defined(options.z1initial)) options.z1initial = 1;
    // setta style e proprietà del div
    options.imageDiv1.setStyles({'position':'absolute', 'z-index':options.z1initial, 'float':'left'});
    // costruisce un div uguale a imageDiv1 e lo inserisce dopo di questo
    imageDiv2 = options.imageDiv1.clone().injectAfter(options.imageDiv1);
    // setta style e proprietà del div
    imageDiv2.setStyles({'z-index':0});
    imageDiv2.setProperty('id', '_'+options.imageDiv1.getProperty('id'));
    var semaphore = options.semaphore;
    options.imageDiv1.addEvent('mouseenter', function(){options.semaphore.light = 'red'});
    options.imageDiv1.addEvent('mouseleave', function(){options.semaphore.light = 'green'});
    imageDiv2.addEvent('mouseenter', function(){light = 'red'});
    imageDiv2.addEvent('mouseleave', function(){light = 'green'});
    return initData = {imageDiv2:imageDiv2};
  },
  
  initializeHorizontalSlide: function(options) {
    // inizializza il verso di scorrimento
    if (!$defined(this.options.direction)) this.options.direction = 'left';
    options.imageDiv1.setStyles({'position':'absolute', 'left':0});
    // crea un div per contenere lo sliding
    slideContainer = new Element('div', {id:'slideContainer'});
    // inizializza le dimensioni del container a quelle dell'immagine contenuta nel div principale
    slideContainer.setStyles({
      'width': options.w,
      'height': options.h
    });
    slideContainer.setStyles({'overflow':'hidden', 'position':'relative'});
    slideContainer.injectBefore(options.imageDiv1);
    var semaphore = options.semaphore;
    slideContainer.addEvent('mouseenter', function(){semaphore.light = 'red'});
    slideContainer.addEvent('mouseleave', function(){semaphore.light = 'green'});
    // sposta il div principale nel container
    options.imageDiv1.injectInside(slideContainer);
    // costruisce un div uguale a imageDiv1 e lo inserisce dopo di questo
    imageDiv2 = options.imageDiv1.clone().injectInside(slideContainer);
    imageDiv2.setProperty('id', '_'+options.imageDiv1.getProperty('id'));
    if (this.options.direction == 'left') imageDiv2.setStyle('left', options.w);
    else imageDiv2.setStyle('left', (-1) * options.w);
    return initData = {imageDiv2:imageDiv2};
  },
  
  choseInOut: function(options) {
    if (options.transitionType == 'fadeInOut') return this.choseInOutFadeInOut(options);
    if (options.transitionType == 'horizontalSlide') return this.choseInOutHorizontalSlide(options);
  },
          
  choseInOutFadeInOut: function(options) {
    // recupera le immagini contenute nel div
    image_1 = options.imageDiv1.getElement('img');
    image_2 = options.imageDiv2.getElement('img');
    content_1 = options.imageDiv1.getElements('div');
    content_2 = options.imageDiv2.getElements('div');
    // sceglie di quale immagine va fatto il fade out e di quale il fade in
    if (image_1.getStyle('opacity') == 1) {
      result = {
        viewable:options.viewable,
        toBeFadedOut : image_1,
        toBeFadedOutContent : content_1,
        toBeFadedIn : image_2,
        toBeFadedInContent : content_2
      }
    }
    else {
      result = {
        viewable:options.viewable,
        toBeFadedOut : image_2,
        toBeFadedOutContent : content_2,
        toBeFadedIn : image_1,
        toBeFadedInContent : content_1
      }
    }
    
    return(result);
  },
  
  choseInOutHorizontalSlide: function(options) {
    if (options.imageDiv1.getStyle('left') == '0px') {
      result = {
        viewable:options.viewable,
        toBeFadedOut: options.imageDiv1,
        toBeFadedIn: options.imageDiv2
      }
    }
    else {
      result = {
        viewable:options.viewable,
        toBeFadedOut: options.imageDiv2,
        toBeFadedIn: options.imageDiv1
      }
    }
    return(result);
  },
  
  applyTransition: function(options) {
    if (options.transitionType == 'fadeInOut') this.applyFadeInOut(options);
    if (options.transitionType == 'horizontalSlide') this.applyHorizontalSlide(options);
  },
  
  applyFadeInOut: function(options) {
    // fade in della vecchia immagine
    fadeImageOut({element:options.toBeFadedOut, duration: options.duration});
    options.toBeFadedOutContent.each(function(content){
      if ($defined(content)) 
        fadeImageOut({element:content, duration: options.duration});
    });
    if ($defined(options.h)) options.toBeFadedOut.getParent().setStyle('height', '0px');
    if ($defined(options.w)) options.toBeFadedOut.getParent().setStyle('width', '0px');
    // setta lo z-index del div dell'immagine
    options.toBeFadedOut.getParent().setStyle('z-index',options.z2);
    // cambia l'immagine
    options.toBeFadedIn.setProperty('src', options.loaderImage);
    // fade in della immagine del loader
    fadeImageIn({element:options.toBeFadedIn, duration: options.duration});
    if ($defined(options.h)) options.toBeFadedIn.getParent().setStyle('height', options.h+'px');
    if ($defined(options.w)) options.toBeFadedIn.getParent().setStyle('width', options.w+'px');
    // setta lo z-index del div dell'immagine
    options.toBeFadedIn.getParent().setStyle('z-index',options.z1);
    // carica l'immagine e ne fa il fadein
    fadeIn = function(fadeInOptions) {
      fadeImageOut({element:fadeInOptions.toBeFadedIn, duration: 0});
      // cambia l'immagine
      fadeInOptions.toBeFadedIn.setProperty('src', fadeInOptions.viewable);
      // fade in della nuova immagine
      fadeImageIn({element:fadeInOptions.toBeFadedIn, duration: fadeInOptions.duration});
      fadeInOptions.toBeFadedInContent.each(function(content){
        if ($defined(content)) 
          fadeImageIn({element:content, duration: fadeInOptions.duration});
      });
      // setta lo z-index del div dell'immagine
      fadeInOptions.toBeFadedIn.getParent().setStyle('z-index',fadeInOptions.z1);
      fadeInOptions.toBeFadedIn.getParent().setStyle('opacity',1);
      // alla fine dell'effetto viene messo il semaforo a verde
      (function(){fadeInOptions.semaphore.light = 'green'}).delay(fadeInOptions.disableTime);
    };
    new Asset.images(options.viewable, {
      onComplete: fadeIn.pass(options)
    });
  },

  applyHorizontalSlide: function(options) {
    // aggiusta la posizione dell'elemento da fare entrare in base alla direzione
    if (options.direction == 'left') options.toBeFadedIn.setStyle('left', options.w);
    else if (options.direction == 'right') options.toBeFadedIn.setStyle('left', (-1) * options.w);
    else return; // se non nè e destra nè sinistra non fa nulla
    // visualizza la nuova immagine
    options.toBeFadedIn.getElement('img').setProperty('src', options.viewable);
    slideImageIn({element:options.toBeFadedIn, duration:options.duration-100, w: options.w, direction: options.direction});
    slideImageOut({element:options.toBeFadedOut, duration:options.duration-100, w: options.w, direction: options.direction});
    if (this.options.direction == 'left') (function(){options.toBeFadedOut.setStyle('left', options.w)}).delay(options.duration);
    else (function(){options.toBeFadedOut.setStyle('left', (-1) * options.w)}).delay(options.duration);
  },
  
  exec: function(){
    if (!$defined(this.options.id_imageDiv1)) {alert("clickAndVieManager::initialize - missing value for id_imageDiv1"); return(0);};
    if (!$defined(this.options.matches)) {alert("clickAndVieManager::initialize - missing value for matches"); return(0);};
    
    // la funzione per fare il fade out di tutti gli elementi di scelta tranne quello selezionato
    var fadeAllOut = function(options){
      if (!$defined(options.fadeValue)) options.fadeValue = 0;
      var fadeValue = options.fadeValue;
      var notToBeFaded = options.notToBeFaded;
      var duration = options.duration;
      options.elements.each(function(elementid){
        toBeFaded = $(elementid);
        if (toBeFaded && notToBeFaded) {
          if (toBeFaded.getProperty('id') != notToBeFaded.getProperty('id')) {
            fadeImageOut({element:toBeFaded, duration: duration, fadeValue: fadeValue});
          }
        }
      });
    };
    
    // fa il fadeout degli elementi di scelta
    if (this.options.highlightSelected) {
      fadeAllOut({notToBeFaded:$(this.options.choiceElements[0]), elements:this.options.choiceElements, fadeValue:this.options.fadeValue, duration: this.options.duration});
    }

    // recupera il div che corrisponde all'id id_imageDiv1
    imageDiv1 = $(this.options.id_imageDiv1);
    if ($defined(imageDiv1)) {
      this.options = Object.extend({imageDiv1:imageDiv1}, this.options);
      
      // inizializza la transizione
      initData = this.initializeTransition(this.options);
      this.options = Object.extend(initData, this.options);
  
      // associa alle choices l'evento per gestire l'immagine associata
      this.options.matches.each((function(couple){
        choiceid = couple.choice;
        var choice = $(choiceid);
        var viewable = couple.viewable;
        
        // aggiunge il listener al click sull'elemento
        if (choice) {
          choice.addEvent(this.options.event, (function(){
            if (this.options.semaphore.light != 'green') {
              if (!this.options.semaphore.activeWaiting) return true;
            }
            
            // registra quale scelta è stata fatta ora e quale era stata fatta prima
            this.options.prevChoice = this.options.currChoice;
            this.options.currChoice = choice;
            
            if (this.options.semaphoreActor.light == 'red') {
              this.options.semaphoreActor.light == 'manual';
              return true;
            }
            this.options.semaphore.light = 'red';
  
            // calcola i dati necessari a effettuare la transizione
            inOutData = this.choseInOut(Object.extend({viewable:viewable}, this.options));
            
            // esegue l'eventuale codice che deve essere eseguito prima di ogni transizione
            if (this.options.execBefore) this.options = Object.extend(this.options, execBefore(Object.extend(inOutData, this.options)));
            
            // applica la transizione
            this.applyTransition(Object.extend(inOutData, this.options));
            
            if (this.options.highlightSelected) {
              // fa il fade out di tutti gli elementi di scelta
              fadeAllOut({notToBeFaded:choice, elements:this.options.choiceElements, fadeValue:this.options.fadeValue, duration: this.options.duration});
              // fa il fade in dell'elemento di scelta selezionato
              fadeImageIn({element:choice, dontHide:true, duration:this.options.duration});
            }
            
            // alla fine dell'effetto viene messo il semaforo a verde
            (function(){this.options.semaphore.light = 'green'}).bind(this).delay(this.options.disableTime);
            this.options.semaphoreActor.light = 'manual';
          }).bind(this));
        }
      }).bind(this));
    }
  }

});


