/*
 * Default Scripts
 */



/*******************************************************************************
 * Services
 */
var Tracking = new Class({
  initialize: function() {
    this.pageview = null;
  },
  getPageview: function() {
    return this.pageview;
  },
  hasPageview: function() {
    return (this.pageview !== null);
  },
  isEnabled: function() {
    return (typeof _gaq === "object");
  },
  setPageview: function(url) {
    this.pageview = url;
  },
  trackEvent: function(category, action, label) {
    _gaq.push(["_trackEvent", category, action, label]);
  },
  trackPageview: function() {
    if (this.hasPageview()) {
      _gaq.push(["_trackPageview", this.pageview]);
    } else {
      _gaq.push(["_trackPageview"]);
    }
  }
});

var Services = {
  initialize: function() {
    this.topper = new Topper({percentage: 100, text: "Haut de la page", title: "Revenir tout en haut de la page"});
    this.tracking = new Tracking();
  },
  getTopper: function() {
    return this.topper;
  },
  getTracking: function() {
    return this.tracking;
  }
};



/*******************************************************************************
 * Modal box class extension
 */
var Modal = new Class({
  Binds: ["onKeyDown"],
  Implements: Options,
  options: {
    opacity: 0.7
  },
  initialize: function(options) {
    // Merges specified options with default ones
    this.setOptions(options);
    
    var body = $E("body");
    
    // Creates the following template and injects it at the end of the page:
    // 
    //   <div id="modal" />
    //   <div id="overlay" />
    // 
    var modal = new Element("DIV");
    modal.setProperty("id", "modal");
    modal.setStyle("display", "none");
    modal.inject(body);
    
    var overlay = new Element("DIV");
    overlay.setProperty("id", "overlay");
    overlay.setStyle("display", "none");
    overlay.inject(body);
    
    // Initializes visual effect
    var overlayEffect = new Fx.Tween(overlay, {property: "opacity", duration: 300});
    var modalEffect = new Fx.Tween(modal, {property: "opacity", duration: 300});
    var modalMoveEffect = new Fx.Move(modal, {duration: 300});
    
    // Hides the text at startup
    overlayEffect.set(0);
    modalEffect.set(0);
    
    // Removes style previously set to hide it during initialization
    overlay.removeStyle("display");
    modal.removeStyle("display");
    
    // Positions the modal box in the center of the viewport (even if it is not
    // visible) so it does not add an invisible margin at the bottom of the page
    modal.position();
    
    // Closes the modal whenever the user clicks on the overlay
    overlay.addEvent("click", function() {
      this.close();
    }.bind(this));
    
    // Initializes an ajax request to retrieve information about a specific
    // coupon
    var request = new Request.HTML({
      method: "get",
      onSuccess: function(responseTree, responseElements, responseHTML, responseJavaScript) {
        responseHTML = responseHTML.trim();
        
        if (!responseHTML.isEmpty()) {
          this.modal.set("html", responseHTML);
          
          this.show();
          
          this.updateLinkBindings();
          
          this.modal.store("url", this.url);
        }
      }.bind(this)
    });
    
    // Setups the clipboard copy mechanism except for Chrome and Safari
    if (!window.chrome && !Browser.Engine.webkit) {
      // Loads the Flash movie which provides clipboard management capabilities
      ZeroClipboard.setMoviePath("/libs/zeroclipboard/ZeroClipboard.swf");
      
      // Initializes a new clipboard client
      var clip = new ZeroClipboard.Client();
      
      // Saves reference for later use
      this.clip = clip;
    }
    
    // Saves references for later use
    this.overlay = overlay;
    this.overlayEffect = overlayEffect;
    this.modal = modal;
    this.modalEffect = modalEffect;
    this.modalMoveEffect = modalMoveEffect;
    this.request = request;
  },
  close: function() {
    this.hide();
  },
  disableKeyBindings: function() {
    document.removeEvent("keydown", this.onKeyDown);
  },
  enableKeyBindings: function() {
    document.addEvent("keydown", this.onKeyDown);
  },
  hide: function() {
    this.modalMoveEffect.start({relativeTo: this.modal, offset: {y: 50}});
    
    this.modalEffect.start(1, 0);
    
    this.overlayEffect.start.delay(300, this.overlayEffect, [this.options.opacity, 0]);
    
    this.disableKeyBindings();
  },
  onKeyDown: function(event) {
    if ((event.key === "enter") || (event.key === "esc")) {
      this.close();
    }
  },
  open: function(url, displayNotice) {
    this.displayNotice = displayNotice;
    
    var oldUrl = this.modal.retrieve("url");
    
    if (url === oldUrl) {
      this.show();
    } else {
      this.url = url;
      
      this.request.send({url: url});
    }
  },
  show: function() {
    if (!this.displayNotice) {
      var notice = this.modal.getElement(".note");
      
      if (notice !== null) {
        notice.dispose();
      }
    }
    
    this.overlay.setStyle("height", window.getScrollHeight());
    
    this.overlayEffect.start(this.options.opacity);
    
    this.modal.position({offset: {y: 100}});
    
    this.modalMoveEffect.start.delay(400, this.modalMoveEffect);
    
    this.modalEffect.start.delay(500, this.modalEffect, [1]);
    
    this.enableKeyBindings();
  },
  updateLinkBindings: function() {
    if (Services.getTracking().isEnabled()) {
      // Extracts the caption slug and coupon identifier from the url
      matches = this.url.match(/promotions\/(.*)$/);
      
      if ((matches !== null) && (matches.length === 2)) {
        // Builds the new url
        var url = "/voir/" + matches[1];
        
        // Tracks the display of this modal box as a page view
        Services.getTracking().setPageview(url);
      }
    }
    
    // Retrieves the button to close the modal box
    var button = this.modal.getElement(".actions BUTTON");
    
    if (button !== null) {
      button.addEvent("click", function() {
        this.close();
      }.bind(this));
    }
    
    // Retrieves the link with the merchant url
    var link = this.modal.getElement("A");
    
    if (link !== null) {
      var url = link.getProperty("href");
      
      link.addEvent("click", function(event) {
        // Stops event propagation (no other listener will ever get it)
        event.stop();
        
        // Opens the target url in a new window
        window.load(url);
        
        // Tracks this click as an event too
        if (Services.getTracking().isEnabled()) {
          Services.getTracking().trackEvent("Coupons", "Use", "Link");
        }
      });
      
      // Retrieves the logo link
      link = this.modal.getElement(".logo A");
      
      if (link !== null) {
        link.addEvent("click", function(event) {
          // Stops event propagation (no other listener will ever get it)
          event.stop();
          
          // Opens the target url in a new window
          window.load(url);
          
          // Tracks this click as an event too
          if (Services.getTracking().isEnabled()) {
            Services.getTracking().trackEvent("Coupons", "Use", "Logo");
          }
        });
      }
      
      // Retrieves the button to visit the merchant
      button = this.modal.getElement(".code > BUTTON, .promotion > BUTTON");
      
      if (button !== null) {
        button.addEvent("click", function() {
          // Opens the target url in a new window
          window.load(url);
          
          // Tracks this click as an event too
          if (Services.getTracking().isEnabled()) {
            Services.getTracking().trackEvent("Coupons", "Use", "Button");
          }
        });
      }
      
      // Retrieves the button to copy code into clipboard
      button = this.modal.getElement(".code .glue > BUTTON");
      
      if (button !== null) {
        // Retrieves the glue container of this button
        var container = button.getParent();
        
        // Setups the clipboard copy mechanism only if supported
        if ($defined(this.clip)) {
          // Links the Flash component to this button (i.e. it will create a 
          // Flash movie above this button with the same exact size)
          this.clip.glue(button, container);
          
          // Retrieves the actual Flash movie
          var movie = container.getElement("EMBED");
          
          // Propagates the title attribute from the button to the Flash movie 
          // so it popups as a tooltip when the user moves his mouse over it
          if (movie !== null) {
            movie.setProperty("title", button.getProperty("title"));
          }
          
          // Retrieves the corresponding link with the coupon code
          var code = container.getPrevious();
          
          // Handles the case where the user clicks on this button
          this.clip.addEventListener("onMouseDown", function(client) {
            // Extracts the code from the link
            var text = code.getProperty("text");
            
            // Copies this code into the clipboard
            client.setText(text);
          });
          
          // Updates button label when the code is copied successfully
          this.clip.addEventListener("onComplete", function(client, text) {
            // Declares chain of events to update the button title
            var chain = new Chain();
            
            chain.chain(function() {
              button.set("text", "Code copié");
              button.addClass("disabled");
            });
            
            chain.chain(function() {
              button.removeClass("disabled");
              button.set("text", "Copier ce code");
            });
            
            // Runs the chain sequentially
            chain.callChain.delay(1700, chain);
            chain.callChain();
            
            // Tracks this click as an event
            if (Services.getTracking().isEnabled()) {
              Services.getTracking().trackEvent("Coupons", "Copy", "Button");
            }
          });
        } else {
          // Destroy the glue container as it is not needed in that case
          container.destroy();
        }
      }
    }
    
    // Makes the modal box fully draggable
    var drag = new Drag(this.modal, {
      handle: ["#modal .name", "#modal .url"],
      snap: 0,
      onComplete: function(element){
        element.removeClass("dragging");
      },
      onStart: function(element){
        element.addClass("dragging");
      }
    });
  }
});



/*******************************************************************************
 * Title helper definition
 */
var Title = {
  truncate: function(heading) {
    // Retrieves the link inside the heading
    var link = heading.getElement("A");
    
    if (link !== null) {
      // Retrieves the width of the heading (i.e. the container) and the link
      // itself (which contains the formatted text)
      var maximumWidth = heading.getSize().x;
      var width = link.getSize().x;
      
      // Checks if this title must be truncated
      if (width > maximumWidth) {
        // Stores the original title
        link.store("original", link.get("html"));
        
        // Converts the collection of child nodes into a Mootools array
        var nodes = $A(link.childNodes);
        
        var previousNode = null;
        for (var i = nodes.length - 1; i > 0 && width > maximumWidth; i--) {
          node = nodes[i];
          
          if (node.nodeType === 3) {
            var value = node.nodeValue.trim();
            
            if ((value === "et") || (value === "plus")) {
              if (previousNode !== null) {
                newNode = document.createTextNode("\u2026 ");
                
                link.replaceChild(newNode, previousNode);
                
                // Computes the new width
                width = link.getSize().x;
                
                // Gets ride of those two nodes as this is not enought yet
                if (width > maximumWidth) {
                  link.removeChild(newNode);
                  link.removeChild(node);
                }
              }
            }
          }
          
          previousNode = node;
        }
        
        // Retrieves the list element (i.e. the coupon itself)
        var parent = heading.getParent();
        
        // Displays the original title when the user mouse over the coupon
        parent.addEvent("mouseenter", function() {
          var html = link.retrieve("altered");
          
          if (html === null) {
            html = link.get("html");
            
            link.store("altered", html);
          }
          
          html = link.retrieve("original");
          
          link.set("html", html);
        });
        
        // Displays the truncated title when the user mouse leaves the coupon
        parent.addEvent("mouseleave", function() {
          html = link.retrieve("altered");
          
          link.set("html", html);
        });
      }
    }
  }
};



/*******************************************************************************
 * Alerts helper definition
 */
var Alerts = {
  start: function() {
    // Retrieves the tooltip element
    var tooltip = $E(".newsletter .tooltip");
    
    if (tooltip !== null) {
      // Initializes visual effects
      var opacityEffect = new Fx.Opacity(tooltip, {duration: 300});
      var moveEffect = new Fx.Tween(tooltip, {property: "left", duration: 300});
      
      // Hides the tooltip at startup
      opacityEffect.set(0);
      
      // Updates style previously set through stylesheets
      tooltip.setStyle("display", "block");
      
      // Retrieves and stores the axis position of the tooltip
      var left = tooltip.getStyle("left");
      tooltip.store("left", Number.toInt(left));
      
      // Displays the tooltip when the user scrolls and the newsletter area is
      // visible (in fact when the tooltip plus some offset can be displayed 
      // effectively)
      window.addEvent("scroll", function() {
        // Defines offset around the tooltip
        var offset = new Hash({
          bottom: 70,
          left: 0,
          right: 0,
          top: 70
        });
        
        // Retrieves position data about the window viewport
        var size = window.getSize();
        var scroll = window.getScroll();
        
        var viewport = new Hash({
          bottom: scroll.y + size.y,
          left: scroll.x,
          right: scroll.x + size.x,
          top: scroll.y
        });
        
        // Retrieves position data about the tooltip
        size = tooltip.getSize();
        var position = tooltip.getPosition();
        
        var element = new Hash({
          bottom: position.y + size.y,
          left: position.x,
          right: position.x + size.x,
          top: position.y
        });
        
        if ((element.bottom <= viewport.bottom - offset.bottom) &&
            (element.left >= viewport.left + offset.left) &&
            (element.right <= viewport.right - offset.right) &&
            (element.top >= viewport.top + offset.top)) {
          if (!opacityEffect.isDisplayed()) {
            var left = tooltip.retrieve("left");
            
            moveEffect.start(left - 20, left);
            
            opacityEffect.start(0, 1);
          }
        } else {
          if (opacityEffect.isDisplayed()) {
            var left = tooltip.retrieve("left");
            
            moveEffect.start(left, left + 20);
            
            opacityEffect.start(1, 0);
          }
        }
      });
      
      // Hides tooltip when the user clicks on it
      tooltip.addEvent("click", function() {
        opacityEffect.start(1, 0);
      });
    }
  }
};



/*******************************************************************************
 * Coupons helper definition
 */
var Coupons = {
  start: function() {
    var modal = new Modal();
    
    // Parses the list of coupons
    $$(".coupons LI").each(function(coupon) {
      var link = coupon.getElement("H3 A");
      
      if (link !== null) {
        link.addEvent("click", function(event) {
          // Stops event propagation (no other listener will ever get it)
          event.stop();
        });
        
        var title = link.getParent();
        
        Title.truncate(title);
      }
      
      var links = coupon.getElements(".actions A[rel=overlay]");
      
      links.each(function(link) {
        link.addEvent("click", function(event) {
          // Stops event propagation (no other listener will ever get it)
          event.stop();
          
          var url = link.getProperty("href");
          
          var openMerchantStore = false;
          
          // Extracts the merchant slug from this url
          var matches = url.match(/-chez-([^\/]+)/);
          
          if ((matches !== null) && (matches.length === 2)) {
            var identifier = matches[1];
            
            var cookie = Cookie.read("__gcs");
            
            if (cookie !== null) {
              // Rebuilds list of merchant slugs already processed
              var identifiers = cookie.split('.');
              
              // Opens the merchant store only if not already opened during the
              // current user browsing session
              if (!identifiers.contains(identifier)) {
                openMerchantStore = true;
                
                identifiers.push(identifier);
                
                Cookie.write("__gcs", identifiers.join('.'), {path: '/'});
              }
            } else {
              openMerchantStore = true;
              
              Cookie.write("__gcs", identifier, {path: '/'});
            }
          }
          
          // Opens the modal box with the specified url
          modal.open(url, openMerchantStore);
          
          // Opens the merchant store in a new window if necessary
          if (openMerchantStore) {
            // Extracts the caption slug and coupon identifier from this url
            matches = url.match(/promotions\/(.*)$/);
            
            if ((matches !== null) && (matches.length === 2)) {
              // Builds the new url
              var merchantUrl = "/utiliser/" + matches[1];
              
              window.load(merchantUrl, true);
              
              // Tracks this click as an event too
              if (Services.getTracking().isEnabled()) {
                Services.getTracking().trackEvent("Coupons", "View", "Button");
              }
            }
          }
        });
      });
    });
  }
};



/*******************************************************************************
 * Log helper definition
 */
var Log = {
  start: function() {
    // Retrieves the url of the current page
    url = location.href;
    var uri = url.toURI();
    
    // Does not log anything coming from the search hints
    if (uri.getData("from") !== "hint") {
      // Extracts the identifier part from this url
      var matches = url.match(/[^\/]*$/);
      
      if ((matches !== null) && (matches.length === 1)) {
        // Retrieves this identifier, which can be either a merchant slug or a
        // coupon id
        var identifier = matches[0];
        
        var request = new Request.JSON({
          url: "/log/" + identifier,
          method: "get"
        });
        
        request.send();
      }
    }
  }
};



/*******************************************************************************
 * All pages
 */
var all = {
  start: function() {
    // Retrieves all elements from the sidebar menu 
    var elements = $$(".menu LI");
    
    if (elements !== null) {
      // Initializes a ramp effect
      var rampEffect = new Fx.Ramp(elements);
      
      // Retrieves the parent list element
      var parent = elements.getParent();
      
      // Removes style previously set through the javascript-enabled stylesheet
      parent.setStyle("visibility", "visible");
      
      // Displays the elements gradually when page has finished loading
      rampEffect.start.delay(500, rampEffect);
    }
    
    // Retrieves the search form
    var form = $E("#search FORM");
    
    if (form !== null) {
      // Retrieves the search input field
      var input = form.getElement("INPUT");
      
      if (input !== null) {
        // Retrieves the submit button
        var button = form.getElement("BUTTON");
        
        if (button !== null) {
          // Simulates a push on the submit button 
          button.addEvent("push", function() {
            var chain = new Chain();
            
            var one = function() {
              button.addClass("pushed");
            };
            
            var two = function() {
              button.removeClass("pushed");
            };
            
            chain.chain(one);
            chain.chain(two);
            
            chain.callChain();
            chain.callChain.delay(400, chain);
          });
          
          // Makes sure the user cannot submit this form without a valid search 
          // query (i.e. a query neither empty nor equal to the text hint)
          form.addEvent("submit", function(event) {
            // Stops event propagation (no other listener will ever get it)
            event.stop();
            
            // Simulates a push on the submit button 
            button.fireEvent("push");
            
            // Retrieves the current value of the search input field
            var value = input.getProperty("value");
            
            // Retrieves the title of the search input field
            var title = input.getProperty("title");
            
            // Submits the form only when a valid value is provided 
            if (!value.isEmpty() && (value !== title)) {
              this.submit();
            } else {
              input.focus();
            }
          });
          
          // Hides the text hint (which is derived from the title attribute) 
          // when the user wants to edit the search input field
          input.addEvent("focus", function() {
            if (this.value === this.title) {
              this.value = "";
            }
            
            button.addClass("active");
          });
          
          // Displays the text hint (which is derived from the title attribute) 
          // when the user leaves the search input field unedited
          input.addEvent("blur", function() {
            if (this.value.isEmpty()) {
              this.value = this.title;
            }
            
            button.removeClass("active");
          });
          
          // Retrieves the current value of the search input field
          var value = input.getProperty("value");
          
          // Handles the case where a search was performed
          if (!value.isEmpty()) {
            // Places cursor in the search input field upon loading page
            input.focus();
          } else {
            // Initializes the search input field with the text hint
            input.fireEvent("blur");
          }
        }
      }
    }
    
    // Processes the newsletter forms
    $$(".newsletter FORM").each(function(form) {
      // Retrieves the search input field
      var input = form.getElement("INPUT");
      
      if (input !== null) {
        // Retrieves the submit button
        var button = form.getElement("BUTTON");
        
        if (button !== null) {
          // Simulates a push on the submit button 
          button.addEvent("push", function() {
            var chain = new Chain();
            
            var one = function() {
              button.addClass("pushed");
            };
            
            var two = function() {
              button.removeClass("pushed");
            };
            
            chain.chain(one);
            chain.chain(two);
            
            chain.callChain();
            chain.callChain.delay(400, chain);
          });
          
          // Makes sure the user cannot submit this form without a valid search 
          // query (i.e. a query neither empty nor equal to the text hint)
          form.addEvent("submit", function(event) {
            // Stops event propagation (no other listener will ever get it)
            event.stop();
            
            // Simulates a push on the submit button 
            button.fireEvent("push");
            
            // Retrieves the current value of the search input field
            var value = input.getProperty("value");
            
            // Retrieves the title of the search input field
            var title = input.getProperty("title");
            
            // Submits the form only when a valid value is provided 
            if (!value.isEmpty() && (value !== title)) {
              this.submit();
            } else {
              input.focus();
            }
          });
          
          // Hides the text hint (which is derived from the title attribute) 
          // when the user wants to edit the search input field
          input.addEvent("focus", function() {
            if (this.value === this.title) {
              this.value = "";
            }
            
            button.addClass("active");
          });
          
          // Displays the text hint (which is derived from the title attribute) 
          // when the user leaves the search input field unedited
          input.addEvent("blur", function() {
            if (this.value.isEmpty()) {
              this.value = this.title;
            }
            
            button.removeClass("active");
          });
          
          // Initializes the search input field with the text hint
          input.fireEvent("blur");
        }
      }
    });
    
    // Processes each list of actions and adds them a bookmark link
    $$("#actions UL, #footer .actions UL").each(function(actions, index) {
      if (!window.chrome && !Browser.Engine.webkit) {
        // Creates the following template and injects it inside the list:
        // 
        //   <li><a href="/" title="Sauver l'adresse de Gary Coupon dans vos bookmarks ou vos sites favoris" class="bookmark">Ajouter Gary Coupon à vos sites favoris</a></li>
        // 
        var element = new Element("LI");
        element.inject(actions);
        
        var link = new Element("A");
        link.setProperty("href", "/");
        link.addClass("bookmark");
        link.inject(element);
        
        if (Browser.Engine.presto) {
          link.setProperty("rel", "sidebar");
        }
        
        if (Browser.Engine.trident) {
          link.setProperty("title", "Sauver l'adresse de Gary Coupon dans vos sites favoris");
          link.set("text", "Ajouter Gary Coupon à vos sites favoris");
        } else {
          link.setProperty("title", "Sauver l'adresse de Gary Coupon dans vos bookmarks");
          link.set("text", "Ajouter Gary Coupon à vos bookmarks");
        }
        
        link.addEvent("click", function(event) {
          if (!Browser.Engine.presto) {
            // Stops event propagation (no other listener will ever get it)
            event.stop();
          }
          
          var url = link.getProperty("href");
          var uri = new URI(url);
          url = uri.toString();
          
          var title = "Gary Coupon";
          
          if (Browser.Engine.gecko) {
            window.sidebar.addPanel(title, url, "");
          } else if (Browser.Engine.presto) {
            var oldTitle = link.getProperty("title");
            
            link.setProperty("title", title);
            
            window.addToFav(url);
            
            link.setProperty("title", oldTitle);
          } else if (Browser.Engine.trident) {
            window.external.AddFavorite(url, title);
          }
          
          // Tracks this click as an event too
          if (Services.getTracking().isEnabled()) {
            Services.getTracking().trackEvent("Site", "Bookmark", "Link");
          }
        });
      }
      
      // Animates only the list of actions in the header
      if (index === 0) {
        // Initializes tickers component
        var tickers = new Tickers({interval: 3000});
        
        // Setups ticker for the list of actions
        tickers.enable(actions);
      }
    });
    
    // Setups links with a 'rel' attribute to open in a new window
    $$("A[rel~=external]").each(function(link) {
      link.addEvent("click", function(event) {
        // Stops event propagation (no other listener will ever get it)
        event.stop();
        
        var url = this.getAttribute("href");
        
        if (!url.isEmpty()) {
          window.open(url, "_blank");
        }
      });
    });
    
    // Tracks clicks on banners as an event too
    if (Services.getTracking().isEnabled()) { 
      $$(".sidebar .highlights A").each(function(link) {
        link.addEvent("click", function(event) {
          Services.getTracking().trackEvent("Ads", "Click", "Banner");
        });
      });
    }
  }
};



/*******************************************************************************
 * Alerts pages
 */
var alertspages = {
  start: function() {
    if (Services.getTracking().isEnabled()) {
      // Retrieves the first message displayed
      var message = $E(".message");
      
      if (message !== null) {
        // Retrieves the url of the current page
        url = location.href;
        var uri = url.toURI();
        
        // Retrieves the whole path from this url
        var path = uri.get("directory") + uri.get("file");
        
        // Tracks the display of this page as a custom page view to reflect the
        // result of the action performed by the user more accurately
        if (message.hasClass("warning")) {
          if (message.hasClass("sending")) {
            if (!message.hasClass("retry")) {
              Services.getTracking().setPageview(path + "/envoye");
            } else {
              Services.getTracking().setPageview(path + "/renvoye");
            }
          }
        } else if (message.hasClass("failure")) {
          Services.getTracking().setPageview(path + "/erreur");
        }
      }
    }
  }
};



/*******************************************************************************
 * Contact page
 */
var contactpage = {
  start: function() {
    // Retrieves the form element
    var form = $E("#content FORM");
    
    if (form !== null) {
      // Retrieves the submit button
      var button = $E("#content FORM BUTTON");
      
      if (button !== null) {
        button.addEvent("click", function(event) {
          // Stops event propagation (no other listener will ever get it)
          event.stop();
          
          // Removes focus on the button to get a nicer display
          this.blur();
          
          form.submit();
        });
      }
      
      if (Services.getTracking().isEnabled()) {
        // Retrieves the first message displayed
        var message = $E(".message");
        
        if (message !== null) {
          // Retrieves the url of the current page
          url = location.href;
          var uri = url.toURI();
          
          // Retrieves the whole path from this url
          var path = uri.get("directory") + uri.get("file");
          
          // Tracks the display of this page as a custom page view to reflect
          // the result of the action performed by the user more accurately
          if (message.hasClass("success")) {
            Services.getTracking().setPageview(path + "/succes");
          } else if (message.hasClass("failure")) {
            Services.getTracking().setPageview(path + "/erreur");
          }
        }
      }
      
      // Retrieves the first field
      var field = $("name");
      
      // Positions cursor on the first field of the form at loading time
      if (field !== null) {
        field.focus();
      }
    }
  }
};



/*******************************************************************************
 * Merchant view page
 */
var merchantsviewpage = {
  start: function() {
    if (Services.getTracking().isEnabled()) {
      // Retrieves the first message displayed
      var message = $E(".message");
      
      if (message !== null) {
        // Retrieves the url of the current page
        url = location.href;
        var uri = url.toURI();
        
        // Retrieves the whole path from this url
        var path = uri.get("directory") + uri.get("file");
        
        // Tracks the display of this page as a custom page view to reflect the
        // result of the action performed by the user more accurately
        if (message.hasClass("creation")) {
          Services.getTracking().setPageview(path + "/alerte/creer/succes");
        } else if (message.hasClass("deletion")) {
          Services.getTracking().setPageview(path + "/alerte/supprimer/succes");
        }
      }
    }
    
    // Retrieves the element containing the merchant name, but only in the case
    // this merchant is enabled (so if it is not the case, no link is added)
    var name = $E(".merchant.enabled .name");
    
    if (name !== null) {
      // Retrieves the name of the merchant itself
      name = name.get("text");
      
      // Retrieves the url of the current page
      url = location.href;
      
      // Extracts the identifier part from this url
      var matches = url.match(/[^\/]*$/);
      
      if ((matches !== null) && (matches.length === 1)) {
        // Retrieves the merchant slug
        var identifier = matches[0];
        
        // Retrieves the link surrounding the merchant url 
        var link = $E(".url A");
        
        if (link !== null) {
          // Updates the link with one that can be tracked
          link.setProperty("href", "/visiter/" + identifier);
          link.addProperty("rel", "nofollow");
          link.appendProperty("title", " dans une nouvelle fenêtre");
          
          link.addEvent("click", function(event) {
            // Stops event propagation (no other listener will ever get it)
            event.stop();
            
            var url = this.getAttribute("href");
            
            // Opens the target url in a new window
            window.load(url);
            
            // Tracks this click as an event too
            if (Services.getTracking().isEnabled()) {
              Services.getTracking().trackEvent("Merchants", "Visit", "Link");
            }
          });
        }
        
        // Retrieves the link surrounding the merchant screenshot 
        var link = $E(".screenshot A");
        
        if (link !== null) {
          // Updates the link with one that can be tracked
          link.setProperty("href", "/visiter/" + identifier);
          link.addProperty("rel", "nofollow");
          link.appendProperty("title", " dans une nouvelle fenêtre");
          
          link.addEvent("click", function(event) {
            // Stops event propagation (no other listener will ever get it)
            event.stop();
            
            var url = this.getAttribute("href");
            
            // Opens the target url in a new window
            window.load(url);
            
            // Tracks this click as an event too
            if (Services.getTracking().isEnabled()) {
              Services.getTracking().trackEvent("Merchants", "Visit", "Screenshot");
            }
          });
        }
        
        // Retrieves the link from the merchant button 
        var link = $E(".merchant .actions LI:last-child A");
        
        if (link !== null) {
          // Updates the link with one that can be tracked
          link.setProperty("href", "/visiter/" + identifier);
          link.addProperty("rel", "nofollow");
          link.appendProperty("title", " dans une nouvelle fenêtre");
          
          link.addEvent("click", function(event) {
            // Stops event propagation (no other listener will ever get it)
            event.stop();
            
            var url = this.getAttribute("href");
            
            // Opens the target url in a new window
            window.load(url);
            
            // Tracks this click as an event too
            if (Services.getTracking().isEnabled()) {
              Services.getTracking().trackEvent("Merchants", "Visit", "Button");
            }
          });
        }
      }
    }
  }
};



/*******************************************************************************
 * Newsletter pages
 */
var newsletterpages = {
  start: function() {
    if (Services.getTracking().isEnabled()) {
      // Retrieves the first message displayed
      var message = $E(".message");
      
      if (message !== null) {
        // Retrieves the url of the current page
        url = location.href;
        var uri = url.toURI();
        
        // Retrieves the whole path from this url
        var path = uri.get("directory") + uri.get("file");
        
        // Tracks the display of this page as a custom page view to reflect the
        // result of the action performed by the user more accurately
        if (message.hasClass("success")) {
          if (message.hasClass("subscribe") || message.hasClass("unsubscribe")) {
            Services.getTracking().setPageview(path + "/succes");
          }
        } else if (message.hasClass("warning")) {
          if (message.hasClass("sending")) {
            if (!message.hasClass("retry")) {
              Services.getTracking().setPageview(path + "/envoye");
            } else {
              Services.getTracking().setPageview(path + "/renvoye");
            }
          }
        } else if (message.hasClass("failure")) {
          Services.getTracking().setPageview(path + "/erreur");
        }
      }
    }
  }
};



/*******************************************************************************
 * Initialization (when document object model is available)
 */
window.addEvent("domready", function() {
  // Initializes services
  Services.initialize();
  
  // Handles behaviors common to all pages
  all.start();
  
  // Retrieves page identifier
  var body = $E("body");
  var page = body.getProperty("id");
  
  // Handles specific page behaviors
   if (page.startsWith("alerts")) {
    alertspages.start();
  } else if (page === "contactpage") {
    contactpage.start();
  } else if (page === "merchantsviewpage") {
    merchantsviewpage.start();
  } else if (page.startsWith("newsletter")) {
    newsletterpages.start();
  }
  
  if (page.startsWith("coupons") || (page === "homepage") || (page === "merchantsviewpage")) {
    Coupons.start();
  }
  
  if ((page === "couponsviewpage") || (page === "merchantsviewpage")) {
    Alerts.start();
    Log.start();
  }
  
  // Makes sure the Google Analytics library is loaded and available
  if (Services.getTracking().isEnabled()) {
    Services.getTracking().trackPageview();
  }
});
