// My custom autocomplete, overlay and tabs
// Can use a nicer data-* attrbute, with function as textual callback.
// Note that for IE8 compatibility, textual callback should look like
// "new Function( \"arg1\" [, \"arg2\" , ... ], \"core\" )"
// These function should only be used for initialization
(function($){
  
  $.xautocomplete = {
    // Cache system
    cache: [] ,
    // Last XML HTTP Request
    lXHR: null ,
    // Default configuration
    defaults: {
      minLength: 2
    }
  };
  
  // jQuery plugin initialization
	$.fn.xautocomplete = function( conf ){
    this.each( function(){
    
      // Get configuration from element
      conf = $.extend( $.xautocomplete.defaults , conf , $(this).data( 'autocomplete' ) );
      // Reset configuration to receive autocomplete object
      $(this).data( 'autocomplete' , null );

      // Check for callbacks (add callbacks that you expect on this part)
      // Useless for now...
//      var funcs = [ 'source' , 'change' ], i = funcs.length;
//      while( i-- ) {
//        if( conf[funcs[i]] && ( ! $.isFunction( conf[funcs[i]] ) ) && conf[funcs[i]].match( /^function/ ) ) conf[funcs[i]] = eval( '('+conf[funcs[i]]+')' );
//      }
      
      if( ! conf.source ) throw new Error( 'A source must be set to use autocomplete.');
      
      if( typeof( conf.source ) === 'string' ) {
        // We are in case of URL request
        var url = conf.source;
        // Enable a more complexe request with caching
        conf.source = function( request , response ) {
          var params = [ url, request.term ] , k = params.join( '@' );
          if ( k in $.xautocomplete.cache ) {
            response( $.xautocomplete.cache[ k ] );
            return;
          }
          $.xautocomplete.lXHR = $.getJSON( url , request, function( data, status, XHR ) {
            $.xautocomplete.cache[ k ] = data;
            if ( XHR === $.xautocomplete.lXHR ) response( data );
          } );
        };
      }

      // Apply autocomplete with html source
      $(this).autocomplete( conf ).data('autocomplete')._renderItem = function( ul, item ) {
        return $( '<li></li>' ).data( 'item.autocomplete', item ).append( $( '<a></a>' ).html( item.label ) ).appendTo( ul );
      };
      
      // Force close on blur event
      $(this).bind( 'focus', function(){
        // Set desired autocompletion flag
        $(this).data( 'autocomplete.focus' , true );
      } ).bind( 'blur' , function(){
        // Remove loading icon, and unset desired autocompletion flag
        $(this).removeClass('ui-autocomplete-loading').data( 'autocomplete.focus' , false );
      } ).bind( 'autocompleteopen' , function(){
        // Remove loading icon
        $(this).removeClass('ui-autocomplete-loading');
        // Make sure that autocompletion still desired
        if( $(this).data( 'autocomplete.focus' ) !== true ) $(this).autocomplete('close');
      } ).bind( 'autocompleteclose' , function(){
        // Remove loading icon
        $(this).removeClass('ui-autocomplete-loading');
      } );
    } );
    return this;
	};
  
  $.xoverlay = {
    // Default configuration
    defaults: {
      expose: {
        color: '#4e5846' ,
        loadSpeed: 500 ,
        opacity: 0.75
      } ,
      left: 'center' ,
      top: 'center' ,
      onClose: function( e ){
        // Undo the display "none" effect for Google maps and other interactive elements
        this.getOverlay().css( {left:'-9999em',display:'block'} );
      }
    }
  };
  
  // jQuery plugin initialization
	$.fn.xoverlay = function( conf ) {
    this.each( function(){
    
      // Get configuration from element
      conf = $.extend( $.xoverlay.defaults , {
        // The special target must be done here
        target: $( $(this).attr('href') ) 
      } , conf , $(this).data( 'overlay' ) );
      // Reset configuration to receive overlay object
      $(this).data( 'overlay' , null );

      // Check for callbacks (all callbacks should be here)
      // Note that textual callback should look like "new Function( \"arg1\" [, \"arg2\" , ... ], \"core\" )" for IE8 compatibility
      var funcs = [ 'onBeforeLoad' , 'onLoad', 'onBeforeClose' , 'onClose' ], i = funcs.length;
      while( i-- ) {
        if( conf[funcs[i]] && ( ! $.isFunction( conf[funcs[i]] ) ) && conf[funcs[i]].match( /^new\s+Function/ ) ) conf[funcs[i]] = eval( '('+conf[funcs[i]]+')' );
      }

      // Apply overlay with this configuration
      $(this).overlay( conf );
    } );
    return this;
	};

  // jQuery plugin initialization
	$.fn.xtabs = function( selector , conf ) {
    this.each( function(){

      // Get configuration from element
      conf = $.extend( {} , conf , $(this).data( 'tabs' ) );
      // Reset configuration to receive tabs object
      $(this).data( 'tabs' , null );

      // Check for callbacks (all callbacks should be here)
      // Note that textual callback should look like new "Function( \"arg1\" , [\"arg2\" , ... ]\"core\" )" for IE8 compatibility
      var funcs = [ 'onBeforeClick' , 'onClick' ], i = funcs.length;
      while( i-- ) {
        if( conf[funcs[i]] && ( ! $.isFunction( conf[funcs[i]] ) ) && conf[funcs[i]].match( /^new Function/ ) ) conf[funcs[i]] = eval( '('+conf[funcs[i]]+')' );
      }

      // Apply tabs with this configuration
      $(this).tabs( selector , conf );
    } );
    return this;
	};

  // jQuery plugin initialization
	$.fn.xunifyheight = function( conf ){
    this.each( function(){
      // Check if the unification has not been allready apply
      if( $(this).data('__unified') ) return true;

      // Get configuration from element
      conf = $.extend( {selector: '.js-unify-height'} , conf , $(this).data( 'unify-height' ) );

      // Set default parent
      if( ! conf.parent ) conf.parent = $(this).parent();
      // Make sure parent is a jQuery object
      else conf.parent = $(this).parents( conf.parent );
      // Make sure that we care only about the first parent
      conf.parent = $( conf.parent[0] );

      var m = $(this).height() ;
      // Determine max height
      conf.parent.find( conf.selector ).each( function(){
        m = Math.max( m , $(this).height() );
      } );
      // Apply max height
      conf.parent.find( conf.selector ).each( function(){
        // Apply height and set data
        $(this).height( m ).data( '__unified' , true );
      } );
    } );
    return this;
	};
  
  $.xclickdelegate = {
    // Default configuration
    defaults: {
      source: 'tbody tr' , // Element which has click effect
      target: 'a:eq(0)' , // Final element to click
      exclude: 'a, button, input, select, textarea' , // Elements to skip
      hover: 'bg-lt-8' , // Class to add on hover event 
      onEnter: function( d ){} , // Event call on enter (after hover class add)
      onLeave: function( d ){} // Event call on leave (after hover class remove)
    }
  };

  // jQuery plugin initialization
	$.fn.xclickdelegate = function( conf ){
    this.each( function(){
      // Get configuration from element
      conf = $.extend( $.xclickdelegate.defaults , conf , $(this).data( 'clickdelegate' ) );

      // Check for callbacks (all callbacks should be here)
      // Note that textual callback should look like new "Function( \"arg1\" , [\"arg2\" , ... ]\"core\" )" for IE8 compatibility
      var funcs = [ 'onEnter' , 'onLeave' ], i = funcs.length;
      while( i-- ) {
        if( conf[funcs[i]] && ( ! $.isFunction( conf[funcs[i]] ) ) && conf[funcs[i]].match( /^new Function/ ) ) conf[funcs[i]] = eval( '('+conf[funcs[i]]+')' );
      }

      // Apply delegation
      $(this).delegate( conf.source , {
        'mouseenter': function( e ){if( conf.hover ) $(this).addClass( conf.hover );conf.onEnter( this );} ,
        'mouseleave': function( e ){if( conf.hover ) $(this).removeClass( conf.hover );conf.onLeave( this );} ,
        'click': function(e){
          if( $(e.target).closest( conf.exclude ).length ) {
            // We are in a clickable element, we must let the system call the base click action
          } else {
            var t = $(this).find( conf.target );
            if( t.length === 1 ) {
              // We are not in a clickable element, and the target is unique, apply delegation
              if( t.triggerHandler('click') === undefined ) {
                // There was not any custom handler on this event, emulate default action from tag name
                if( t.is( 'a' ) ) {
                  window.location.href = t[0].href;
                } else if( t.is('button[type="submit"]') ) {
                  t.parents('form').trigger('submit');
                }
              }
            }
          }
        }
      } );
    } );
  };
  
  $.xcar = {
    // Default configuration
    defaults: {
      timeout: 1000, // Timeout for animation
      top: 20, // offset for top
      bottom: 20, // offset for bottom
      ratio: 0.2, // ratio for randomization
      duration: 5000, // duration for animation
      area: 200, // area for stop
      api: false // return api
    }
  };
  
  function MoveCar( trigger , conf )
  {
    var self = this,
        timeoutID = null ,
			  uid = Math.random().toString().slice(10);
        
    // Set default parent
    if( ! conf.parent ) conf.parent = $(trigger).parent();
    // Make sure parent is a jQuery object
    else conf.parent = $(trigger).parents( conf.parent );
    // Make sure that we care only about the first parent
    conf.parent = $( conf.parent[0] );
      
		// API methods
    $.extend(self, {  
      run: function() {
        
        // Top position to go
        var f = $(trigger).position().top - Math.min( conf.parent.outerHeight() - conf.bottom - $(trigger).outerHeight() , Math.max( conf.top , $(window).scrollTop() - conf.parent.offset().top + ( ( $(window).height() * $(window).scrollTop() ) / ( $('body').outerHeight() - $(window).height() ) ) ) ); 
        // Randomize a little bit this destination
        var c = ( f * conf.ratio  ) < conf.area ? ( f * ( 1 - conf.ratio ) ) + ( f * conf.ratio * Math.random() ) : ( f - conf.area ) + ( conf.area * Math.random() ) ; 
        
        self.stop();
        
        $( trigger ).stop( true ).animate( {top: new String( Math.floor( $(trigger).position().top - c ) )+'px'} , {
          duration: Math.floor( ( conf.duration * ( 1 - conf.ratio ) ) + ( conf.duration * conf.ratio * Math.random() ) ) ,
          queue: true
        } );
        
        // Chaining
        return self;
      } ,
      init: function() {
        
        self.stop();
        
        $(window).bind( 'scroll' , function() {
          timeoutID = window.setTimeout( self.run , Math.floor( ( conf.timeout * conf.ratio ) + ( conf.timeout * ( 1 - conf.ratio ) * Math.random() ) ) );
        } );
        
        // Chaining
        return self.run();
      },
      stop: function(){
        // Stop timeout if any
        if( timeoutID ) window.clearTimeout( timeoutID );
        
        // Chaining
        return self;
      }
    } );
    
    
    return self;
  };
  
  $.fn.xcar = function( conf ) {
    
		// already constructed --> return API
		var el = this.data('__cars');
		if (el) { return el; }
    
    this.each( function(){
      // Get configuration from element
      var localconf = $.extend( $.xcar.defaults , conf , $(this).data( 'car' ) );
      
      el = new MoveCar( $(this), localconf );
      
      $(this).data('__cars', el);
      
      el.init();
      
    } );
    
    return conf.api ? el: this;
  };
  
  // Special functions for google maps correction on luxembourg
  
  // @tag google-luxembourg-postalcode-issue
  // @see http://code.google.com/p/gmaps-api-issues/issues/detail?id=3418
  // because google does not remember any postal codes from luxembourg,
  // this function used to preserve postal code on autocompletion 
  // when the result comes from luxembourg country, but we need to 
  // add the country code to the autocompletion definition...
  $.fn.PostMixedAutocomplete = function( d , val ) {
    // At this point, d can be in the form "[postal ]locality country"
    // where country is a two letter iso code
    var p = /^\s*(L[^0-9]?)?[0-9]+/gi, m;
    // on luxembourg, no postal code in the result and postal code in the input
    if( val.substr( val.length - 2 ) === 'LU' && val.match( p ) === null && ( m = $(d).val().match( p ) ) ) {
      // We have a postal code, preserve it
      p = /[0-9]+$/g;
      m = m[0].match( p );
      val = m[0]+' '+val;
    }
    // Assign value without country code
    $(d).val( val.substr( 0 , val.length - 4 ) );
  };
  
  // @tag google-luxembourg-geocoding-issue
  // because each time we search for a postal code followed by luxembourg,
  // google maps systematically return the "rue de luxembourg" at Mondercange
  // this function restrict query strictly on luxembourg locality
  $.fn.PreMixedAutosearch = function( d ) {
    var p = /luxemb/gi, c = $(d).parents('fieldset').find('.js-autocomplete-country');

    if( ( ! c.val() ) && $(d).val().match( p ) ) c.val( 'lu' );

    return $(d).val();
  };
  
} )( jQuery );


$(document).ready( function(){
    
  window.console = window.console || {}; // Do not overwrite console if there is one
  if(window.opera) console.log || ( console.log = opera.postError );
  
  // Enable select menu for karzoo country choice
  // Do it at first to minimize flick effect
  // Necessary workaround to make select menu working
  $('.js-karzoocountry-choice option').addClass('ui-selectmenu-karzoocountry');
  // Load select menu
  // For some pragmaticall reasons, we prefer to use CSS instaed of menuWidth configuration
  $('.js-karzoocountry-choice').bind('change',function(){if(!$(this).val().match(/^\s*$/))this.form.submit();}).selectmenu( {
    icons: [ {find: '.ui-selectmenu-karzoocountry'} ], 
    bgImage: function(){return $(this).css('background-image');}
  } );

  $('input[placeholder], textarea[placeholder]').placeholder();

  // Height unification, note that it must appears before tabs effect
  $('.js-unify-height').xunifyheight();

  // Apply tabs
  $('.js-tabs').xtabs( 'div.js-tab-panel' );

  // Apply autocomplete (using custom autocomplete function)
  $('.js-autocomplete').xautocomplete();

  // Enable overlay link (using custom overlay function)
  // Overlay link are considerer as simple link to an overlay element
  $('.js-overlay-link').xoverlay();

  // Apply xclick
  $('.js-clickdelegate').xclickdelegate();
  
//  var header = $('#header');
//  var carTopMin = header.offset().top + header.height() + 5;
//  var adjustCarTop = function() {
//    var car = $('#little-car-box img').show();
//    if(car.offset().top < carTopMin) {
//      car.hide()
//    }
//  }
//  adjustCarTop();
//  $(window).bind('scroll', function() {
//    adjustCarTop();
//  })
  
  $('.js-springy').each( function(){
    var t = $(this);
    t.find('.js-springy-trigger').click( function(){t.toggleClass('opened').find('.js-springy-performer').slideToggle( 'normal' );return false;} );
  } );

  $('.shut-nav .in').click( function(){
    $(this).toggleClass('cl-eee').parent().toggleClass('bg-5');
  } );
  
  if( $.browser.webkit && parseInt($.browser.version, 10) < 534 ) {
    $('.arrow-right').css({fontFamily: 'Webdings', display: 'inline'}).html(4);
    $('.arrow-left').css({fontFamily: 'Webdings', display: 'inline'}).html(3);
  }

  // If there is any error on ajax call, reload the current page
  // Note that this handler must be attach to a document element
  $('body').ajaxError( function(){window.location.href = window.location.href;} );

  // Embed flash file
  // Requires flashembed tool
  // @see http://flowplayer.org/tools/toolbox/flashembed.html)
  $('.js-flashembed').each( function(){
    flashembed( this , $.extend( {
      wmode: 'transparent' ,
      play: 'true' ,
      autoplay: 'true' ,
      allowscriptaccess: 'false'
    } , $(this).data('config') ) );
  } );
  
  // Cars animation
  $('.js-car').xcar( { parent: '.container' } );

});
