/**
 * @author jgornick
 */

Element.addMethods({
  getBorderWidth: function(element)
  {
    element = $(element);
    
    var top = parseInt(element.getStyle('border-top-width').sub('px', ''));
    var left = parseInt(element.getStyle('border-left-width').sub('px', ''))
    var bottom = parseInt(element.getStyle('border-bottom-width').sub('px', ''))
    var right = parseInt(element.getStyle('border-right-width').sub('px', ''))
    
    return {
      top: top ? top : 0,
      left: left ? left : 0,
      bottom: bottom ? bottom : 0,
      right: right ? right : 0
    }
  },
  getPadding: function(element)
  {
    element = $(element);
    
    var top = parseInt(element.getStyle('padding-top').sub('px', ''));
    var left = parseInt(element.getStyle('padding-left').sub('px', ''))
    var bottom = parseInt(element.getStyle('padding-bottom').sub('px', ''))
    var right = parseInt(element.getStyle('padding-right').sub('px', ''))
    
    return {
      top: top ? top : 0,
      left: left ? left : 0,
      bottom: bottom ? bottom : 0,
      right: right ? right : 0
    }
  },  
  center: function(element)
  {
    element = $(element);

    var offset = parseInt((element.getOffsetParent().getWidth() - element.getWidth()) / 2);
    element.setStyle({
      marginLeft: offset + 'px'
    });
  },
  makeSameWidth: function(element, sourceElement)
  {
    element = $(element);    
    element.setStyle({
      width: sourceElement.getWidth() + 'px'
    });
  },
  makeSameHeight: function(element, sourceElement)
  {
    element = $(element);    
    element.setStyle({
      height: sourceElement.getHeight() + 'px'
    });
  },
  makeSameSize: function(element, sourceElement)
  {
    element = $(element);  
    element.makeSameWidth(sourceElement);
    element.makeSameHeight(sourceElement);    
  }  
});

var TextResizeDetection = Class.create({
  initialize: function(time)
  {
    this.time = (time / 1000);
    this._size = 0;
    this._createSpan();
    this.start();
  },
  
  start: function()
  {
    this.size = this.el.getHeight();
    this.pe = new PeriodicalExecuter(this._onTextResize.bind(this), this.time);
  },
  
  stop: function()
  {
    this.pe.stop(); 
    this.pe = null;   
  },
  
  _createSpan: function()
  {
    this.el = 
      new Element('span', {id: '_text_resize_detection_span'})
      .setStyle({
        position: 'absolute',
        top: '-9999px',
        left: '-9999px'
      })
      .update('&nbsp;');
    
    $(document.body).insert({top: this.el});
  },
      
  _onTextResize: function()
  {
    var currentSize = this.el.getHeight();
    if (this.size != currentSize) 
    {
      document.fire('text:resized', {
        previousSize: this.size,
        currentSize: currentSize
      });
      this.size = currentSize;
    }  
  }
});

var Wizard = Class.create({
  initialize: function(container, options)
  {
    this.options = {
      index: 0,
      onPageChange: Prototype.emptyFunction
    };
    Object.extend(this.options, options || { });
    
    this.container = $(container);

    this.index = this.options.index;

    this.setupUI();
   
    // Setup Events
    Event.observe(window, 'resize', this.setupDimensions.bind(this));    
    new TextResizeDetection(200);
    Event.observe(document, 'text:resized', this.setupDimensions.bind(this));

    this.showPageByIndex(this.index);
    
    this.setupDimensions();    
  },
  
  setupUI: function()
  {
    this._setupContainer();

    this._buildCaption();
    this._buildPagesContainer();
    this._buildControls();
  },
  
  setupDimensions: function(e)
  {
    var dimensions = this._getDimensions();

    var containerBorderWidth = this.container.getBorderWidth();
    dimensions.container.width = dimensions.container.width - containerBorderWidth.left - containerBorderWidth.right;         
    dimensions.container.height = dimensions.container.height - containerBorderWidth.top - containerBorderWidth.bottom;
    
    this.controls.setStyle({
      width: dimensions.container.width + 'px'
    });
    $$('#' + this.container.id + ' .controls .status').invoke('center');
    $$('#' + this.container.id + ' .controls .next').invoke('makeSameWidth', this.prevButton);  
    
    var pagesContainerHeight = dimensions.container.height - dimensions.caption.height - dimensions.controls.height;    
    this.pagesContainer.setStyle({
      marginTop: dimensions.caption.height + 'px',
      width: dimensions.container.width + 'px',
      height: pagesContainerHeight + 'px'
    });        
  },

  showPageByIndex: function(index)
  {
    if (!this._onPageChange(index)) return;

    // Hide current page and show specified index
    this.pages[this.index].hide();
    this.index = index;
    this.pages[this.index].show();
    
    // Update caption and status information
    this.caption.update(this.pages[this.index].caption);    
    this.statusDiv.update('Step ' + (this.index + 1) + ' of ' + this.pages.length);

    // Enable/disable buttons depending on index
    (index == 0) ? this.prevButton.disable() : this.prevButton.enable();
    (index == this.pages.length - 1) ? this.nextButton.disable() : this.nextButton.enable();
    
  },

  prevPage: function()
  {
    var index = (this.index == 0) ? this.index : this.index - 1;
    this.showPageByIndex(index);  
  },
  
  nextPage: function()
  {
    var index = (this.index == this.pages.length - 1) ? this.index : this.index + 1;
    this.showPageByIndex(index);   
  },
  
  _onPageChange: function(index)
  {
    if (this.options.onPageChange != Prototype.emptyFunction)
      return this.options.onPageChange(index);
    
    return true;
  },
  
  _setupContainer: function()
  {
    this.container.setStyle({
      position: (this.container.getStyle('position') == 'absolute') ? 'absolute' : 'relative',
      overflow: 'hidden'      
    });
  },
  
  _buildCaption: function()
  {
    this.caption = new Element('div', {id: 'wizard_caption'})
      .addClassName('caption');
    
    this.container.insert({
      top: this.caption
    });
  },
  
  _buildControls: function()
  {
    this.controls = new Element('div', {id: 'wizard_controls'})
      .addClassName('controls')
      .setStyle({
        position: 'absolute',
        bottom: '0'
      });
    
    this.prevButton = new Element('input', {id: 'wizard_controls_prev_button', type: 'button'})
      .addClassName('prev')
      .observe('click', this.prevPage.bind(this))
      .setValue('Previous');
      
    this.statusDiv = new Element('div', {id: 'wizard_controls_status_div'})
      .addClassName('status')
      .setStyle({ position: 'absolute' });
      
    this.nextButton = new Element('input', {id: 'wizard_controls_next_button', type: 'button'})
      .addClassName('next')
      .observe('click', this.nextPage.bind(this))      
      .setStyle({
        position: 'absolute',
        right: '0'
      })
      .setValue('Next');      
    
    this.controls
      .insert(this.statusDiv)
      .insert(this.prevButton)
      .insert(this.nextButton);
    
    this.container.insert({
      bottom: this.controls
    });
  },
  
  _buildPagesContainer: function()
  {
    this.pagesContainer = new Element('div', {id: 'wizard_pages_container'})
      .setStyle({
        position: 'absolute',
        top: '0',
        overflow: 'auto'        
      });
    
    this._buildPages();
    
    // Move each page into the pages container.
    $$('#' + this.container.id + ' .page').each(function(page) 
    { 
      this.pagesContainer.insert(page);
    }.bind(this));
           
    this.caption.insert({
      after: this.pagesContainer
    });
  },
  
  _buildPages: function()
  {
    var pages = $$('#' + this.container.id + ' .page');
    pages.invoke('hide');
    
    this.pages = $A();
    
    pages.each(function(page, index)
    {
      this.pages.push(new WizardPage(page, {index: index}));      
    }.bind(this));
  },
  
  _getDimensions: function()
  {
    var container = null;
    if (this.container)
      container = this.container.getDimensions();

    var caption = null;
    if (this.caption)
      caption = this.caption.getDimensions();    

    var controls = null;
    if (this.controls)
      controls = this.controls.getDimensions();    
    
    return {
      container: container,
      caption: caption,
      controls: controls
    }
  }
});

var WizardPage = Class.create({
  initialize: function(el, options)
  {
    this.options = {
      index: 0
    };
    Object.extend(this.options, options || { });
    
    this.el = $(el);
    this.el.id = 'page_' + this.options.index;
    this.el.addClassName('page-' + this.options.index);
    
    this.caption = this.el.readAttribute('title');
  },
  
  hide: function() { this.el.hide(); },
  show: function() { this.el.show(); }  
});

