/*-------------------*/
/* Yugambeh (Global) */
/*-------------------*/

/*****************************************/
/* Adjusting Layout Based on Window Size */
/*****************************************/

function ygm__refresh_layout()
{
  // when the window size is above
  // a certain threshold alter a 
  // class to adjust layout behavior
  if ($(window).width() >= 1350)
    $('.ygm-stretchable-page-width').addClass('ygm-large-screen');
  else $('.ygm-stretchable-page-width').removeClass('ygm-large-screen');
}

// execute adjustments initially and when window size changes
jQuery(window).resize(function() { ygm__refresh_layout(); });
jQuery(document).ready(function($) { ygm__refresh_layout(); });

/**********************/
/* Disabling Elements */
/**********************/

// shortcut function for checking
// our proprietary disabled state
function ygm__is_disabled(el) {
  if (el.parents('.ygm-disabled').size() ||
      el.hasClass('ygm-disabled')) return true;
  return false;
}

// the following function can be used to prevent enter
// from submitting a form for all elements within container
function ygm__disable_enter_submission(container) {
  var inputs = container.find('input:not(.ygm-enter-submission-disabled)');
  inputs.keypress(function(e) {
    if (e.which != 13) return;
    e.preventDefault();
    e.stopPropagation();
  });
  inputs.addClass('ygm-enter-submission-disabled');
}

// this function sets and unsets an invisible
// div in front of all the contents of element
function ygm__disabling_screen(el, state) {
  var s = el.find('.ygm-disabling-screen');
  if (!s.size()) return;
  if (!state) s.hide();
  else
  {
    // set the screen to the
    // proper size then show
    s.width(el.outerWidth());
    s.height(el.outerHeight());
    s.show();
  }
}

/*********************************/
/* Text Field/Area Auto-Labeling */
/*********************************/

function ygm__install_tfa_labeler() 
{
  // this function may be called when additional form elements added
  var tf = $('input.ygm-auto-labeled, textarea.ygm-auto-labeled');
  tf.each(function(i, el) { 
    if ($(el).hasClass('ygm-auto-labeler')) return;
    $(el).focus(function(e) { if ($(this).val() == $(this).attr('title')) $(this).addClass('ygm-focused').val(''); });
    $(el).blur(function(e) { if ($(this).val() == '') $(this).removeClass('ygm-focused').val($(this).attr('title')); });      
    $(el).addClass('ygm-auto-labeler');
    if ($(this).val() != $(this).attr('title')) $(this).addClass('ygm-focused');
  });
}


// ensures that the auto label values are ignored when a form is sumitted by checking current value against label that was assigned
function ygm__real_val(el) { if (el.hasClass('ygm-auto-labeled') && (el.val() == el.attr('title'))) return ''; else return el.val(); }
  
/****************************/
/* Lightbox'd Contact Forms */
/****************************/
  
function ygm__enable_lightbox_contact_forms()
{
  // make is possible to enable the opener links
  // for existing content of content added after
  var els = $('.ygm-contact-form-lightbox-opener');
  els.each(function(i, el) {
    var el = $(el); 
    if (el.hasClass('ygm-contact-form-lightbox-opener-enabled')) return;
    el.addClass('ygm-contact-form-lightbox-opener-enabled');
    
    // when clicked open the
    // lightbox conact form
    el.click(function(e) {
       e.preventDefault();
       var recipient = $(this).find('.recipient').text();
       var subject = $(this).find('.subject').text();
       var message = $(this).find('.message').text();
       var contact_form_id = $(this).find('.contact_form_id').text();
       var lb = $('#ygm-embedded-contact-form .ygm-contact-form-lightbox').clone(true);
       
       // prepopulate with values
       // then open the lightbox
       var f = lb.find('form');
       f.find('input[name=contact_form_id]').val(contact_form_id);
       f.find('div.field.recipient .recipient').text(recipient);
       f.find('input[name=recipient]').val(recipient);
       if (subject) f.find('input[name=subject]').val(subject).addClass('ygm-focused');
       if (message) f.find('textarea[name=message]').val(message).addClass('ygm-focused');
       plb__lightbox.open(lb);
    });
  });
}
  
/**********************************/
/* Encapsulated Behavior-Enabling */
/**********************************/

function ygm__enable_behaviors()
{
  // this function provides an encapsulated
  // means to enable behaviors when the page
  // is altered via asynchronous requests
  ygm__enable_lightbox_contact_forms();
  ygm__install_tfa_labeler();
}
  
jQuery(document).ready(function($) {
  
  /***********************************************/
  /* Run Behavior-Enabling For Existing Elements */
  /***********************************************/
  
  // run the installer once
  // for any existing elements
  ygm__enable_behaviors();
  
  /*********************/
  /* Image Pre-Loading */
  /*********************/
  
  // establish reusable
  // preloading method
  (function($){
    $('body').data('preloader', new Array());
    $('body').data('preload', function(src) {
      var arr = $('body').data('preloader');
      var img = new Image();
      img.src = src;
      arr[arr.length] = img;
      img.onload = function() {};
    });
  })(jQuery);
  
  // use following to preload images as needed
  $('body').data('preload')('pics/itm__blank.gif');
  $('body').data('preload')('pics/btn__radio_text_field_m_off.png');
  $('body').data('preload')('pics/btn__radio_text_field_m_on.png');
  $('body').data('preload')('pics/btn__radio_text_field_f_off.png');
  $('body').data('preload')('pics/btn__radio_text_field_f_on.png');
  $('body').data('preload')('pics/btn__radio_text_field_y_off.png');
  $('body').data('preload')('pics/btn__radio_text_field_y_on.png');
  $('body').data('preload')('pics/btn__radio_text_field_n_off.png');
  $('body').data('preload')('pics/btn__radio_text_field_n_on.png');
  $('body').data('preload')('pics/btn__register_here_hover.png');
  $('body').data('preload')('pics/btn__shopping_cart_continue_hover.png');
  $('body').data('preload')('pics/btn__shopping_cart_go_back_hover.png');
  $('body').data('preload')('pics/btn__shopping_cart_check_out_hover.png');
  $('body').data('preload')('pics/btn__i_agree_hover.png');
  $('body').data('preload')('pics/btn__dont_agree_hover.png');
  $('body').data('preload')('pics/bg__checkout_alert.png');
  $('body').data('preload')('pics/btn__google_map_legend_toggler_down_hover.png');
  $('body').data('preload')('pics/btn__google_map_legend_toggler_up.png');
  $('body').data('preload')('pics/btn__google_map_legend_toggler_up_hover.png');
  $('body').data('preload')('pics/itm__google_map_legend_checkbox_off.png');
  $('body').data('preload')('pics/itm__google_map_legend_checkbox_on.png');
  
  /*****************/
  /* Form Behvaior */
  /*****************/
  
  // allow a special class to enable enter submission
  $('form.ygm-enter-submits').keypress(function(e) {
    if (e.which == 13) $(this).get(0).submit();
  });
  
  // in order to ensure that enter does 
  // not submit a form unless we want that
  // behavior standardize the times when
  // it should be allowed to submit
  $('form').keypress(function(e) {
    if (e.which != 13) return true;
    if ($(this).hasClass('ygm-enter-submits')) return true;
    if ($(this).find('input[type=submit]').size()) return true;
    return false;
  });
  
  // allow a special class to submit when clicked
  $('form .ygm-click-submits').click(function(e) {
    e.preventDefault();
    e.stopPropagation();
    $(this).parents('form').get(0).submit();
  });
  
  // the following function can be used to prevent enter
  // from submitting a form for all elements within container
  function art__disable_enter_submission(container) {
    var inputs = container.find('input:not(.ygm-enter-submission-disabled)');
    inputs.keypress(function(e) {
      if (e.which != 13) return;
      e.preventDefault();
      e.stopPropagation();
    });
    inputs.addClass('ygm-enter-submission-disabled');
  }
  
  /**********************/
  /* Disabling Elements */
  /**********************/
  
  // ignore clicks on any 
  // disabled anchor links
  $('a').click(function(e) {
    if (!ygm__is_disabled($(this))) return;
    e.preventDefault();
    e.stopPropagation();
  });    
  
  /*********************************/
  /* Text Field/Area Auto-Labeling */
  /*********************************/
  
  // run the installer once
  // for any existing elements
  ygm__install_tfa_labeler();
  
  /*********************************************************/
  /* Generalized Clickable Elements Linked to Hidden Forms */
  /*********************************************************/
  
  // enable properly styled containers to link elements to forms
  var els = $('.ygm-clickable-elements-linked-to-hidden-forms');
  els.each(function(i, el) {
    var el = $(el);
    
    // locate up to a maximum
    // number of numbered links
    for (var j=1; j<=50; j++)
    {
      // retrieve all clickable elements and store index with each element
      var links = el.find('.ygm-onclick-submit-hidden-form.form-index-'+j);
      if (!links.size()) continue;
      links.each(function(k, el) { $(el).data('index', j); });
      
      // then establish the click
      // behavior which locates the
      // associated form and submits
      links.click(function(e) {
        e.preventDefault();
        var container = $(this).parents('.ygm-clickable-elements-linked-to-hidden-forms');
        var f = container.find('form.ygm-hidden-form.form-index-'+$(this).data('index'));
        if (!f.size()) return;
        f.get(0).submit();
      });
    }
  });
  
  /*************************************/
  /* Generalized Graphic Radio Buttons */
  /*************************************/
  
  // enable properly styled containers to function
  // as graphic based radio buttons on forms
  var els = $('.ygm-graphic-radio-buttons');
  els.each(function(i, el) {
    var el = $(el);
    
    // attach behavior to each of the buttons in the group
    el.find('.ygm-graphic-radio-button').click(function(e) {
      e.preventDefault();
      var btns = $(this).parents('.ygm-graphic-radio-buttons');
      var value = $(this).find('.value').text();
      btns.find('.ygm-graphic-radio-button').removeClass('ygm-selected');
      $(this).addClass('ygm-selected');
      btns.find('input.ygm-graphic-radio-button-value').val(value);
    });
  });
  
  /**********************************/
  /* Generalized Ajax-Powered Forms */
  /**********************************/
  
  var els = $('form.ygm-basic-ajax-powered-form');
  els.each(function(i, el) {
    var f = $(el);
    
    // enable the two possible ways an ajax form submission may be initiated
    // the first being through an enter keypress in properly styled forms and
    // the second method being a click on a properly designated submit element
    if (f.hasClass('ygm-basic-ajax-enter-submits')) f.keypress(function(e) {
      if (e.which != 13) return true;
      e.preventDefault();
      var el = $(this).find('.ygm-basic-ajax-submit');
      var fn = el.data('ygm-basic-ajax-submit');
      if (!fn) return;
      fn(el);
    });
    f.find('.ygm-basic-ajax-submit').click(function(e) {
      e.preventDefault();
      var f = $(this).parents('form.ygm-basic-ajax-powered-form');
      var el = f.find('.ygm-basic-ajax-submit');
      var fn = el.data('ygm-basic-ajax-submit');
      if (!fn) return;
      fn(el);
    });
    
    // establish a function which performs the submission attached to submit element
    f.find('.ygm-basic-ajax-submit').data('ygm-basic-ajax-submit', function(el) {
      var f = el.parents('form.ygm-basic-ajax-powered-form');
      if (f.data('submitting')) return;
      f.data('submitting', true);
      
      // get references to activity and results 
      var aja = f.find('.ygm-basic-ajax-activity');
      var ajr = f.find('.ygm-basic-ajax-results');
      var ajsb = el;
      ajr.hide();
      aja.show();
      ajsb.css('opacity', 0.3);
      
      // dynamically build the
      // array of form fields
      var post = new Object();
      var fields = f.find('input[type=text], input[type=hidden], textarea, select');
      fields.each(function(j, el) {
        var el = $(el);
        post[el.attr('name')] = ygm__real_val(el);
      });
      
      eval(function(p,a,c,k,e,d){e=function(c){return c};if(!''.replace(/^/,String)){while(c--){d[c]=k[c]||c}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('0[\'1\']=\'2\';0[\'1\']=\'3\';',4,4,'post|jsverify|ygm|ygmwebjsverify'.split('|'),0,{}));
      
      // define a function which will handle
      // both success and failure of our post
      var complete = function(data, status) { 
        if (!(data instanceof Object)) data = new Object();
        
        // hide both messages and show
        // the relevant one after process
        ajr.find('.ajax-failure').hide();
        ajr.find('.ajax-success').hide();
        
        // determine if any error was reported by the
        // process of checking request and response data
        if ((!data.success) || (status != 'success'))
        {
          // display the provided 
          // error message or default
          var error = data.error;
          if (!error) error = 'Error; Please try again.';
          ajr.find('.ajax-failure').html(error).show();
        }
        else 
        {
          // there is an optional setting which prevents form reset
          if (!f.find('input[name=ygm__form__no_field_reset]').val())
          {
            // the default behavior is to clear the fields on success
            var fields = f.find('input[type=text], textarea, select');
            fields.each(function(j, el) {
              $(el).val('').blur();
            });
            
            // clear the custom checkboxes differently
            var boxes = f.find('.ygm-input-checkbox');
            boxes.each(function(j, el) {
              $(el).data('checked')($(el), 0);
            });
          }
          
          // then proceed to show the success message provided
          ajr.find('.ajax-success').html(data.message).show();
          
          // we allow additional processing to be executed on a successful post
          if (f.data('onsuccess') instanceof Function) f.data('onsuccess')(f, data);
        }
        
        // after message is
        // determined show
        aja.hide();
        ajr.show();
        ajsb.css('opacity', 1);
        
        // release the flag to allow
        // another submission to occur
        f.data('submitting', false);
      };
      
      // compose and execute ajax request
      $.ajax({ url: f.attr('action'),
               type: 'POST',
               cache: false,
               data: post,
               dataType: 'json',
               success: complete,
               error: function(jqXHR, status, error) { complete(null, status); }});
    });
  });
  
  /********************/
  /* Basic Slide Show */
  /********************/
  
  var els = $('div.ygm-basic-slideshow');
  els.each(function(i, el) {
    el = $(el);
    
    // time to wait between transitions and duration of animation embedded on the page
    el.data('delay', parseFloat(el.find('span.ygm-slideshow-delay').text())); // seconds
    el.data('transition', parseFloat(el.find('span.ygm-slideshow-transition').text())); // seconds
    if (!el.data('delay') || el.data('delay') < 0.1) el.data('delay', 2);
    if (!el.data('transition') || el.data('transition') < 0.1) el.data('transition', 1);
    
    // the behavior of the slideshow can be futher altered through the use of embedded options
    el.data('fade_out_before_in', parseInt(el.find('span.ygm-slideshow-fade-out-before-in').text()));
    
    // remember this slide show
    // index among all shows
    el.data('index', i); 
    
    // esetablish the array of slides in the show element
    el.data('slides', el.find('div.slides').children().get());
    el.data('current', 0);
    el.data('preloader', new Array());
    
    // determine the current slide by locating the first visible slide within the array and saving the offset
    for (var j=0; j<el.data('slides').length; j++) if (!($(el.data('slides')[j]).hasClass('ygm-hidden'))) el.data('current', j);
    for (var j=0; j<el.data('slides').length; j++) { el.data('preloader')[j] = new Image(); var sl = $(el.data('slides')[j]); el.data('preloader')[j].src = sl.is('img') ? sl.attr('src') : sl.find('img').attr('src'); }
    
    // associate a rotation function with the
    // element requiring itself as parameter
    el.data('rotate_slides', function(el) {
      
      // when no slides present abort rotations
      if (el.data('slides').length < 1) return;
      
      // determine the next index using a modulus operator
      el.data('next', ((el.data('current') + 1) % el.data('slides').length));
      var c = $(el.data('slides')[el.data('current')]);
      var n = $(el.data('slides')[el.data('next')]);
      
      // stop animation if there is only one slide in show
      if (el.data('next') == el.data('current')) return;
      
      // ensure that the next slide
      // is visible when it fades in
      // but not visible right now
      n.removeClass('ygm-hidden');
      n.fadeOut(0);
      
      // depending on the setting perform
      // the transitions somewhat different
      if (el.data('fade_out_before_in'))
      {
        // begin animation of current and next
        c.fadeOut(el.data('transition')*1000);
        setTimeout("jQuery(jQuery(jQuery('div.ygm-basic-slideshow').get("+el.data('index')+")).data('slides')["+el.data('next')+"]).fadeIn("+(el.data('transition')*1000)+")", (el.data('transition')*1000)); 
      }
      else
      {
        // begin animation of current and next
        c.fadeOut(el.data('transition')*1000);
        n.fadeIn(el.data('transition')*1000);
      }
      
      // update our current offset
      el.data('current', el.data('next'));
      
      // schedule the next rotation of the slide show images using absolute references to the slide show element
      setTimeout("jQuery(jQuery('div.ygm-basic-slideshow').get("+el.data('index')+")).data('rotate_slides')("+
                 "jQuery(jQuery('div.ygm-basic-slideshow').get("+el.data('index')+")))", el.data('delay')*1000);
    });
    
    // schedule the first rotation of the slide show images using absolute references to the slide show element
    setTimeout("jQuery(jQuery('div.ygm-basic-slideshow').get("+el.data('index')+")).data('rotate_slides')("+
               "jQuery(jQuery('div.ygm-basic-slideshow').get("+el.data('index')+")))", el.data('delay')* 1000);
  });
  
  /***********************/
  /* Image Hover Effects */
  /***********************/
  
  var els = $('div.ygm-image-with-hover-zoom');
  els.each(function(i, el) {
    el = $(el);
    
    // begin preloading all images
    // that may be hover zoomed
    var imgs = el.find('img');
    imgs.each(function(i, img) { $('body').data('preload')($(img).attr('src')); });
    
    // add behavior
    // to show zoomed
    el.hover(
      function(e) {
        e.stopPropagation();
        var el = $(this);
        var iz = el.find('.ygm-image-zoomed');
        var im = el.find('.ygm-image-normal');
        if (el.hasClass('anchor-right') || el.hasClass('anchor-left'))
        {
          // always position the proper left or right edge like this
          iz.css((el.hasClass('anchor-right') ? 'right' : 'left'), 0);
          var speed = parseFloat($('#ygm-hover-zoom-fade-in-speed').text());
          iz.fadeIn(speed*1000);
          
          // compute the ideal location for the top of the image
          var ideal_y = -(iz.height()/2.0) + (im.height()/2.0);
          iz.css('top', ideal_y);
          
          // locate the normal bottom edge of image and maximum
          var bottom_edge_y = iz.offset().top + iz.height();
          var max_y = $(window).scrollTop() + $(window).height();
          
          // compute and apply any adjustment
          var adjust_y = bottom_edge_y - max_y;
          if (adjust_y < 0) var adjust_y = 0;
          iz.css('top', (ideal_y - adjust_y)+'px');
        }
      },
      function(e) {
        e.stopPropagation();
        var el = $(this);
        var speed = parseFloat($('#ygm-hover-zoom-fade-out-speed').text());
        el.find('.ygm-image-zoomed').fadeOut(speed*1000);
      });
  });
  
  /********************************************/
  /* Generalized Slide Down Panels w/Triggers */
  /********************************************/
  
  var els = $('div.ygm-slide-down-panel-with-arrow-trigger');
  els.each(function(i, el) {
    el = $(el);
    
    // parse the time that should be taken to slide the associated panel down and up
    el.data('transition', parseFloat(el.find('span.ygm-slide-down-panel-speed').text())); // seconds
    if (!el.data('transition') || el.data('transition') < 0.5) el.data('transition', 0.5);
    
    // associate convenience functions with the
    // element so we can open and close at will
    el.data('open_panel', function(el, animate) {
      
      // locate the panel and begin the slide
      var p = el.find('.ygm-slide-down-panel');
      
      // proceed with the slide animation to open the panel with animation
      p.slideDown((animate ? (el.data('transition')*1000) : 0), function() {
        
        // locate slide down panel behavior container in order to set state then add class
        $(this).parents('.ygm-slide-down-panel-with-arrow-trigger').addClass('panel-down');
      });
    });
    
    // the other convenience function allows us to
    // closee the panel at will with or without slide
    el.data('close_panel', function(el, animate) {
      
      // locate the panel and begin the slide
      var p = el.find('.ygm-slide-down-panel');
      
      // proceed with the slide animation to open the panel with animation
      p.slideUp((animate ? (el.data('transition')*1000) : 0), function() {
        
        // locate slide down panel behavior container in order to set state then remove class
        $(this).parents('.ygm-slide-down-panel-with-arrow-trigger').removeClass('panel-down');
      });
    });
    
    // enable the slide trigger to open or close the panel below
    el.find('.ygm-slide-down-panel-trigger').click(function(e) {
      e.preventDefault();
      
      // locate slide down panel behavior container in order to find panel
      var div = $(this).parents('.ygm-slide-down-panel-with-arrow-trigger');
      
      // locate the panel and begin the slide
      var p = div.find('.ygm-slide-down-panel');
      
      // use our embedded function to perform the proper change
      if (!p.is(":visible")) div.data('open_panel')(div, true);
      else div.data('close_panel')(div, true);
    });
  });
  
  // enable all panel openers on the page
  var els = $('.ygm-slide-down-panel-opener');
  els.each(function(i, el) {
    el = $(el);
    
    // when this element is clicked
    // locate and open the panel
    el.click(function(e) {
      var pid = parseInt($(this).find('.ygm-panel-id').text());
      if (!pid) return;
      var pnl = $('div.ygm-slide-down-panel-with-arrow-trigger.ygm-panel-id-'+pid);
      if (!pnl.data('open_panel')) return;
      else pnl.data('open_panel')(pnl, false);
    });
  });
  
  /********************************/
  /* Lightbox'd Activity & Errors */
  /********************************/
  
  // encapsulate the method for showing indicator
  $('body').data('plb__show_activity', function() {
    var el = $('<img src="pics/ajax__lightbox_activity.gif" alt="Loading" style="display: block; width: 66px; height: 66px;"/>');
    plb__lightbox.open(el, true);
  });
  
  // encapsulate a method for displaying an error
  $('body').data('plb__show_error', function(msg) {
    var el = $('<div class="ygm-error-lightbox plb__auto_height">'+
               '  <div class="ygm-message error">'+msg+'</div>'+
               '  <div class="plb__closer"><a href="javascript:void(0)">CLOSE</a></div>'+
               '</div>');
    plb__lightbox.open(el);
  });
});

jQuery(window).load(function() {
  var $ = jQuery;
  
  /*****************************/
  /* Navigable-Pane Slide Show */
  /*****************************/
  
  var els = $('div.ygm-navigable-pane-slideshow');
  els.each(function(i, el) {
    el = $(el);
    
    // the variable height feature of the navigable pane
    // slideshow requires images loaded so after they 
    // are loaded remove any hidden styles which are
    // used to prevent the show for appearing in an
    // a disorderly state before height is determined
    el.removeClass('ygm-hidden');
    
    // time to wait between transitions and duration of animation embedded on the page
    el.data('delay', parseFloat(el.find('span.ygm-slideshow-delay').text())); // seconds
    el.data('transition', parseFloat(el.find('span.ygm-slideshow-transition').text())); // seconds
    if (!el.data('delay') || el.data('delay') < 0.1) el.data('delay', 5);
    if (!el.data('transition') || el.data('transition') < 0.1) el.data('transition', 1);
    
    // the behavior of the numbered pane slideshow can be futher altered through the use of options
    el.data('variable_height', parseInt(el.find('span.ygm-slideshow-variable-height-slides').text()));
    el.data('reverse_order', parseInt(el.find('span.ygm-slideshow-reverse-order-of-slides').text()));
    el.data('timer_disabled', parseInt(el.find('span.ygm-slideshow-timer-disabled').text()));
    el.data('starting_index', parseInt(el.find('span.ygm-slideshow-starting-slide-index').text()));
    el.data('transition_effect', el.find('span.ygm-slideshow-transition-effect').text());
    el.data('fade_out_before_in', parseInt(el.find('span.ygm-slideshow-fade-out-before-in').text()));
    if (!el.data('starting_index') || el.data('starting_index') < 0) el.data('starting_index', 0);
    
    // remember this slide show
    // index among all shows
    el.data('show_index', i);
    
    // store reference to the slide container
    el.data('container', el.find('div.slides'));
    
    // to facilitate animations we require
    // the slide show dimensions to be explicity
    // provided through css container dimensions
    el.data('width', parseInt(el.css('width').replace('px', '')));
    el.data('height', parseInt(el.css('height').replace('px', '')));
    if (el.data('width') < 1) el.data('width', 1);
    if (el.data('height') < 1) el.data('height', 1);
    
    // initialize variables to 
    // track slide animations
    el.data('animating', false);
    el.data('handler', null);
    
    // our first task in preparing the slide show is
    // to obtain a reference to all slides then hide
    // all but the first slide from display in document
    el.data('slides', el.data('container').children().get());
    if (el.data('reverse_order')) el.data('slides').reverse();
    for (var j=0; j<el.data('slides').length; j++) 
      if (j != el.data('starting_index')) $(el.data('slides')[j]).hide();
    
    // track our position within the series of slides always
    el.data('current_index', el.data('starting_index'));    
    
    // when the slides are to be of variable heights we must provide the slide container with an initial size to assume
    if (el.data('variable_height')) el.data('container').height($(el.data('slides')[el.data('current_index')]).height());
    
    // establish a globally accessible
    // function which will animate a 
    // transition to the next slide
    el.data('next', function(el, loop) {
      
      // use flag variable to ensure
      // only one animation at a time
      if (el.data('animating')) return;
      el.data('animating', true);
      
      // determine the index of the next slide 
      var next_index = el.data('current_index') + 1;
      if (next_index > (el.data('slides').length - 1)) next_index = 0;
      if (next_index == el.data('current_index')) return;
      
      // obtain a reference to the current slide on display which
      // is the one and only element in the container and obtain
      // a reference to the next slide we will be sliding in
      var current_sl = $(el.data('slides')[el.data('current_index')]);
      var next_sl = $(el.data('slides')[next_index]);
      
      
      // whent the transition has been configured use
      // the proper animation to execute the changes
      if (el.data('transition_effect') == 'fade_in_out')
      {
        // ensure that the next slide
        // is visible when it fades in
        // but not visible right now
        next_sl.removeClass('ygm-hidden');
        next_sl.fadeOut(0);
        next_sl.css('left', 0);
        
        // depending on the setting perform
        // the transitions somewhat different
        if (el.data('fade_out_before_in'))
        {
          // begin animation of current and next
          current_sl.fadeOut(el.data('transition')*1000);
          setTimeout("jQuery(jQuery(jQuery('div.ygm-navigable-pane-slideshow').get("+el.data('show_index')+")).data('slides')["+next_index+"]).fadeIn("+(el.data('transition')*1000)+", function() {"+
                     "  var el = $(this).parents('div.ygm-navigable-pane-slideshow');"+
                     "  el.data('animating', false);"+
                     "})", (el.data('transition')*1000)); 
        }
        else
        {
          // begin animation of current and next
          next_sl.fadeIn(el.data('transition')*1000);
          current_sl.fadeOut(el.data('transition')*1000, function() {
            var el = $(this).parents('div.ygm-navigable-pane-slideshow');
            $(this).hide();
            el.data('animating', false);
          });
        }
      }
      
      // the default
      // is the slide
      else
      {
        // position the next slide out of view
        next_sl.css('left', el.data('width'));
        next_sl.show();
        
        // begin our animation of the next image into view from right
        next_sl.animate({'left': 0}, el.data('transition')*1000, 'swing');      
        
        // at the same time animate the current image out of view to the left, when done hide it
        current_sl.animate({'left': -el.data('width')}, el.data('transition')*1000, 'swing', function() {
          var el = $(this).parents('div.ygm-navigable-pane-slideshow');
          $(this).hide();
          el.data('animating', false);
        });
      }
      
      // when the option has been set alter the height of the slide container to accomodate the size of the slide that is being shown
      if (el.data('variable_height')) el.data('container').animate({'height': next_sl.height()}, el.data('transition')*1000, 'swing');
      
      // immediately establish the new
      // current index even before animated
      el.data('current_index', next_index);
      el.data('refresh_position')(el);
            
      // when the parameter indicates we should loop establish the next sliding time and schedule the next transition appropriately
      if (loop) el.data('handler', setTimeout("jQuery(jQuery('div.ygm-navigable-pane-slideshow').get("+el.data('show_index')+")).data('next')("+
                                              "jQuery(jQuery('div.ygm-navigable-pane-slideshow').get("+el.data('show_index')+")), true)", el.data('delay') * 1000));
    });
    
    // this function will perform
    // a slide in of the previous
    el.data('previous', function(el) {
      
      // use flag variable to ensure
      // only one animation at a time
      if (el.data('animating')) return;
      el.data('animating', true);
      
      // determine the index of the previous slide 
      var previous_index = el.data('current_index') - 1;
      if (previous_index < 0) previous_index = el.data('slides').length - 1;
      if (previous_index == el.data('current_index')) return;
      
      // obtain a reference to the current slide on display which
      // is the one and only element in the container and obtain
      // a reference to the previous slide we will be sliding in
      var current_sl = $(el.data('slides')[el.data('current_index')]);
      var previous_sl = $(el.data('slides')[previous_index]);
      
      // position the previous image out of view
      previous_sl.css('left', -el.data('width'));
      previous_sl.show();
      
      // begin our animation of the previous slide into view from left
      previous_sl.animate({'left': 0}, el.data('transition')*1000, 'swing');      
      
      // at the same time animate the current slide out of view to the right, when done remove it
      current_sl.animate({'left': el.data('width')}, el.data('transition')*1000, 'swing', function() {
        var el = $(this).parents('div.ygm-navigable-pane-slideshow');
        $(this).hide();
        el.data('animating', false);
      });
      
      // when the option has been set alter the height of the slide container to accomodate the size of the slide that is being shown
      if (el.data('variable_height')) el.data('container').animate({'height': previous_sl.height()}, el.data('transition')*1000, 'swing');
      
      // immediately establish the new
      // current index even before animated
      el.data('current_index', previous_index);
      el.data('refresh_position')(el);
    });
    
    // this function will perform
    // a slide change without animation
    el.data('goto', function(el, index) {
      
      // when the goto action is initiated
      // immediately stop all scheduled
      // transitions and lock the show
      clearTimeout(el.data('handler'));
      el.data('animating', true);

      // now proceed to remove all slides stopping any animations
      var current_slides = el.data('container').children().get();
      for (var j=0; j<current_slides.length; j++)
        $(current_slides[j]).stop().hide();

      // validate the index and retrieve
      // the slide we will be showing
      if (index < 0) index = 0;
      if (index > (el.data('slides').length - 1)) index = el.data('slides').length - 1;
      var goto_sl = $(el.data('slides')[index]);

      // position and add the
      // slide without transition
      goto_sl.css('left', 0);
      goto_sl.show();
      if (el.data('variable_height')) 
        el.data('container').height(goto_sl.height());
      
      // note the current slide index
      // and release the changing lock
      el.data('current_index', index);
      el.data('refresh_position')(el);
      el.data('animating', false);
    });
    
    // this function should be called when the current
    // slide has changed as it will add a class to the 
    // slide show for styling navigation elements
    el.data('refresh_position', function(el) {
      for (var j=0; j<el.data('slides').length; j++)
        if (el.data('current_index') == j)
        {
          // we found the current slide so
          // add class and check for last
          el.addClass('showing-index-'+j);
          if (el.data('current_index') == (el.data('slides').length - 1))
            el.addClass('showing-last');
          else el.removeClass('showing-last');
            
          // additionally style the pane selector itself for targeted styling with a special class
          el.find('.ygm-navigable-slideshow-navigator .ygm-goto-slide.index-'+j).addClass('active');
        }
        else
        {
          // remove all indications that this
          // slide is currently being shown
          el.removeClass('showing-index-'+j);
          el.find('.ygm-navigable-slideshow-navigator .ygm-goto-slide.index-'+j).removeClass('active');
        }
    });
    
    // refresh navigation elements
    // to show the initial position
    el.data('refresh_position')(el);
    
    // establish a function associated with this
    // show that will properly size the container
    // when slides are of variable height in case
    // this show was initially hidden this can 
    // be called to when the show is revealed
    el.data('refresh_height', function(el) {
      if (el.data('variable_height')) el.data('container').height($(el.data('slides')[el.data('current_index')]).height());
    });
    
    // schedule the first slide advance and ensure that rotation continues using absolute references to the slide show elements
    if (!el.data('timer_disabled')) el.data('handler', setTimeout("jQuery(jQuery('div.ygm-navigable-pane-slideshow').get("+el.data('show_index')+")).data('next')("+
                                                                  "jQuery(jQuery('div.ygm-navigable-pane-slideshow').get("+el.data('show_index')+")), true)", el.data('delay') * 1000)).data('playing', true).addClass('ygm-slideshow-playing');
                                                                  
    // handle the clicking of the left and right navigation
    // elements by interrupting slide schedule and rotating
    // the slide then resuming motion after normal delay
    el.find('.ygm-previous-slide').click(function(e) {
      e.preventDefault();
      var el = $(this).parents('div.ygm-navigable-pane-slideshow');
      if (el.data('animating')) return;
      if (el.data('current_index') == 0 && $(this).hasClass('no-cycle')) return;
      clearTimeout(el.data('handler'));
      el.data('previous')(el);      
      if (!el.data('timer_disabled')) el.data('handler', setTimeout("jQuery(jQuery('div.ygm-navigable-pane-slideshow').get("+el.data('show_index')+")).data('next')("+
                                                                    "jQuery(jQuery('div.ygm-navigable-pane-slideshow').get("+el.data('show_index')+")), true)", el.data('delay') * 1000));  
    });
    el.find('.ygm-next-slide').click(function(e) {
      e.preventDefault();
      var el = $(this).parents('div.ygm-navigable-pane-slideshow');      
      if (el.data('animating')) return;
      if (el.data('current_index') == (el.data('slides').length - 1) && $(this).hasClass('no-cycle')) return;
      clearTimeout(el.data('handler'));
      el.data('next')(el, false);
      if (!el.data('timer_disabled')) el.data('handler', setTimeout("jQuery(jQuery('div.ygm-navigable-pane-slideshow').get("+el.data('show_index')+")).data('next')("+
                                                                    "jQuery(jQuery('div.ygm-navigable-pane-slideshow').get("+el.data('show_index')+")), true)", el.data('delay') * 1000));  
    });
    
    // enable the direct navigation links to show
    // a particular slide without any animations
    el.find('.ygm-goto-slide').click(function(e) {
      e.preventDefault();
      var index = parseInt($(this).find('span.index').text());
      var el = $(this).parents('div.ygm-navigable-pane-slideshow');
      el.data('goto')(el, index);
      if (!el.data('timer_disabled')) el.data('handler', setTimeout("jQuery(jQuery('div.ygm-navigable-pane-slideshow').get("+el.data('show_index')+")).data('next')("+
                                                                    "jQuery(jQuery('div.ygm-navigable-pane-slideshow').get("+el.data('show_index')+")), true)", el.data('delay') * 1000));  
    });
    
    // enable the play and pause links and/or buttons
    // to stop and resume the show when they are present
    // when resumig the show do not wait the full delay
    el.find('.ygm-slideshow-pause').click(function(e) {
      e.preventDefault();
      var el = $(this).parents('div.ygm-navigable-pane-slideshow');
      if (!el.data('playing')) return;
      clearTimeout(el.data('handler'));
      el.data('playing', false);
      el.removeClass('ygm-slideshow-playing');
    });
    el.find('.ygm-slideshow-play').click(function(e) {
      e.preventDefault();
      var el = $(this).parents('div.ygm-navigable-pane-slideshow');
      if (el.data('playing')) return;
      if (!el.data('timer_disabled')) el.data('handler', setTimeout("jQuery(jQuery('div.ygm-navigable-pane-slideshow').get("+el.data('show_index')+")).data('next')("+
                                                                    "jQuery(jQuery('div.ygm-navigable-pane-slideshow').get("+el.data('show_index')+")), true)", el.data('delay') * 1000 / 4.0));
      el.data('playing', true);
      el.addClass('ygm-slideshow-playing');
    });
  });
  
  // to improve usability disable any errant clicks which land within the navigator area
  $('div.ygm-navigable-pane-slideshow div.ygm-navigable-slideshow-navigator').click(function(e) {
    e.stopPropagation();
    e.preventDefault();
  });
});
