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 freaknWindow = Class.create();
freaknWindow.prototype = {
  _w : null,
  _h : null,
  gallery: null,
  bgallery: null,
  pointerX: null,
  
  initialize: function() {
    this._w = 30;
    this._h = 30;

    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('div');
    this.close.setAttribute('id', 'freaknclose');
    this.close.setAttribute('title', 'fermer');
    this.close.setAttribute('alt', 'fermer');
    Element.extend(this.close);
    this.close.setOpacity(0.0);
    this.close.hide();
    document.body.appendChild(this.close);
  },
  
  load: function(id, path) {
    this._size();
    this._show(id, path);
    this._observe();
  },
  
  _show: function(id, path) {
    this.gallery.show();
    this.bgallery.show();
    
    this.bgallery.setStyle({opacity: 0.8});
    
    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(path, {
      evalScripts: true,
      parameters: 'image=' + id,
      onSuccess: function(transport) {
        this.gallery.update(transport.responseText);
        this.gallery.firstDescendant().setStyle({border: 'solid 4px #990100'});
      }.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: (parseInt(this.gallery.getStyle('top').replace(/px$/, '')) - 15) + 'px',
      left: (parseInt(this.gallery.getStyle('left').replace(/px$/, '')) - 15) + '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] - 15 + 'px', top: size[1] - 15 + 'px', 
      width: '30px', 
      height: '30px',   
      opacity: 0.0,
      cursor: 'pointer',
      cursor: 'hand',
      zIndex: 502
    });
    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.center)
      center = this.centerPicture();
    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;
    if (element_h > parent_h) var ratio_h =  parent_h / element_h;

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

    if (ratio_w > ratio_h && ratio_w != 1) var ratio = ratio_w;
    if (ratio_w < ratio_h && ratio_h != 1) var ratio = ratio_h;
    if (!ratio) var ratio = (ratio_w > ratio_h) ? ratio_h : ratio_w;
    
    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; }
};

var Apilab = Class.create();
Apilab.prototype = {
  options        : null,      // options
  element        : null,      // the img element
  name           : null,
  enable         : false,
  direction      : 0,
  parent         : null,
  pointerY       : null,
  
  initialize: function(name, options) {
    this.name       = name;
    this.options    = options || {};
  },
  
  setScrollable: function(element, options) {
    this.element = $(element);
    this.options = options;
    this.options.scrollable_method = options.method || 'mouse';
    if (this.element.getStyle('left'))
      this.element._x = parseInt(this.element.getStyle('left').replace(/px$/, ''));
    else
      this.element._x = 0;
    this.parent = this.element.up();
    var method = this.options.scrollable_method.charAt(0).toUpperCase();
    method = method + this.options.scrollable_method.substr(1, this.options.scrollable_method.length-1);
    if (this.element.getWidth() > this.parent.getWidth()) eval('this.observeWith' + method + '()');
    //this.options.buttons.each(function(element) { $(element).hide(); });
  },
  
  observeWithMouse: function() {
    Event.observe(this.parent, 'mouseover', this.enableScrollWithMouse.bindAsEventListener(this), false);
    Event.observe(this.parent, 'mouseout', this.disableScrollWithMouse.bindAsEventListener(this), false);
  },
  
  scrollWithMouse: function() {
    decal = this.element._x + (2 * this.pointerX);
    max = this.element.getWidth() - this.parent.getWidth();
    if (decal <= 2 && decal >= -max - 2) {
      if (this.options.method == 'button') {
        percent = Math.round(decal / -max * 100) / 100;
        $(this.options.buttons[0]).setOpacity(percent);
        $(this.options.buttons[1]).setOpacity(1 -percent);
      }
    }

    if (decal <= 0 && decal >= -max) {
      this.element._x = decal;
      this.element.setStyle({left: this.element._x + 'px'});
    }
  },
  
  getDirection: function(event) {
    pointerX = this.getPointerWithin(parseInt(Event.pointerX(event)));
    if (pointerX != null) {
      this.pointerX = 0;
      if (pointerX < eval(this.parent.getWidth() / 3)) this.pointerX = 1;
      if (pointerX > eval(this.parent.getWidth() / 3 * 2)) this.pointerX = -1;
      
      return true;
    }
  },
  
  getPointerWithin: function(pointerX) {
    Position.prepare();
    var offsets = Position.cumulativeOffset(this.parent);
    return pointerX - offsets[0];
  },
  
  enableScrollWithMouse: function() {
    this.enable =  true;
  
    this.event_check_mouse = this.getDirection.bindAsEventListener(this);
    Event.observe(this.parent, 'mousemove', this.event_check_mouse, false);
    
    new PeriodicalExecuter(function(pe) {
      if (!this.enable) pe.stop();
      if (this.pointerX == 1 || this.pointerX == -1) this.scrollWithMouse();
    }.bind(this), 0.1);
  },
  
  disableScrollWithMouse: function() {
    this.enable =  false;
    Event.stopObserving(this.parent, 'mousemove', this.event_check_mouse);
  },
  

  observeWithButton: function() {
    $(this.options.buttons[0]).setOpacity(0.0);
    $(this.options.buttons[1]).setOpacity(1.0);
    Event.observe(this.parent, 'mouseover', this.enableScrollWithButton.bindAsEventListener(this), false);
    Event.observe(this.parent, 'mouseout', this.disableScrollWithButton.bindAsEventListener(this), false);
  },

  enableScrollWithButton: function() {
    this.enable =  true;

    this.event_check_button = this.getDirection.bindAsEventListener(this);
    Event.observe(this.parent, 'mousemove', this.event_check_button, false);
    
    new PeriodicalExecuter(function(pe) {
      if (!this.enable) pe.stop();
      if (this.pointerY == 1 || this.pointerY == -1) this.scrollWithMouse();
    }.bind(this), 0.01);
  },
  
  disableScrollWithButton: function() {
    this.enable =  false;
    Event.stopObserving(this.parent, 'mousemove', this.event_check_button);
  }
};

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));
  }
});