/*

Adding the THQ Universal Hat
============================

To add the THQ Universal Hat include the following code before the closing </body> tag:

  <script src="http://www.thq.com/universal-hat/universal-hat.js"></script>
  <script>

  THQ.UniversalHat({
    territories : [
      // Your available territories will go here, see below for details
    ]
  });

  </script>

The THQ Universal Hat is configured by passing in an object of configuration options.


Setting the available territories
=================================

Specify the available territories for your site by setting the `territories` configuration option. This should be an array of available territories using the following format:

  THQ.UniversalHat({
    territories : [
      {
        locale : 'us',
        url : '/us'
      },
      {
        locale : 'Japan',
        url : 'http://thqgame.jp/'
      }
    ]
  });

Each locale can have the following options:

`locale` - A required two letter country code for the locale.
`url` - A required URL for the locale. You can specify an absolute or relative URL.
`name` - An optional name to be used for the locale. If this is not included the relative country name will be used.
`mythq_url` - An optional URL to link to MyTHQ for this territory.

Locales will be ignored from the list if they do not specify both `locale` and `url` values.

If a `locale` value is specified that is not in the set of core locales (`au`, `de`, `dk`, `es`, `fi`, `fr`, `it`, `jp`, `nl`, `no`, `se`, `uk`, `us`) and a `name` has not been specified then a `Locale not found` error message will be displayed.

If you do not specify a value for `mythq_url` the MyTHQ link will be hidden, this is useful for territories which do not have the MyTHQ functionality.

A subset of the core locales (`au`, `de`, `es`, `fr`, `it`, `uk`, `us`) have a default `mythq_url`, you should not specify a value for these, and the default value can not be over ridden.


Setting the current locale.
===========================

The THQ Universal Hat will attempt to automatically detect the current locale.

If your site uses any of the following common URL patterns....

1. A two letter country code as the lang or locale query string parameter, for example:

  http://www.mydomain.com/index.php?lang=de // Detects `de` as the locale.
  http://www.mydoamin.com/index.php?locale=fr // Detects `fr` as the locale.

2. A two letter country code as the first part of the URL directory, for example:

  http://www.mydomain.com/es // Detects `es` as the locale
  http://www.mydomain.com/us/faq // Detects `us` as the locale

3. A two letter country code subdomain, for example:

  http://fr.mydomain.com // Detects `fr` as the locale
  http://de.forums.mydomain.com/ // Detects `de` as the locale

These URL patterns are matched in the order given above, for example:

  http://us.mydomain.com/index.php?locale=de // Detects `de` as the locale
  http://es.mydomain.com/fr/games // Detects `fr` as the locale

If your site does not use any of these URL patterns, or you want to override the automatic locale detection you can specify the current locale as a configuration option when initializing the THQ Universal Hat:

  THQ.UniversalHat({
    locale : 'us', // Sets `us` as the locale and skips any automatic detection of the locale
    ...
  });


Setting a default locale
========================

If the THQ Universal Hat is unable to detect a valid locale a default locale is used instead The default locale is set to `us` but this can be overridden as a configuration option when initializing the THQ Universal Hat:

  THQ.UniversalHat({
    defaultLocale : 'fr', // Sets `fr` as the default locale
    ...
  })


Manually updating the current locale.
=====================================

If your site is Flash or AJAX based you may need to manually update the current locale. To do this call the updateLocale method of the THQ Universal Hat and pass in the new locale.

  THQ.UniversalHat.updateLocale('fr'); // Sets `fr` as the current locale


Simple Example
==============

  THQ.UniversalHat({
    territories  : [
      {locale : 'us', url : '/us'},
      {locale : 'uk', url : '/uk'},
      {locale : 'au', url : '/au'},
      {locale : 'fr', url : '/fr'},
      {locale : 'it', url : '/it'},
      {locale : 'de', url : '/de'},
      {locale : 'es', url : '/es'},
      {locale : 'jp', url : 'http://thqgame.jp/'}
    ]
  });

In this example the current locale will be automatically detected, default territory names will be used, and the MyTHQ link will not show for `jp`.


Complex Example
===============

  THQ.UniversalHat({
    locale : 'fr',
    territories  : [
      {locale : 'us', url : '/us'},
      {locale : 'uk', url : '/uk', name : 'UK'},
      {locale : 'au', url : '/au'},
      {locale : 'fr', url : '/fr'},
      {locale : 'it', url : '/it'},
      {locale : 'de', url : '/de'},
      {locale : 'es', url : '/es'},
      {locale : 'jp', url : 'http://thqgame.jp/', mythq_link : 'http://thqgame.jp/my_account'}
    ]
  });

In this example the current locale will be set to `fr`, default territory names will be used for all territories execpt `uk` which overrides the `name` property, and the MyTHQ link will show for all territories, including `jp`, which overrides the `mythq_link` property.


Top Tips
========

If your website uses Flash you should ensure that the SWF is embedded with the wmode="transparent" this will ensure that the drop down menus of the THQ Universal Hat appear above the Flash content.

The THQ Universal Hat is 28 pixels tall, so you should account for this is your designs. To allow room for the THQ Universal Hat the following CSS rules are added to your page.:

  html {
    margin-top: 28px !important;
  }

  * html body {
    margin-top: 28px !important;
  }

If you are having issues working with the height of your content (for example detecting the page height using Javascript or Flash), you can add these rules to your own stylesheet.


*/


THQ = window.THQ || {};

(function() {
  if (THQ && THQ.UniversalHat) {
    // this is most likely to happen when people try to embed multiple
    // Universal Hats on the same page and include this script again
    return;
  }

  var CREATE_ELEMENT = 'createElement';
  var GET_ELEMENT_BY_ID = 'getElementById';
  var GET_ELEMENTS_BY_TAG_NAME = 'getElementsByTagName';
  var ID = 'thq-universal-hat';
  var IE = navigator.userAgent.match(/MSIE\s([^;]*)/);
  var IFRAMES = {};
  var NO_LOCALE_MESSAGE = 'Locale not found';

  var MYTHQ_URL = 'mythq/register';
  var SITES_JSON_URL = 'thq_sites.php?locale=';
  var STYLESHEET_URL = 'universal-hat.css';

  var DEFAULT_LOCALE = 'us';

  var TERRITORIES = {
    au : {
      mythq_url : 'au/' + MYTHQ_URL,
      name : 'Australia'
    },
    de : {
      mythq_url : 'de/' + MYTHQ_URL,
      name : 'Deutschland',
      thq_sites : 'THQ-Webseiten'
    },
    dk : {
      name : 'Danmark'
    },
    es : {
      mythq_url : 'es/' + MYTHQ_URL,
      name : 'España',
      thq_sites : 'Sitios de THQ'
    },
    fi : {
      name : 'Suomi'
    },
    fr : {
      mythq_url : 'fr/' + MYTHQ_URL,
      name : 'France',
      thq_sites : 'Sites THQ'
    },
    it : {
      mythq_url : 'it/' + MYTHQ_URL,
      name : 'Italia',
      thq_sites : 'Siti THQ'
    },
    jp : {
      name : 'Japan'
    },
    nl : {
      name : 'Nederland'
    },
    no : {
      name : 'Norge'
    },
    se : {
      name : 'Sverige'
    },
    uk : {
      mythq_url : 'uk/' + MYTHQ_URL,
      name : 'United Kingdom'
    },
    us : {
      mythq_url : 'us/' + MYTHQ_URL,
      name : 'USA'
    }
  };


  var urlRegex = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
  var urlKeys = ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"];

  function parseUrl (str) {
    var m = urlRegex.exec(str),
      url = {},
      i = 14;

    while (i--){
      url[urlKeys[i]] = m[i] || '';
    }

    return url;
  };

  // Parse the location of the current page to get the protocol and domain.
  var scriptUrl, pageUrl = parseUrl(window.location.href);
  var PROTOCOL = pageUrl.protocol;
  var DOMAIN = pageUrl.authority;

  if (document.currentScript) {
    // Mozilla provide document.currentScript which refers to this file.
    scriptUrl = parseUrl(document.currentScript.src);
  } else {
    // This script will be the last script tag in the document, this is because of the blocking nature of Javascript.
    // This will (probably) fail if this script is included asynchronusly, which is why we try to use document.currentScript if we can.
    var scripts = document.getElementsByTagName("script")
    scriptUrl = parseUrl(scripts[scripts.length-1].src);
  }

  // Get the protocol of this file if it is different to the protocol of the current page.
  if (scriptUrl.protocol && scriptUrl.protocol !== PROTOCOL) {
    PROTOCOL = scriptUrl.protocol;
  }

  // Get the domain of this file if it is different to the domain of the current page.
  if (scriptUrl.authority && scriptUrl.authority !== DOMAIN) {
    DOMAIN = scriptUrl.authority;
  }

  // Get the directory of this file.
  if (scriptUrl.directory) {
    var PATH = scriptUrl.directory;
  }

  function addListeners(el){
    on(el, 'mouseover', function(e){
      show(this);
    });

    on(el, 'mouseout', function(e){
      if (!descendantOf(e.relatedTarget || e.toElement, this)){
        hide(this);
      }
    });
  }

  function descendantOf(current, element){
    var body = document.body;
    while (current && current != element && current != document.body) {
      current = current.parentNode;
    }
    if (typeof(current) == "undefined" || typeof(current) == "null") {
        return false;
    } else if (current == element) {
        return true;
    } else if (current == document.body) {
        return false;
    }
  }

  function hide(element){
    if(element.className.indexOf(ID + '-open') !== -1) {
      element.className = element.className.replace(ID + '-open', '');
      if (IE && IFRAMES[element.id]) {
        IFRAMES[element.id].style.display = 'none';
      }
    }
  }

  function on(element, eventName, callback){

    if (element.addEventListener) {
      element.addEventListener(eventName, callback, false);
    } else if (element.attachEvent) {
      element.attachEvent('on' + eventName, function(){
        var e = window.event;
        e.preventDefault = preventDefault;
        e.target = e.srcElement;
        callback.call(element, e);
      });
    }

  }

  function preventDefault(){
    this.returnValue = false;
  }

  function show(element){
    var doc = document, s;
    if (element.className.indexOf(ID + '-open') === -1) {
      element.className += ' ' + ID + '-open';

      // Add iframe shim beneath element to ensure select elements do not show above the element in IE 6.
      if (IE) {
        if (!IFRAMES[element.id]) {
          var iframe = doc[CREATE_ELEMENT]('iframe');
          iframe.src = 'javascript:false;';
          iframe.frameBorder = 0;
          iframe.scrolling = 'no';
          s = iframe.style;
          s.display = 'none';
          s.position = 'absolute';
          s.top = '28px';
          s.left = '1px';
          s.filter='progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)';
          s.zIndex = 99998;
          element.insertBefore(iframe, element.firstChild);
          IFRAMES[element.id] = iframe;
        }

        s = IFRAMES[element.id].style;
        s.height = element.lastChild.offsetHeight;
        s.width = element.lastChild.offsetWidth;
        s.display = 'block';

      }
    }
  }


  THQ.UniversalHat = function(config){
    // Hat is already initialized, so bail out
    if (THQ.UniversalHat.isInitialized) {
      return;
    }

    THQ.UniversalHat.on = function(eventName, callback){
      on(document.documentElement, eventName, callback);
    };

    config = config || {};
    config.territories = config.territories || [];

    STYLESHEET_URL = config.stylesheet_url || PROTOCOL + '://' + DOMAIN + PATH + STYLESHEET_URL;
    SITES_JSON_URL = config.sites_json_url || PROTOCOL + '://' + DOMAIN + '/' + SITES_JSON_URL;

    var
      c,
      defaultLocale = config.defaultLocale || DEFAULT_LOCALE,
      doc = document,
      element,
      head,
      i,
      l,
      initialLocale = config.locale || null,
      script,
      sitesElement,
      stylesheet,
      t,
      territories = {},
      territoriesElement;

    head = doc[GET_ELEMENTS_BY_TAG_NAME]('head')[0];

    stylesheet = doc[CREATE_ELEMENT]('link');
    stylesheet.href = STYLESHEET_URL;
    stylesheet.rel = 'stylesheet';
    stylesheet.type = 'text/css';
    head.appendChild(stylesheet);

    doc.write('<div id="' + ID + '"><div id="' + ID + '-wrapper"><div id="' + ID + '-sites" class="' + ID + '-list"></div><div id="' + ID + '-territories" class="' + ID + '-list"></div><div id="' + ID + '-mythq" style="display: none;"><a href="' + MYTHQ_URL + '" id="' + ID + '-mythq-link">myTHQ</a></div></div></div>');

    if (!config.hideMyTHQ) {
      doc[GET_ELEMENT_BY_ID](ID + '-mythq').style.display = '';
    }

    element = doc[GET_ELEMENT_BY_ID](ID);
    sitesElement = doc[GET_ELEMENT_BY_ID](ID + '-sites');
    territoriesElement = doc[GET_ELEMENT_BY_ID](ID + '-territories');

    for (i = 0, l = config.territories.length; i < l; i++) {
      t = config.territories[i];
      if (t.locale && t.url) {
        c = t.locale.toLowerCase();
        territories[c] = {
          locale : c,
          url : t.url,
          mythq_url : (TERRITORIES[c] ? (TERRITORIES[c].mythq_url ? PROTOCOL + '://' + DOMAIN + '/' + TERRITORIES[c].mythq_url  : false) : false) || t.mythq_url,
          name : t.name || (TERRITORIES[c] ? TERRITORIES[c].name :  NO_LOCALE_MESSAGE),
          thq_sites : TERRITORIES[c] ? (TERRITORIES[c].thq_sites ? TERRITORIES[c].thq_sites : 'THQ Sites') : 'THQ Sites'
        };
      }
    }

    var sitesCallback = function(sites, locale){
      var i, l, s, sitesList = [];
      if (sites) {
        for (i = 0, l = sites.length; i < l; i++) {
          s = sites[i];
          sitesList.push('<li><a href="' + s.url + '"><span>' + s.name + '</span></a></li>');
        }
        sitesElement.innerHTML = '<a href="#"><span>' + locale.thq_sites + '</span></a><div><ul>' + sitesList.join('') + '</ul><span></span></div>';
      }
      script.parentNode.removeChild(script);
      script = null;
    };

    var updateSites = function(locale){
      script = doc[CREATE_ELEMENT]("script"),
      script.type = 'text/javascript';
      script.src = SITES_JSON_URL + locale;
      head.appendChild(script);
    };

    THQ.UniversalHat.changeSite = function(site){
      window.open(site.url);
    }

    THQ.UniversalHat.changeLocale = function(territory){
      window.location.href = territory.url;
    };

    THQ.UniversalHat.updateLocale = function(locale){
      var territoriesList = [];

      var url = parseUrl(window.location.href);

      // No locale was set, attempt to detect it from the URL of the current page.
      if (!locale) {

        if (url.query.locale) {
          locale = url.query.locale;
        } else if (url.query.lang) {
          locale = url.query.lang;
        } else {
          var path = url.directory.match(/^\/(\w\w)\//);
          if (path) {
            locale = path[1];
          } else {
            path = url.directory.match(/^\/(\w\w)$/);
            if (path) {
              locale = path[1];
            } else {
              var domain = url.authority.match(/^(\w\w)\./);
              if (domain) {
                locale = domain[1];
              }
            }
          }
        }
      }

      // Check to see if the locale is in the list of territories.
      if ((!locale || !territories[locale.toLowerCase()]) && defaultLocale) {
        locale = defaultLocale;
      }

      locale = territories[locale.toLowerCase()] || {
        locale : 'us',
        mythq_url : PROTOCOL + '://' + DOMAIN + '/' + TERRITORIES.us.mythq_url,
        thq_sites : 'THQ Sites'
      };

      THQ.UniversalHat.callback = function(sites){
        sitesCallback(sites, locale);
      };

      updateSites(locale.locale);

      for (property in territories) {
        t = territories[property];
        if (territories.hasOwnProperty(property) && t.locale !== locale.locale) {
          territoriesList.push('<li><a href="' + t.url + '" class="' + ID + '-' + t.locale + '"><span>' + t.name + '</span></a></li>');
        }
      }

      if (territoriesList.length > 0) {
        territoriesElement.innerHTML = '<a href="#" class="' + ID + '-' + locale.locale + '"><span>' + locale.name + '</span></a><div><ul>' + territoriesList.join('') + '</ul><span></span></div>';
      }

      doc[GET_ELEMENT_BY_ID](ID + '-mythq').style.display = (config.hideMyTHQ || !locale.mythq_url) ? 'none' : '';
      doc[GET_ELEMENT_BY_ID](ID + '-mythq-link').href = locale.mythq_url;

    };

    on(sitesElement, 'click', function(e){
      e.preventDefault();

      var element = e.target;

      while(element.tagName.toLowerCase() != 'a' && element.nodeType != 10) {
        element = element.parentNode;
      }

      var href = element.getAttribute('href');

      if (href && href != '#') {

        hide(sitesElement);

        THQ.UniversalHat.changeSite({
          url : element.getAttribute('href'),
          name : element.getElementsByTagName('span')[0].innerHTML
        });

      }

    });

    on(territoriesElement, 'click', function(e){
      e.preventDefault();

      var element = e.target;

      while(element.tagName.toLowerCase() != 'a' && element.nodeType != 10) {
        element = element.parentNode;
      }

      var href = element.getAttribute('href');

      if (href && href != '#') {

        hide(territoriesElement);

        var t = territories[element.className.replace(ID + '-', '')];

        THQ.UniversalHat.updateLocale(t.locale);
        THQ.UniversalHat.changeLocale({
          locale : t.locale,
          name : t.name,
          url : t.url
        });

      }

    });

    THQ.UniversalHat.updateLocale(initialLocale);

    addListeners(territoriesElement);
    addListeners(sitesElement);

    THQ.UniversalHat.isInitialized = true;


  };

})();
