
var Rollout = new Class({

  options: {
    rightAlign: false,
    autoAlign: false,
    focusFirst: true,
    bind: true
  },

  initialize: function(point, box, options) {
    this.point = $(point);
    this.box = $(box);
    this.setOptions(options);
    this.disabled = false;
    this.opened = false;
  
    this.handlers = {
      open: this.open.bindWithEvent(this),
      close: this.close.bindWithEvent(this),
      overlayClick: this.overlayClick.bindWithEvent(this),
      resize: this.resized.bind(this)
    };
    
    this.attach();
  },
  
  attach: function() {
    if (!this.point) return;
    if (this.options.bind) {
      this.point.addEvent('click', this.handlers.open);
    }
  },
  
  resized: function() {
    var overlay = $('rollout-overlay');
    if (overlay) {
      var sizes = window.getSize();
      /*overlay.setStyles({
        'left': sizes.scroll.x,
        'top': sizes.scroll.y,
        'width': sizes.size.x,
        'height': sizes.size.y
      });*/
      overlay.setStyles({
        'left': sizes.scroll.x,
        'top': sizes.scroll.y,
        'width': sizes.size.x,
        'height': sizes.size.y
      });
      if (this.opened) {
        this.point_bounds = this.point.getCoordinates();
        var x = this.point_bounds.left;
        if (this.options.rightAlign) {
          x -= (this.box.getSize().size.x - this.point_bounds.width);
        }
        this.box.setStyles({
          'left': x,
          'top': this.point_bounds.top + this.point_bounds.height
        });        
      }
    }
  },

  toggleListeners: function(state) {
    var task = state ? 'addEvent' : 'removeEvent';
    window[task]('resize', this.handlers.resize);
    window[task]('scroll', this.handlers.resize);
  },

  showOverlay: function() {
    var overlay = $('rollout-overlay');
    if (!overlay) {
      overlay = new Element('div', {
        'id': 'rollout-overlay',
        'styles': {
          'position': 'absolute',
          'left': 0,
          'top': 0,
          'width': 1,
          'height': 1,
          'padding': 0,
          'margin': 0,
          'background': 'white',
          'opacity': 0,
          'visibility': 'visible'
        }
      }).injectInside(document.body);
    } else {
      overlay.setStyle('display', '');
    }
    this.resized();
    this.toggleListeners(true);
    overlay.addEvent('click', this.handlers.overlayClick);
  },

  hideOverlay: function() {
    var overlay = $('rollout-overlay');
    if (overlay) {
      overlay.setStyle('display', 'none');
      this.toggleListeners(false);
      overlay.removeEvent('click', this.handlers.close);
    }
  },
  
  open: function(event) {
    if (event) event.stop();
    this.point.blur();
    if (!this.box) return;
    if (this.box.getStyle('display') == 'block') {
      this.close();
      return;
    }
    if (this.disabled) return;
    
    this.showOverlay();

    this.point_bounds = this.point.getCoordinates();

    if (this.options.autoAlign) {
      this.options.rightAlign = (this.point_bounds.left >= Math.round(window.getWidth() / 2));
    }

    this.box.setStyles({
      'position': 'absolute',
      'overflow': 'hidden',
      'opacity': 0,
      'display': 'block',
      'left': 0,
      'top': 0
    });

    this.point.addClass('rolled');
    
    var x = this.point_bounds.left;
    if (this.options.rightAlign) {
      x -= (this.box.getSize().size.x - this.point_bounds.width);
    }
    x -= this.options.rightAlign ? -(this.point.getStyle('padding-right').toInt() + this.box.getStyle('border-right-width').toInt()) : (this.point.getStyle('padding-left').toInt() + this.box.getStyle('border-left-width').toInt());
    var height = this.box.getSize().size.y;
    $H(this.box.getStyles('padding-top', 'border-top-width', 'padding-bottom', 'border-bottom-width')).each(function(value) {
      height -= value.toInt();
    });

    this.opened = true;
    Rollout.current = this;

    /*this.point.effects({duration: 200}).
      addEvent('onComplete', function() {
        this.point.addClass('rolled');
      }.bind(this)).
      start('a.rolled');*/
    this.box.setStyles({
      'left': x,
      'top': this.point_bounds.top + this.point_bounds.height,
      'height': 0,
      'opacity': 1
    });
    if (this.options.focusFirst) {
      var box = this.box;
      (function() {
        var form = box.getElement('form');
        if (form) {
          try {
            form.focusFirstElement();
          } catch(e) {}
        }
      }).delay(200);
    }
    this.box.effects({duration: 1000, transition: Fx.Transitions.elasticOut}).
      addEvent('onComplete', function() {
        this.box.setStyle('height', '');
        /*if (this.options.focusFirst) {
          var form = this.box.getElement('form');
          if (form) {
            form.focusFirstElement();
          }
        }*/
        this.callChain();
        this.fireEvent('onOpen');
      }.bind(this)).
      start({
        'height': height,
        'opacity': 1
      });
    return this;
  },
  
  close: function(event) {
    if (event) event.stop();
    this.point.blur();
    if (this.box.getStyle('display') != 'block') return;
    if (this.disabled) return;

    var height = this.box.getSize().size.y;
    $H(this.box.getStyles('padding-top', 'border-top-width', 'padding-bottom', 'border-bottom-width')).each(function(value) {
      height -= value.toInt();
    });
    
    this.box.effects({duration: 600, transition: Fx.Transitions.elasticIn}).
      addEvent('onComplete', function () {
        $(this.point).removeClass('rolled');
        $(this.box).setStyles({
          'height': height,
          'display': 'none'
        });
        this.opened = false;
        Rollout.current = null;
        this.callChain();
        this.fireEvent('onClose');
      }.bind(this)).
      start({
        'height': 0
      });
      
    this.hideOverlay();
    return this;
  },

  overlayClick: function(event) {
    if (event) event.stop();
    this.fireEvent('onOverlayClick');
    this.close();
  },
  
  disable: function() {
    this.disabled = true;
    return this;
  },
  
  enable: function() {
    this.disabled = false;
    return this;
  }

});

Rollout.implement(new Options, new Chain, new Events);

Rollout.current = null;

Rollout.methods = {
  element: {
    rollpoint: function(box, options) {
      var rollout = this.retrieve('rollout');
      if (!rollout) {
        rollout = new Rollout(this, box, options);
      } else {
        rollout.point = this;
      }
      this.store('rollout', rollout);
      return rollout;
    },

    rollin: function(box, options) {
      var rollout = this.retrieve('rollout');
      if (!rollout) {
        rollout = new Rollout(this, box, $merge(options, {bind: false}));
      } else {
        rollout.point = this;
      }
      rollout.open();
      this.store('rollout', rollout);
      return rollout;
    },
    
    rollout: function() {
      var rollout = this.retrieve('rollout');
      if (rollout) {
        rollout.close();
      }
      return rollout;
    },

    disableRollout: function() {
      var rollout = this.retrieve('rollout');
      if (rollout) {
        rollout.disable();
      }
    },

    enableRollout: function() {
      var rollout = this.retrieve('rollout');
      if (rollout) {
        rollout.enable();
      }
    }
  }
}

Element.extend(Rollout.methods.element);

var RolloutForm = new Class({

  options: {
    validate: true,
    update: null,
    rightAlign: true,
    autoAlign: false,
    validatorOptions: {},
    ajax: true,
    submit: true
  },

  initialize: function(rollout, form, options) {
    this.rollout = $(rollout);
    this.form = $(form);
    this.setOptions(options);
    this.parameters = [];
    this.link = null;

    if (this.options.validate && this.form) {
      this.validator = new FormValidator(this.form, $merge(this.options.validatorOptions, {
        useTitles: true,
        evaluateFieldsOnBlur: false,
        evaluateOnSubmit: false,
        useHideFX: false,
        onElementValidate: function(isValid, field) {
          if (!isValid) {
            field.focus();
          }
        }
      })); 
    }
    
    this.bind = {
      reset: this.reset.bind(this),
      cancel: this.cancel.bind(this),
      postComplete: this.postComplete.bind(this)
    }
  },
  
  open: function(el) {
    this.parameters = Array.prototype.slice.call(arguments, 1);
    this.fireEvent('onOpen', $A(arguments));
    this.link = $(el);
    
    if (this.form) {
      this.form.reset();
      var values = (this.parameters.length > 0) ? this.parameters[0] : {};
      $H(values).each(function(value, key) {
        var fields = this.rollout.getElements('form *[name=' + key + ']');
        fields.each(function(field) {
          field = $(field); if (!field) return;
          if (field.hasClass('ignore-popup-field')) return;
          if ((field.type == 'radio') || (field.type == 'checkbox')) {
            field.checked = (field.value == value);
          } else if ((field.type == 'select') || (field.type == 'select-one')) {
            for (var i = 0; i < field.options.length; i++) {
              if (field.options[i].value == value) {
                field.selectedIndex = i;
                break;
              }
            }
          } else {
            field.value = value;
          }
        });
      }.bind(this));
    }
    
    $(el).rollin(this.rollout, {
        rightAlign: this.options.rightAlign,
        autoAlign: this.options.autoAlign,
        //onOverlayClick: this.bind.reset
        onOverlayClick: this.bind.cancel
      });
  },
  
  post: function() {
    this.fireEvent('onBeforePost');
    if (this.options.validate) {
      if (this.validator && !this.validator.validate()) {
        return;
      }
    }
    if (!this.options.onFailure) {
      if (Rollout.current)
        Rollout.current.close().chain(function() {
          // pocess form.action if contains %s
          url = this.form.action;
          if ((url.indexOf('%s') != -1)) {
            url = url.sprintf($splat(this.parameters));
          }
          if (this.options.ajax) {
            new Ajax(url, {
              method: 'post',
              data: this.form.toQueryString(), 
              evalScripts: true,
              useWaiter: true,
              update: this.options.update,
              onComplete: this.bind.postComplete,
              onFailure: function(transport) {
                //this.reset();
                if (this.options.onFailure) {
                  if (this.options.onFailure.attempt([transport.status, transport.responseText])) return;
                }
                new SimpleBox(transport.responseText, {title: 'Îøèáêà', size: {width: 300, height: 150} });
              }.bind(this)
            }).request();
          } else if (this.options.submit) {
            this.form.submit();
          }
        }.bind(this));
    } else {
      // pocess form.action if contains %s
      url = this.form.action;
      if ((url.indexOf('%s') != -1)) {
        url = url.sprintf($splat(this.parameters));
      }
      if (this.options.ajax) {
        new Ajax(url, {
          method: 'post',
          data: this.form.toQueryString(), 
          evalScripts: true,
          useWaiter: true,
          update: this.options.update,
          onComplete: this.bind.postComplete,
          onFailure: function(transport) {
            if (this.options.onFailure) {
              if (this.options.onFailure.attempt([transport.status, transport.responseText])) return;
            }
            new SimpleBox(transport.responseText, {title: 'Îøèáêà', size: {width: 300, height: 150} });
            this.reset();
            this.close();
          }.bind(this)
        }).request();
      } else if (this.options.submit) {
        this.form.submit();
      }
    }
  },
  
  cancel: function() {
    if (Rollout.current)
      Rollout.current.close().chain(function() {
        this.reset();
        this.fireEvent('onClose', [this.link]);
      }.bind(this));
  },
  
  close: function() {
    this.cancel();
  },

  postComplete: function(transport) {
    if (this.options.onFailure && Rollout.current) Rollout.current.close();    
    
    this.reset();
    this.fireEvent('onPost', [transport, this.link]);
    this.fireEvent('onComplete', [transport, this.link]);
  },
  
  reset: function() {
    if (this.validator) {
      this.validator.reset();
    }
    if (this.form) {
      this.form.reset();
    }
    this.fireEvent('onReset', [this.link]);
  }
  
});

RolloutForm.implement(new Options, new Events);

function toggle_view(el, mode) {
  el = $(el);
  if (!el) return;
  
  var old_state = '';
  var exist = false;
  if (/items-([^\b]+)/i.test(el.className)) {
    old_state = RegExp.$1;
    exist = true;
  } else {
    old_state = 'table';
  }

  //console.log(old_state, ' -> ', mode);
  
  try {
    $('items-' + old_state + '-toggler').removeClass('current');
  } catch(e) {}
  if (exist) {
    el.className = el.className.replace(/items-([^\b]+)/ig, 'items-' + mode);
  } else {
    el.addClass('items-' + mode);
  }
  try {
    $('items-' + mode + '-toggler').addClass('current');
  } catch(e) {}
  Cookie.set('view-mode', mode, {duration: 365, path: '/'});
}
