function useAddressLookup(params) {
    $(function() {
        var addressField = $('#' + params.addressFieldId);
        var countryField = $('#' + params.countryFieldId);
        $('#' + params.addressFieldId).autocomplete(
            function(address, callback) {
                var addr = {
                    'country': countryField[0].value,
                    'address': addressField[0].value
                };
                $.get('/lookup_address.php', {addr: $.toJson(addr) }, function(addrList) {
                    addrList = $.parseJson(addrList);
                    var filteredAddrList = [];
                    for (var i = 0; i < addrList.length; i++) {
                        // strip country, we have separate select box for it
                        var displayAddress = addrList[i].split(',').slice(0,-1).join(',');
                        if (displayAddress) filteredAddrList[i] = [displayAddress];
                    }
                    callback(filteredAddrList);
                });
            }, {
            //valueFieldId: params.addressFieldId + '_placemark',
            matchCase: false,
            emptyHint: (params.locationHelper != undefined) ? params.locationHelper : 'Select a location from the list<br> that appears as you type',
            //noMatchHint: 'No matches found',
            placeholder: params.placeholder || ''
        });
        
        // reset address on country change
        countryField.change(function() {
            addressField[0].value = params.placeholder || '';
            addressField.change();
        });
    });
}

//default email domains to autocomplete
var emailDomains = ['hotmail.com','yahoo.com','hotmail.co.uk','yahoo.co.uk','aol.com','gmail.com','live.co.uk','btinternet.com','googlemail.com','msn.com',
                             'live.com','ntlworld.com','tiscali.co.uk','ymail.com','sky.com','blueyonder.co.uk','comcast.net','fsmail.net','rocketmail.com',
                             'aim.com','talktalk.net','yahoo.co.in','aol.co.uk','sbcglobal.net','rediffmail.com','breakthru.com','verizon.net','virgin.net',
                             'yahoo.ca','wp.pl','att.net','yahoo.ie','o2.co.uk','live.ie','cox.net','lycos.co.uk','bellsouth.net','tesco.net','eircom.net',
                             'yahoo.com.au','btopenworld.com','live.ca','excite.com','btconnect.com','talk21.com','yahoo.fr','rock.com','gmx.com','charter.net','o2.pl',
                             'peoplepc.com','mailinator.com','earthlink.net','live.com.au','lycos.com','gmx.co.uk','yahoo.in','hotmail.fr','orange.net'];

/* autocomplete email field with mail domains */
function autocomplete_email_domain(params) {
    $(function() {
         var emailField = $('#' + params.emailFieldId);
         var domains = params.domains || emailDomains; 
         $('#' + params.emailFieldId).autocomplete(
             function(email, callback) {
                 emails = []
                 if(email) {
                 
                    if(email.search(/@/) > 0) {
                       var emailParts = email.split("@");
                       if(emailParts.length == 2 && emailParts[1]) {
                            for(var i = 0; i < domains.length; i++) {
                               regExp = new RegExp("^" + emailParts[1],"i");

                               if(regExp.test(domains[i]))
                                   emails[i] = [emailParts[0] + '@' + domains[i]];
                            }
                       } 
                    }
                 }
                 callback(emails);
             }, 
             {
                matchCase: false, 
                validate: params.validate || false,
               	emptyHint: (params.locationHelper != undefined) ? params.locationHelper : 'Select a email domain from the list<br> that appears as you type'
             }
        );
    });
}

jQuery.fn.lookupAddress = function(options) {
    var $lookupAddress = this;
    
    options = $.extend({
        prefix: '',
        error: false,
        countrySelector: null,
        onError: function() {},
        onReset: function() {},
        onItemSelect: function() {},
        placeholder: T('city or postal code')
    }, options);
    
    $lookupAddress.onError = function(handler) {
        options.onError = handler;
        return $lookupAddress;
    };
    
    $lookupAddress.onReset = function(handler) {
        options.onReset = handler;
        return $lookupAddress;
    };
    
    $lookupAddress.onItemSelect = function(handler) {
        options.onItemSelect = handler;
        return $lookupAddress;
    };
    
    $lookupAddress.each(function() {
        var self = this;
        var $self = $(this);

        var $location = $self.find('input.location');
        var $country = options.countrySelector ? $(options.countrySelector) : $self.find('input.country');
        var $help = $self.find('.help');
        var $error = $self.find('.' + options.prefix + 'error');

        var _query = '';
        var _locations = [];
        var _default_value = '';

        var el = null;
        
        var _cache = {};
        
        $(function() {
            _default_value = ($location.val() != options.placeholder ? $location.val() : '');
            el = $location.autocomplete(function(query, callback) {
                _reset();
                var addr = {
                    'country': $country.val(),
                    'address': query
                };
                var _handleResponse = function(response) {
                    if (!response) response = [];

                    if (_cache[addr.country] == undefined) _cache[addr.country] = {};
                    _cache[addr.country][addr.address] = $.parseJson($.toJson(response));

                    _query = query;
                    _locations = response;

                    if (!_locations.length) {
                        _locations = [];
                        _onError();
                    }

                    $(_locations).each(function(key, location) {
                        if (typeof location == 'string') {
                            _locations[key] = [location];
                        }
                        _locations[key][0] = _locations[key][0].split(',').slice(0, -1).join(',');
                    });

                    callback(_locations);
                };

                if (_cache[addr.country] != undefined
                    && _cache[addr.country][addr.address] != undefined)
                {
                    _handleResponse(_cache[addr.country][addr.address]);
                } else {
                    $.get('/lookup_address.php', { addr: $.toJson(addr), v: '2' }, _handleResponse, 'json');
                }
            }, {
                matchContains: 1,
                maxItemsToShow: 10,
                cacheLength: 0,
                selectFirst: true,
                minChars: 2,
                formatItem: function(location, i, n) {
                    return _highlight(escapeHtml(location[0]))
                        + (location.length > 1 ? '<br><span class="small">' + escapeHtml(location[1]) + '</span>' : '');
                },
                onListHide: function() {
                    setTimeout(function() {
                        if (_locations.length > 0 && !_isChoosen() && $location.val() != _default_value) {
                            $location.val(_locations[0][0]);
                        }
                    }, 100);
                },
                onDataReceived: function(obj, q, data) {
                    obj.flushCache();
                },
                onItemSelect: function(data) {
                    options.onItemSelect(data);
                },
                emptyHint: (options.locationHelper != undefined) ? options.locationHelper : T('select_location'),
                placeholder: options.placeholder,
                delay: 200
            });
            
            if (options.error) {
                _onError();
            }
        })

        function _highlight(item) {
            return item.replace(new RegExp("(" + $.trim(_query).split(/[^\w]+/).join("|") + ")", "gi"), "<strong>$1</strong>");
        }
        
        function _isChoosen() {
            var value = $location.val();
            var choosen = false;
            $(_locations).each(function() {
                if (this[0] == value) choosen = true;
            });
            return choosen;
        };

        function _reset() {
            _locations = [];
            _query = '';
            _resetAddress();
            options.onReset();
        }
        
        function _resetAddress() {
            $help.show();
            $error.hide();
            $location.removeClass(options.prefix + 'error');
        }
        function _showError() {
            $help.hide();
            $error.show();
            $location.addClass(options.prefix + 'error');
        }
        function _onError() {
            _showError();
            options.onError();
        }
        self.validate = function() {
            if (!self.isValid()) {
                _showError();
                return false;
            } else {
                return true;
            }
        };
        self.isValid = function() {
            return ($location.val() != '' && $location.val() != options.placeholder);
        };
        
        $location.keyup(function() {
            if ($(this).val() == '') {
                _reset();
            }
        });
    });

    $lookupAddress.validate = function() {
        $lookupAddress.each(function() {
            this.validate();
        });
    };

    $lookupAddress.isValid = function() {
        var is_valid = true;
        $lookupAddress.each(function() {
            if (!this.isValid()) {
                is_valid = false;
                return false;
            }
        });
        return is_valid;
    }
    
    return this;
};

