/**
 * ImageBlock functions.
 */
var ImageBlock = {
  /**
   * Correctly size image gallery block.
   * @param {Object} block
   */
  sizeGallery : function(block) {
    // The gallery.
    var gallery = $(block).down('.gallery');
    // Get the column count. This will be imbedded in the gallery's class names.
    var columnCountCls = $w(gallery.className).detect(function(c) {
      return c.startsWith('columns-');
    });
    var columnCount = parseInt(columnCountCls.sub('columns-', ''));
    // The first frame in the gallery.
    var firstFrame = gallery.down('.frame');
    // Use the first frame to calculate the width of the gallery.
    if(firstFrame) {
      var frameWidth = firstFrame.getWidth();
      var frameMargin = parseInt(firstFrame.getStyle('margin-right'));
      var galleryWidth = ((frameWidth + frameMargin) * columnCount) - frameMargin;
      gallery.setStyle({width: galleryWidth + 'px'});
    }
  }
};

/**
 * FormTemplateBlock functions.
 */
var FormTemplateBlock = {
  /**
   * Resets the form.
   * @param {Object} formTemplateId
   */
  reset : function(formTemplateId) {
    if($('form_alert_' + formTemplateId)) {
      $('form_alert_' + formTemplateId).hide();
    }
    var form = $('form_' + formTemplateId);
    form.select('.form-msg').each(function(m) {
      m.hide();
    });
    form.reset();    
  },
  
  /**
   * 
   * @param {Object} formTemplateId
   */
  validate: function(formTemplateId) {
    // Assume the form is valid.
    var isValid = true;
    // Get the form items.
    var form = $('form_' + formTemplateId);
    var formItems = form.select('.form-item');
      
    // Check each form item.
    for(var i = 0; i < formItems.length; i++) {
      // The item and child fields.
      var item = formItems[i];
      var field = item.down('.form-field');
      var fields = item.select('.form-field');
      
      // The message box.
      var msgBox = item.down('.form-msg');
      // If there's no message box, create one.
      if(!msgBox) {
        var label = item.down('label');
        var msgBox = new Element('span', {'class': 'form-msg'});
        label.insert(msgBox);
      }
      
      // Init error message.
      var msg = '';
  
      // Do we have one or more form fields?
      for(var j = 0; j < fields.length; j++) {
        var field = fields[j];
        // Get the value, and init message.
        var value = $F(field);
              
        // Check required fields.
        if(item.hasClassName('required')) {
          if(value == '') msg = 'is required';
        }
        // Check numeric fields.
        if(msg == '') {
          if(item.hasClassName('numeric')) {
            if(!value.match(/^\d*$/)) msg = 'is not a number'; 
          }
        }
        // Check phone fields.
        if(msg == '') {
          if(item.hasClassName('phone')) {
            if(value != '' && !value.match(/^[0-9+ ()]+$/)) msg = 'is not valid'; 
          }
        }
        // Check email fields.
        if(msg == '') {
          if(item.hasClassName('email')) {
            if(value != '' && !value.match(/^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/)) {
              msg = 'is not a valid email'; 
            }
          }
        }
        // Check time fields.
        if(msg == '') {
          if(item.hasClassName('time')) {
            if(value != 'AM' && value != 'PM' && !value.match(/^[\d:.]*$/)) msg = 'is not valid'; 
          }
        }
        
        // No error message means everything's OK.
        if(msg == '') {
          msgBox.update('');
          msgBox.hide();
        } else {
          // Otherwise, show error message.
          msgBox.update(msg);
          msgBox.show();
          // Mark form as invalid.
          isValid = false;        
        }
      }
    }
    
    // Invalid form? Alert user.
    if(!isValid) this.alert(formTemplateId);
    
    return isValid;
  },
  
  /**
   * Add a visual alert to the form.
   * @param {Object} formTemplateId
   */
  alert : function(formTemplateId) {
    // The form.
    var form = $('form_' + formTemplateId);
    // The alert box.
    var alertBox = $('form_alert_' + formTemplateId);
    
    // If we already have an alert box, no need to recreate it.
    if(!alertBox) {
      // A DIV.
      var alertBox = new Element('div', {
        id: 'form_alert_' + formTemplateId,
        'class': 'form-alert'
      });
      // With a generic error message.
      alertBox.update('<strong>Oops!</strong><br/>There was a problem with your submission. Please review the form.');
      // Add it to the top of the form.
      form.insert({
        top: alertBox
      }); 
    }
    
    // Display the alert.
    alertBox.show();
    alertBox.scrollTo();
    new Effect.Pulsate(alertBox, {pulses: 2});
  },
  
  /**
   * Submission succeeded.
   * @param {Object} formTemplateId
   */
  succeeded : function(formTemplateId, xhr) {
    var form = $('form_' + formTemplateId);
    var thankyouBox = $('form_thanks_' + formTemplateId);
    if(!thankyouBox) {
      var thankyouBox = new Element('div', {
        id: 'form_thanks_' + formTemplateId,
        'class': 'form-thanks'
      });
      form.insert({
        top: thankyouBox
      });
    }
    var msg = xhr.responseText;
    msg += '<p><a href="#" onclick="FormTemplateBlock.returnTo(\'' + formTemplateId +'\'); return false;">Return to the form</a></p>';
    thankyouBox.update(msg);
    thankyouBox.show();
    if($('form_alert_' + formTemplateId)) {
      $('form_alert_' + formTemplateId).hide();
    }
    $('form_fields_' + formTemplateId).hide();
  },
  
  /**
   * Submission failed.
   * @param {Object} formTemplateId
   * @param {Object} xhr
   */
  failed : function(formTemplateId, xhr) {
    // The form.
    var form = $('form_' + formTemplateId);
    
    // Add the error messages.
    xhr.responseJSON.errors.each(function(e) {
      var field = $(e.id);
      if(field) {
        var item = $(e.id).up('.form-item');
        var msgBox = item.down('.form-msg');
        msgBox.update(e.msg);
        msgBox.show();
      }
    });
    
    // Add visual alert.
    this.alert(formTemplateId);
  },
  
  /**
   * Return to form-template form from thank you message.
   * @param {Object} formTemplateId
   */
  returnTo : function(formTemplateId) {
    $('form_thanks_' + formTemplateId).hide();
    $('form_fields_' + formTemplateId).show();
    this.reset(formTemplateId);    
  }
};

/**
 * PhotoGalleryBlock functions.
 */
var PhotoGalleryBlock = {
  /**
   * Load a thumbnail into the main frame.
   * @param {Object} link
   */
  load : function(link) {
    // Init.
    link = $(link);
    // The thumb.
    var thumb = link.down('img');
    var thumbFrame = link.up('.frame');
    // We assume the thumb padding is the same as that of the main frame.
    var framePadding = parseInt(thumbFrame.getWidth()) - parseInt(thumb.getWidth());
    // The main frame.
    var mainFrame = this.mainFrame(link);
    framePadding = mainFrame.down('img').getStyle('border');
    // The photo width will be in the link's class name.
    var photoWidth = parseInt(link.className.sub('width-', ''));
    // Update main frame.
    mainFrame.down('img').src = thumb.src.sub('/thumbnail', ''); 
    mainFrame.setStyle({width: photoWidth + 'px'});
    // Clear the currently selected thumbnail.
    this.selectedThumbnail(link).removeClassName('selected');
    // So we can select the current one.
    thumb.addClassName('selected');
    // 
    this.positionThumbnails(link);
    // Show/hide navigation links.
    this.toggleNav(link);
  },
  
  /**
   * Jump to the previous photo.
   * @param {Object} link
   */
  previous : function(link) {
    var previousThumb = this.previousThumbnail(link);
    if(previousThumb) this.load(previousThumb.down('a'));
  },
  
  /**
   * Jump to the next photo.
   * @param {Object} link
   */
  next : function(link) {
    var nextThumb = this.nextThumbnail(link);
    if(nextThumb) this.load(nextThumb.down('a'));
  },
  
  /**
   * Move the thumbnails.
   * @param {Object} el
   */
  positionThumbnails : function(el) {
    // The wrapper - we'll be moving this.
    var thumbWrapper = $(el).up('.gallery').down('.thumbnails .wrapper');
    // The currently selected thumb.
    var selectedThumb = this.selectedThumbnail(el).up('.frame');
    // The total width of an individual thumb.
    var thumbWidth = this.thumbnailAndMarginWidth(el);
    // The number of thumbs to the left or right of the current thumb.
    var leftSiblingCount = selectedThumb.previousSiblings().size();
    var rightSiblingCount = selectedThumb.nextSiblings().size();
    
    // Don't scroll if we're at the start of the list.
    var leftIndex = leftSiblingCount - this.centreThumbnailIndex(el);
    if(leftIndex < 0) leftIndex = 0;
        
    // The required left position.
    var requiredLeft = leftIndex * thumbWidth;
    // We only scroll if there are enough images to fill the wrapper.
    if(requiredLeft > this.maxLeftPosition(el)) {
      requiredLeft = this.maxLeftPosition(el);
    }
        
    // Calculate how much we need to scroll by.
    var currentLeft = parseInt(thumbWrapper.getStyle('left'));
    var leftOffset = requiredLeft + currentLeft;      
    // And scroll.
    new Effect.MoveBy(thumbWrapper, 0, -leftOffset, {duration: 0.5});
  },
  
  /**
   * The maximum left position that the thumbnail wrapper should be moved.
   * @param {Object} el
   */
  maxLeftPosition : function(el) {
    var maxIndex = this.thumbnails(el).size() - (2 * this.centreThumbnailIndex(el));
    maxIndex--  ;
    return maxIndex * this.thumbnailAndMarginWidth(el);
  },
  
  /**
   * How many thumbnails can be seen?
   * @param {Object} el
   */
  visibleThumbnailCount : function(el) {
    var mainWidth = $(el).up('.gallery').getWidth();
    var thumbWidth = this.thumbnailAndMarginWidth(el);
    return (mainWidth / thumbWidth).ceil();
  },
  
  /**
   * Get the index of the thumbnail in the centre of the wrapper.
   * @param {Object} el
   */
  centreThumbnailIndex : function(el) {
    var thumbCount = this.visibleThumbnailCount(el);
    if(this.thumbnails(el).size() < thumbCount) {
      thumbCount = this.thumbnails(el).size();
    }
    var index = (thumbCount / 2).floor();
    return (thumbCount % 2 == 0) ? index - 1: index;
  },
  
  /**
   * Show/hide navigation links.
   * @param {Object} el
   */
  toggleNav : function(el) {
    // 'Previous'.
    if(this.previousThumbnail(el)) {
      this.navPrevious(el).show();
    } else {
      this.navPrevious(el).hide();
    }
    // 'Next'.
    if(this.nextThumbnail(el)) {
      this.navNext(el).show();
    } else {
      this.navNext(el).hide();
    }    
  },
    
  /**
   * Get the main photo frame.
   * @param {Object} el
   */
  mainFrame : function(el) {
    return $(el).up('.gallery').down('.frame');
  },
  
  /**
   * Get the gallery thumbnails.
   * @param {Object} el
   */
  thumbnails : function(el) {
    return $(el).up('.gallery').down('.thumbnails .wrapper').childElements();
  },
  
  /**
   * The total width of a thumbnail, including right margin.
   * @param {Object} el
   */
  thumbnailAndMarginWidth : function(el) {
    var width = this.selectedThumbnail(el).up('.frame').getWidth();
    width += parseInt(this.selectedThumbnail(el).up('.frame').getStyle('margin-right')); 
    return width;
  },
    
  /**
   * Get the currently selected thumbnail.
   * @param {Object} el
   */
  selectedThumbnail : function(el) {
    return $(el).up('.gallery').down('.thumbnails .selected');
  },
  
  /**
   * Get the previous thumbnail.
   * @param {Object} el
   */
  previousThumbnail : function(el) {
    var currentThumb = this.selectedThumbnail(el).up('.frame');
    var previousThumbs = currentThumb.previousSiblings();
    if(previousThumbs.size() > 0) {      
      return previousThumbs[0];
    } else {
      return false;
    }    
  },
  
  /**
   * Get the next thumbnail.
   * @param {Object} el
   */
  nextThumbnail : function(el) {
    var currentThumb = this.selectedThumbnail(el).up('.frame');
    var nextThumbs = currentThumb.nextSiblings();
    if(nextThumbs.size() > 0) {      
      return nextThumbs[0];
    } else {
      return false;
    }
  },
  
  /**
   * The 'Previous Photo' link.
   * @param {Object} el
   */
  navPrevious : function(el) {
    return $(el).up('.gallery').down('.nav .previous');
  },
  
  /**
   * The 'Next Photo' link.
   * @param {Object} el
   */
  navNext : function(el) {
    return $(el).up('.gallery').down('.nav .next');
  }
};