﻿/// <reference name="MicrosoftAjax.js" />
/// <reference name="MicrosoftAjaxWebForms.js" />
/// <reference path="jquery-vsdoc.js" />


/****************************************************************************************************/
/***** jQuery 3rd-Party Plugins *********************************************************************/
/****************************************************************************************************/

/*
* jqModal - Minimalist Modaling with jQuery
*   (http://dev.iceburg.net/jquery/jqModal/)
*
* Copyright (c) 2007,2008 Brice Burgess <bhb@iceburg.net>
* Dual licensed under the MIT and GPL licenses:
*   http://www.opensource.org/licenses/mit-license.php
*   http://www.gnu.org/licenses/gpl.html
* 
* $Version: 07/06/2008 +r13
*/
(function($)
{
  $.fn.jqm = function(o)
  {
    var p = {
      overlay: 50,
      overlayClass: 'jqmOverlay',
      closeClass: 'jqmClose',
      trigger: '.jqModal',
      ajax: F,
      ajaxText: '',
      target: F,
      modal: F,
      toTop: F,
      onShow: F,
      onHide: F,
      onLoad: F
    };
    return this.each(function()
    {
      if (this._jqm) return H[this._jqm].c = $.extend({}, H[this._jqm].c, o); s++; this._jqm = s;
      H[s] = { c: $.extend(p, $.jqm.params, o), a: F, w: $(this).addClass('jqmID' + s), s: s };
      if (p.trigger) $(this).jqmAddTrigger(p.trigger);
    });
  };

  $.fn.jqmAddClose = function(e) { return hs(this, e, 'jqmHide'); };
  $.fn.jqmAddTrigger = function(e) { return hs(this, e, 'jqmShow'); };
  $.fn.jqmShow = function(t) { return this.each(function() { $.jqm.open(this._jqm, t); }); };
  $.fn.jqmHide = function(t) { return this.each(function() { $.jqm.close(this._jqm, t) }); };

  $.jqm = {
    hash: {},
    open: function(s, t)
    {
      var h = H[s], c = h.c, cc = '.' + c.closeClass, z = (parseInt(h.w.css('z-index'))), z = (z > 0) ? z : 3000, o = $('<div></div>').css({ height: '100%', width: '100%', position: 'fixed', left: 0, top: 0, 'z-index': z - 1, opacity: c.overlay / 100 }); if (h.a) return F; h.t = t; h.a = true; h.w.css('z-index', z);
      if (c.modal) { if (!A[0]) L('bind'); A.push(s); }
      else if (c.overlay > 0) h.w.jqmAddClose(o);
      else o = F;

      h.o = (o) ? o.addClass(c.overlayClass).prependTo('body') : F;
      if (ie6) { $('html,body').css({ height: '100%', width: '100%' }); if (o) { o = o.css({ position: 'absolute' })[0]; for (var y in { Top: 1, Left: 1 }) o.style.setExpression(y.toLowerCase(), "(_=(document.documentElement.scroll" + y + " || document.body.scroll" + y + "))+'px'"); } }

      if (c.ajax)
      {
        var r = c.target || h.w, u = c.ajax, r = (typeof r == 'string') ? $(r, h.w) : $(r), u = (u.substr(0, 1) == '@') ? $(t).attr(u.substring(1)) : u;
        r.html(c.ajaxText).load(u, function() { if (c.onLoad) c.onLoad.call(this, h); if (cc) h.w.jqmAddClose($(cc, h.w)); e(h); });
      }
      else if (cc) h.w.jqmAddClose($(cc, h.w));

      if (c.toTop && h.o) h.w.before('<span id="jqmP' + h.w[0]._jqm + '"></span>').insertAfter(h.o);
      (c.onShow) ? c.onShow(h) : h.w.show(); e(h); return F;
    },
    close: function(s)
    {
      var h = H[s]; if (!h.a) return F; h.a = F;
      if (A[0]) { A.pop(); if (!A[0]) L('unbind'); }
      if (h.c.toTop && h.o) $('#jqmP' + h.w[0]._jqm).after(h.w).remove();
      if (h.c.onHide) h.c.onHide(h); else { h.w.hide(); if (h.o) h.o.remove(); } return F;
    },
    params: {}
  };
  var s = 0, H = $.jqm.hash, A = [], ie6 = $.browser.msie && ($.browser.version == "6.0"), F = false,
i = $('<iframe src="javascript:false;document.write(\'\');" class="jqm"></iframe>').css({ opacity: 0 }),
e = function(h) { if (ie6) if (h.o) h.o.html('<p style="width:100%;height:100%"/>').prepend(i); else if (!$('iframe.jqm', h.w)[0]) h.w.prepend(i); f(h); },
f = function(h) { try { $(':input:visible', h.w)[0].focus(); } catch (_) { } },
L = function(t) { $()[t]("keypress", m)[t]("keydown", m)[t]("mousedown", m); },
m = function(e) { var h = H[A[A.length - 1]], r = (!$(e.target).parents('.jqmID' + h.s)[0]); if (r) f(h); return !r; },
hs = function(w, t, c)
{
  return w.each(function()
  {
    var s = this._jqm; $(t).each(function()
    {
      if (!this[c]) { this[c] = []; $(this).click(function() { for (var i in { jqmShow: 1, jqmHide: 1 }) for (var s in this[i]) if (H[this[i][s]]) H[this[i][s]].w[i](this); return F; }); } this[c].push(s);
    });
  });
};
})(jQuery);

/**
* Copyright (C) 2009 Jonathan Azoff <jon@azoffdesign.com>
*
* jQuery.log v1.0.0 - A jQuery plugin that unifies native console logging across browsers
*/

(function($)
{
  $.extend({ "log": function()
  {
    if (arguments.length > 0)
    {
      // join for graceful degregation
      var args = (arguments.length > 1) ? Array.prototype.join.call(arguments, " ") : arguments[0];

      // this is the standard; firebug and newer webkit browsers support this
      try
      {
        console.log(args);
        return true;
      } catch (e)
      {
        // newer opera browsers support posting erros to their consoles
        try
        {
          opera.postError(args);
          return true;
        } catch (e) { }
      }

      // catch all; a good old alert box
      //      alert(args);
      return false;
    }
  }
  });
})(jQuery);



/****************************************************************************************************/
/***** CMG Branded Stores ***************************************************************************/
/****************************************************************************************************/

Type.registerNamespace("BrandedStores");



///
/// Class PinEntryBarWidget
///
/// Wraps the client functionality of the promotional code entry bar. The
/// bar has the text entry field and the submit button, which is clicked
/// by user when promo code is entered.
///
/// Class is static and cannot be instanciated. The class contains a static
/// Init() fucntion which initialized the singleton instance of the class.
/// All functions of this class are used internally and are not intended to
/// be used anywhere else on the page.
///

BrandedStores.PinEntryBarWidget = function()
{
  var instance = this;
  BrandedStores.PinEntryBarWidget.getInstance = function() { return instance; }

  this.$ctl = null; // control selector used as selector scope
  this.settings = null; // some extra params that will be set on init

  return BrandedStores.PinEntryBarWidget;
}

BrandedStores.PinEntryBarWidget.prototype =
{
  /*
  * Initializes and sets up the client-side object represending current widget. 
  * The call to Init() function must follow the constructor.
  */
  Init: function(settings)
  {
    this.settings = settings;

    //
    // HANDLE PAGEREQUESTMANAGER EVENTS
    //

    var instance = BrandedStores.PinEntryBarWidget.getInstance();
    var prm = Sys.WebForms.PageRequestManager.getInstance();
    // handle pageLoaded that occurs after content is updated as a result of regular or async postback
    prm.add_pageLoaded(Function.createDelegate(this, function(sender, args)
    {
      // if dynamic content was refreshed for the current widget
      $.each(args.get_panelsUpdated(), function(idx, elem)
      {
        if (elem.id == instance.settings.UpdatePanelID)
        {
          instance.DynamicContentLoaded(args);
          return false;
        }
      });
    }));

    //
    // DO THE REST OF INITIALIZATION
    //

    // setup control scope selector
    this.$ctl = $("#" + this.settings.ContainerID);
    if (this.$ctl.length != 1) throw "Unable to get control selector";

    // call function to complete initialization
    this.InitialContentLoaded();
    // initically trigger dynamic content handler as well
    this.DynamicContentLoaded();

    Sys.Debug.trace("PinEntryBarWidget: Init() completed");
  },

  /*
  * InitialContentLoaded() called only once at 1st page load. Should be used to perform initial widget
  * setup (before dynamic content is loaded) such as binding jQuery events to static content (outside 
  * of the update panel) or somehting else.
  */
  InitialContentLoaded: function()
  {
    var $ctl = this.$ctl;
    var instance = this;

    Sys.Debug.trace("PinEntryBarWidget: InitialContentLoaded() completed");
  },

  /*
  * DynamicContentLoaded() called each time after content is loaded to the update panel of current 
  * widget EXCEPT initial loading. Might be used to rebind jQuery events, since event bingings for
  * updatable content are discarded each time after update panel is refreshed.
  */
  DynamicContentLoaded: function(args)
  {
    var $ctl = this.$ctl;
    var instance = this;

    //
    // jquery event binding
    //

    $(".PTBS-btn-submit", this.$ctl).click(function()
    {
      // retrieve pin code entered by user
      var inputText = $(".PTBS-input-text", $ctl).val();

      // simulate async postback to catch it on the server side
      var updatePanelID = BrandedStores.PinEntryBarWidget.getInstance().settings.UpdatePanelID;
      __doPostBack(updatePanelID, "SubmitUserInput|" + inputText);
      // IMPORTANT !!! Return false to prevent any default behavior on the clickable
      // element to prevent automatic form postback for image and submit buttons
      return false;
    });

    Sys.Debug.trace("PinEntryBarWidget: DynamicContentLoaded() completed");
  }
};

// allow .net-style fully qualified static calls for the class 
BrandedStores.PinEntryBarWidget = new BrandedStores.PinEntryBarWidget();

// static function Init() - a shortcut for member fucntion Init()
BrandedStores.PinEntryBarWidget.Init = function(settings)
{
  BrandedStores.PinEntryBarWidget.getInstance().Init(settings);
}

// register newly created class
BrandedStores.PinEntryBarWidget.registerClass('BrandedStores.PinEntryBarWidget');



///
/// Class ShoppingCartWidget 
///
/// Wraps the client functionality of the shopping cart bar. The bar displays
/// the status of the shopping cart and the account/checkout action buttons
/// appropriate at the current state.
///
/// Class is static and cannot be instanciated. The class contains several
/// public static methods to operate with the shopping cart on the client
/// side. Functions AddTrack(..) and AddAlbum(..) can be called from anywhere
/// on the page to add the appropriate item to the cart.
///

BrandedStores.ShoppingCartWidget = function()
{
  var instance = this;
  BrandedStores.ShoppingCartWidget.getInstance = function() { return instance; }

  this.$ctl = null; // control selector used as selector scope
  this.settings = null; // some extra params that will be set on init
  this.resultCallback = null; // callback invoked on widget postback completion
  this.wishCallback = null; // callback invoked on add to wishlist completion
 
  // bind add to cart buttons when DOM is fully loaded
  $(document).ready(function()
  {
    BrandedStores.ShoppingCartWidget.getInstance().BindAddToCartTriggers();
  });

  return BrandedStores.ShoppingCartWidget;
}

BrandedStores.ShoppingCartWidget.prototype =
{
  /*
  * Initializes and sets up the client-side object represending current widget. 
  * The call to Init() function must follow the constructor.
  */
  Init: function(settings)
  {
    this.settings = settings;

    //
    // HANDLE PAGEREQUESTMANAGER EVENTS
    //

    var instance = BrandedStores.ShoppingCartWidget.getInstance();
    var prm = Sys.WebForms.PageRequestManager.getInstance();
    // handle pageLoaded that occurs after content is updated as a result of regular or async postback
    prm.add_pageLoaded(Function.createDelegate(this, function(sender, args)
    {
      // if dynamic content was refreshed for the current widget
      $.each(args.get_panelsUpdated(), function(idx, elem)
      {
        if (elem.id == instance.settings.UpdatePanelID)
        {
          instance.DynamicContentLoaded(args);
          return false;
        }
      });
    }));

    //
    // DO THE REST OF INITIALIZATION
    //

    // setup control scope selector
    this.$ctl = $("#" + this.settings.ContainerID);
    if (this.$ctl.length != 1) throw "Unable to get control selector";

    // call function to complete initialization
    this.InitialContentLoaded();
    // initically trigger dynamic content handler as well
    this.DynamicContentLoaded();

    Sys.Debug.trace("ShoppingCartWidget: Init() completed");
  },

  BindAddToCartTriggers: function()
  {
    var instance = this;

    $(".AddToCartTrigger").live("click", function(event)
    {
      $button = $(this);

      if (!$button.hasClass("ui-state-select"))
      {
        var trackID = $button.attr("track");
        var albumID = $button.attr("album");

        if (trackID) // trigger for track
        {
          var callback = function(result, btn)
          {
            if (result.IsSuccess)
            {
              $(btn).removeClass("ui-state-default").addClass("ui-state-select");
              if (result.FullAlbum) $(".AddToCartTrigger[album=" + result.FullAlbum + "]").removeClass("ui-state-default").addClass("ui-state-select");
            }
          };
          BrandedStores.ShoppingCartWidget.AddTrack(trackID, callback, $button);
        }
        else if (albumID) // trigger for album
        {
          var callback = function(result, btn)
          {
            if (result.IsSuccess)
            {
              $(btn).removeClass("ui-state-default").addClass("ui-state-select");
              $(".AddToCartTrigger[track^=" + albumID + "_]").removeClass("ui-state-default").addClass("ui-state-select");
            }
          };
          BrandedStores.ShoppingCartWidget.AddAlbum(albumID, callback, $button);
        }
      }

      event.preventDefault();
      return false;
    });

    $(".AddToWishTrigger").live("click", function(event)
    {
      $button = $(this);

      if (!$button.hasClass("ui-state-select"))
      {
        var trackID = $button.attr("track");
        var albumID = $button.attr("album");

        if (trackID) // trigger for track
        {
          var callback = function(result, btn)
          {
            if (result.IsSuccess)
            {
              $(btn).removeClass("ui-state-default").addClass("ui-state-select");
              if (result.FullAlbum) $(".AddToWishTrigger[album=" + result.FullAlbum + "]").removeClass("ui-state-default").addClass("ui-state-select");
            }
          };
          BrandedStores.ShoppingCartWidget.WishTrack(trackID, callback, $button);
        }
        else if (albumID) // trigger for album
        {
          var callback = function(result, btn)
          {
            if (result.IsSuccess)
            {
              $(btn).removeClass("ui-state-default").addClass("ui-state-select");
              $(".AddToWishTrigger[track^=" + albumID + "_]").removeClass("ui-state-default").addClass("ui-state-select");
            }
          };
          BrandedStores.ShoppingCartWidget.WishAlbum(albumID, callback, $button);
        }
      }

      event.preventDefault();
      return false;
    });

    Sys.Debug.trace("ShoppingCartWidget: BindAddToCartTriggers() completed");
  },

  /*
  * InitialContentLoaded() called only once at 1st page load. Should be used to perform initial widget
  * setup (before dynamic content is loaded) such as binding jQuery events to static content (outside 
  * of the update panel) or somehting else.
  */
  InitialContentLoaded: function()
  {
    var $ctl = this.$ctl;
    var instance = this;

    Sys.Debug.trace("ShoppingCartWidget: InitialContentLoaded() completed");
  },

  /*
  * DynamicContentLoaded() called each time after content is loaded to the update panel of current 
  * widget EXCEPT initial loading. Might be used to rebind jQuery events, since event bingings for
  * updatable content are discarded each time after update panel is refreshed.
  */
  DynamicContentLoaded: function(args)
  {
    var $ctl = this.$ctl;
    var instance = this;

    // get extra server side data for current control
    var srvsideData = null;
    if (args != null) srvsideData = args.get_dataItems()[this.settings.UpdatePanelID];

    //
    // jQuery event binding
    //

    if (srvsideData)
    {
      if (typeof (this.resultCallback) == "function")
      {
        this.resultCallback(srvsideData);
        this.resultCallback = null;
      }
      else if (typeof (this.wishCallback) == "function")
      {
        this.wishCallback(srvsideData);
        this.wishCallback = null;
      }
    }

    Sys.Debug.trace("ShoppingCartWidget: DynamicContentLoaded() completed");
  },

  /* Add track to the shopping cart */
  AddTrack: function(trackID, resultCallback, ctx)
  {
    // simulate async postback to catch it on the server side
    var updatePanelID = this.settings.UpdatePanelID;
    __doPostBack(updatePanelID, "AddTrack|" + trackID);
    // save callback to invoke it on postback completion
    if (typeof (resultCallback) == "function")
    {
      this.resultCallback = Function.createCallback(resultCallback, ctx);
    }
  },

  /* Add album to the shopping cart */
  AddAlbum: function(productID, resultCallback, ctx)
  {
    // simulate async postback to catch it on the server side
    var updatePanelID = this.settings.UpdatePanelID;
    __doPostBack(updatePanelID, "AddAlbum|" + productID);
    // save callback to invoke it on postback completion
    if (typeof (resultCallback) == "function")
    {
      this.resultCallback = Function.createCallback(resultCallback, ctx);
    }
  },

  /* Add track to the user wishlist */
  WishTrack: function(trackID, wishCallback, ctx)
  {
    // simulate async postback to catch it on the server side
    var updatePanelID = this.settings.UpdatePanelID;
    __doPostBack(updatePanelID, "WishTrack|" + trackID);
    // save callback to invoke it on postback completion
    if (typeof (wishCallback) == "function")
    {
      this.wishCallback = Function.createCallback(wishCallback, ctx);
    }
  },

  /* Add album to the user wishlist */
  WishAlbum: function(productID, wishCallback, ctx)
  {
    // simulate async postback to catch it on the server side
    var updatePanelID = this.settings.UpdatePanelID;
    __doPostBack(updatePanelID, "WishAlbum|" + productID);
    // save callback to invoke it on postback completion
    if (typeof (wishCallback) == "function")
    {
      this.wishCallback = Function.createCallback(wishCallback, ctx);
    }
  }
};

// allow .net-style fully qualified static calls for the class
BrandedStores.ShoppingCartWidget = new BrandedStores.ShoppingCartWidget();

// static function Init() - a shortcut for member fucntion Init()
BrandedStores.ShoppingCartWidget.Init = function(settings)
{
  BrandedStores.ShoppingCartWidget.getInstance().Init(settings);
}

// static function AddTrack(..) - a shortcut for member function AddTrack(..)
BrandedStores.ShoppingCartWidget.AddTrack = function(trackID, resultCallback, ctx)
{
  BrandedStores.ShoppingCartWidget.getInstance().AddTrack(trackID, resultCallback, ctx);
}

// static function AddAlbum(..) - a shortcut for member function AddAlbum(..)
BrandedStores.ShoppingCartWidget.AddAlbum = function(productID, resultCallback, ctx)
{
  BrandedStores.ShoppingCartWidget.getInstance().AddAlbum(productID, resultCallback, ctx);
}

// static function WishTrack(..) - a shortcut for member function WishTrack(..)
BrandedStores.ShoppingCartWidget.WishTrack = function(trackID, wishCallback, ctx)
{
  BrandedStores.ShoppingCartWidget.getInstance().WishTrack(trackID, wishCallback, ctx);
}

// static function WishAlbum(..) - a shortcut for member function WishAlbum(..)
BrandedStores.ShoppingCartWidget.WishAlbum = function(productID, wishCallback, ctx)
{
  BrandedStores.ShoppingCartWidget.getInstance().WishAlbum(productID, wishCallback, ctx);
}


// register newly created class
BrandedStores.ShoppingCartWidget.registerClass('BrandedStores.ShoppingCartWidget');



///
/// Class SearchBarWidget 
///
/// Wraps the client functionality of the search bar. The bar has the
/// search type selectior, keyword entry field and search button which 
/// can be clicked by the user.
///
/// Class is static and cannot be instanciated. The class contains a static
/// Init() fucntion which initialized the singleton instance of the class.
/// All functions of this class are used internally and are not intended to
/// be used anywhere else on the page.
///

BrandedStores.SearchBarWidget = function()
{
  var instance = this;
  BrandedStores.SearchBarWidget.getInstance = function() { return instance; }

  this.$ctl = null; // control selector used as selector scope
  this.settings = null; // some extra params that will be set on init

  return BrandedStores.SearchBarWidget;
}

BrandedStores.SearchBarWidget.prototype =
{
  /*
  * Initializes and sets up the client-side object represending current widget. 
  * The call to Init() function must follow the constructor.
  */
  Init: function(settings)
  {
    this.settings = settings;

    //
    // HANDLE PAGEREQUESTMANAGER EVENTS
    //

    var instance = BrandedStores.SearchBarWidget.getInstance();
    var prm = Sys.WebForms.PageRequestManager.getInstance();
    // handle pageLoaded that occurs after content is updated as a result of regular or async postback
    prm.add_pageLoaded(Function.createDelegate(this, function(sender, args)
    {
      // if dynamic content was refreshed for the current widget
      $.each(args.get_panelsUpdated(), function(idx, elem)
      {
        if (elem.id == instance.settings.UpdatePanelID)
        {
          instance.DynamicContentLoaded(args);
          return false;
        }
      });
    }));

    //
    // DO THE REST OF INITIALIZATION
    //

    // setup control scope selector
    this.$ctl = $("#" + this.settings.ContainerID);
    if (this.$ctl.length != 1) throw "Unable to get control selector";

    // call function to complete initialization
    this.InitialContentLoaded();
    // initically trigger dynamic content handler as well
    this.DynamicContentLoaded();

    Sys.Debug.trace("SearchBarWidget: Init() completed");
  },

  /*
  * InitialContentLoaded() called only once at 1st page load. Should be used to perform initial widget
  * setup (before dynamic content is loaded) such as binding jQuery events to static content (outside 
  * of the update panel) or somehting else.
  */
  InitialContentLoaded: function()
  {
    var $ctl = this.$ctl;
    var instance = this;

    Sys.Debug.trace("SearchBarWidget: InitialContentLoaded() completed");
  },

  /*
  * DynamicContentLoaded() called each time after content is loaded to the update panel of current 
  * widget EXCEPT initial loading. Might be used to rebind jQuery events, since event bingings for
  * updatable content are discarded each time after update panel is refreshed.
  */
  DynamicContentLoaded: function(args)
  {
    var $ctl = this.$ctl;
    var instance = this;

    // get extra server side data for current control
    var srvsideData = null;
    if (args != null) srvsideData = args.get_dataItems()[this.settings.UpdatePanelID];

    //
    // jQuery event binding
    //


    if (srvsideData)
    {
      // show/hide error indicator
      if (srvsideData.IsSuccess) $(".PTBS-error-empty", this.$ctl).css("display", "none");
      else $(".PTBS-error-empty", this.$ctl).css("display", "");
    }

    // postback with params when submit button is clicked
    $(".PTBS-btn-submit", this.$ctl).click(function()
    {
      // retrieve search criteria entered by user
      var type = $(".PTBS-search-type", $ctl).val();
      var text = $(".PTBS-search-text", $ctl).val();

      // simulate async postback to catch it on the server side
      var updatePanelID = BrandedStores.SearchBarWidget.getInstance().settings.UpdatePanelID;
      __doPostBack(updatePanelID, "StartSearch|" + type + "|" + text);
      // IMPORTANT !!! Return false to prevent any default behavior on the clickable
      // element to prevent automatic form postback for image and submit buttons
      return false;
    });

    // automatically postback when enter is clicked 
    $(".PTBS-search-text", this.$ctl).keydown(function(e)
    {
      if (e.keyCode == 13)
      {
        e.stopPropagation();
        $(".PTBS-btn-submit", $ctl).trigger("click");
        // IMPORTANT !!! Return false to prevent any default behavior on the clickable
        // element to prevent automatic form postback for image and submit buttons
        return false;
      }
    });


    Sys.Debug.trace("SearchBarWidget: DynamicContentLoaded() completed");
  }
};

// allow .net-style fully qualified static calls for the class
BrandedStores.SearchBarWidget = new BrandedStores.SearchBarWidget();

// static function Init() - a shortcut for member fucntion Init()
BrandedStores.SearchBarWidget.Init = function(settings)
{
  BrandedStores.SearchBarWidget.getInstance().Init(settings);
}

// register newly created class
BrandedStores.SearchBarWidget.registerClass('BrandedStores.SearchBarWidget');




///
/// Class AsyncProgressWidget
///
/// Manages client behavior of the async progress loader display with
/// screen overlay. Whenever the async postback occurs, the clickable
/// site area is covered by the overlay so that user knows that request
/// is being processed.
///
/// Class is static and cannot be instanciated. The class contains a static
/// Init() fucntion which initialized the singleton instance of the class.
/// All functions of this class are used internally and are not intended to
/// be used anywhere else on the page.
///

BrandedStores.AsyncProgressWidget = function()
{
  var instance = this;
  BrandedStores.AsyncProgressWidget.getInstance = function() { return instance; }

  this.$ctl = null; // control selector used as selector scope
  this.settings = null; // some extra params that will be set on init

  this.timerID = null; // save current timer ID
  this.$overlay = null; // save overlay while visible
  this.$splash = null; // hold splash loader image

  return BrandedStores.AsyncProgressWidget;
}

BrandedStores.AsyncProgressWidget.prototype =
{
  /*
  * Initializes and sets up the client-side object represending current widget. 
  * The call to Init() function must follow the constructor.
  */
  Init: function(settings)
  {
    this.settings = settings;

    //
    // HANDLE PAGEREQUESTMANAGER EVENTS
    //

    var instance = BrandedStores.AsyncProgressWidget.getInstance();
    var prm = Sys.WebForms.PageRequestManager.getInstance();
    // handle beginRequest and endRequest to show/hide the progress animation
    prm.add_beginRequest(Function.createDelegate(this, function(sender, args) { instance.OnBeginRequest(); }));
    prm.add_endRequest(Function.createDelegate(this, function(sender, args) { instance.OnEndRequest(); }));


    //
    // DO THE REST OF INITIALIZATION
    //

    // setup control scope selector
    this.$ctl = $("#" + this.settings.ContainerID);
    if (this.$ctl.length != 1) throw "Unable to get control selector";

    // save overlay and splash refs
    this.$overlay = $(".overlayContainer", this.$ctl);
    this.$splash = $(".splashContainer", this.$ctl);


    Sys.Debug.trace("AsyncProgressWidget: Init() completed");
  },

  OnBeginRequest: function()
  {
    this.CancelCurrentTimer();
    this.timerID = setTimeout("BrandedStores.AsyncProgressWidget.getInstance().DisplayOverlay()", 500);
  },

  DisplayOverlay: function()
  {
    var instance = this;

    this.CancelCurrentTimer();

    // set only height (width is controlled by CSS)
    this.$overlay.height($(document).height());

    this.$overlay.css("display", "block");
    this.$splash.css("display", "block");
  },

  OnEndRequest: function()
  {
    var instance = this;

    this.CancelCurrentTimer();

    // hide overlay if displayed
    if (this.$overlay.css("display") != "none")
    {
      this.$overlay.fadeOut("normal", function()
      {
        instance.$overlay.css("display", "none");
        instance.$splash.css("display", "none");
      });
    }
  },

  CancelCurrentTimer: function()
  {
    if (this.timerID)
    {
      clearTimeout(this.timerID);
      this.timerID = null;
    }
  }
};

// allow .net-style fully qualified static calls for the class
BrandedStores.AsyncProgressWidget = new BrandedStores.AsyncProgressWidget();

// static function Init() - a shortcut for member fucntion Init()
BrandedStores.AsyncProgressWidget.Init = function(settings)
{
  BrandedStores.AsyncProgressWidget.getInstance().Init(settings);
}

// register newly created class
BrandedStores.AsyncProgressWidget.registerClass('BrandedStores.AsyncProgressWidget');




///
/// Class CheckoutPopupWidget
/// 
/// Wraps the client functionality of the popup window displayed when user 
/// tries to checkout without being sign in. The popup allows the user to 
/// choose if he wants to sign in or proceed anonimously entering his email
/// and zip code. 
///
/// Class is static and cannot be instanciated. It contains two functions:
/// Show() and Hide() allowing to show and hide the dialog by javascript 
/// calls. Hide() is used by the dialog internally and is not intended to
/// be used anywhere else on the page.
///

BrandedStores.CheckoutPopupWidget = function()
{ 
  // initialization is called when DOM is fully loaded
  $(document).ready(function()
  {
    // save dialog in the member var
    BrandedStores.CheckoutPopupWidget.$dialog = $(".CheckoutPopupWidget .dialogPanel");
    // add modal behaviour to the dialog
    BrandedStores.CheckoutPopupWidget.$dialog.jqm({
      overlayClass: "ui-modal-overlay",
      overlay: 50,
      modal: true
    });
  });

  return BrandedStores.CheckoutPopupWidget;
}

// allow .net-style fully qualified static calls for the class 
BrandedStores.CheckoutPopupWidget = new BrandedStores.CheckoutPopupWidget();

// static function ShowDialog()
BrandedStores.CheckoutPopupWidget.ShowDialog = function()
{
  BrandedStores.CheckoutPopupWidget.$dialog.jqmShow();
  $(".CheckoutPopupWidget .editEmail").get(0).focus();
}

// static function HideDialog()
BrandedStores.CheckoutPopupWidget.CloseDialog = function()
{
  BrandedStores.CheckoutPopupWidget.$dialog.jqmHide();
}

// register newly created class
BrandedStores.CheckoutPopupWidget.registerClass('BrandedStores.CheckoutPopupWidget');



///
/// Class PreviewButtonWidget
///
/// Manages functionality and state of all currenly displayed preview buttons.
/// Instanciates the Flash Player and wraps all necessary functions to provide 
/// user-friendly media previewing without player UI.
///
/// Class is static and cannot be instanciated. It contains static Init() method
/// which binds click handlers to all preview buttons on load. All methods of
/// the class are used by the system internally and are not to be called directly
/// anywhere on the page.
///

BrandedStores.PreviewButtonWidget = function()
{
  var instance = this;
  BrandedStores.PreviewButtonWidget.getInstance = function() { return instance; }

  // var to save player implementation
  this.playerKey = null;
  this.playerObject = null;

  // hold current WMPlayer check state timeout
  this.checkStateTimeout = null;

  this.callbacksStart = new Array();
  this.callbacksStop = new Array();

  // initialization is called when DOM is fully loaded
  $(document).ready(function()
  {
    BrandedStores.PreviewButtonWidget.getInstance().Init();
    BrandedStores.PreviewButtonWidget.getInstance().BindPreviewButtons();
  });

  return BrandedStores.PreviewButtonWidget;
}

BrandedStores.PreviewButtonWidget.prototype =
{
  /* Initialize preview buttons functionality. Add player object. */
  Init: function()
  {
    // append player object placeholder to the bottom of the body
    $("body").append('<div id="PreviewPlayerContainer"><a id="PreviewPlayer"></a></div>')
    // set JWPlayer5 to be default player for MP3s
    $.fn.media.defaults.mp3Player = "../mediaplayer/JWPlayer5.swf";
    $.fn.media.defaults.flashVersion = "9.0.0";

    Sys.Debug.trace("PreviewButtonWidget: Init() completed");
  },

  BindPreviewButtons: function()
  {
    var instance = this;

    // switch play/stop modes when button is clicked
    $(".PreviewButtonWidget .buttonPreview").live("click", function()
    {
      // for PLAY button
      if ($(this).hasClass("ui-state-default"))
      {
        // switch buttons if playback starts 
        var previewURL = $(this).attr("preview");
        if (instance.StartPlayback(previewURL))
        {
          // reset all buttons to play button
          $(".PreviewButtonWidget .buttonPreview").each(function() { $(this).removeClass("ui-state-select").addClass("ui-state-default"); });
          // switch current button to stop button
          $(this).removeClass("ui-state-default").addClass("ui-state-select");

          // execute callbacks
          instance.ExecuteStartCallbacks($(this));

          Sys.Debug.trace("PreviewButtonWidget: playback started for " + previewURL);
        }
      }
      // for STOP button
      else if ($(this).hasClass("ui-state-select"))
      {
        // switch buttons if playback stops
        if (instance.StopPlayback())
        {
          // switch back to play button
          $(this).removeClass("ui-state-select").addClass("ui-state-default");

          Sys.Debug.trace("PreviewButtonWidget: playback stopped");
        }
      }
    });

    // when title is clicked, the click should be just 
    // redirected to the corresponding preview button
    $(".PreviewButtonWidget .titlePreview").live("click", function()
    {
      $(this).parent(".PreviewButtonWidget").find(".buttonPreview").trigger("click");
    });

    Sys.Debug.trace("PreviewButtonWidget: BindPreviewButtons() completed");
  },

  /* Play audio stream from specified URL */
  StartPlayback: function(previewURL)
  {
    try
    {
      // find player implementation
      this.playerKey = this.SelectPlayer(previewURL);
      if (!this.playerKey) throw "Player not found";

      // add object markup to HTML page
      switch (this.playerKey)
      {
        case "flash": this.InstallFlashPlayer(previewURL); break;
        case "winmedia": this.InstallWMPlayer(previewURL); break;
        default: throw "Unknown player";
      }

      return true;
    }
    catch (ex)
    {
      return false;
    }
  },

  /* Stop currently playing audio */
  StopPlayback: function()
  {
    try
    {
      switch (this.playerKey)
      {
        case "flash": this.StopFlashPlayer(); break;
        case "winmedia": this.StopWMPlayer(); break;
        default: throw "Unknown player";
      }

      return true;
    }
    catch (ex)
    {
      return false;
    }
  },

  SelectPlayer: function(mediaURL)
  {
    // create regex to match types
    var types = '';
    var players = $.fn.media.defaults.players;
    for (var key in players)
    {
      if (types.length) types += ',';
      types += players[key].types;
    };
    var reType = RegExp('\\.(' + types.replace(/,/ig, '|') + ')\\b', 'ig');

    // search for player associated with this type
    var matchType = reType.exec(mediaURL);
    if (!matchType) throw "Unknown media type";
    for (var key in players)
    {
      if (players[key].types.indexOf(matchType[1]) != -1) return key;
    }
    return null;
  },

  AddStartStopCallback: function(callbackStart, callbackStop)
  {
    if (typeof (callbackStart) == "function") this.callbacksStart.push(callbackStart);
    if (typeof (callbackStop) == "function") this.callbacksStop.push(callbackStop);
  },

  ExecuteStartCallbacks: function(arg)
  {
    for (var i = 0; i < this.callbacksStart.length; i++)
    {
      this.callbacksStart[i].apply(this, [arg]);
    }
  },

  ExecuteStopCallbacks: function(arg)
  {
    for (var i = 0; i < this.callbacksStop.length; i++)
    {
      this.callbacksStop[i].apply(this, [arg]);
    }
  },


  ///////////////////////////////////////////////////////////////////////////////////
  // JWPlayer5 Flash Player implementation

  InstallFlashPlayer: function(mediaURL)
  {
    var flashvars =
    {
      file: mediaURL,
      duration: 30, // limit playback by 30 seconds
      autostart: "true",
      playerready: "BrandedStores.PreviewButtonWidget.getInstance().callbackFlash_OnReady"
    };

    $("#PreviewPlayer").media({
      width: 1,
      height: 1,
      src: mediaURL,
      attrs: { name: "PreviewPlayer" },
      flashvars: flashvars,
      caption: false
    });

    this.playerObject = $("#PreviewPlayerContainer [name=PreviewPlayer]").get(0);
    if (!this.playerObject) throw "Failed to add player object to HTML page";
  },

  StopFlashPlayer: function()
  {
    if (!this.playerObject) throw "Player object not set";
    this.playerObject.sendEvent("STOP", "true");

    // execute callbacks
    this.ExecuteStopCallbacks();
  },

  callbackFlash_OnReady: function(e)
  {
    var object = document.getElementById(e.id);
    object.addModelListener("STATE", "BrandedStores.PreviewButtonWidget.getInstance().callbackFlash_StateChanged");
  },

  callbackFlash_StateChanged: function(e)
  {
    if (e.newstate == "COMPLETED")
    {
      // reset all buttons to Play button (default state)
      $(".PreviewButtonWidget .buttonPreview").each(function()
      {
        $(this).removeClass("ui-state-select").addClass("ui-state-default");
      });

      // execute callbacks
      this.ExecuteStopCallbacks();
    }
  },


  ///////////////////////////////////////////////////////////////////////////////////
  // Windows Media Player implementation

  InstallWMPlayer: function(mediaURL)
  {
    $("#PreviewPlayer").media({
      width: 1,
      height: 1,
      autoplay: true,
      src: mediaURL,
      attrs: { name: "PreviewPlayer" },
      caption: false
    });

    this.playerObject = $("#PreviewPlayerContainer [name=PreviewPlayer]").get(0);
    if (!this.playerObject) throw "Failed to add player object to HTML page";

    // call check state launcher with delay to give WMPlayer object some time to initialize   
    this.checkStateTimeout = setTimeout("BrandedStores.PreviewButtonWidget.getInstance().callbackWMPlayer_LaunchStateChecker();", 1000);
  },

  StopWMPlayer: function()
  {
    if (!this.playerObject) throw "Player object not set";

    // cleanup timer variables
    if (this.checkStateTimeout)
    {
      clearTimeout(this.checkStateTimeout);
      this.checkStateTimeout = null;
    }

    if (this.playerObject.controls)
    {
      this.playerObject.controls.stop();
    }
  },

  callbackWMPlayer_LaunchStateChecker: function()
  {
    if (this.playerObject)
    {
      if (this.playerObject.playState)
      {
        this.checkStateTimeout = setTimeout("BrandedStores.PreviewButtonWidget.getInstance().callbackWMP_CheckState();", 1000);
      }
      else
      {
        this.checkStateTimeout = setTimeout("BrandedStores.PreviewButtonWidget.getInstance().callbackWMP_CheckState();", 30000);
      }
    }
  },

  callbackWMP_CheckState: function()
  {
    if (this.playerObject)
    {
      var bStopped = false; // flag indicates if we need to switch to stop button
      // if playing longer then 30 seconds, then force it to stop
      if (this.playerObject.controls && this.playerObject.controls.currentPosition >= 30)
      {
        this.StopWMPlayer();
        bStopped = true;
      }
      // if playState is available (might be unavailable for wrong plugin)
      else if (this.playerObject.playState)
      {
        // set flag if playback stopped or completed
        if (this.playerObject.playState == 1 || this.playerObject.playState == 8) bStopped = true;
        // otherwise, set timeout to check again after a while
        else this.checkStateTimeout = setTimeout("BrandedStores.PreviewButtonWidget.getInstance().callbackWMP_CheckState();", 1000);
      }
      // otherwise, just force the button to switch
      else
      {
        bStopped = true;
      }

      // if media stopped, reset all buttons to  
      // default state i.e. to PLAY button state
      if (bStopped)
      {
        $(".PreviewButtonWidget .buttonPreview").each(function()
        {
          $(this).removeClass("ui-state-select").addClass("ui-state-default");
        });

        // cleanup timer variables
        if (this.checkStateTimeout)
        {
          clearTimeout(this.checkStateTimeout);
          this.checkStateTimeout = null;
        }
      }
    }
  }
}


// allow .net-style fully qualified static calls for the class
BrandedStores.PreviewButtonWidget = new BrandedStores.PreviewButtonWidget();

BrandedStores.PreviewButtonWidget.AddStartStopCallback = function(callbackStart, callbackStop)
{
  BrandedStores.PreviewButtonWidget.getInstance().AddStartStopCallback(callbackStart, callbackStop);
}

BrandedStores.PreviewButtonWidget.StopPlayback = function()
{
  BrandedStores.PreviewButtonWidget.getInstance().StopPlayback();
}

// register newly created class
BrandedStores.PreviewButtonWidget.registerClass('BrandedStores.PreviewButtonWidget');



///
/// Class DateSelectionAssist
///
/// Prevents user from selecting future dates on registration
/// and account pages.
///

BrandedStores.DateSelectAssistant = function()
{
  var instance = this;
  BrandedStores.DateSelectAssistant.getInstance = function() { return instance; }

  this.$DaySelect = null;
  this.$MonthSelect = null;
  this.$YearSelect = null;

  return BrandedStores.DateSelectAssistant;
}

BrandedStores.DateSelectAssistant.prototype =
{
  Install: function(daySelectID, monthSelectID, yearSelectID)
  {
    var inst = this;

    $(document).ready(function()
    {
      if (inst.$DaySelect || inst.$MonthSelect || inst.$YearSelect) return;

      inst.$DaySelect = $("#" + daySelectID);
      inst.$MonthSelect = $("#" + monthSelectID);
      inst.$YearSelect = $("#" + yearSelectID);

      if (inst.$DaySelect.length == 0 ||
        inst.$MonthSelect.length == 0 ||
        inst.$YearSelect.length == 0)
        return;

      inst.$DaySelect.unbind("change");
      inst.$MonthSelect.unbind("change");
      inst.$YearSelect.unbind("change");

      inst.$DaySelect.change(function() { inst.OnSelectionChanged(); });
      inst.$MonthSelect.change(function() { inst.OnSelectionChanged(); });
      inst.$YearSelect.change(function() { inst.OnSelectionChanged(); });

      Sys.Debug.trace("DateSelectAssistant: READY!!!");
    });
  },

  OnSelectionChanged: function()
  {
    // reset options for all selectors
    for (var i = 0; i < this.$DaySelect.get(0).options.length; i++) this.$DaySelect.get(0).options[i].disabled = false;
    for (var i = 0; i < this.$MonthSelect.get(0).options.length; i++) this.$MonthSelect.get(0).options[i].disabled = false;
    for (var i = 0; i < this.$YearSelect.get(0).options.length; i++) this.$YearSelect.get(0).options[i].disabled = false;

    // set max date as current date
    var maxDate = new Date();
    // sample date is build as following: user selected items (day, month, year)
    // are assigned; all unselected date (day, month, year) are assigned to 
    // the minimum possible values
    var sampleDate = new Date();
    // get user selected items
    var day = parseInt(this.$DaySelect.val());
    var month = parseInt(this.$MonthSelect.val());
    var year = parseInt(this.$YearSelect.val());
    if (isNaN(day) && isNaN(month) && isNaN(year)) return;
    // assign to actual value if selected or to 
    // the minimum possible value otherwise
    if (isNaN(year)) sampleDate.setYear(1);
    else sampleDate.setYear(year);
    if (isNaN(month)) sampleDate.setMonth(0);
    else sampleDate.setMonth(month - 1);
    if (isNaN(day)) sampleDate.setDate(1);
    else sampleDate.setDate(day);


    // vary day within sample date to disable impossible choices
    if (isNaN(day))
    {
      var options = this.$DaySelect.get(0).options;
      for (var i = 0; i < options.length; i++)
      {
        var nVal = parseInt(options[i].value, 10);
        if (!isNaN(nVal))
        {
          var testDate = new Date(sampleDate);
          testDate.setDate(nVal);
          
          if (testDate >= maxDate ||
            testDate.getMonth() != sampleDate.getMonth() ||
            testDate.getFullYear() != sampleDate.getFullYear())
          {
            options[i].disabled = true;
          }
        }
      }
    }

    // vary month within sample date to disable impossible choices
    if (isNaN(month))
    {
      var options = this.$MonthSelect.get(0).options;
      for (var i = 0; i < options.length; i++)
      {
        var nVal = parseInt(options[i].value, 10);
        if (!isNaN(nVal))
        {
          var testDate = new Date(sampleDate);
          testDate.setMonth(nVal - 1);
          
          if (testDate >= maxDate ||
            testDate.getDate() != sampleDate.getDate() ||
            testDate.getFullYear() != sampleDate.getFullYear())
          {
            options[i].disabled = true;
          }
        }
      }
    }

    // vary year within sample date to disable impossible choices
    if (isNaN(year))
    {
      var options = this.$YearSelect.get(0).options;
      for (var i = 0; i < options.length; i++)
      {
        var nVal = parseInt(options[i].value, 10);
        if (!isNaN(nVal))
        {
          var testDate = new Date(sampleDate);
          testDate.setFullYear(nVal);
          
          if (testDate >= maxDate ||
            testDate.getDate() != sampleDate.getDate() ||
            testDate.getMonth() != sampleDate.getMonth())
          {
            options[i].disabled = true;
          }
        }
      }
    }
  }
}

// allow .net-style fully qualified static calls for the class
BrandedStores.DateSelectAssistant = new BrandedStores.DateSelectAssistant();

// static function Install() - a shortcut for member fucntion Install()
BrandedStores.DateSelectAssistant.Install = function(daySelectID, monthSelectID, yearSelectID)
{
  BrandedStores.DateSelectAssistant.getInstance().Install(daySelectID, monthSelectID, yearSelectID);
}

// register newly created class
BrandedStores.DateSelectAssistant.registerClass('BrandedStores.DateSelectAssistant');


//
// FBAsyncDialog jQuery Plugin 
//

; (function($)
{
  $.fn.FBAsyncDialog = function()
  {
    var $this = $(this).eq(0);
    var $overlay = $this.find(".fbui-overlay");
    var $dialog = $this.find(".fbui-dialog");
    var $initial = $dialog.find(".fbui-dialog-initial");
    var $content = $dialog.find(".fbui-dialog-content");
    var $closebtn = $dialog.find(".fbui-dialog-closebtn");

    var srcURL = $this.attr("src");
    if (!srcURL) $.error("FBAsyncDialog data source not specified");

    var ajaxReq = null;

    var fnClose = function()
    {
      if (ajaxReq) ajaxReq.abort();
      $this.css("display", "none");
      $content.html("");
    };

    $overlay.click(function()
    {
      fnClose();
      return false;
    });

    $closebtn.click(function()
    {
      BrandedStores.PreviewButtonWidget.StopPlayback();
      fnClose();
      return false;
    });

    $overlay.height($("body").outerHeight());
    $overlay.width($("body").outerWidth());

    $initial.css("display", "block");
    $content.css("display", "none");

    $this.fadeIn("slow", function()
    {
      ajaxReq = $.ajax({
        url: srcURL,
        cache: false,
        success: function(html)
        {
          $initial.css("display", "none");
          $content.html(html);
          $content.css("display", "block");
        },
        error: function()
        {
          fnClose();
        }
      });
    });
  };
})(jQuery);

///
/// 
/// 

if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();
