// allow only alphanumeric, underscore, and hyphens in the location hash
locationHash = location.hash.replace(/[^\w\-]/g,'');

/**
 * Simple template class that replaces brace-delimited tokens.
 *
 * example:
 * <div>{lastName}, {firstName}</div>
 */
function Template(html)
{
  var getVal = function(d, key)
    {
      // base case: key is not in dot notation
      if (-1 == key.indexOf('.')) return d[key];
      
      // complex case: convert dot notation key into nested map lookup
      //   e.g. foo.bar.baz ==> d['foo']['bar']['baz']
      eval("var val = d['" + key.replace(/\./g, "']['") + "'];");
      return val;
    };

  // compile the template to produce a this.render() method
  eval(
    "this.render = function(d) { return '" +
       html.replace(/(['\n])/g,'\\$1')                           /* escape quote and crlf     */
           .replace(/\{([^}]+)\}/g, "' + getVal(d,'$1') + '") +  /* replace each braced token */
    "'; }"
  );
}
Template.prototype = 
{
  /**
   * Overwrites the html in the passed jquery element with the template data.
   * If the data passed is an array a copy of the template will be inserted
   * for each object in the array.
   */
  overwrite: function(jQueryElement, data)
    {
      var html = '';

      if ($.isArray(data))
      {
        for(var i=0; i<data.length; i++)
        {
          // make a deep copy of the data so we can add the {#} token (array
          // index) to the map without modifying the supplied data
          html += this.render($.extend(true,{'#':i},data[i]));
        }
      }
      else
      {
        html = this.render(data);
      }
      
      jQueryElement.html(html);
    }
};

$(document).ready(function()
{
  var eq = function(index)
  {
    return ':eq(' + index + ')';
  }

  // add as homepage
  $("a.jqhomepage").click(
    function(event)
    {
      event.preventDefault(); // cancel the click
      var url = this.href;
      var title = this.title;

      if (document.all) // IE
      {
        document.body.style.behavior = 'url(#default#homepage)';
        document.body.setHomePage(url);
      }
      else if (window.sidebar) // FF
      {
        if (window.netscape)
        {
          try
          {
            netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
          }
          catch (e)
          {
            alert('Your browser did not allow the bookmark to be\nadded. You may still add it manually from\n\nTools menu > Options... > Main tab > Startup');
          }
        }

        Components.classes['@mozilla.org/preferences-service;1']
         .getService(Components.interfaces.nsIPrefBranch)
           .setCharPref('browser.startup.homepage', url);
      }
    });

  // bookmarks
  if(window.opera)
  {
    if ($("a.jqbookmark").attr("rel") != "")
    {
      $("a.jqbookmark").attr("rel","sidebar");
    }
  }

  $("a.jqbookmark").click(
    function(event)
    {
      event.preventDefault(); // cancel the click
      var url = this.href;
      var title = this.title;

      if (window.sidebar) // FF
      {
        window.sidebar.addPanel(title, url, '');
      }
      else if( window.external ) // IE
      {
        window.external.AddFavorite(url, title);
      }
      else if (!window.opera) // anything not opera
      {
        alert('This browser does not support automatic bookmarks.\nPlease book mark this page manually.');
      }
    });

  // configure search bar events to prompt message
  //
  // todo: icon dropdown to select: movies, tv, actors, tags, friends
  $('#mainnav .search form input')
    .focus(function()
      {
        var f = $(this.form);
        if(f.hasClass('prompt'))
        {
          this.value = '';
          f.removeClass('prompt');
        }
      })
    .blur(function()
      {
        var f = $(this.form),
            quote = $(this).attr('data-movie-quote'),
            qRE = new RegExp('^('+quote+')?$');
        if ($.trim(this.value).match(qRE))
        {
          f.addClass('prompt');
          this.value = quote;
        }
      });

  // list-box li hovering
  //
  $('.list-box li')
    .mouseover(function(){$(this).addClass('hover');})
    .mouseout(function(){$(this).removeClass('hover');});

  // gbtn-hover-list
  //  o  hover the list adds the 'hover' class to the <li>
  //  o  click the list navigates the a.gbtn url (GO)
  //  o  hover the username/thumbnail adds the 'profile-hover' class to the <li>
  //  o  click the username/thumbnail navigates to the profile
  //
  $('ul.gbtn-hover-list li, #comments ul li')
    .each(
      function(i)
      {
        var li = $(this);
        li.mouseover(function(){li.addClass('hover');})
          .mouseout(function(){li.removeClass('hover');})
          .click(function(){location.href=li.find('a.gbtn').get();})
          .find('a.profile')
            .mouseover(function(){li.addClass('profile-hover') ;})  
            .mouseout(function(){li.removeClass('profile-hover');});
      });

  // *** navbar highlighting on mouseover
  //
  $(".submenu").each(function () {
      $(this).hover(function () {
          $(this).prev('.url').toggleClass('submenu-hover');
      });
  });

  // nav-switch content switcher
  //
  $('.nav-switch').each(
    function()
    {
      $(this)
        .find('.nav a:not(.noswitch)').each(
          function(i)
          {
            $(this)
              .data('index', i)
              .click(function()
                {
                  var sel = $(this);
                  var old = sel.siblings('.selected');
                  var cx = sel.parents('.nav-switch');

                  old.removeClass('selected');
                  sel.addClass('selected');

                  cx.find('.switch' + eq(old.data('index'))).hide();
                  cx.find('.switch' + eq(sel.data('index'))).show();
                  
                  return false;
                });
          })
        .end()
        .find('.nav a.selected').click();
      
      // support for menu selection via location hash match on the class name
      
      if (locationHash)
      {
        $(this).find('.nav a.'+locationHash).click();
      }
      
    });

  // initializes the promo player
  //
  $('#promoplayer').each(
    function()
    {
      var promo = $(this);
      var items = $('#promoplayer ul li img');

      var setText =
        function(movie, tag)
        {
          var hasTag = (tag) ? true : false;
          $('#promoplayer #promolabel').text(movie).toggleClass('tag', hasTag);
          $('#promoplayer #promotagline').text(tag);
        };

      var fadeTo =
        function(index)
        {
          // fade out the current promo
          $('#promoplayer li.selected')
            .removeClass('selected')
            .fadeOut('normal',
              function() // fade in the new promo
              {
                // deselect the current thumb
                $('#promoplayer img.th-sel').removeClass('th-sel');
                // select thumbnail+promo, and set the promo label and tagline
                $('#promoplayer .promothumb'+eq(index)).addClass('th-sel');
                setText(items[index].title, items[index].alt);
                $('#promoplayer li'+eq(index)).addClass('selected').fadeIn('normal');
              });
        };

      var fadeToNext =
        function()
        {
          fadeTo((1 + $('#promoplayer img.th-sel').data('index')) % items.length);
        };

      var cancelLoop =
        function()
        {
          clearInterval(promo.data('loopid'));
        };

      // create the elements for the label and label background
      promo.append(
          '<div id="promolabelbg"></div>'
        + '<div id="promolabel"></div>'
        + '<div id="promotagline"></div>');

      // add the thumbnails to the ui
      for (var i=0, len=items.length; i<len; i++)
      {
        var promoId = 'promo_thumb_' + i;
        promo.append('<img class="promothumb"'
             + ' id="'    + promoId      + '"'
             + ' src="'   + items[i].src + '"'
             + ' title="' + items[i].title + '"'
             + '>');

        // position the thumbs relative at: 5, 56, 107, 158...
        // and assign the event handlers and set up the promos

        $('#'+promoId)
          .css('top', (5 + (i * 51)) + 'px')
          .mouseover(function(){$(this).addClass('th-hover');})
          .mouseout(function(){$(this).removeClass('th-hover');})
          .click(function(){cancelLoop();fadeTo($(this).data('index'));})
          .data('index',i)
          .data('tagline', items[i].src);
      }

      $('#promolabelbg').fadeTo('slow',0.75);

      // select first thumbnail+promo, and set the promo label
      $('#promoplayer .promothumb:first').addClass('th-sel');
      $('#promoplayer li:first').addClass('selected');
      setText(items[0].title, items[0].alt);

      // hide all the other promos
      $('#promoplayer li:gt(0)').css('display', 'none');

      // hide all the other promos
      $('#promoplayer li:gt(0)').css('display', 'none');

      // start the automatic looping of promos
      promo.data('loopid', setInterval(function(){fadeToNext()}, 6000) );
    });

  // singletons are attached to the window since we're in a closure

  /**
   * User singleton class.
   */
  window.User = new (function()
  {
    var LOGGED_IN = 'is-logged-in';
    
    var loginUrl = '/user/login?' + $.param({'return':location.pathname});
  
    this.isLoggedIn =
      function()
      {
        return $('body').hasClass(LOGGED_IN);
      };
      
    this.setLoggedIn =
      function(isLoggedIn)
      {
        $('body').toggleClass(LOGGED_IN, isLoggedIn)
      };
      
    this.gotoLoginPage =
      function()
      {
        location.href = loginUrl;
      };

    this.gotoProfile =
      function()
      {
        if (!this.isLoggedIn)
        { 
          this.gotoLoginPage();
        }

        location.href = $('.content .welcome a.profile').attr('href');
        return false;
      }

    /**
     * fix no-op urls to cancel the link navigation
     */
    $('a[href="#"]').click(function(){return false;});
  })();

  /**
   * Textarea limiter singleton class. The basic markup below may be expanded
   * to support more complex markups or additional elements. The var element
   * should be set to the maximum string length, but once initialized it shows
   * the number of characters remaining.
   *
   * <div class="maxlength-textarea">
   *   <textarea></textarea>
   *   <var>15</var>
   * </div>
   */
  window.TextareaLimiter = new (function()
  {
    // Public function to synchronize the passed textarea to its counter.
    this.sync = 
      function(textarea)
      {
        syncFn($(textarea));
      }

    // Private function synchronizes a counter to a textarea and chops the
    // textarea if it is longer than the configured maximum.
    var syncFn = 
      function(txt)
      {
        var val = txt.val();
        var len = val.length;
        var max = txt.data('max');
        var ctr = txt.parents('.maxlength-textarea').find('var');

        if (len > max)
        {
          txt.val(val.substring(0,max));
          ctr.text(0);
        }
        else
        {
          ctr.text(max-len);
        }
      }
    
    // init the maxlength textareas so the watch function runs when the
    // textarea is focused and then stops once the textarea is blurred
    
    var initFn =
      function()
      {
        var el = $(this);

        if (!el.attr('max'))
        {
          el.attr('max', el.find('var').text());
        }

        var tx =
          el.find('textarea')
            .data('max', el.attr('max'))
            .focus(function(e)
              { 
                // sync the counter to the textarea every second -- this
                // approach causes no slowdown while typing compared to
                // listening to the textarea's change or keypress events
                var txt = $(this);
                txt.data('intervalId', window.setInterval(
                  function() { syncFn(txt); }, 1000));
              })
            .blur(function(e)
              {
                window.clearInterval($(this).data('intervalId'));
              });
            
        syncFn(tx); // sync the counter to its textarea
      };

    this.init = initFn;
    
    $('.maxlength-textarea').each(initFn);

  })();

  /**
   * Custom jQuery validators
   */
  if (jQuery.validator)
  {
    // add custom username regex mask
    jQuery.validator.addMethod('username', function(val, el) { 
      return this.optional(el) || /^[a-zA-Z0-9.@_-]+$/.test(val); },
      'Use only letters, numbers, (.), (-), (_), or (@).'
    );
  }

});

var Trailers = new (function() {
  var index = 0;
  var trailerData = [];

  this.init = function(data)
    {
      trailerData = data;
      var count = trailerData.length;
      
      if (count > 0)
      {
        $('#user-trailers')
          .removeClass('no-trailers')
          .toggleClass('no-nav', count == 1);

        drawTrailer(trailerData[index]);
      }
      
    };

  this.prev = function()
    {
      index = (0==index) ? trailerData.length-1 : --index;
      drawTrailer(trailerData[index]);
    };

  this.next = function()
    {
      index = (index + 1) % trailerData.length;
      drawTrailer(trailerData[index]);
    };

  this.remove = function(urlPrefix)
    {
      if (confirm('Delete this trailer?'))
      {
        location.href = urlPrefix + trailerData[index].id;
      }
    }

  // private members
  var drawTrailer = function(data)
    {
      $('#user-trailers h3').html(data.title);
      $('#user-trailers .video').html(data.embed);

      // set the "N of M" polls message
      $('#user-trailers .position').html((trailerData.length > 1)
        ? (1+index) + ' of ' + trailerData.length
        : '');

    
    };
    
})();

// gotcha colorbox configuration:
$(function(){

  $(".email-invitation").colorbox({
    width:"60%",
    height:"70%",
    iframe:true,
    onOpen:function() { $('embed, object').css('visibility', 'hidden'); },
    onClosed:function() { $('embed, object').css('visibility', 'visible'); }
  });

  if (locationHash == 'invite')
  {
    $.fn.colorbox({
      width:"60%",
      height:"70%",
      iframe:true,
      onOpen:function() { $('embed, object').css('visibility', 'hidden'); },
      onClosed:function() { $('embed, object').css('visibility', 'visible'); },
      href:'/user/email-invite'
    });
  }

  if (locationHash == 'ad-evolve')
  {
    $('.cbox-countdown').live('click', function() {
      var el = $(this);
      clearInterval(el.find('span').data('interval'));
      el.hide();
    });

    $.fn.colorbox({
      width:'995px',
      height:'458px',
      iframe:true,
      title:'<div style="font:12pt arial; margin-right:25px; color:#000;">Content will be available in <span>15 seconds</span>.</div>',
      onLoad:
        function()
        {
          // hide cose button for a few seconds
          $('#cboxClose').hide();
          setTimeout(function() {$('#cboxClose').show();}, 5000);
        },
      onClosed:function() { $('embed, object').css('visibility', 'visible'); },
      overlayClose: false,
      href:'http://www.gotchamovies.com/test/ad-evolve.php'
    });
  }
});

// showtimes and tickets form
$(function() {
  var loc = $('form.showtimes .loc'),
      placeholder = 'Enter ZIP code or City, State';

  // wipe/restore the location placeholder on focus/blur
  loc.focus(function(){ if (placeholder==this.value) this.value = '' })
     .blur(function() { if (!$.trim(this.value)) this.value=placeholder })
     .blur();

  // cancels form submit if location field is empty or has placeholder text
  $('form.showtimes').submit(function() {
      if (placeholder==loc.blur().val()) {
          loc.focus();
          return false;
      }
  })
});

