var StoreLocator = new Class({

    no_location_msg: "(MAP NOT YET AVAILABLE FOR THIS LOCATION)",

    initialize: function(selectors, stores, details, spinner, map_options, cache, url){

        this.selectors = $(selectors);
        this.stores = $(stores);
        this.details = $(details);
        this.spinner = $(spinner);
        this.url = url;

        this.map_canvas = $(map_options.map);
        this.map_overlay = new Element('div', {'id': 'map-overlay'})
            .setStyles({'display': 'none', 'position': 'absolute', 'opacity': 0.7})
            .adopt(new Element('div', {'class': 'spinner'}).set('html', this.no_location_msg))
            .inject(document.body);

        this.hide_map();
        this.map = new GMap2(document.getElementById(map_options.map));

        this.cache = cache;
        this.requests = {};
        this.markers = {};
        this.markers_groups = {};
        this.markers_types = [];

        this.icon = new GIcon();
        this.icon.image = map_options.icon;
        this.icon.iconSize = new GSize(25,25);
        this.icon.iconAnchor = new GPoint(12,12);

        this.TYPE_STORE = 'store';
        this.TYPE_CITY = 'city';


        this.map.setMapType(G_NORMAL_MAP);
        this.map.addControl(new GSmallMapControl());
        this.map.addControl(new GMapTypeControl());
//        this.map.enableScrollWheelZoom();

        this.set_events_handlers();

        this.get_selected_data();


    },


    get_selected_data: function()
    {
        var name = false;
        var value = false;
        var o = null;
        var i = 0;

        var selects = this.selectors.getElements('select');
        if(!selects || !selects.length) return false;

        for(i=0; i < selects.length; i++)
        {
            o = selects[i].getSelected();
            var v = o[0].getProperty('value');

            if(v == "-1") break;

            name = selects[i].name;
            value = v;
        }

        if(!name || !value)
        {
            for(i=0; i < selects[0].options.length; i++)
            {
                o = selects[0].options[i];
                if(o.getAttribute('selected') != null)
                {
                    name = selects[0].name;
                    value = o.getProperty('value');
                }
            }
        }

        if(name && value) this.selector_changed(name, value);
    },

    set_events_handlers: function()
    {
        var _this = this;
        this.selectors.getElements('select').each(function(selector){
            _this.set_selector_handler(selector);
        });

    },

    set_selector_handler: function(selector)
    {
        var _this = this;
        $(selector).addEvents({
            'change': function(ev) { _this.clear_next_selectors(ev.target.name); _this.selector_changed(ev.target.name, ev.target.value) }
        });
    },

    selector_changed: function(name, value)
    {
        this.clear_stores();

        if(value == "-1")
        {
            this.get_selected_data();
            return;
        }

        if(name != this.TYPE_CITY) {
            this.hide_map();
        }

        var all_selectors = {};
        this.selectors.getElements('select').each(function(s){
            if(s.name == name) s.value = value;
            all_selectors[s.name] = s.value;
        });


        var data = {
            selectors: all_selectors,
            changed_selector: {name: name, value: value}
        };

//        if(this.is_in_cache(name, value))
//        {
//            this.mapTo(this.cache[name][value]);
//        }

        this.send_request(data);
    },

    send_request: function(data)
    {
        var _this = this;
        var key = Hash.toQueryString(data);

        if(this.requests[key])
        {
            this.process_request(this.requests[key], data.changed_selector);
        }
        else
        {
            this.spinner.removeClass('hidden');
            new Request.JSON({
                url: this.url,
                data: data,
                onSuccess: function(json){
                    _this.spinner.addClass('hidden');
                    if(json && json.status == 'success')
                    {
                        _this.requests[key] = json.data;
                        _this.process_request(json.data, data.changed_selector);
                    }
                }
            }).send();
        }
    },

    is_in_cache: function(name, id)
    {
        return this.cache[name] && this.cache[name][id];
    },


    pack_selector: function(selector)
    {
        return {
            'name': selector.name,
            'value': selector.value
        }
    },

    pack_selector_to_assoc: function(selector)
    {
        var obj = {};
        obj[selector.name] = selector.value;
        return obj;
    },

    process_request: function(data, changed_selector){

        if(data.last){
            this.hide_markers();
            this.create_areas_markers(this.TYPE_STORE, data.stores, true, changed_selector);
            this.display_stores(data.stores, changed_selector);
            return;
        }

        if(data.areas.length)
        {
            var last_name = this.selectors.getElements('select').getLast().name;

            if(last_name != data.type)
            {
                var selector = this.build_selector(data.type, data.areas);
                this.set_selector_handler(selector.getElement('select'));
                if(data.areas.length == 1)
                {
                    this.selector_changed(data.type, data.areas[0].id);
                }
            }

            this.hide_markers();
            this.create_areas_markers(data.type, data.areas, true, changed_selector);
            this.cache_coords(data.type, data.areas);
        }
    },

    build_selector: function (name, options)
    {
        var field       = new Element('div', {'class': 'field'});
        field.inject(this.selectors);

        var div_input   = new Element('div', {'class': 'input'});
        var select      = new Element('select', {'name': name});
        select.inject(div_input.inject(field));

        var choose_str = 'Select ' + name + ':';
        var empty_option = new Element('option', {'value': '-1', 'selected': 'selected', 'class': 'inactive', 'html': choose_str});
        empty_option.inject(select, 'top');

        options.each(function(o){
            var option = new Element('option', {'value': o.id, 'html': o.name});
            option.inject(select);
        });

        return field;
    },


    display_stores: function(stores, city)
    {
        if(!stores.length) return;
        this.show_stores();

        var list = new Element('ul', {'class': 'list'});
        var _this = this;

        var n; //last name
        var has_resolved = false;

        stores.each(function(s){
            var loc = s.city;
            loc = s.state.length ? loc + ', ' + s.state : loc;

            var name = new Element('li', {'id': 'store_name_' + s.id, 'html': s.name});

            var events = {
                'mouseover': function(){ _this.hover_store(name); },
                'mouseout': function(){ _this.clean_store(name); },
                'click': function() { _this.select_store(s, name); _this.go_to_store(s, city);}
            };

            name.addEvents(events);

            name.inject(list);
            n = name;
            if(_this.coords_resolved(s)) has_resolved = true;
        })

        var old_stores = this.stores.getElement('.list');
        if(old_stores) old_stores.dispose();
        list.inject(this.stores);

        this.show_map();
        if((stores.length == 1) && n)
        {
            this.select_store(stores[0], n);
            if(has_resolved)
            {
                this.location_available();
                this.go_to_store(stores[0], city);
            }
            else
            {
                this.mapTo(this.cache[city.name][city.value]);
                this.location_unavailable();
            }
        }
        else if(stores.length > 1)
        {
            this.location_available();
            this.mapTo(this.cache[city.name][city.value]);
        }
    },

    select_store: function(store, name)
    {
        var selected = this.stores.getElements('.selected');
        if(selected.each) selected.each(function(s){
            s.removeClass('selected');
        })

        name.addClass('selected');

        this.print_address(store);
        this.show_details();
    },


    unselect_store: function(name)
    {
        name.removeClass('selected');
        this.hide_details();
    },

    print_address: function(store)
    {
        var street = store.formated_address.split(',')[0];
        var email = store.email.replace(/(\b[A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4}\b)/gi, "<a href='mailto:$&'>E-mail Us</a>");
        var address = street + "<br />" + store.city + ", " + store.state + ", " + store.postcode + "<br/>Phone " + store.phone
        
        if (email.length > 0)
        {
            address += " or " + email + ' <span class="small">(Resumes Welcome)</span>';
        }

        address += '<br/><span class="small">' + store.tradinghours + '</span>';

        this.details.getElement('.address').set('html', address);
    },

    hover_store: function(name)
    {
        name.addClass('hover');
    },

    clean_store: function(name)
    {
        name.removeClass('hover');
    },

    clear_stores: function()
    {
        this.stores.addClass('hidden');
        this.details.addClass('hidden');

        this.details.getElement('.address').set('html', '');
        var list = this.stores.getElement('.list');
        if(list) list.dispose();
    },

    clear_next_selectors: function(name)
    {
        var remove = false;

        this.selectors.getElements('select').each(function(s){
            if(remove) s.getParent('.field').dispose();
            if(s.name == name) remove = true;
        });
    },

    show_stores: function()
    {
        this.stores.removeClass('hidden');
    },

    show_details: function()
    {
        this.details.removeClass('hidden');
    },

    hide_details: function()
    {
        this.details.addClass('hidden');
    },

    show_map: function()
    {
        this.map_canvas.removeClass('hidden');
    },

    hide_map: function()
    {
        this.location_available();
        this.map_canvas.addClass('hidden');
    },

    go_to_store: function(store, city)
    {
        var street = store.formated_address.split(',')[0];
        var message = "<b>" + store.name + "</b><br/>" + street;

        this.create_marker(this.TYPE_STORE, store, message);
        var res = this.mapTo(store);
        if(res)
        {
            this.location_available();
        }
        else
        {
            this.location_unavailable();
            this.mapTo(this.cache[city.name][city.value]);
        }
    },

    create_marker: function(type, coords, message, show)
    {
        if(!this.coords_resolved(coords)){
            return false;
        }

        show = show || true;
        message = message || '';

        var _this = this;
        var marker = this.has_marker(type, coords);
        if(marker) return marker;


        var latlng = new GLatLng(coords.lat, coords.lng);
        marker = new GMarker(latlng, {icon: this.icon});


        marker.value = coords.name;

        if( (type == _this.TYPE_STORE) && coords.id )
        {
            GEvent.addListener(marker,"click", function() {
//                _this.map.openInfoWindowHtml(latlng, message);
                  _this.select_store(coords, $('store_name_' + coords.id));
            });
        }

        if(show) this.map.addOverlay(marker);

        this.cache_marker(type, marker);
        return marker;
    },


    create_areas_markers: function(type, areas, show, changed_selector)
    {
        show = show || true;
        if(!areas.each) return;

        var _this = this;
        areas.each(function(a){
            var m = _this.create_marker(type, a, '', show);
            if(m){
                GEvent.addListener(m,"click", function() {
                    if(type != _this.TYPE_STORE)
                    {
                        _this.map.closeInfoWindow();
                        _this.selector_changed(type, a.id || -1);
                    }
                    else
                    {
                        _this.display_stores(areas, changed_selector);
                        _this.select_store(a, $('store_name_' + a.id));
                        _this.go_to_store(a, changed_selector);
                    }
                });
            }
        });
    },


    hide_markers: function(type)
    {
        type = type || 'all';

        if( this.markers_groups[type] )
        {
            this.markers_groups[type].each(function(m){
                m.closeInfoWindow();
                m.hide();
            });
        }
        else if(type == 'all')
        {
            for (var t in this.markers_groups)
            {
                this.hide_markers(t);
            }
        }
    },

    show_markers: function(type)
    {
        type = type || 'all';

        if( this.markers_groups[type] )
        {
            this.markers_groups[type].each(function(m){
                m.show();
            });
        }
        else if(type == 'all')
        {
            for (var t in this.markers_groups)
            {
                this.show_markers(t);
            }
        }
    },

    mapTo: function(coords)
    {
        if(!this.coords_resolved(coords)){
//            this.location_unavailable();
            return false;
        }
        else
        {
//            this.location_available();
        }

        var center = new GLatLng(coords.lat, coords.lng);
        var sw = new GLatLng(coords.south, coords.west);
        var ne = new GLatLng(coords.north, coords.east);

        var bounds  = new GLatLngBounds(sw, ne);

        this.map.setCenter(center);
        this.map.setZoom(this.map.getBoundsZoomLevel(bounds));
        return true;
    },


    cache_coords: function(name, coords)
    {
        if(!this.cache[name]) this.cache[name] = [];
        var _this = this;
        coords.each(function(c){
            _this.cache[name][c.id] = c;
        });
    },

    has_marker: function(type, coords)
    {
        if (this.markers[type] && this.markers[coords.lat] && this.markers[coords.lat][coords.lng])
        {
            return this.markers[type][coords.lat][coords.lng];
        }

        return false;
    },


    cache_marker: function(type, marker)
    {
        var latlng = marker.getLatLng();
        this.markers[type] = this.markers[type] || {};
        this.markers[type][latlng.lat()] = this.markers[type][latlng.lat()] || {};
        this.markers[type][latlng.lat()][latlng.lng()] = marker;

        this.markers_groups[type] = this.markers_groups[type] || [];
        this.markers_groups[type].push(marker);
    },

    coords_resolved: function(coords)
    {
        return (coords.lat != 0) && (coords.lng != 0);
    },

    location_unavailable: function()
    {
        var pos = this.map_canvas.getCoordinates();
        this.map_overlay.getElement('.spinner').set({'html': this.no_location_msg});
        this.map_overlay.setStyles({
            'top': pos.top,
            'left': pos.left,
            'width': pos.width,
            'height': pos.height,
            'display': '',
            'opacity': 0.9
        });
        var _this = this;
        this.map_overlay.addEvent('click', function(){_this.location_available()});
    },

    location_available: function()
    {
        this.map_overlay.fade('out').setStyle('display', 'none');
    }

});