var GJM = {

    prefix : 'gjm',

    // the submitted form
    form : false,

    // google maps api features holder
    api_features : false,

    // target element
    target : false,

    // address field
    address_field : false,

    //coordinates
    lat_field : false,
	
    lng_field : false,

    auto_located : false,

    enter_clicked : false,

    prevent_submission : false,

    locator_button : false,

    /**
     * Run on page load
     * 
     * @return {[type]} [description]
     */
    init : function() {
		
        GJM.custom_map_location();
        GJM.enable_geolocation_features();
        GJM.reset_form_fields();
        GJM.form_filters_trigger();
        GJM.update_form();
    },

    /**
     * Set cookie
     * 
     * @param {[type]} name   [description]
     * @param {[type]} value  [description]
     * @param {[type]} exdays [description]
     */
    set_cookie : function( name, value, exdays ) {
        var exdate = new Date();
        exdate.setTime( exdate.getTime() + ( exdays * 24 * 60 * 60 * 1000 ) );
        var cooki = escape( value ) + ( ( exdays == null ) ? "" : "; expires=" + exdate.toUTCString() );
        document.cookie = name + "=" + cooki + "; path=/";
    },

    /**
     * Get cookie
     * 
     * @param  {[type]} name [description]
     * @return {[type]}      [description]
     */
    get_cookie : function( name ) {
        var results = document.cookie.match( '(^|;) ?' + name + '=([^;]*)(;|$)' );
        return results ? decodeURIComponent( results[2]) : null;
    },

    /**
     * Delete cookie
     * 
     * @param  {[type]} name [description]
     * @return {[type]}      [description]
     */
    delete_cookie : function( name ) {
    	document.cookie = encodeURIComponent( name ) + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
    },

    /**
     * This is a fix for a conflict with the GJM element ID when
     *
     * loading results from history.state
     *
     * The gjm_element_id is also passes via the state. But because the element ID
     * 
     * is generated randomly on page load ( unless specified by the user via shortcode attribute )
     * 
     * The element ID saved in the state will be different than the new ID generated on page load.
     * 
     * This cause a conflict with the map element.
     *
     * This fix remove the gjm_element_id parameter from the state when the page first loads.
     * 
     * @return {[type]} [description]
     */
    
    /**
     * Auto locator feature
     * 
     * @param  {[type]} locator_element [description]
     * @return {[type]}                 [description]
     */
    auto_locator : function( locator_element ) {

        GJM.locator_button = locator_element;
        GJM.prefix         = GJM.form.find( '.gjm-enabled' ).data( 'prefix' );
        GJM.form           = locator_element.closest( 'form' );
        
        // aniumate loader
        GJM.locator_button.addClass( 'animate-spin' );

        // if GPS exists locate the user //
        if ( navigator.geolocation ) {

            navigator.geolocation.getCurrentPosition( GJM.navigator_success, GJM.navigator_failed, { timeout: 10000 } );

        } else {

            GJM.locator_button.removeClass( 'animate-spin' );

            // if nothing found we cant do much. we cant locate the user :( //
            alert(localizeMsg.geo_not_supported);
        }
    },

    /**
     * Navigator success callback function
     * 
     * @param  {[type]} position [description]
     * @return {[type]}          [description]
     */
    navigator_success : function( position ) {

        var geocoder = new google.maps.Geocoder();

        geocoder.geocode( { 'latLng': new google.maps.LatLng(position.coords.latitude, position.coords.longitude ) }, function( results, status ) {

            if ( status == google.maps.GeocoderStatus.OK ) {

            	//set cookie to prevent future autolocation for one day
		        GJM.set_cookie( 'gjm_autolocate', 1, 1 );

            	// get location data.
            	var address = results[0].formatted_address;
            	var lat     = results[0].geometry.location.lat();
            	var lng     = results[0].geometry.location.lng();

            	// save location data in cookies.
            	GJM.set_cookie( 'gjm_ul_address', address, 7 );
            	GJM.set_cookie( 'gjm_ul_lat', lat, 7 );
            	GJM.set_cookie( 'gjm_ul_lng', lng, 7 );

            	// populate location data in form fields.
                GJM.form.find( '#search_location' ).val( address );
                GJM.form.find( '.gjm-lat' ).val( lat );
                GJM.form.find( '.gjm-lng' ).val( lng );
                
                //run the ajax search
                //give it a bit of extra time to set the coordinates in the hidden fields
                setTimeout( function() {

                    GJM.form.find( '#search_location' ).change();
                    
                    GJM.locator_button.removeClass( 'animate-spin' );

                }, 500 );

            } else {

            	//set cookie to prevent future autolocation for one day
		        GJM.set_cookie( 'gjm_autolocate', 1, 1 );

                GJM.locator_button.removeClass( 'animate-spin' );

                alert( localizeMsg.geocoder_failed + status );
            }
        });        
    },

    /**
     * Navigator failed callback function
     * 
     * @param  {[type]} error [description]
     * @return {[type]}       [description]
     */
    navigator_failed : function( error ) {

        if ( ! GJM.auto_located ) {
            
            switch ( error.code ) {

                case error.PERMISSION_DENIED :

                    alert( localizeMsg.user_denied_request );
                    
                break;

                case error.POSITION_UNAVAILABLE :

                    alert( localizeMsg.location_information );

                break;

                case 3 :

                    alert( localizeMsg.user_location_timed );

                break;

                case error.UNKNOWN_ERROR :

                    alert( localizeMsg.unknown_error );

                break;
            }
        }

        //hide locator button and show loader 
        GJM.locator_button.removeClass( 'animate-spin' );
    },

    /**
     * Display map in custom location using shortcode
     *
     * if using results map shortcode elsewhere on the page remove the map from its original place
     * which is above the list of results into the new map holder.
     * 
     * @return {[type]} [description]
     */
    custom_map_location : function() {

        jQuery( '.gjm-map-wrapper, .grm-map-wrapper' ).each( function() {

            GJM.form   = jQuery( this ).closest( 'form' );
            GJM.prefix = GJM.form.find( 'gjm-enabled' ).data( 'prefix' );
            
            var mapId = jQuery( this ).attr( 'data-map-id' );

            if ( jQuery( '#' + GJM.prefix + '-results-map-holder-' + mapId ).length ) {
				
                jQuery( this ).detach().appendTo( '#' + GJM.prefix + '-results-map-holder-' + mapId );

            } else if ( jQuery( '.results-map-holder' ).length ) {

                jQuery( this ).detach().appendTo( '.results-map-holder' );
            }
        });
    },

    /**
     * Enable various geolocation features
     * 
     * @return {[type]} [description]
     */
    enable_geolocation_features : function() {

        // enable some features
        jQuery( '.gjm-enabled' ).each( function() {

            // temporary fix for petsitter and babysitter themes
            jQuery( 'body.petsitter, body.petsitter-child, body.babysitter, body.babysitter-child' ).find( 'select.gjm-filter, select.grm-filter' ).unwrap( '.select-style' );

            GJM.form         = jQuery( this ).closest( 'form' );
            GJM.api_features = jQuery( this ).data();

            GJM.form.addClass( 'gjm-features-enabled' );

            if ( wpjm_options.select2 == true && jQuery.fn.select2 ) {
            	
            	// do not enable select2 oh Jobify hero page for now.
            	jQuery( 'select.' + GJM.api_features.prefix + '-filter' ).not( 'body.page-template-jobify .hero-search select.' + GJM.api_features.prefix + '-filter' ).select2();
            
            } else if ( jQuery.fn.chosen ) {
                
                jQuery( 'select.' + GJM.api_features.prefix + '-filter' ).chosen( { search_contains: true } );
            }

            // add class if no filters exists in the form
            // Also remove a class added by jobify theme
            if ( ! GJM.form.find( '.gjm-filters-wrapper' ).length ) {
                GJM.form.find( '.search_jobs' ).addClass( 'gjm_no_filters' ).removeClass( 'gjm_use' );
            } else {
            	GJM.form.find( '.search_jobs' ).addClass( 'gjm_filters_enabled' );
            }

            if ( ! GJM.form.find( '.grm-filters-wrapper' ).length ) {
                GJM.form.find( '.search_resumes' ).addClass( 'grm_no_filters' );
            } else {
            	GJM.form.find( '.search_resumes' ).addClass( 'grm_filters_enabled gjm_use' );
            }

            if ( jQuery( 'body.listify' ).length && GJM.form.find( '.search-radius-wrapper' ).length ) {
                GJM.form.find( '.search-radius-wrapper' ).remove();
            }

            if ( GJM.form.find( '.search_submit' ).length ) {
            	GJM.form.find( '.gjm-filters-wrapper, .grm-filters-wrapper' ).detach().insertBefore( GJM.form.find( '.search_submit:first' ) ).show();
            } else {
            	GJM.form.find( '.gjm-filters-wrapper, .grm-filters-wrapper' ).show();
            }

            if ( jQuery( 'body.listingeasy' ).length ) {

            	var sjElement = GJM.form.find( '.search_jobs' );

                GJM.form.find( '.gjm-filters-wrapper' ).detach().insertAfter( sjElement );
            }

            // if action attribute exists means this is a custom form and will show results in a different page.
            // In this case we need to disable some value to prevent theme from passing into the URL
            if ( GJM.form.attr( 'action' ) ) {
                GJM.form.find( '.url-disabled' ).attr( 'disabled', 'disabled' );
            }  

            // check if we need to autolocate the user on page load
            if ( GJM.api_features.autolocator == 'enabled' && navigator.geolocation && ! jQuery.trim( GJM.form.find( '#search_location' ).val() ).length ) {

	            if ( GJM.get_cookie( 'gjm_autolocate' ) == 1 && GJM.api_features.save_autolocator == 1 ) {

	            	jQuery( window ).on( 'load' ).on( 'load', ( function () {

	            		var address = GJM.get_cookie( 'gjm_ul_address' );
	            		
	            		if ( address != 'undefined' && address != null ) {

			            	// populate location data in form fields.
			                GJM.form.find( '#search_location' ).val( address );
			                GJM.form.find( '.gjm-lat' ).val( GJM.get_cookie( 'gjm_ul_lat' ) || '' );
			                GJM.form.find( '.gjm-lng' ).val( GJM.get_cookie( 'gjm_ul_lng' ) || '' );
			                
			                //run the ajax search
			                //give it a bit of extra time to set the coordinates in the hidden fields
			                setTimeout( function() {

			                    GJM.form.find( '#search_location' ).change();
			                    
			                }, 500 );
			            }
		            }));

	            } else {

	                var locator_element = jQuery( this );

	                jQuery( window ).on( 'load' ).on( 'load', ( function () {

	                    GJM.auto_located = true;

	                    GJM.auto_locator( locator_element );
	                })); 
		        }
		    }

            // Enable locator button
            if ( GJM.api_features.locator_button == 'enabled' ) {

                var locatorBtn = jQuery( '<i class="' + GJM.api_features.prefix + '-filter ' + GJM.api_features.prefix +'-locator-btn gjm-icon-target-1" title="' + GJM.api_features.locator_btn_title + '"></i>' ).click( function() {

                    GJM.auto_located = false;

                    GJM.auto_locator( jQuery( this ) );

                }).insertAfter( GJM.form.find( 'input#search_location' ) );

            }

            // enable address autocomplete
            if ( GJM.api_features.autocomplete == 'enabled' ) {
                
                acField = GJM.form.find( '#search_location' )[0];
                
                // options               
                var acOptions = {
                    types : [GJM.api_features.results_type]
                };

                if ( GJM.api_features.country != '' ) {
                    acOptions.componentRestrictions = { country : GJM.api_features.country };
                } 

                var acObject = new google.maps.places.Autocomplete( acField , acOptions );
                
                google.maps.event.addListener( acObject, 'place_changed', function(e) {

                    GJM.form.find( '.gjm-country, .gjm-state' ).val( '' );
                       
                    var place = acObject.getPlace();

                    if ( ! place.geometry ) {
                        return;
                    }

                    // if only country entered set its value in hidden fields
                    if ( place.address_components.length == 1 && place.address_components[0].types[0] == 'country' ) {
                                        
                        GJM.form.find( '.gjm-country' ).val( place.address_components[0].short_name );

                    // otherwise if only state entered.
                    } else if ( place.address_components.length == 2 && place.address_components[0].types[0] == 'administrative_area_level_1' ) {
                        
                        GJM.form.find( '.gjm-state' ).val( place.address_components[0].short_name );
                        GJM.form.find( '.gjm-country' ).val( place.address_components[1].short_name );
                    }

                    //update coords fields
                    GJM.form.find( '.gjm-lat' ).val( place.geometry.location.lat().toFixed( 6 ) );
                    GJM.form.find( '.gjm-lng' ).val( place.geometry.location.lng().toFixed( 6 ) );

                    //update prev_field to be the same as address field. This way
                    //we don't need to geocode the address again since we have coordinates already
                    GJM.form.find( '.gjm-prev-address' ).val( GJM.form.find( '#search_location' ).val() );       
                });
            }
        });
    },
    
    /**
     * Reset GJM form Fields when "Reset" link clicked
     * 
     * @return {[type]} [description]
     */
    reset_form_fields : function() {
        
        jQuery( '.job_filters, .resume_filters' ).on( 'click', '.reset', function( e ) {

            GJM.form = jQuery( this ).closest( 'form' );   

            GJM.form.find( '.gjm-filter option:first-child, .grm-filter option:first-child' ).attr( 'selected', 'selected' ).trigger( 'chosen:updated' );
            GJM.form.find( 'select.gjm-filter, select.grm-filter' ).chosen( 'updated' );

            GJM.form.find( '.gjm-lat, .gjm-lng, .gjm-prev-address' ).val( '' );
        } );
    },

    /**
     *
     * Form Filters Trigger
     * 
     * Trigger form submission when GJM filters update
     * 
     * @return {[type]} [description]
     */
    form_filters_trigger : function() {
     
        jQuery( '.gjm-filter, .grm-filter' ).change( function() {

            if ( ( jQuery( this ).hasClass( 'radius-filter' ) || jQuery( this ).hasClass( 'units-filter' ) ) && jQuery( this ).closest( 'form' ).find( '#search_location' ).val() == '' ) {
                return;
            }

            jQuery( this ).closest( 'div.job_listings, div.resumes' ).trigger('update_results', [ 1, false ] );
        });
    },

    /**
     * update form and geocode address
     * 
     * @return {[type]} [description]
     */
    update_form : function() {

        jQuery( '.gjm-enabled' ).closest( 'form' ).find( '#search_location' ).keydown( function( event ) {

            if ( event.keyCode == 13 ) {
                
                GJM.enter_clicked = true;
               
                event.preventDefault();

                return false;

            } else {
                jQuery( this ).closest( 'form' ).find( '.gjm-lat, .gjm-lng' ).val( '' );
            }
        });

        /**
         * When filters changed in the search form trigger a change event on the location field.
         *
         * This way the function below will take action which is responsiable for geocoding the address.
         *
         * We do it this way since the next function disable then enable the change event of the target
         *
         * which causes for conflicts with the select2 and might be with other elements.
         * 
         * 
         * @return {[type]}   [description]
         */
        jQuery( '.gjm-enabled' ).closest( 'form' ).find( '#search_categories, .job_types :input, .job-manager-filter' ).on( 'change', function() {
        	jQuery( this ).closest( 'form' ).find( '#search_location' ).trigger( 'change' );
        });

        /**
         * Modify the submission of the form and add address geocoding process to it.
         * 
         * @return {[type]}       [description]
         */
        jQuery( '.gjm-enabled' ).closest( 'form' ).find( '#search_keywords, #search_location' ).off( 'change' ).on( 'change', ( function ( event ) {
    
            // work around to prevent multiple submissions when enter click
            // For some reason, when enter key presses in the address field the form is being submitted.
            // However, after leaving the address field ( focusout ) the form is being submitted again.
            if ( GJM.prevent_submission && ! GJM.enter_clicked ) {

                GJM.enter_clicked      = false;
                GJM.prevent_submission = false;

                return false;
            
            } else {

                if ( GJM.enter_clicked ) {

                    GJM.enter_clicked      = false;
                    GJM.prevent_submission = true;     
                }
            }

            //get some fields
            GJM.form      = jQuery( this ).closest( 'form' );
            GJM.target    = jQuery( this ).closest( 'div.job_listings, div.resumes' );
            GJM.lat_field = GJM.form.find( '.gjm-lat' );
            GJM.lng_field = GJM.form.find( '.gjm-lng' );
            //GJM.previous_address = GJM.form.find( '.gjm-prev-address' );

            //set timeout to let enough time for the address autocomplete value to set in the location field.
            //This is kind of a "hack" since the change event happesn faster then the address value can be set for the field
            //which results in a "currapted" address value.
            setTimeout( function() {
                
                var address   = GJM.form.find( '#search_location' ).val();
                var latitude  = GJM.lat_field.val();
                var longitude = GJM.lng_field.val();

                // skip geocoding if no address provided or if the coordinates already exist.
                if (  ! jQuery.trim( address ).length || ( jQuery.trim( latitude ).length && jQuery.trim( longitude ).length ) ) {

                    console.log('no geocoding');
                    
                    GJM.target.triggerHandler( 'update_results', [ 1, false ] );
                    
                    return false;
                }

                //dynamically set the radius dropdown to the last option
                //if address entered and the radius dropdown value selected is default
                if ( jQuery( '.gjm-radius option:first-child' ).is( ':selected' ) ) {
                    jQuery( '.gjm-radius option:last-child' ).attr( 'selected', 'selected' );
                }
                
    	        console.log('new address ' + address );

                GJM.form.find( '.gjm-country, .gjm-state' ).val( '' );
           
                //geocode the address
                var geocoder = new google.maps.Geocoder();

                apiRegion = typeof GJM.api_features.api_region !== undefined ? GJM.api_features.api_region : 'us';

                geocoder.geocode( { 'address': address, 'region' : apiRegion }, function( results, status ) {
                    
                    //if geocoding successful
                    if ( status == google.maps.GeocoderStatus.OK ) {

                        // if only country entered set its value in hidden fields
                        if ( results[0].address_components.length == 1 && results[0].address_components[0].types[0] == 'country' ) {
                            
                            GJM.form.find( '.gjm-country' ).val( results[0].address_components[0].short_name );

                        // otherwise, if only state entered.
                        } else if ( results[0].address_components.length == 2 && results[0].address_components[0].types[0] == 'administrative_area_level_1' ) {
 
                            GJM.form.find( '.gjm-state' ).val( results[0].address_components[0].short_name );
                            GJM.form.find( '.gjm-country' ).val( results[0].address_components[1].short_name );
                        }

                        //set the coordinates
                        GJM.lat_field.val( results[0].geometry.location.lat().toFixed( 6 ) );
                        GJM.lng_field.val( results[0].geometry.location.lng().toFixed( 6 ) );

                        //run the ajax search
                        //give it a bit of extra time to set the coordinates in the hidden fields
                        setTimeout( function() {
                            GJM.target.triggerHandler( 'update_results', [ 1, false ] );
                        }, 500 );
                    
                    //if geocoding failed
                    } else {

                        GJM.lat_field.val( '' );
                        GJM.lng_field.val( '' );
                        
                        //if address could not geocoded abort the function and display an error message
                        alert( localizeMsg.different_address_error_message + status );     
                    }
                });
            }, 500 );

            return false;    
        }));
    }
};

jQuery( document ).ready( function(jQuery) {
	GJM.init();
});