var Apibubble = Class.create();
Apibubble.prototype = {
	initialize: function() {
	  this.name = arguments[0];
	  this.x = 0;
	  this.y = 0;
    this.pattern = '.source_rater';
    this.source_pattern = '.bubble_rater';
    this.bubble = -2;
    this.oldBubble = -1;
    this.current = '';
    this.source = null;
	 },
	
	load: function() {
		$$(this.pattern).each(function(element) {
			Event.observe(element, 'mouseover', this.showBubble.bindAsEventListener(this), false);
			Event.observe(element, 'focus', this.showBubble.bindAsEventListener(this), false);
			Event.observe(element, 'mouseout', this.checkBubble.bindAsEventListener(this), false);
			//Event.observe(element, 'blur', this.checkBubble.bindAsEventListener(this), false);
		}.bind(this));
		
		$$(this.source_pattern).each(function(element) {
			Event.observe(element, 'mouseover', this.enableSource.bindAsEventListener(this), false);
			Event.observe(element, 'mouseout', this.disableSource.bindAsEventListener(this), false);
		}.bind(this));
		return true;
	},
	
	showBubble: function(event) {
	  element = $(Event.element(event));
	  if (this.bubble != element) {
		  this.oldBubble = this.bubble ? this.bubble : element.id;
		  this.bubble = element.id;
		  this.current = element;
	    Position.prepare();
		  var offsets = Position.cumulativeOffset(element);
		  var top = offsets[1];
		  var left = offsets[0];
		  var width = element.clientWidth;
		  var height = element.clientHeight;
		  this.positionBubble(element.id, width, height, left, top);
		  this.source = 'bubble_' + this.bubble;
      //$(this.source).show();
		  //$(this.source).setStyle({opacity: 0.0});
	  }
	},
	
	hideBubble: function(event, bubble) {
	  if (bubble && bubble.indexOf('bubble') != -1) {
	    bubble = $(bubble);
	  } else {
	    bubble = bubble ? $('bubble_' + bubble) : $('bubble_' + this.bubble);
	  }
	  //alert('hide : ' +  + this.source + ' - bubble : ' + bubble);

	  if (bubble && bubble.visible() && this.source == null) {
	    //new Effect.Opacity(bubble, { duration: 0.2, from: 1.0, to: 0.0, queue: { position: 'end', scope: 'bubble_queue', limit: 2 } });
      new Effect.Fade(bubble, { duration: 0.2, queue: { position: 'end', scope: 'bubble_queue', limit: 2 } });
      this.oldBubble = -2;
      this.source = null;
    }
    if (this.source != null) {
      setTimeout('myApibubble.hideBubble(\'\', this.source)', 500);
    }
    return true;
	},
	
  positionBubble: function(bubble, w, h, x, y) {
	  bubble = $('bubble_' + bubble);
	  oldBubble = $('bubble_' + this.oldBubble);

	  if (bubble && !bubble.visible()) {
		  var _x = x + 4;
		  var _y = y + h + 16;
		  bubble.setStyle({left: _x + 'px'});
		  bubble.setStyle({top: _y + 'px'});
	    //bubble.setStyle({opacity: 0});
	    if (oldBubble && oldBubble.visible())
	      oldBubble.hide();
	    new Effect.Appear(bubble, { duration: 0.3 });
      //new Effect.Opacity(bubble, { duration: 0.2, from: 0.0, to: 1.0, queue: { position: 'end', scope: 'bubble_queue', limit: 2 } });
	    /*
	    new Effect.Parallel([
	      new Effect.Appear(bubble, { sync: true, duration: 0.3 }),
	      new Effect.Move(bubble, { sync: true, x: 4, y: 4, mode: 'relative' })
	    ], { delay: 0.4, duration: 0.3, queue: { position: 'end', scope: 'bubble_queue', limit: 2 }, beforeUpdate: function(effect) { if (!this.source || this.source != bubble.id) effect.cancel(); }.bind(this) });
	    */
	  }
    return true;
	},
	
	checkBubble: function(event) {
	  if (event) var element = $(Event.element(event));
	  if (this.bubble) {
		  this.source = null;
		  setTimeout('myApibubble.hideBubble(\'\', element.id)', 300);
	  }
	},
	
	enableSource: function(event) {
	  var element = $(Event.element(event));
	  if (this.bubble) {
	    this.source = element.id;
	  }
	},
	
	disableSource: function(event) {
	  var element = $(Event.element(event));
	  if (this.bubble) {
	    this.source = null;
	    this.checkBubble(null);
	  }
	}
	
};

var Apiform = Class.create();
Apiform.prototype = {
	initialize: function() {
	  this.formName = arguments[0];
	  if (!this.formName) throw(Effect._elementDoesNotExistError);
	  this.validForm = true;
	  this.validField = false;
	  this.inputForm = {};
	  this.options = arguments[1] || {};
	  if (this.options && this.options.error) this.options.error.method = this.options.error.method;
	  else this.options.error = {method: 'popup'};
	  this.options.multiple = new Hash();
	  this.pattern = '#' + this.formName + ' input[required]';
	 },
	
	loadValidator: function() { 
			$$(this.pattern).each(function(element) {
			//Event.observe(element, 'change', this.validateFieldObserved.bindAsEventListener(this), false);
      //Event.observe(element, 'click', this.validateFieldObserved.bindAsEventListener(this), false);
			if (element.value.length < 2) this.inputForm[element.id] = false;
			else this.inputForm[element.id] = true;
			element_name = element.name.replace("[]", "");
      if (element.name != element_name) { 
        if (this.options.multiple.get(element_name)) {
          h = this.options.multiple.get(element_name);
        }
        else {
          h = new Hash();
        }
        h.set(element.id, false);
        this.options.multiple.set(element_name, h);
      }
		}.bind(this));
		return true;
	},
	
	checkMultiple: function(element_name) {
	  this.validField = false;
	  $H(this.options.multiple.get(element_name)).each(function(h) { if (h.value == true) { this.validField = true;} }.bind(this));
	  //alert('validField : ' + this.validField);
	  return this.validField;
	},
	
	validateFieldObserved: function(event) {
	  this.validateField(Event.element(event));
	},
	
	validateField: function(element) {
    element_name = element.name.replace("[]", "");
    if (this.options.multiple.get(element_name)) {
      if (this.checkMultiple(element_name)) {
        this.inputForm[element.id] = true;
        return true;
      }
    }
	
		if ((element.value).length < 2 || this.validateExtField(element) == false) {
			this.inputForm[element.id] = false;
      return false;
		} else {
			this.inputForm[element.id] = true;
      if (this.options.multiple.get(element_name)) {
        h = this.options.multiple.get(element_name);
        h.set(element.id, true);
      } 
		}
		return true;
	},
	
	validateExtField: function(element) {
	  this.validField = true;
    if (this.options.validate)
      if (this.options.validate.mail)
        this.options.validate.mail.each(function(name) { if (name == element.name) this.validField = this.validateMail(element.value); }.bind(this));
    //alert('FORM : ' + this.validField);
    return this.validField;
	},
	
	validateForm: function() {
		this.validForm = true;
		$$(this.pattern).each(function(element) {
		  this.validateField(element);
		}.bind(this));
		
		$$(this.pattern).each(function(element) {
      if (this.validForm != false && this.inputForm[element.id] == false) {
        element_name = element.name.replace("[]", "");
        var pattern = 'label[for="' + element_name + '"]';
        var label = $$(pattern).first();
      
        if (this.options.name)
          if ((element_replace = eval('this.options.name.' + element_name)) != undefined)
            element_name = element_replace;
        if (this.options.error) {
          if (this.options.error.method == 'inline')
            $(this.options.error.element).update('Veuillez saisir un ' + element_name + ' valide');
          else
            alert('Veuillez saisir un ' + element_name + ' valide');
        }
        this.validForm = false; 
      }
		}.bind(this));
		
		return this.validForm;
	},
	
	validateMail: function(mail) {
	  var reg = /^[a-z0-9._-]+@[a-z0-9.-]{2,}[.][a-z]{2,3}$/
    return (reg.exec((mail))!=null)
	},
	
	_parseField: function(fieldContent) {
	  return (fieldContent.indexOf('*') != -1 ? fieldContent.substr(0, fieldContent.length - 1) : fieldContent);
	},
	
	_checkField: function(fieldName) {
	  return ($$($A(this.options.fields).indexOf(fieldName)));
	}
};

var freaknGallery = Class.create();
freaknGallery.prototype = {
  _w : null,
  _h : null,
  gallery: null,
  bgallery: null,
  pointerX: null,
  
  initialize: function() {
    this._w = 30;
    this._h = 31;

    this.bgallery = document.createElement('div');
    this.bgallery.setAttribute('id', 'freaknbgallery');
    this.bgallery.setAttribute('title', 'Cliquer pour fermer !');
    Element.extend(this.bgallery);
    this.bgallery.setOpacity(0.0);
    this.bgallery.hide();
    document.body.appendChild(this.bgallery);

    this.gallery = document.createElement('div');
    this.gallery.setAttribute('id', 'freakngallery');
    Element.extend(this.gallery);
    this.gallery.setOpacity(0.0);
    this.gallery.hide();
    document.body.appendChild(this.gallery);
    
    this.gallery.center(this._w, this._h);
    
    this.close = document.createElement('img');
    this.close.setAttribute('id', 'freaknclose');
    this.close.setAttribute('title', 'fermer');
    this.close.setAttribute('alt', 'fermer');
    this.close.setAttribute('src', '/images/book/close_zoom.gif');
    Element.extend(this.close);
    this.close.setOpacity(0.0);
    this.close.hide();
    document.body.appendChild(this.close);
  },
  
  load: function(id) {
    this._size();
    this._show(id);
    this._observe();
  },
  
  _show: function(id) {
    this.gallery.show();
    this.bgallery.show();
    
    this.bgallery.setStyle({opacity: 0.9});
    
    new Effect.Parallel([
      new Effect.Opacity(this.gallery, { sync: true, transition: Effect.Transitions.linear, from: 0.0, to: 1.0 }),
      new Effect.Opacity(this.close, { sync: true, transition: Effect.Transitions.linear, from: 0.0, to: 1.0 })
    ], { duration: 0.1, queue: { position: 'end', scope: 'gallery_queue', limit: 2 } });

    new Ajax.Request('/oeuvre/zoom', {
      evalScripts: true,
      parameters: 'id=' + id,
      onSuccess: function(transport) {
        this.gallery.update(transport.responseText);
        this.gallery.firstDescendant().setStyle({border: 'solid 4px #E9E9E9'});
      }.bind(this)
    });
    
  },
  
  _hide: function() {
    this.bgallery.setStyle({opacity: 0.0});
    
    new Effect.Parallel([
      new Effect.Opacity(this.gallery, { sync: true, from: 1.0, to: 0.0 }),
      new Effect.Opacity(this.close, { sync: true, from: 1.0, to: 0.0  })
    ], { duration: 0.1, queue: { position: 'end', scope: 'gallery_queue', limit: 2 }, afterFinish: function(effect) {
        this.gallery.hide();
        this.gallery.update('');
        this.bgallery.hide();
        this.close.hide();
      }.bind(this) });
      Event.stopObserving(this.close, 'click', this.eventclickclose);
      Event.stopObserving(this.bgallery, 'click', this.eventclick);
  },
  
  _size: function() {
    scrolls = document.viewport.getScrollOffsets();

    this.bgallery.setStyle({
      position: 'absolute', left: '0px', top: '0px', 
      width: document.viewport.getWidth() + 'px', 
      height: document.viewport.getHeight() + getPageScroll() + 'px',                       
      backgroundColor: '#FFF',
      zIndex: 100
    });

    this.gallery.setStyle({   
      position: 'absolute',
      width: this._w + 'px', 
      height: this._h + 'px',   
      backgroundColor: 'transparent',
      overflow: 'hidden',
      whiteSpace: 'nowrap',
      zIndex: 101
    });
    
    this.gallery.center();
    
    this.close.setStyle({
      top: this.gallery.getStyle('top').replace(/px$/, '') - 27 + 'px'
    });
  },
  
  _observe: function() {
    this.eventclick = this._hide.bindAsEventListener(this);
    new Event.observe(this.bgallery, 'click', this.eventclick);
    
    this.eventclickclose = this._hide.bindAsEventListener(this);
    new Event.observe(this.close, 'click', this.eventclickclose);
    
    this.eventscroll = this._size.bindAsEventListener(this);
    new Event.observe(window, 'scroll', this.eventscroll);
  },
  
  initContent: function(w, h) {
    this._w = w;
    this._h = h;
    this.gallery.setStyle({width: w + 'px', height: h + 'px'});
    size = this.gallery.center(w, h);

    this.close.setStyle({
      position: 'absolute', left: size[0] + 'px', top: size[1] - 27 + 'px', 
      width: '92px', 
      height: '23px',   
      opacity: 0.0,
      cursor: 'pointer',
      cursor: 'hand',
      zIndex: 102
    });
    this.close.show();
    new Effect.Opacity(this.close, { delay: 0.4, duration: 0.2, from: 0.0, to: 1.0 });
  }
}

var Apicture = Class.create();
Apicture.prototype = {
  options        : null,      // options
  element        : null,      // the img element
  loading        : false,     // loading
  loadedPictures : [],        // store pictures
  
  initialize: function(element, options) {
    this.loading              = false;
    this.options              = options || {};
    this.element              = $(element);
    Element.extend(this.element);
    this.parent               = this.element.up();
    Element.extend(this.parent);
    this.options.scale        = this.options.scale  || false;
    this.options.center       = this.options.center || false;
    this.options.afterFinish  = this.options.afterFinish || false;
    this.options.size         = [this.parent.getWidth(), this.parent.getHeight()];
    this.options.loadingImage = this.options.loadingImage || '/images/default/loading.gif';
    this.options.replaceImage = this.options.replaceImage || '/images/default/spacer.gif';
    if (this.options.prepare) this.preparePicture();
  },

  preparePicture: function(src) {
    if (!src || src != this.element.src && !this.loading) {
      this.loading          = true;
      this.element.origSrc  = src ? src : this.element.src;
      if (this.newImage == undefined || this.newImage == null) {
        this.newImage       = null;
        this.newImage       = new Image();
        this.newImage.src   = this.element.origSrc;
        //this.parent.addClassName('img_loading');
      }
      new Effect.Fade(this.element, { duration: 0.5, queue: { position: 'end', scope: 'picture_queue', limit: 2 }, afterFinish:
        function(effect) { this.loadPicture(); }.bind(this)
      });
    }
  },
  
  loadPicture: function() {
    this.element.setStyle({width: '', height: '', marginLeft: '', marginTop: ''});
    this.element.setAttribute('width', '');
    this.element.setAttribute('height', '');
    this.element.src  = this.options.replaceImage;

    newImage          = this.getNewImage();
   
    if (newImage.complete != null) {
      this.showPicture();
    } else {
      this.event_show_picture = this.showPicture.bindAsEventListener(this);
      Event.observe(newImage, 'load', this.event_show_picture, false);
    }
  },
  
  showPicture: function(event) {
    newImage = this.getNewImage();
    Event.stopObserving(newImage, 'load', this.event_show_picture);
    this.element.src     = newImage.src;
    if (!this.getLoadedPicture(newImage.src)) this.setLoadedPicture(newImage);
    size = this.setSize();
    if (this.options.scale)
      resized = this.resizePicture();
    if (this.options.afterFinish)
      eval(this.options.afterFinish + '(' + (size[0] + 8) + ',' +  + (size[1] + 8) + ')');
    
    new Effect.Appear(this.element, { delay: 0.0, duration: 0.2, queue: { position: 'end', scope: 'picture_queue', limit: 2 }, 
    afterFinish:
      function(effect) { this.setNewImage(null); this.parent.removeClassName('img_loading'); this.loading = false; }.bind(this)
    });
  },

  setSize: function() {
    var element_w = parseInt(newImage.width);
    var element_h = parseInt(newImage.height);
    if (element_w && element_h)
      this.element.setStyle({width: element_w + 'px', height: element_h + 'px'});
    if (element_w)
      this.element.setAttribute('width', element_w + 'px');
    if (element_h)
      this.element.setAttribute('height', element_h + 'px');

    return [element_w, element_h];
  },
  
  getSize: function() {
    var element_w = parseInt(newImage.width);
    var element_h = parseInt(newImage.height);

    return [element_w, element_h];
  },
    
  resizePicture: function() {
    newImage = this.getNewImage();
    
    var element_w = parseInt(newImage.width);
    var parent_w  = parseInt(this.parent.getWidth());
    var element_h = parseInt(newImage.height);
    var parent_h  = parseInt(this.parent.getHeight());

    ratio_w = 1; ratio_h = 1;
    if (element_w > parent_w) var ratio_w = parent_w / element_w || 1;
    if (element_h > parent_h) var ratio_h =  parent_h / element_h || 1;

    if (ratio_w == 1 && ratio_h == 1) return true;

    var ratio = ratio_w > ratio_h ? ratio_w : ratio_h;
    this.element.setStyle({width: element_w * ratio + 'px', height: element_h * ratio + 'px'});
    return true
  },
  
  centerPicture: function() {
    var element_w = parseInt(this.element.getWidth());
    var parent_w  = parseInt(this.parent.getWidth());
    var element_h = parseInt(this.element.getHeight());
    var parent_h  = parseInt(this.parent.getHeight());
    
    margin_left = 0; margin_top = 0;
    if (element_w < parent_w) var margin_left = (parent_w - element_w) / 2;
    if (element_h < parent_h) var margin_top = (parent_h - element_h) / 2;

    if (margin_left == 0 && margin_top == 0) return true;
    this.element.setStyle({marginLeft: margin_left + 'px', marginTop: margin_top + 'px'});
    return true;
  },
  
  getLoadedPicture: function(src) { return this.loadedPictures[src] != undefined ? this.loadedPictures[src] : null; },
  setLoadedPicture: function(newImage) { if (newImage) this.loadedPictures[newImage.src] = newImage;  },
  
  getLoadedPictures: function() { return this.loadedPictures; },
  
  getNewImage: function(newImage) { return this.newImage; },
  setNewImage: function(newImage) { this.newImage = newImage; }
};

Element.addMethods({
  center: function(element, _w, _h, elt) {
    element = $(element);
    
    _w = _w || element.getWidth();
    _h = _h || element.getHeight();
    
    var w = elt ? elt.getWidth() : document.viewport.getWidth();
    var h = elt ? elt.getWidth() : document.viewport.getHeight();
    
    var _x = (w - _w) / 2;
    var _y = (h - _h) / 2;

    if (!elt) {
      scrolls = document.viewport.getScrollOffsets();
      _x += scrolls[0];
      _y += scrolls[1];
    }

    element.setStyle({position: 'absolute', left: _x + 'px', top: _y + 'px' });
    return [_x, _y];
  }
});


// following code is MIT licensed (C) Gary Haran 2007

/**
* Provide the same behavior as window.scrollTo to divs with overflow without removing
* the ability to scroll a page to a given element.
*/
Element.addMethods({
  scrollTo: function(element, left, top){
    var element = $(element);
    if (arguments.length == 1){
      var pos = element.cumulativeOffset();
      window.scrollTo(pos[0], pos[1]);
    } else {
      element.scrollLeft = left;
      element.scrollTop  = top;
    }
    return element;
  }
});

/**
* Effect.Scroll allows you to animate scrolling on a page (or div w/ overflow: scroll || auto)
*/
Effect.Scroll = Class.create();
Object.extend(Object.extend(Effect.Scroll.prototype, Effect.Base.prototype), {
  initialize: function(element) {
    this.element = $(element);
    if(!this.element) throw(Effect._elementDoesNotExistError);
    this.start(Object.extend({x: 0, y: 0}, arguments[1] || {}));
  },
  setup: function() {
    var scrollOffsets = (this.element == window) 
                ? document.viewport.getScrollOffsets() 
                : Element._returnOffset(this.element.scrollLeft, this.element.scrollTop) ;
    this.originalScrollLeft = scrollOffsets.left;
    this.originalScrollTop  = scrollOffsets.top;
  },
  update: function(pos) {
    this.element.scrollTo(Math.round(this.options.x * pos + this.originalScrollLeft), Math.round(this.options.y * pos + this.originalScrollTop));
  }
});