$(document).ready(function () {

   /**
    * Archive
    */
   if (typeof(ARCHIVE_SLIDESHOW_DATA) != 'undefined') {
      (function(years) {
         var yearCount,
            maxOffset,
            currentOffset,
            targetOffset,
            createItem, // const
            createLabel, // const
            labelParentWidth, // const
            layerElement, // const
            getOffsetStyle, // const
            items,
            labels,
            populateLayer, // const
            populateContent, // const
            loadPageContent, // const
            activeSection,
            load, // const
            unload, // const
            step, // const
            setTargetOffset, // const
            interval,
            openVideo, // const
            loadPlayer; // const

         yearCount = years.length;
         interval = null;

         if (yearCount > 0) {
            // Gather basic data.
            maxOffset = yearCount - 1;

            targetOffset = currentOffset = (function () {
               var offset,
                  activeYearId; // const

               offset = maxOffset;
               activeYearId = $.cookie('ARCHIVE_ACTIVE_YEAR');

               if (activeYearId) {
                  // Find year offset by ID.
                  $.each(years, function (index, year) {
                     if (year.id == activeYearId) {
                        offset = index;
                        return false;
                     }

                     return true;
                  });
               }

               return offset;
            }());

            labelParentWidth = $('.archive-labels').width();
            layerElement = $('.archive-slideshow .archive-layer');
            activeSection = $.cookie('ARCHIVE_ACTIVE_SECTION') || null;

            /**
             * Creates an item based on a prototype.
             */
            createItem = (function () {
               var itemPrototype;

               itemPrototype = $('<div class="archive-item">'
                                   +'<img class="archive-image" src="" alt="" />'
                                   +'<div class="archive-shading"></div>'
                                +'</div>');

               return function () {
                  return itemPrototype.clone();
               };
            }());

            /**
             * Creates a label based on a prototype.
             */
            createLabel = (function () {
               var labelPrototype;

               labelPrototype = $('<div class="archive-label">'
                                   +'<div class="year"></div>'
                                   +'<div class="line"></div>'
                                +'</div>');

               return function () {
                  return labelPrototype.clone();
               };
            }());

            /**
             * Computes position and dimensions of an item based on its position.
             */
            getOffsetStyle = (function () {
               var slideshowElement, // const
                  slideshowWidth, // const
                  slideshowHeight, // const
                  itemElement,
                  itemImageElement,
                  itemWidth, // const
                  itemHeight; // const

               slideshowElement = $('.archive-slideshow');
               slideshowWidth = slideshowElement.width();
               slideshowHeight = slideshowElement.height();

               itemElement = createItem().appendTo(slideshowElement);
               itemImageElement = itemElement.find('.archive-image');
               itemWidth = itemImageElement.width();
               itemHeight = itemImageElement.height();
               itemElement.remove();
               itemElement = null;
               itemImageElement = null;

               return function(offset, target) {
                  var style,
                     differenceToTargetOffset,
                     scaleFactor;

                  style = {
                     visible:    true,
                     dimensions: {},
                     position:   {},
                     shading:    0.0
                  };

                  // Calculate offset position.
                  differenceToTargetOffset = target - offset;
                  scaleFactor = 1 - Math.abs(differenceToTargetOffset) * 0.1;

                  // Calculate dimensions.
                  style.dimensions.width = Math.round(itemWidth * scaleFactor);
                  style.dimensions.height = Math.round(itemHeight * scaleFactor);

                  // Calculate position.
                  style.position.x = Math.round(slideshowWidth / 2 - style.dimensions.width / 2);
                  style.position.y = Math.round((slideshowHeight / 2 - style.dimensions.height / 2) - (differenceToTargetOffset * 40));
                  style.position.z = (yearCount - Math.abs(differenceToTargetOffset)) * 2;

                  // Calculate shading.
                  if (Math.abs(differenceToTargetOffset) < 3) {
                     style.shading = Math.abs(differenceToTargetOffset) * 0.33;
                  } else if (Math.abs(differenceToTargetOffset) == 3) {
                     style.shading = 1.0;
                  } else {
                     style.visible = false;
                  }

                  return style;
               };
            }());

            /**
             * Fills the info layer with the currently active year.
             */
            populateLayer = (function () {
               var infoElement, // const
                  titleElement, // const
                  yearElement, // const
                  linksElement, // const
                  playButtonElement; // const

               infoElement = layerElement.find('.info');
               titleElement = infoElement.find('.title');
               yearElement = infoElement.find('.year');
               linksElement = infoElement.find('.links');
               playButtonElement = layerElement.find('.play-button');

               return function () {
                  var year; // const

                  year = years[currentOffset];
                  titleElement.text(year.name);
                  yearElement.text(year.year);
                  playButtonElement.toggle(!!year.cbFilmId);

                  // Set required links.
                  $.each(['Selections', 'Nominations', 'Winners'], function(index, value) {
                     linksElement.find('.'+value.toLowerCase()+'-link').toggle(!!year['has'+value]);
                  });
               }
            }());

            /**
             * Fills the content-region of the page with additional information.
             */
            populateContent = (function () {
               var contentElement; // const

               contentElement = $('.content');

               return function(callback) {
                  var year; // const

                  year = years[currentOffset];
                  callback = callback || $.noop;

                  // Use the first available section if no description is
                  // available and no selection has been made manually.
                  if (activeSection === null && !year.description) {
                     $.each(['Selections', 'Nominations', 'Winners'], function(index, value) {
                        if (year['has'+value]) {
                           activeSection = value;
                           return false;
                        }

                        return true;
                     });
                  }

                  if (activeSection !== null && year['has'+activeSection]) {
                     contentElement.find('.headline-container .headline').text('');
                     contentElement.find('.content-text').html('<div class="content-box content-entry-box"><div class="archive-loader"></div></div>');

                     loadPageContent(activeSection, function(data) {
                        var contentElement;

                        data = $(data).find('.content');
                        contentElement = $('.content');

                        contentElement.find('.content-text').replaceWith(data.find('.content-text').find('a').each(function () {
                           var element = $(this);
                           element.attr('href', element.attr('href')+'?efa_mgmt_year='+year.id+'&archive');
                        }).end());

                        contentElement.find('.headline-container .headline').replaceWith(data.find('.headline-container .headline'));

                        // type-specific style corrections
                        $('.nominations-entry-block').each(function () {
                           $('.nominations-entry-box:even', this).css('margin-right', '10px');
                        });

                        callback();
                     });
                  } else {
                     // Set title.
                     contentElement.find('.headline-container .headline').text(year.description ? year.name : '');

                     // Set description.
                     contentElement.find('.content-text').html('<div class="content-box content-entry-box">'+(year.description || '')+'</div>');

                     callback();
                  }
               };
            }());

            /**
             * Replaces the content section of a given page with the content
             * of a given one.
             */
            loadPageContent = (function () {
               var sectionMapping, // const
                  cache;

               sectionMapping = {
                  'Winners':     'efanight/winners',
                  'Selections':  'selection/films',
                  'Nominations': 'nominations/films'
               };

               cache = {};

               return function(section, callback) {
                  var year, // const
                     url; // const

                  callback = callback || $.noop;
                  year = years[currentOffset];
                  url = DR+'en_EN/'+sectionMapping[section]+'?efa_mgmt_year='+year.id;

                  if (cache[url]) {
                     callback(cache[url]);
                  } else {
                     $.get(url, function(data) {
                        cache[url] = data;
                        callback(cache[url]);
                     });
                  }
               };
            }());

            /**
             * Fires if the slideshow reaches its target position.
             */
            load = function () {
               // Fill in new information.
               populateLayer();
               populateContent();

               // Show info layer.
               layerElement.stop().animate({
                  opacity: 1.0
               }, 500);
            };

            /**
             * Fires if the slideshow moves away from its last target position.
             */
            unload = function () {
               // Stop running videos.
               $('#player').html('').hide();

               // Hide info layer.
               layerElement.stop().animate({
                  opacity: 0.0
               }, 50);
            };

            /**
             * Moves the slideshow one step further to the targeted item (year).
             */
            step = (function () {
               var isMoving,
                  isAtTargetOffset,
                  moveCallback,
                  activeMoveCount,
                  stepOffset;

               // We are not moving by default.
               isMoving = false;

               // We initialize with the target offset.
               isAtTargetOffset = true;

               /**
                * Gets called if an animation finishes.
                */
               moveCallback = function () {
                  activeMoveCount -= 1;

                  // Are we done moving?
                  if (activeMoveCount == 0) {
                     isMoving = false;
                     currentOffset = stepOffset;
                     $.cookie('ARCHIVE_ACTIVE_YEAR', years[currentOffset].id);

                     if (currentOffset == targetOffset) {
                        isAtTargetOffset = true;

                        if (interval !== null) {
                           clearInterval(interval);
                           interval = null;
                        }

                        load();
                     }
                  }
               };

               /**
                * Triggers a step if it is possible and needed.
                */
               return function () {
                  var direction,
                     duration;

                  // Set animation direction. Possible values are:
                  //  -1   backward
                  //   0   no movement (default)
                  //   1   forward
                  direction = 0;

                  // Start a new step only of we are not already at our targeted
                  // position.
                  if (currentOffset != targetOffset) {
                     // Start a new step only if we are not moving already.
                     if (!isMoving) {
                        isMoving = true;

                        // Fire callback if we are moving away from the last
                        // reached target position.
                        if (isAtTargetOffset) {
                           isAtTargetOffset = false;
                           unload();
                        }

                        // Determine direction.
                        if (currentOffset < targetOffset) {
                           direction = 1;
                        } else if (currentOffset > targetOffset) {
                           direction = -1;
                        }

                        // Calculate offset of the current step.
                        stepOffset = currentOffset + direction;

                        // There are no active animations when reaching this.
                        activeMoveCount = 0;

                        // Calculate duration of the animation (the greater the
                        // distance between current offset and target offset,
                        // the faster the animation).
                        duration = 500 / ((Math.abs(targetOffset - stepOffset) + 1) * 1.5);

                        // Traverse items and apply animations.
                        $.each(items, function(index, item) {
                           var style;

                           style = getOffsetStyle(index, stepOffset);

                           // Is the item visible at all?
                           if (style.visible) {
                              // Make sure the item can be seen.
                              item.show();

                              // Track the number of awaited callbacks to
                              // identify the last one that gets invoked.
                              activeMoveCount += 3;

                              // Move.
                              if (index == currentOffset) {
                                 activeMoveCount += 1;

                                 item.animate({
                                    opacity: 0.0
                                 }, {
                                    duration: Math.round(duration * 0.4),
                                    queue:    false,
                                    easing:   'linear',
                                    complete: function () {
                                       item.animate({
                                          opacity: 1.0
                                       }, {
                                          duration: Math.round(duration * 0.6),
                                          queue:    false,
                                          easing:   'linear',
                                          complete: moveCallback
                                       });
                                    }
                                 });
                              } else if (index == stepOffset) {
                                 item.css({
                                    zIndex: style.position.z - 1
                                 });
                              }

                              item.animate({}, {
                                 duration: Math.round(duration * 0.4),
                                 queue:    false,
                                 complete: function () {
                                    $(this).css({
                                       zIndex: style.position.z
                                    });
                                 }
                              });

                              item.animate({
                                 top:  style.position.y+'px',
                                 left: style.position.x+'px'
                              }, {
                                 duration: duration,
                                 queue:    false,
                                 easing:   'linear',
                                 complete: moveCallback
                              });

                              item.find('.archive-image').animate({
                                 width:  style.dimensions.width+'px',
                                 height: style.dimensions.height+'px'
                              }, {
                                 duration: duration,
                                 queue:    false,
                                 easing:   'linear',
                                 complete: moveCallback
                              });

                              item.find('.archive-shading').animate({
                                 opacity: style.shading
                              }, {
                                 duration: duration,
                                 queue:    false,
                                 easing:   'linear',
                                 complete: moveCallback
                              });
                           } else {
                              // Ignore item to save some CPU cycles, since it
                              // would not even be visible.
                              item.hide();
                           }
                        });
                     }
                  }
               };
            }());

            /**
             * Sets the target offset.
             */
            setTargetOffset = function(offset) {
               if (offset != targetOffset) {
                  targetOffset = offset;
                  labels[targetOffset].addClass('active').siblings().removeClass('active');

                  if (!jQuery.fx.off) {
                     if (interval === null) {
                        interval = setInterval(step, 16);
                     }
                  } else {
                     // Jump to the given offset.
                     while (currentOffset != targetOffset) {
                        step();
                     }
                  }
               }
            };

            /**
             * Embeds a player for the given video.
             */
            loadPlayer = function(file, image, id) {
               var container = $('#player');

               // Make sure the player is fully visible.
               container.stop().css({
                  opacity: 1.0
               }).show();

               // Remove everything in the container and add a player element.
               container.empty();
               $(document.createElement('div')).addClass('__CbUiPlayer').appendTo(container);

               // Fire it up!
               CbPlayerWindow.create(container, {
                  config:   'efa',
                  movie_id: id,
                  image:    image,
                  width:    720,
                  height:   400,
                  modal:    false
               }, 'CbSimplePlayerWindow');
            };

            /**
             * Loads a videos meta data and embeds the player for displaying it.
             */
            openVideo = (function () {
               var cache;

               cache = {};

               return function(id) {
                  if (!cache[id]) {
                     $.post(DR+'ajax.php?method=getFilm', {id:id}, function(data) {
                        cache[id] = data;
                        loadPlayer(cache[id].file, cache[id].image, id);
                     }, 'json');
                  } else {
                     loadPlayer(cache[id].file, cache[id].image, id);
                  }
               };
            }());

            // Create all items.
            items = [];
            labels = [];
            $.each(years, function(index, year) {
               var style,
                  item,
                  label;

               style = getOffsetStyle(index, targetOffset);

               // Create item and set position.
               item = createItem().css({
                  top:    style.position.y+'px',
                  left:   style.position.x+'px',
                  zIndex: style.position.z
               });

               // Set item size.
               item.find('.archive-image').attr('src', year.image ? year.image.replace(/&amp;/g, '&') : DR+'media/jpg/archive_slideshow_default.jpg').css({
                  width:  style.dimensions.width+'px',
                  height: style.dimensions.height+'px'
               });

               // Set initial item shading.
               item.find('.archive-shading').css({
                  opacity: style.shading
               });

               // Do we need to calculate the items properties?
               if (!style.visible) {
                  item.hide();
               }

               items.push(item.appendTo('.archive-slideshow'));

               // Create label.
               label = createLabel().css({
                  left: (labelParentWidth / maxOffset * index)+'px'
               });

               // Add year to label.
               label.find('.year').text(year.year);

               // Set the last item active.
               if (index == maxOffset) {
                  label.addClass('active');
               }

               labels.push(label.appendTo('.archive-labels'));
            });

            // Lets get ready to rumble!
            (function () {
               var sliderElement,
                  layerLinksElement,
                  isLoadingContent;

               isLoadingContent = false;

               sliderElement = $('#ui-archive-slider').slider({
                  value:   currentOffset,
                  min:     0,
                  max:     maxOffset,
                  step:    0.001,
                  animate: false,
                  slide:   function(event, ui) {
                     setTargetOffset(Math.round(ui.value));
                  },
                  change:  function(event, ui) {
                     var animatedObject;

                     if (event.originalEvent) {
                        animatedObject = {
                           pos: ui.value
                        };

                        // Move slider back to the rounded target offset.
                        $(animatedObject).animate({
                           pos: Math.round(ui.value)
                        }, {
                           duration: 250,
                           step:     function () {
                              sliderElement.slider('value', animatedObject.pos);
                           },
                           complete: function () {
                              sliderElement.slider('value', Math.round(ui.value));
                           }
                        });
                     }
                  }
               });

               // Bind play-button.
               $('.archive-layer .play-button').click(function () {
                  $(this).hide();

                  $('#player').css({
                     opacity: 0.0
                  }).show().animate({
                     opacity: 0.5
                  }, 250);

                  openVideo(years[currentOffset].cbFilmId);
                  return false;
               });

               // Fix slider caps not being clickable.
               $('.archive-slider').click(function(e) {
                  var clickPosition;

                  clickPosition = e.pageX - $(this).offset().left;

                  if (clickPosition <= parseInt(sliderElement.css('margin-left'), 10)) {
                     sliderElement.slider('value', 0);
                     setTargetOffset(0);
                  } else if (clickPosition >= $(this).width() - parseInt(sliderElement.css('margin-right'), 10)) {
                     sliderElement.slider('value', maxOffset);
                     setTargetOffset(maxOffset);
                  }

                  return false;
               });

               // Paste initial data.
               populateLayer();
               populateContent();

               // Disable animations for older IE's and iPad/iPhone/iPad.
               if (($.browser.msie && $.browser.version < 9) || navigator.userAgent.match(/iPhone|iPod|iPad/i)) {
                  jQuery.fx.off = true;
               }

               // Bind layer links.
               layerLinksElement = layerElement.find('.links');

               $.each(['Selections', 'Nominations', 'Winners'], function(index, value) {
                  layerLinksElement.find('.'+value.toLowerCase()+'-link').click(function () {
                     var sliderShadingElement; // const

                     if (!isLoadingContent) {
                        isLoadingContent = true;

                        sliderShadingElement = $('.archive-container .archive-slider-shading');
                        sliderShadingElement.css('opacity', 0.7).show();

                        activeSection = value;
                        $.cookie('ARCHIVE_ACTIVE_SECTION', activeSection);

                        populateContent(function () {
                           sliderShadingElement.hide();
                           isLoadingContent = false;
                        });
                     }

                     return false;
                  });
               });

               layerElement.find('.info .title, .info .year').click(function () {
                  activeSection = null;
                  populateContent();
                  return false;
               });
            }());
         }
      }(ARCHIVE_SLIDESHOW_DATA));
   }

});
