var messagePopup;
var savedSearchId = false;

// Global registers.
Ajax.Responders.register({
  onCreate: function() {
    if(Ajax.activeRequestCount > 0) {
			$('ajax_loader').show();
			var elements = $$('.report-popup .ajax-loader');
			for(var i = 0; i < elements.length; i++) {
				elements[i].show();
			}
		}
	},
	onComplete: function() {
		if(Ajax.activeRequestCount == 0) {
		  $('ajax_loader').hide();
			var elements = $$('.report-popup .ajax-loader');
			for(var i = 0; i < elements.length; i++) {
				elements[i].hide();
			}
		}
	}  
});


/**
 * Functions for login form.
 */
var Login = {
  /**
   * Show 'forgot password' form.
   */
  showForgotPassword : function() {
    $('messages').hide();
    $('login').hide();
    $('forgot_password').show();
  },

  /**
   * Hide 'forgot password' form.
   */
  hideForgotPassword : function() {
    $('messages').hide();
    $('login').show();
    $('forgot_password').hide();
  }
};


/**
 * Functions for 'My Settings'.
 */
var MySettings = {
  /**
   * Toggle search-date description based on selection.
   * @param {Object} el
   */
  toggleSearchDateDesc : function(el) {
    el = $(el);
    $('media_start_date_desc').hide();
    $('media_active_date_desc').hide();
    if($F(el) == 'true') {
      $('media_active_date_desc').show();
    } else {
      $('media_start_date_desc').show();
    }
  }
};


/**
 * Functions for homepage.
 */
var Homepage = {
  animating: false,
  currentPane: 'commercially-retail',
  
  /**
   * Reset banner.
   */
  resetBanner : function() {
    this.cycleBanner($('content').down('.commercially-retail-pane'), 'commercially-retail');
  },
  
  /**
   * Cycle banner tagline/image.
   */
  cycleBanner : function(el, target) {
    el = $(el);
    var pane = el.className.replace(/pane /, '').replace(/-pane/, '');
    
    if(!this.animating && pane != this.currentPane) {
      this.animating = true;
      this.currentPane = pane;
            
      var selectedTagline = $('tagline').down('span.selected');
      var targetTagline = $('tagline').down('span.' + pane);
      var selectedImage = $('hero').down('img.selected');
      var targetImage = $('hero').down('img.' + pane);
      
      if(selectedTagline != targetTagline) {
        selectedTagline.fade();
        selectedTagline.removeClassName('selected');
        targetTagline.appear();
        targetTagline.addClassName('selected');
        selectedImage.fade();
        selectedImage.removeClassName('selected');
        targetImage.appear({afterFinish: function() {
          Homepage.animating = false;
        }});
        targetImage.addClassName('selected');
      }
    }
  }
}


/**
 * Functions for email alerts.
 */
var EmailAlert ={
  /**
   * Populate region options, according to the selected country.
   */
  selectCategory : function() {
    if($('email_alert_subcategory_id')) {
      $('email_alert_subcategory_id').update('');
      new Ajax.Request('/reports/email_alerts/select_category', {
        asynchronous: true,
        evalScripts: true,
        parameters: {
          category_id: $F('email_alert_category_id')
        }
      });
    }
  },

  /**
   * Populate region options, according to the selected country.
   */
  selectCountry : function() {
    $('email_alert_region_id').update('');
    if($('email_alert_retailer_id')) $('email_alert_retailer_id').update('');
    new Ajax.Request('/reports/email_alerts/select_country', {
      asynchronous: true,
      evalScripts: true,
      parameters: {
        country_id: $F('email_alert_country_id'),
        email_alert_template_id: $F('email_alert_email_alert_template_id'),
        update_retailer_list: $('email_alert_retailer_id') ? 1 : 0
      }
    });
  },

  /**
   * Populate media-type options, according to the selected medium.
   */
  selectMedium : function() {
    if($('email_alert_media_type_id')) {
      $('email_alert_media_type_id').update('');
      new Ajax.Request('/reports/email_alerts/select_medium', {
        asynchronous: true,
        evalScripts: true,
        parameters: {
          medium: $F('email_alert_medium'),
          email_alert_template_id: $F('email_alert_email_alert_template_id')
        }
      });
    }
  }
};

/**
 * Functions for FAQs.
 */
var Faq = {
  /**
   * Show answer to question.
   * @param {Object} el
   */
  showAnswer : function(el) {
    el = $(el);
    el.up('li').siblings().each(function(s) {
      s.down('.answer').hide();
    });
    el.up('li').down('.answer').show();
  }
};


/**
 * Functions for page help.
 */
var Help = {
  /**
   * Toggle menu help.
   */
  toggleMenuHelp : function() {
    $('menu').select('li.report-family ul li .menu-help').invoke('toggle');
    if($('search_help')) $('search_help').toggle();
  }
}


/**
 * Functions for reports.
 */
var Report = {
  /**
   * Called *after* a report has been set as the default.
   * @param {Object} reportId
   */
  setAsDefault : function(reportId) {
    $('my_reports').select('.report').invoke('removeClassName', 'default-report');
    $('report_' + reportId).addClassName('default-report');
  },
  
  /**
   * Called *after* a report has been unset as the default.
   * @param {Object} reportId
   */
  unsetAsDefault : function(reportId) {
    $('my_reports').select('.report').invoke('removeClassName', 'default-report');
  }
};


/**
 * Functions for search form.
 */
var SearchForm = {
  /**
   * Show search form.
   */
  show : function() {
    $('search_form').show();
    $('search_content').show();
    $('search_form').setStyle({width: '800px'});
  },
  
  /**
   * Slide search form.
   */
  slide : function() {
    if(Element.visible('search_form')) {
      Effect.SlideOutOfView('search_form');
      $('search_tab').addClassName('collapsed');
    } else {
      Effect.SlideIntoView('search_form');
      $('search_tab').removeClassName('collapsed');
    }
  },
  
  /**
   * Validate search form.
   */
  validate : function(reportType) {
    // Always need a category.
    if(this.numberCategoriesSelected() < 1) {
      alert('At least one category must be selected.')
      return false;
    }
    // Always need a subcategory.
    if(this.numberSubcategoriesSelected() < 1) {
      alert('At least one subcategory must be selected.')
      return false;
    }
    // Always need a distributor.
    if(this.numberDistributorsSelected() < 1) {
      alert('At least one distributor must be selected.')
      return false;
    }
    // Always need a retailer.
    if(this.numberRetailersSelected() < 1) {
      alert('At least one retailer must be selected.')
      return false;
    }
    
    // Report limitations satisfied?
    // DAPP, RAPP and price range.
    if(reportType == 'dapp' || reportType == 'rapp' || reportType == 'price_range') {
      // Only one category.
      if(this.numberCategoriesSelected() > 1) {
        alert('Only one category can be selected.')
        return false;
      }
      // Only one distributor for DAPP report.
      if(reportType == 'dapp') {
        if(this.numberDistributorsSelected() > 1) {
          alert('Only one distributor can be selected.')
          return false;
        }      
      } else if(reportType == 'rapp' || reportType == 'price_range') {
        // Only one retailer for RAPP and price-range report.
        if(this.numberRetailersSelected() > 1) {
          alert('Only one retailer can be selected.')
          return false;
        }      
      }
    }
    
    // Custom date OK?
    if($F('search_date_shortcut') == 'custom') {
      var today = new Date();
      var startDate = new Date($F('search_start_on_1i'), 
                               $F('search_start_on_2i') - 1, 
                               $F('search_start_on_3i'), 0, 0, 0, 0);
      var endDate = new Date($F('search_end_on_1i'), 
                             $F('search_end_on_2i') - 1, 
                             $F('search_end_on_3i'), 0, 0, 0, 0);
      
      if(startDate.getTime() > today.getTime()) {
        alert('Start date cannot be in the future.');
        return false;
      }
      if(endDate.getTime() > today.getTime()) {
        alert('End date cannot be in the future.');
        return false;
      }
      if(startDate.getTime() > endDate.getTime()) {
        alert('Start date cannot be after end date.');
        return false;
      }
    }
    
    // All OK.
    return true;
  },

  /**
   * 
   * @param {Object} target
   */
  toggleFavourites : function(target) {
    var favouriteOptions = $('favourite_' + target + '_options');
    var allOptions = $('all_' + target + '_options');
    var favouriteLink = $('favourite_' + target + '_link')
    var allLink = $('all_' + target + '_link')
    var hiddenField = $('search_use_favourite_' + target);
    
    favouriteOptions.toggle();
    allOptions.toggle();
    
    if(favouriteLink.hasClassName('selected')) {
      favouriteLink.removeClassName('selected');
      allLink.addClassName('selected');
      hiddenField.value = 0;
    } else {
      allLink.removeClassName('selected');
      favouriteLink.addClassName('selected');
      hiddenField.value = 1;
    }
    
    if(target == 'categories') this.selectCategory();
  },

  /**
   * 
   * @param {Object} startDay
   * @param {Object} startMonth
   * @param {Object} startYear
   * @param {Object} endDay
   * @param {Object} endMonth
   * @param {Object} endYear
   */
  updateCustomDateFields : function(startDay, startMonth, startYear, 
                                    endDay, endMonth, endYear) {
    $('search_start_on_3i').value = startDay;
    $('search_start_on_2i').value = startMonth;
    $('search_start_on_1i').value = startYear;
    $('search_end_on_3i').value = endDay;
    $('search_end_on_2i').value = endMonth;
    $('search_end_on_1i').value = endYear;
  },
    
  /**
   * Toggle search-date description based on selection.
   * @param {Object} el
   */
  toggleSearchDateDesc : function(el) {
    el = $(el);
    $('media_start_date_desc').hide();
    $('media_active_date_desc').hide();
    if($F(el) == 'active_date') {
      $('media_active_date_desc').show();
    } else {
      $('media_start_date_desc').show();
    }
  },

  /**
   * Start search.
   * @param {Object} updateMainContent
   */
  start : function(updateMainContent, params) { 
    // Hide search form.
    if($('search_form').visible()) {
      Effect.SlideOutOfView('search_form');
      $('search_tab').addClassName('collapsed');
    }
    // Hide overlay.
    Search.hideOverlay();
    // Add indicator.
  	if(updateMainContent) {
      // Indicate activity.
      this.performingSearch();
      // Populate results iframe.
      var url = $F('report_route') + '?';
      url += $('main_search_form').serialize();
      if(params) url += '&' + $H(params).toQueryString();
      window.frames.results_iframe.location.href = url;
    }    
  },
  
  /**
   * Indicate that we're performing a search.
   */
  performingSearch : function() {
    window.frames.results_iframe.document.fire('cr:performing_search');
    $('search_loader').show();
  },
  
  /**
   * Toggle search params.
   */
  toggleSearchParams : function() {
    if($('search_params').visible()) {
      $('toggle_search_params_link').innerHTML = 'Show Params';
    } else {
      $('toggle_search_params_link').innerHTML = 'Hide Params';
    }
    $('search_params').toggle();
  },
  
  /**
   * Check to see whether we should use a custom date period.
   */
  changeCustomDate : function() {
  	$('date_shortcut_description').update('');
  	new Ajax.Request('/reports/search/date_period_description',
  	                 {parameters: {date_shortcut: $F('search_date_shortcut')}});
  },
  
  /**
   * Change the date period to 'Custom'.
   */
  setDatePeriodToCustom : function() {
  	$('search_date_shortcut').selectedIndex = 9;
  	$('date_shortcut_description').update('');	
  },
  
  /**
   * Keep date drop-downs and date popups in sync.
   * @param {Object} widget
   */
  dateChanged : function(widget) {
  	this.setDatePeriodToCustom();
    var today = new Date();
    var date = new Date($F(widget + '_1i'), $F(widget + '_2i') - 1, $F(widget + '_3i'), 0, 0, 0, 0);
    $(widget + '_input').value = date.print('%d/%m/%Y');
  },
  
  /**
   * Validate date selections.
   * @param {Object} date
   * @param {Object} y
   * @param {Object} m
   * @param {Object} d
   */
  dateStatusHandler : function(date, y, m, d) {
    var today = new Date();
    if(date.getTime() > today.getTime()) return true;
    return false;
  },
  
  /**
   * Select the given options of the given widget.
   * All previsouly selected options will be unselected.
   * @param {Object} widget
   * @param {Object} options
   */
  selectOptions : function(widget, options) {
    widget = $(widget);
    for(i = 0; i < widget.options.length; i++) {
      var option = widget.options[i];
      option.selected = false;
      for(j = 0; j < options.length; j++) {
        if(options[j] == option.value) option.selected = true;
      }
    }
  },
  
  /**
   * Clear the options for subcategory, distributor and retailer.
   */
  prepareCategorySelect : function() {
    Element.update('search_distributor_ids', '');
    Element.update('search_favourite_distributor_ids', '');
    Element.update('search_retailer_ids', '');
    Element.update('search_favourite_retailer_ids', '');
    Element.update('search_subcategory_ids', '');
    $('submit_button').setStyle({visibility: 'hidden'});
  },
  
  /**
   * Populate subcategory, distributor and retailer options,
   * according to the selected category/categories.
   */
  selectCategory : function() {
    this.prepareCategorySelect();
    
    if($F('search_use_favourite_categories') == 0) {
      var params = 'category_ids=' + $F('search_category_ids');
      params += '&use_favourites=0';
    } else {
      var params = 'category_ids=' + $F('search_favourite_category_ids');
      params += '&use_favourites=1';
    }
    if(savedSearchId) {
      params += '&saved_search_id=' + savedSearchId;
      savedSearchId = false;
    }
    if($('search_country_id')) {
      params += '&country_id=' + $F('search_country_id');
    }    
    new Ajax.Request('/reports/search/select_category', {
      asynchronous: true, 
      evalScripts: true, 
      onComplete: function(request) {
        $('submit_button').setStyle({visibility: 'visible'})
      }, 
      parameters: params
    });
  },
  
  /**
   * Populate region options, according to the selected country.
   */
  selectCountry : function() {
    $('search_retailer_ids').update('');
    if($('search_favourite_retailer_ids')) $('search_favourite_retailer_ids').update('');
    $('search_region_ids').update('');
    $('submit_button').setStyle({visibility: 'hidden'})
    
    if($F('search_use_favourite_categories') == 0) {
      var params = 'category_ids=' + $F('search_category_ids');
      params += '&use_favourites=0';
    } else {
      var params = 'category_ids=' + $F('search_favourite_category_ids');
      params += '&use_favourites=1';
    }
    params += '&country_id=' + $F('search_country_id');

    new Ajax.Request('/reports/search/select_country', {
      asynchronous: true,
      evalScripts: true,
      onComplete: function(request){
        $('submit_button').setStyle({visibility: 'visible'})
      },
      parameters: params
    });
  },

  /**
   * Populate media-type options, according to the selected medium.
   */
  selectMedium : function() {
    $('search_media_type_ids').update('');
    $('submit_button').setStyle({visibility: 'hidden'})
    new Ajax.Request('/reports/search/select_medium', {
      asynchronous: true,
      evalScripts: true,
      onComplete: function(request){
        $('submit_button').setStyle({visibility: 'visible'})
      },
      parameters: {
        medium: $F('search_medium')
      }
    });
  },

  /**
   * Initialise select widgets.
   * If we're loading a saved search, 
   * then select the 'All' option only if all options are indeed selected.
   * @param {Object} isSavedSearch
   * @param {Object} useFavouriteCategories
   * @param {Object} useFavouriteDistributors
   * @param {Object} useFavouriteRetailers
   */
  initDropDowns : function(isSavedSearch, 
                           useFavouriteCategories, 
                           useFavouriteDistributors, 
                           useFavouriteRetailers) {
    if(isSavedSearch) {
      if(useFavouriteCategories) {
        $('search_category_ids').selectedIndex = 0;
      } else {
        $('search_favourite_category_ids').selectedIndex = 0;
      }
      if(this.allOptionsSelected('search_subcategory_ids')) {
        $('search_subcategory_ids').selectedIndex = 0;
      }
      if(useFavouriteDistributors) {
        $('search_distributor_ids').selectedIndex = 0;
        if(this.allOptionsSelected('search_favourite_distributor_ids')) {
          $('search_favourite_distributor_ids').selectedIndex = 0;
        }
      } else {
        $('search_favourite_distributor_ids').selectedIndex = 0;
        if(this.allOptionsSelected('search_distributor_ids')) {
          $('search_distributor_ids').selectedIndex = 0;
        }
      }
      if(useFavouriteRetailers) {
        $('search_retailer_ids').selectedIndex = 0;
        if(this.allOptionsSelected('search_favourite_retailer_ids')) {
          $('search_favourite_retailer_ids').selectedIndex = 0;
        }
      } else {
        $('search_favourite_retailer_ids').selectedIndex = 0;
        if(this.allOptionsSelected('search_retailer_ids')) {
          $('search_retailer_ids').selectedIndex = 0;
        }
      }
      if(this.allOptionsSelected('search_media_type_ids')) {
        $('search_media_type_ids').selectedIndex = 0;
      }
      if($('search_region_ids')) {
        if(this.allOptionsSelected('search_region_ids')) {
          $('search_region_ids').selectedIndex = 0;
        }
      }
    } else {
      $('search_category_ids').selectedIndex = 0;
      $('search_favourite_category_ids').selectedIndex = 0;
      $('search_subcategory_ids').selectedIndex = 0;
      $('search_distributor_ids').selectedIndex = 0;
      $('search_favourite_distributor_ids').selectedIndex = 0;
      $('search_retailer_ids').selectedIndex = 0;
      $('search_favourite_retailer_ids').selectedIndex = 0;
      $('search_media_type_ids').selectedIndex = 0;
      if($('search_region_ids')) {
        $('search_region_ids').selectedIndex = 0;
      }
    }
  },
  
  /**
   * Category has been selected.
   */
  categorySelected : function() {
    if(($F('search_use_favourite_categories') == '0' && $F('search_category_ids').include('-1')) ||
       ($F('search_use_favourite_categories') == '1' && $F('search_favourite_category_ids').include('-1'))) {
      $('search_subcategory_ids').disabled = true;
      $('search_distributor_ids').disabled = true;
      $('search_favourite_distributor_ids').disabled = true;
      $('search_product_string').disabled = true;
      $('search_min_price').disabled = true;
      $('search_max_price').disabled = true;
      $('search_subcategory_ids').up('.form-column').setStyle({opacity: 0.5});
      $('search_distributor_ids').up('.form-column').setStyle({opacity: 0.5});
      $('search_product_string').up('.form-column').setStyle({opacity: 0.5});
      $('search_min_price').up('.form-column').setStyle({opacity: 0.5});
    } else {
      $('search_subcategory_ids').disabled = false;
      $('search_distributor_ids').disabled = false;
      $('search_product_string').disabled = false;
      $('search_min_price').disabled = false;
      $('search_max_price').disabled = false;
      $('search_subcategory_ids').up('.form-column').setStyle({opacity: 1});
      $('search_distributor_ids').up('.form-column').setStyle({opacity: 1});
      $('search_product_string').up('.form-column').setStyle({opacity: 1});
      $('search_min_price').up('.form-column').setStyle({opacity: 1});
    }
  },
  
  /**
   * Are all the options for the given widget selected?
   * @param {Object} widget
   */
  allOptionsSelected : function(widget) {
    return (this.selectedOptionCount(widget) == $(widget).options.length - 1);
  },
  
  /**
   * Get the number of options that are selected for the given widget.
   * @param {Object} widget
   */
  selectedOptionCount : function(widget) {
    var count = 0;
    var options = $(widget).options;
    
    for(var i = 0; i < options.length; i++) {
      if(options[i].selected) count++;
    }
    
    return count;
  },
  
  /**
   * Get the number of categories selected.
   */
  numberCategoriesSelected : function() {
    var widget = $('search_category_ids');
    if($F('search_use_favourite_categories') == 1) {
      widget = $('search_favourite_category_ids');
    }
    if(widget.selectedIndex == 0 && widget.options[widget.selectedIndex].text == 'All') {
      return widget.options.length - 1;
    } else {
      return this.selectedOptionCount(widget);
    }
  },
  
  /**
   * Get the number of subcategories selected.
   */
  numberSubcategoriesSelected : function() {
    var widget = $('search_subcategory_ids');
    if(widget.selectedIndex == 0 && widget.options[widget.selectedIndex].text == 'All') {
      return widget.options.length - 1;
    } else {
      return this.selectedOptionCount(widget);
    }
  },

  /**
   * Get the number of distributors selected.
   */
  numberDistributorsSelected : function() {
    var widget = $('search_distributor_ids');
    if($F('search_use_favourite_distributors') == 1) {
      widget = $('search_favourite_distributor_ids');
    }    
    if(widget.selectedIndex == 0 && widget.options[widget.selectedIndex].text == 'All') {
      return widget.options.length - 1;
    } else {
      return this.selectedOptionCount(widget);
    }
  },
  
  /**
   * Get the number of retailers selected.
   */
  numberRetailersSelected : function() {
    var widget = $('search_retailer_ids');
    if($F('search_use_favourite_retailers') == 1) {
      widget = $('search_favourite_retailer_ids');
    }
    if(widget.selectedIndex == 0 && widget.options[widget.selectedIndex].text == 'All') {
      return widget.options.length - 1;
    } else {
      return this.selectedOptionCount(widget);
    }
  }  
}


/**
 * Functions for all searches.
 */
var Search = {
  /**
   * Display user message, and start timer for its demise.
   * @param {Object} widget
   */
  showMessagePopup : function(widget) {
    messagePopup = widget;
    setTimeout('Search.hideMessagePopup()', 2000);  
  },
  
  /**
   * Hide user message.
   */
  hideMessagePopup : function() {
    if($(messagePopup)) $(messagePopup).hide();
  },
  
  /**
   * Hide error message.
   */
  hideMessages : function() {
    if($('error_message')) $('error_message').hide();
  },

  /**
   * Hide popup overlay.
   */
  hideOverlay : function() {
    Search.hideReportPopups();
    Search.showSelectBoxes();
  },

  /**
   * 
   */
  exportSummary : function() {
    var url = '/reports/search/export_summary';
    if($('show_ad_count') && $('show_ad_count').hasClassName('selected')) {
      url += '?method=ad_count'
    }
    if($('show_market_share') && $('show_market_share').hasClassName('selected')) {
      url += '?method=market_share'
    }
    if($('show_sov') && $('show_sov').hasClassName('selected')) {
      url += '?method=sov'
    }
    if($('show_custom_sov') && $('show_custom_sov').hasClassName('selected')) {
      url += '?method=custom_sov'
    }
    document.location = url;
  },
  
  /**
   * 
   * @param {Object} controller
   */
  printSummary : function(url) {
    if($('show_ad_count') && $('show_ad_count').hasClassName('selected')) {
      url += '?method=ad_count'
    }
    if($('show_market_share') && $('show_market_share').hasClassName('selected')) {
      url += '?method=market_share'
    }
    if($('show_sov') && $('show_sov').hasClassName('selected')) {
      url += '?method=sov'
    }
    if($('show_custom_sov') && $('show_custom_sov').hasClassName('selected')) {
      url += '?method=custom_sov'
    }
    window.open(url);
  },

  showSelectBoxes : function()
  {
  	var selects = document.getElementsByTagName('select');
  	for(i = 0; i != selects.length; i++) {
  		selects[i].style.visibility = 'visible';
  	}
  },
  
  hideSelectBoxes : function() {
    if(BrowserDetect.browser == 'Internet Explorer' && BrowserDetect.version < 7) {
      var selects = document.getElementsByTagName('select');
      for(i = 0; i != selects.length; i++) {
        selects[i].style.visibility = 'hidden';
      }
    }
  },

  /**
   * 
   */
  hideReportPopups : function() {
  	if($('search_params')) $('search_params').hide();
    if($('did_you_mean')) $('did_you_mean').hide();
    if($('save_search')) $('save_search').hide();
    if($('media_item')) $('media_item').hide();
    if($('media_items')) $('media_items').hide();
    if($('media_edition_browser')) {
      $('media_edition_browser').hide();
      $('media_edition_browser').setStyle({width: '900px'});
      $('media_edition_browser').down('h3 .title').update('Media Edition Browser');
    }
    if($('graph')) $('graph').hide();
    if($('changelog')) $('changelog').hide();
    $('overlay').hide();
  },

  /**
   * 
   * @param {Object} widget
   */
  showReportPopup : function(widget) {
    if(!$(widget).visible()) {
      this.hideReportPopups();
      this.hideSelectBoxes();
      if($(widget + '_content')) {
        $(widget + '_content').update('<p>Loading...</p>');
      }
      this.positionReportPopup(widget);
      $(widget).show();
      $('overlay').show();
    }
  },
  
  /**
   * 
   * @param {Object} widget
   */
  positionReportPopup : function(widget) {
    // Position popup in middle of screen.
    var cWidth = clientWidth();
    var pWidth = $(widget).getWidth();
    var leftOffset = (cWidth - pWidth) / 2;
    var topOffset = 20 + scrollTop();
    $(widget).setStyle({left: leftOffset + 'px', top: topOffset + 'px'})
    // Extend overlay over full height.
    var bHeight = $('body').getHeight();
    bHeight += parseInt($('body').getStyle('margin-top'));
    bHeight += parseInt($('body').getStyle('margin-bottom'));
    if(self.innerHeight > bHeight) bHeight = self.innerHeight;
    if(document.body.clientHeight > bHeight) bHeight = document.body.clientHeight;
    if(clientHeight() > bHeight) bHeight = clientHeight();
    if(document.documentElement && document.documentElement.clientHeight > bHeight) {
      bHeight = document.documentElement.clientHeight;
    }
    $('overlay').setStyle({height: bHeight + 'px'});
  },

  sizeReportPopup : function(widget, heightOffset) {
    var sizeableContent = $(widget).down('.sizeable-content');
    if(!heightOffset) heightOffset = 150;
    var maxHeight = (document.viewport.getHeight() - heightOffset);
    if(sizeableContent.getHeight() > maxHeight) {
      sizeableContent.setStyle({height: maxHeight + 'px'});
    }
    sizeableContent.show();
  },

  /**
   * 
   * @param {Object} mediaItemId
   * @param {Object} advertId
   */
  showMediaItem : function(mediaItemId, advertId) {
    var url = '/reports/search/media_item/' + mediaItemId;
    if(advertId) url += '?advert_id=' + advertId;    
    this.showReportPopup('media_item');
    new Ajax.Request(url, {asynchronous: true, evalScripts: true});
  }  
}


/**
 * Functions for engine report.
 */
var Engine = {
  /**
   * 
   * @param {Object} rowId
   */
  expandRow : function(rowId) {
    var url = '/reports/engine/engine/expand/' + rowId;
    new Ajax.Request(url, {asynchronous:true, evalScripts:true});
  },
  
  /**
   * 
   */
  expandNextRow : function() {
    if(unexpandedDistributorIds.length > 0) {
      var url = '/reports/engine/engine/expand/' + unexpandedDistributorIds.shift();
      new Ajax.Request(url, {asynchronous:true, evalScripts:true, parameters:'expand_all=1'});  
    }
  },
  
  /**
   * 
   */
  expandAll : function() {
    // Assume we don't need to expand any rows.
    unexpandedDistributorIds = new Array();
    
    // Each distributor will have its own row.
    for(var i = 0; i < distributorIds.length; i++) {
      distributorId = distributorIds[i];
      distributorWidget = $('d' + distributorId);
      distributorInnerWidget = $('d' + distributorId + 'x');
      if(distributorInnerWidget && !distributorInnerWidget.visible()) {
        this.toggleRowByDistributorId(distributorId);
      } else if(distributorWidget.hasClassName('expandable')) {
        unexpandedDistributorIds.push(distributorId);
      }
    }
    
    // Expand the first row.
    this.expandNextRow();
  },
  
  /**
   * 
   */
  collapseAll : function() {
    // Each distributor will have its own row.
    for(var i = 0; i < distributorIds.length; i++) {
      distributorId = distributorIds[i];
      distributorWidget = $('d' + distributorId);
      distributorInnerWidget = $('d' + distributorId + 'x');
      if(distributorInnerWidget && distributorInnerWidget.visible()) {
        this.toggleRowByDistributorId(distributorId);
      }
    }
  
    // We need to explictly set the table height,
    // since otherwise the datagrid gets confused.
    if($('datagrid_left')) {
      $('datagrid_table').setStyle({height: Element.getHeight('datagrid_left') + 'px'})
    }
  },
  
  /**
   * 
   * @param {Object} distributorId
   */
  toggleRowByDistributorId: function(distributorId) {
    $('d' + distributorId).down('span.collapsed').toggleClassName('expanded');
    $('d' + distributorId + 'x').toggle();
    $('d' + distributorId + 'tx').toggle();
    for(var i = 0; i < retailerIds.length; i++) {
      $('d' + distributorId + 'r' + retailerIds[i] + 'x').toggle();
    }
  },
  
  /**
   * 
   * @param {Object} className
   */
  toggleRowByClassName : function(className) {
    var elements = $$('#datagrid div.' + className);
    for(var i = 0; i < elements.length; i++) {
      elements[i].toggle();
    }
  },
  
  /**
   * 
   * @param {Object} mediaItemId
   * @param {Object} advertId
   */
  showMediaItem : function(mediaItemId, advertId) {
    Search.showMediaItem(mediaItemId, advertId)
  }
}

/**
 * Functions for ad-summary report.
 */
var AdSummary = {
  /**
   * Hide all stats.
   */
  hideStats : function() {
    var elements = $$('#datagrid span.stat');
    for(var i = 0; i < elements.length; i++) {
      elements[i].hide();
    }
    
    $('show_ad_count').removeClassName('selected');
    $('show_market_share').removeClassName('selected');
    if($('show_sov')) {
      $('show_sov').removeClassName('selected');
    }
    if($('show_custom_sov')) {
      $('show_custom_sov').removeClassName('selected');
    }
  },

  /**
   * Show selected stats.
   */
  showStats : function(spreadMethod) {
    this.hideStats();
    
    var cls = spreadMethod.replace(/_/, '-');
    
    var elements = $$('#datagrid span.' + cls);
    for(var i = 0; i < elements.length; i++) {
      elements[i].show();
    }
    
    $('show_' + spreadMethod).addClassName('selected');  
  },

  /**
   * Show ad-count stats.
   */
  showAdCount : function() {
    this.showStats('ad_count');
  },
  
  /**
   * Show market-share stats.
   */
  showMarketShare : function() {
    this.showStats('market_share');
  },
  
  /**
   * Show SoV stats.
   */
  showSov : function() {
    this.showStats('sov');
  },
  
  /**
   * Show custom-SoV stats.
   */
  showCustomSov: function() {
    this.showStats('custom_sov');
  }
};


/**
 * Functions for SoV reports.
 */
var Sov = {
  /**
   * 
   * @param {Object} method
   */
  setSpreadMethod : function(sovType, method) {
    spreadMethod = method;
    selectedYear = false;
    selectedMonthOrWeek = false;
    
    $('ad_count').removeClassName('selected');
    $('market_share').removeClassName('selected');
    if($('share_of_voice')) {
      $('share_of_voice').removeClassName('selected');
    }
    if($('custom_share_of_voice')) {
      $('custom_share_of_voice').removeClassName('selected');
    }
    
    if(method == 'ad_count') {
      $('ad_count').addClassName('selected');
    } else if(method == 'market_share') {
      $('market_share').addClassName('selected');
    } else if(method == 'sov') {
      $('share_of_voice').addClassName('selected');
    } else {
      $('custom_share_of_voice').addClassName('selected');
    }
  
    var url = '/reports/sov/' + sovType + '/graph_data';
    url += '?spread_method=' + spreadMethod;
    
    var lineGraph = getChartFromId('fusion_line_graph');
    lineGraph.setDataURL(escape(url));
    
    this.generatePieChart(sovType, false, false);
  },
  
  /**
   * 
   * @param {Object} year
   * @param {Object} monthOrWeek
   */
  generatePieChart : function(sovType, year, monthOrWeek) {
    var url = '/reports/sov/' + sovType + '/chart_data';
    url += '?spread_method=' + spreadMethod;
    if(year) {
      url += '&year=' + year;
      url += '&month_or_week=' + monthOrWeek;
      selectedYear = year;
      selectedMonthOrWeek = monthOrWeek;
    } else {
      selectedYear = false;
      selectedMonthOrWeek = false;  
    }
    
    var pieChart = getChartFromId('fusion_pie_chart');
    pieChart.setDataURL(escape(url));
    var pieGrid = getChartFromId('fusion_pie_grid');
    pieGrid.setDataURL(escape(url + '&grid=yes'));
  },
  
  /**
   * Export line graph.
   */
  exportLineGraph : function() {
    var lineGraph = getChartFromId('fusion_line_graph');
    lineGraph.saveAsImage();
  },
  
  /**
   * 
   */
  exportPieChart : function() {
    var pieChart = getChartFromId('fusion_pie_chart');
    pieChart.saveAsImage();
  },

  /**
   * 
   */  
  printLineGraph : function() {
    var lineGraph = getChartFromId('fusion_line_graph');
    lineGraph.print();
  },
  
  /**
   * 
   */
  printPieChart : function() {
    var pieChart = getChartFromId('fusion_pie_chart');
    pieChart.print();
  }
}


/**
 * Functions for pricing reports.
 */
var Pricing = {
  /**
   * Show data.
   */
  showData : function() {
    $('graph').hide();
    $('data').show();
    $('show_graph').removeClassName('selected');
    $('show_data').addClassName('selected');    
  },
  
  /**
   * Show graph.
   */
  showGraph : function() {
    $('data').hide();
    $('graph').show();
    $('show_data').removeClassName('selected');
    $('show_graph').addClassName('selected');    
  }
};


/**
 * Functions for best-advertised-price report.
 */
var BestAdvertisedPrice = {
  /**
   * Toggle row details.
   * @param {Object} el
   */
  toggleRow: function(el, rowId){
    el = $(el);
    if(BrowserDetect.browser == 'Internet Explorer' && BrowserDetect.version < 7) {
      $('products_' + rowId).toggle();
    } else {
      el.up('tr').nextSiblings()[0].toggle();
      $('products_' + rowId).toggle();
    }
  }
}

/**
 * Fucntions for price-variation report.
 */
var PriceVariation = {
  // The method of calculating averages.
  averageMethod : null,
  
  /**
   * Toggle the warning about calculating medians.
   */
  toggleAverageMethodDescription : function() {
    if($F('search_average_method') == 'median') {
      $('average_method_description').show();
    } else {
      $('average_method_description').hide();
    }
  },
  
  /**
   * Show the candlestick comparison graph as a popup.
   * @param {Object} productId
   */
  displayGraph : function(productId, averageMethod) {
    this.averageMethod = averageMethod;
    Search.showReportPopup('graph');
    
    var url = '/reports/pricing/price_variation/graph?product_id=' + productId;
    url += '&average_method=' + this.averageMethod;
    
    new Ajax.Request(url, {asynchronous:true, evalScripts:true});
  },
  
  /**
   * Show media items for a given product/period.
   * @param {Object} productId
   * @param {Object} year
   * @param {Object} monthOrWeek
   * @param {Object} stat
   * @param {Object} advertId
   */
  showMediaItems : function(productId, year, monthOrWeek, stat, advertId) {
    Search.showReportPopup('media_items');
    
    var url = '/reports/pricing/price_variation/media_items?';
    url += 'product_id=' + productId;
    url += '&stat=' + stat;
    if(year) {
      url += '&year=' + year;
      url += '&month_or_week=' + monthOrWeek;
    }
    
    new Ajax.Request(url, {asynchronous:true, evalScripts:true});
  }
};


/**
 * Functions for price-range report.
 */
var PriceRange = {
  /**
   * 
   */
  showAdCount : function() {
    spreadMethod = 'ad_count';
    AdSummary.showStats('ad_count');
    this.updateBarChartData('ad_count');
  },
  
  /**
   * 
   */
  showMarketShare : function() {
    spreadMethod = 'market_share';
    AdSummary.showStats('market_share');
    this.updateBarChartData('market_share');
  },
  
  /**
   * 
   */
  showSov : function() {
    spreadMethod = 'sov';
    AdSummary.showStats('sov');
    this.updateBarChartData('sov');
  },
  
  /**
   * 
   */
  showCustomSov : function() {
    spreadMethod = 'custom_sov';
    AdSummary.showStats('custom_sov');
    this.updateBarChartData('custom_sov');
  },
  
  /**
   * 
   * @param {Object} spreadMethod
   */
  updateBarChartData : function(spreadMethod) {
    var url = '/reports/pricing/price_range/chart_data';
    url += '?spread_method=' + spreadMethod;
  
    if($('show_graph').hasClassName('selected')) {
      var barChart = getChartFromId('fusion_bar_chart');
      if(barChart) barChart.setDataURL(escape(url));
    }
  }  
};


/**
 * Functions for media-archive report.
 */
var MediaArchive = {
  // Sensible defaults.
  imageResizeAmount: 0,
  maxPages: 0,
  mediaEditionId: 0,
  
  /**
   * The page frames.
   */
  frames : function() {
    return $('browser').down('.frames');
  },
  
  /**
   * Sort results.
   */
  sort : function(dir) {
    SearchForm.start(true, {sort_dir: dir});
  },
  
  /**
   * Change display mode of results.
   */
  setDisplay : function(display, archiveType) {
    var resultsEl = $('datagrid').down('ul.results');
    var tbarSmall = $('tbar_small_thumbs');
    var tbarLarge = $('tbar_large_thumbs');
    if(display == 'small_thumbs') {
      tbarLarge.removeClassName('selected');
      tbarSmall.addClassName('selected');
      resultsEl.removeClassName('large-thumbs');
      resultsEl.addClassName('small-thumbs');
      resultsEl.select('a.thumbnail').each(function(el) {
        Tips.remove(el);
      });
    } else if(display == 'large_thumbs') {
      tbarSmall.removeClassName('selected');
      tbarLarge.addClassName('selected');
      resultsEl.removeClassName('small-thumbs');
      resultsEl.addClassName('large-thumbs');
      resultsEl.select('a.thumbnail').each(function(el) {
        new Tip(el, {
          offset: {x: 10, y: 10},
          stem: 'topLeft',
          title: el.rel,
          width: 280,
          ajax: {
            url: '/reports/media_summary/' + archiveType + '_archive/prototip',
            options: {
              parameters: {
                media_edition_id: el.id.replace('thumb_', '')
              }
            }
          }
        });
      });
    }
  },
  
  /**
   * Init browser. Only called once, on first page load.
   */
  initBrowser : function(img, mediaEditionId, maxPages) {    
    // Init.
    img = $(img);
    this.maxPages = maxPages;
    this.mediaEditionId = mediaEditionId;
    var frames = this.frames();
    var viewport = document.viewport.getDimensions();
    var browserWindow = $('media_edition_browser');
    var browserContainer = $('browser');
    var windowVerticalPadding = browserWindow.getHeight() - browserContainer.getHeight();
    windowVerticalPadding += (browserWindow.positionedOffset()[1] * 2);
    var windowHorizontalPadding = browserWindow.getWidth() - browserContainer.getWidth();
    windowHorizontalPadding += (browserWindow.positionedOffset()[1] * 2);
    var framesWidth = 0;
    // Calculate maximum dimensions of page image.
    var maxImageHeight = viewport.height - windowVerticalPadding;
    var maxImageWidth = Math.ceil((viewport.width - windowHorizontalPadding) / 2);
    // Calculate ratios.
    var viewportRatio = maxImageHeight / maxImageWidth;
    var imageRatio = img.getHeight() / img.getWidth();
    // Resize this image and store dimensions for use with other images.
    if(viewportRatio > imageRatio) {
      img.setStyle({width: maxImageWidth + 'px'});
      maxImageHeight = img.getHeight();
    } else {
      img.setStyle({height: maxImageHeight + 'px'});
      maxImageWidth = img.getWidth();
    }
    this.imageResizeAmount = img.getWidth();
    img.setStyle({width: maxImageWidth + 'px'});
    // Resize all frames to fit the child images.
    frames.select('.frame').each(function(frame) {
      frame.setStyle({height: maxImageHeight + 'px', width: maxImageWidth + 'px', visibility: 'visible'});
      framesWidth += maxImageWidth;
    });
    // Init browser and frame container.
    $('browser').down('.loading').hide();
    $('browser').setStyle({height: maxImageHeight + 'px'});  
    frames.setStyle({height: maxImageHeight + 'px', width: framesWidth + 'px'});
    // Init browser window.
    var browserWindowWidth = (maxImageWidth * 2) + (browserWindow.getWidth() - browserContainer.getWidth()) - 2;
    var browserWindowLeft = (viewport.width - browserWindowWidth) / 2;
    browserWindow.setStyle({left: browserWindowLeft + 'px', width: browserWindowWidth + 'px'});
    // Flag image as having been loaded.
    img.up().addClassName('loaded');
    
    // Init zoom.
    this.initZoom(img);
    
    // Show image.
    img.setStyle({visibility: 'visible'});
    img.up().down('.loading').hide();

    // Load all other pages.
    var frameElements = frames.select('.frame');
    for(var i=0; i<frameElements.length; i++) {
      var frame = frameElements[i];
      var img = frame.down('img');
      if(img && !frame.hasClassName('loaded')) {
        img.observe('load', this.initImage.bindAsEventListener(this));
        img.src = img.alt;
      }
    }    
  },
  
  /**
   * Init image. Called once loaded.
   */
  initImage : function(e) {
    var img = e.element();
    img.setStyle({width: this.imageResizeAmount + 'px'});
    if(img.up()) img.up().addClassName('loaded');
    this.initZoom(img);
    img.setStyle({visibility: 'visible'});
    img.up().down('.loading').hide();
  },

  /**
   * Init zoom box.
   */
  initZoom : function(img) {
    img = $(img);
    img.observe('mouseover', function() {
      if($('zoom_button').hasClassName('selected')) TJPzoom(img);
    });
  },

  /**
   * Toggle zoom on/off.
   */
  toggleZoom : function() {
    el = $('zoom_button');
    el.toggleClassName('selected');
    if(!el.hasClassName('selected')) {
      $('browser').select('.tjp-win').invoke('remove');
      $('browser').select('.tjp-stage').invoke('remove');
    }
  },
  
  /**
   * Turn page.
   */
  turnPage : function(btn) { 
    btn = $(btn);  
    var frames = this.frames();
    var left = frames.positionedOffset().left;
    var maxLeft = 0;
    
    if(btn.id == 'previous') {
      left = left + (this.imageResizeAmount * 2);      
      if(left <= 0) frames.setStyle({left: left + 'px'});
    } else {
      left = left - (this.imageResizeAmount * 2);
      maxLeft = left - (this.imageResizeAmount * 2);
      if(maxLeft + frames.getWidth() >= 0) frames.setStyle({left: left + 'px'});
    }
    
    $('page_selector').selectedIndex = 0;
    this.initNavigation();
  },
  
  /**
   * Init navigation.
   */
  initNavigation : function() {
    var frames = this.frames();
    var left = frames.positionedOffset().left;
    var maxLeft = left - (this.imageResizeAmount * 2);
    left == 0 ? $('previous').hide() : $('previous').show();
    (maxLeft + frames.getWidth() == 0) ? $('next').hide() : $('next').show();
  },
    
  /**
   * Jump to given page.
   */
  showPage : function(pageNumber, index) {
    index = Math.ceil(index / 2);
    var frames = this.frames();
    var left = index * 2 * this.imageResizeAmount;
    frames.setStyle({left: -left + 'px'});
    this.initNavigation();
  },

  /**
   * Jump to page.
   */  
  jumpToPage : function(el) {
    var index = Math.ceil($F(el) / 2);
    var frames = this.frames();
    var left = index * 2 * this.imageResizeAmount;
    frames.setStyle({left: -left + 'px'});
    this.initNavigation();    
  },
  
  /**
   * The pages that are currently visible.
   */
  visiblePages : function() {
    var frames = this.frames();
    var left = Math.abs(frames.positionedOffset().left) + this.imageResizeAmount;
    var rightPage = left / this.imageResizeAmount;
    var leftPage = rightPage - 1;
    var maxRightPage = frames.select('.frame').collect()
    if(leftPage == 0) {
      return [rightPage];
    } else if(rightPage > this.maxPages) {
      return [leftPage];
    } else {
      return [leftPage, rightPage];
    }    
  },
  
  /**
   * PDF currently visible pages.
   */
  pagesPdf : function() {
    var pages = this.visiblePages();
    var url = '/reports/media_summary/media_archive/pdf/' + this.mediaEditionId + '?pages=' + pages.join(',');
    document.location = url;
  }
};

/**
 * Functions for retailer-edm-archive report.
 */
var RetailerEdmArchive = {
  /**
   * Sort results.
   */
  sort : function(dir) {
    SearchForm.start(true, {sort_dir: dir});
  },
  
  /**
   * Change display mode of results.
   */
  setDisplay : function(display) {
    var resultsEl = $('datagrid').down('ul.results');
    var tbarSmall = $('tbar_small_thumbs');
    var tbarLarge = $('tbar_large_thumbs');
    if(display == 'small_thumbs') {
      tbarLarge.removeClassName('selected');
      tbarSmall.addClassName('selected');
      resultsEl.removeClassName('large-thumbs');
      resultsEl.addClassName('small-thumbs');
      resultsEl.select('a.thumbnail').each(function(el) {
        Tips.remove(el);
      });
    } else if(display == 'large_thumbs') {
      tbarSmall.removeClassName('selected');
      tbarLarge.addClassName('selected');
      resultsEl.removeClassName('small-thumbs');
      resultsEl.addClassName('large-thumbs');
      resultsEl.select('a.thumbnail').each(function(el) {
        new Tip(el, {
          offset: {x: 10, y: 10},
          stem: 'topLeft',
          title: el.rel,
          width: 280,
          ajax: {
            url: '/reports/media_summary/retailer_edm_archive/prototip',
            options: {
              parameters: {
                media_edition_id: el.id.replace('thumb_', '')
              }
            }
          }
        });
      });
    }
  }
};


/**
 * Functions for Fusion charts.
 */
var Fusion = {
  /**
   * Export bar graph.
   */
  exportBarChart : function() {
    var pieChart = getChartFromId('fusion_bar_chart');
    pieChart.saveAsImage();
  },

  /**
   * Export line graph.
   */
  exportLineGraph : function() {
    var lineGraph = getChartFromId('fusion_line_graph');
    lineGraph.saveAsImage();
  },
  

  exportPieChart : function() {
    var pieChart = getChartFromId('fusion_pie_chart');
    pieChart.saveAsImage();
  }
};


/**
 * Functions for media explorer.
 */
var MediaExplorer = {
  /**
   * 
   * @param {Object} el
   */
  selectPeriod : function(el) {
    el = $(el);
    el.up('ul').getElementsBySelector('li').invoke('removeClassName', 'selected');
    el.up('li').addClassName('selected');
  }
};


/**
 * Functions for 'Did You Mean?'.
 */
var DidYouMean = {
  /**
   * Toggle suggestions.
   * @param {Object} suggestionMethod
   */
  toggleSuggestions : function(suggestionMethod) {
  	// Update hidden field.
  	$('search_method').value = suggestionMethod;
  	
  	// Substring search?
  	if(suggestionMethod == 'substring') {
  		$('spelling_link').removeClassName('selected');
  		$('simple_link').addClassName('selected');
  		$('spelling_suggestions').hide();
  		$('substring_suggestions').show();		
  	} else {
  		// Must be spelling search then.
  		$('simple_link').removeClassName('selected');
  		$('spelling_link').addClassName('selected');
  		$('substring_suggestions').hide();
  		$('spelling_suggestions').show();
  	}
  },
  
  /**
   * This is what I meant.
   * @param {Object} i
   * @param {Object} replacementName
   * @param {Object} replacementId
   * @param {Object} suggestionMethod
   */
  iMeantThis : function(i, replacementName, replacementId, suggestionMethod) {
    $(suggestionMethod + '_replacement' + i).update(replacementName);
    $(suggestionMethod + '_term' + i).value = replacementId;
  },

  /**
   * Rerun the search, after populating form with chosen product.
   * @param {Object} productString
   */  
  rerunSearch : function(productString) {
    $('search_product_string').value = productString;
    SearchForm.start(true);
  }
};









function hideChartElements()
{
  var chartElements = $$('#main_content .chart-wrapper');
  for(var i = 0; i < chartElements.length; i++) {
    chartElements[i].setStyle({visibility: 'hidden'})
  }
}

function showChartElements()
{
  var chartElements = $$('#main_content .chart-wrapper');
  for(var i = 0; i < chartElements.length; i++) {
    chartElements[i].setStyle({visibility: 'visible'})
  }
}

function toggleMediaItemImage(target)
{
  if(target == 'adverts') {
    $('media_item_image').hide()    
    if($('highlighting_link')) $('highlighting_link').hide();
    $('media_item_adverts').show();
    $('print_preview_link').hide();
    $('blowup_image_link').hide();
    $('media_item_image_link').removeClassName('selected');
    $('media_item_adverts_link').addClassName('selected');
  } else {
    $('media_item_adverts').hide();
    if($('highlighting_link')) $('highlighting_link').show();
    $('media_item_image').show()
    $('print_preview_link').show();
    $('blowup_image_link').show();
    $('media_item_adverts_link').removeClassName('selected');
    $('media_item_image_link').addClassName('selected');    
  }
}

/**
 * Initialises the advert box.
 * @param {Object} left
 * @param {Object} top
 * @param {Object} width
 * @param {Object} height
 */
function initMediaHighlighting(left, top, width, height, highlight)
{
  // Show image.
  $('media_item_img').show();
    
  // The dimensions of the image.
  var imageDimensions = $('media_item_img').getDimensions();
  
  // The details box.
  var details = $('media_item_image').up('.details');
  details.setStyle({height: (document.viewport.getHeight() - 225) + 'px'});
  
  // The image wrapper.
  var wrapper = $('media_item_image').down('.wrapper');
  wrapper.setStyle({width: imageDimensions.width + 'px'});
  
  // Size and position the boxes.
  if($('advert_highlight')) {
    // Advert placement and dimensions.
    var boxLeft = Math.round((left * imageDimensions.width) / 100);
    var boxTop = Math.round((top * imageDimensions.height) / 100); 
    var boxWidth = Math.round((width * imageDimensions.width) / 100);
    var boxHeight = Math.round((height * imageDimensions.height) / 100);
    
    // Position the actual advert.
    $('advert_highlight').style.left = (boxLeft - 1) + 'px';
    $('advert_highlight').style.top = (boxTop - 1) + 'px';
    $('advert_highlight').style.width = boxWidth + 'px';
    $('advert_highlight').style.height = boxHeight + 'px';

    // NW overlay.
    $('highlight_overlay_nw').style.left = 0;
    $('highlight_overlay_nw').style.top = 0;
    $('highlight_overlay_nw').style.width = (boxLeft + boxWidth) + 'px';
    $('highlight_overlay_nw').style.height = (boxTop) + 'px';

    // NE overlay.
    $('highlight_overlay_ne').style.right = 0;
    $('highlight_overlay_ne').style.top = 0;
    $('highlight_overlay_ne').style.width = (imageDimensions.width - (boxLeft + boxWidth)) + 'px';
    $('highlight_overlay_ne').style.height = (boxTop + boxHeight) + 'px';    

    // SE overlay.
    $('highlight_overlay_se').style.right = 0;
    $('highlight_overlay_se').style.bottom = 0;
    $('highlight_overlay_se').style.width = (imageDimensions.width - boxLeft) + 'px';
    $('highlight_overlay_se').style.height = (imageDimensions.height - boxTop - boxHeight) + 'px';

    // SW overlay.
    $('highlight_overlay_sw').style.left = 0;
    $('highlight_overlay_sw').style.top = boxTop + 'px';
    $('highlight_overlay_sw').style.width = boxLeft + 'px';
    $('highlight_overlay_sw').style.height = (imageDimensions.height - boxTop) + 'px';

    // Scroll to advert?    
    if(highlight) {
      var pos = $('advert_highlight').positionedOffset();
      var scroll = pos[1] - 20;
      if(scroll < 0) scroll = 0;
      $('media_item_image').up('.details').scrollTop = scroll;
    }
  }
}

/**
 * Show/hide the advert box.
 */
function toggleMediaHighlighting()
{
  // Hide.
  if($('highlighting_link').hasClassName('selected')) {
    $('highlighting_link').removeClassName('selected');
    $('advert_highlight').hide();
    $('highlight_overlay_nw').hide();
    $('highlight_overlay_ne').hide();
    $('highlight_overlay_se').hide();
    $('highlight_overlay_sw').hide();
  } else {
    // Show, scrolling to ad if need be.
    $('highlighting_link').addClassName('selected');
    $('advert_highlight').show();
    $('highlight_overlay_nw').show();
    $('highlight_overlay_ne').show();
    $('highlight_overlay_se').show();
    $('highlight_overlay_sw').show();
    var pos = $('advert_highlight').positionedOffset();
    var scroll = pos[1] - 20;
    if(scroll < 0) scroll = 0;
    $('media_item_image').up('.details').scrollTop = scroll;
  }
}

function selectAll(widget)
{
  widget = $(widget);
  for(i = 0; i < widget.options.length; i++) {
    widget.options[i].selected = true;
  }
}

function scrollBarSize()
{
  return /MSIE/.test(navigator.userAgent) ? 16 : 16;
}

function windowDimensions() 
{
  var width = 0, height = 0;
  
  if(typeof(window.innerWidth) == 'number') {
    // Non-IE.
    width = window.innerWidth;
    height = window.innerHeight;
  } else if(document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)) {
    //IE6+ in standards-compliant mode.
    width = document.documentElement.clientWidth;
    height = document.documentElement.clientHeight;
  } else if(document.body && (document.body.clientWidth || document.body.clientHeight)) {
    // IE4 compatible.
    width = document.body.clientWidth;
    height = document.body.clientHeight;
  }
  
  return [width, height];
}

function clientWidth() {
	return filterResults (
		window.innerWidth ? window.innerWidth : 0,
		document.documentElement ? document.documentElement.clientWidth : 0,
		document.body ? document.body.clientWidth : 0
	);
}

function clientHeight() {
	return filterResults (
		window.innerHeight ? window.innerHeight : 0,
		document.documentElement ? document.documentElement.clientHeight : 0,
		document.body ? document.body.clientHeight : 0
	);
}

function scrollLeft() {
	return filterResults (
		window.pageXOffset ? window.pageXOffset : 0,
		document.documentElement ? document.documentElement.scrollLeft : 0,
		document.body ? document.body.scrollLeft : 0
	);
}

function scrollTop() {
	return filterResults (
		window.pageYOffset ? window.pageYOffset : 0,
		document.documentElement ? document.documentElement.scrollTop : 0,
		document.body ? document.body.scrollTop : 0
	);
}

function filterResults(win, docel, body) {
	var result = win ? win : 0;
	if(docel && (!result || (result > docel))) result = docel;
	return body && (!result || (result > body)) ? body : result;
}

function resizeWindow()
{
  var offset = 80;
  var width = clientWidth();
  var contentWidth = width - offset;
  Element.setStyle('top_content', {width: contentWidth + 'px'});
}


/**
 * Patches [http://simonwillison.net/2006/Jan/20/escape/].
 */
RegExp.escape = function(text) {
  if(!arguments.callee.sRE) {
    var specials = [
      '/', '.', '*', '+', '?', '|',
      '(', ')', '[', ']', '{', '}', '\\', '$'
    ];
    arguments.callee.sRE = new RegExp(
      '(\\' + specials.join('|\\') + ')', 'g'
    );
  }
  return text.replace(arguments.callee.sRE, '\\$1');
}


/**
 * Calls from results iframe.
 */

// Search loaded.
document.observe('cr:search_loaded', function(event) {
  $('search_loader').hide();
});

// Did you mean?
document.observe('cr:did_you_mean', function(event) {
  Search.showReportPopup('did_you_mean');
  new Ajax.Request('/reports/search/did_you_mean');  
});

// Search params.
document.observe('cr:search_params', function(event) {
  Search.showReportPopup('search_params');
  new Ajax.Request('/reports/search/search_params');  
});

// Media item.
document.observe('cr:media_item', function(event) {
  Search.showReportPopup('media_item');
  new Ajax.Request('/reports/search/media_item/' + event.memo.id);  
});

// Media items.
document.observe('cr:media_items', function(event) {
  Search.showReportPopup('media_items');
  new Ajax.Request(event.memo.url);  
});

// Media-edition browser.
document.observe('cr:media_edition_browser', function(event) {
  Search.showReportPopup('media_edition_browser');
  new Ajax.Request('/reports/media_summary/media_archive/browser/' + event.memo.id, {
    method: 'get'
  });
});

// Engine media item.
document.observe('cr:engine_media_item', function(event) {
  Engine.showMediaItem(event.memo.mediaItemId, event.memo.advertId);
});

// Price-variaton graph.
document.observe('cr:price_variation_graph', function(event) {
  PriceVariation.displayGraph(event.memo.rowId, event.memo.method);
});

// Price-variaton media items.
document.observe('cr:price_variation_media_items', function(event) {  
  PriceVariation.showMediaItems(event.memo.rowId, 
                                event.memo.year, 
                                event.memo.weekOrMonth, 
                                event.memo.method);
});

// Media archive.
document.observe('cr:media_archive_sort', function(event) {
  MediaArchive.sort(event.memo);
});


/**
 * Behaviours.
 */

/**
 * Behaviour to add ajax pagination.
 */
var RemotePagination = Behavior.create({
  initialize : function() {
    this.list = this.element.up('.remote-pagination').up().down('table.datagrid tbody');
  },
  
  onclick : function(e) {
    if(this.list) this.list.setStyle({opacity: 0.5});
    new Ajax.Request(this.element.href, {
      method: 'get'
    });
    return false;
  }
});

// Ajaxify remote-pagination.
Event.observe(window, 'load', function() {
  Event.addBehavior.reassignAfterAjax = true;
  Event.addBehavior({
    '.remote-pagination a' : RemotePagination
  });  
});
