Ext.namespace('NovaDine.storelocator');

NovaDine.storelocator.app = function () {

    var startOrder = function (restaurantid) {
        var startOrderURL = 'http://' +
            document.location.host.replace(/^api\./, '') +
            '/mp/pub/start?restid=' + restaurantid;
        top.location = startOrderURL;

        // This is how to embed the OrderWizard, but has security issues
        // with some configurations of Internet Explorer:
        //
        // var wizard = new NovaDine.OrderWizard({
        //     restaurantId: restaurantid
        // });
        // var window = new Ext.Window({
        //     renderTo: Ext.getBody(),
        //     baseCls: 'x-box',
        //     modal: true,
        //     resizable: false,
        //     closable: false,
        //     items: [wizard]
        // });
        // window.show();
    };

    var map;

    var shouldPreferActive = false;

    var _ = function (msg) {
        return msg;
    };

    var log = function () {
        try { console.log.apply(console, arguments); } catch (e) { }
    };


    var cleanRestaurantName = function (name) {
        return name.replace(/^Quiznos\s*(-\s*)?/, '');
    };


    var restaurantBoxTemplate = new Ext.XTemplate(
        '<div class="restaurantbox">',
        '  <div class="badges">',
        '    <tpl for="badges">',
        '      <div class="badge">',
        '        <tpl if="values.badge_url">',
        '          <a href="{values.badge_url}" target="_blank">',
        '        </tpl>',
        '        <img src="/images_menus/badge_{values.badge_name}" alt="{values.badge_name}">',
        '        <tpl if="values.badge_url">',
        '          </a>',
        '        </tpl>',
        '      </div>',
        '    </tpl>',
        '  </div>',
        '  <div class="name">{letter}{name}</div>',
        '  <div class="address">',
        '    <div>Store #{storeId}</div>',
        '    <div>{address1}</div>',
        '    <div>{city}, {statecode} {zipcode}',
        '    <div>{phone}</div>',
        '  </div>',
        '  <tpl if="active">',
        '    <div class="hours">',
        '      {hoursToday}<br>',
        '      <span>{businessHours}</span>',
        '    </div>',
        '    <div class="ordernow">{orderNow}</div>',
        '  </tpl>',
        '  <tpl if="!active">',
        '    <div class="callToOrder">{callToOrder}</div>',
        '  </tpl>',
        '</div>').compile();

    var createRestaurantBox = function (index, rest) {
        return restaurantBoxTemplate.apply({
            letter: index !== false && index < 26 ?
                (String.fromCharCode("A".charCodeAt(0) + index) + ') ') : '',
            name: cleanRestaurantName(rest.restaurantname),
            storeId: rest.storeid,
            address1: rest.address1,
            address2: rest.address2,
            city: rest.city,
            statecode: rest.statecode,
            zipcode: rest.zipcode,
            phone: rest.phone,
            active: rest.active && (rest.deliveryavailable || rest.pickupavailable),
            badges: rest.badges || [],
            deliveryAvailable: rest.active && rest.deliveryavailable ?
                _('Delivery Available') : '',
            acceptsCoupons: rest.accepts_coupons ? _('Accepts Coupons') : '',
            hoursToday: _('Hours Today'),
            businessHours: rest.businesshours ? rest.businesshours : '',
            orderNow: _('Order Now'),
            callToOrder: _(
                'Online ordering is not available, please call to order.')
        });
    };


    var infoElementTemplate = new Ext.XTemplate(
        '<div class="infoWindow">',
        '<div class="name">{name}</div>',
        '<div class="address">',
        '<div>{address1}</div>',
        '<tpl if="address2"><div>{address2}</div></tpl>',
        '<div>{city}, {statecode}  {zipcode}</div>',
        '<div>{phone}</div>',
        '<tpl if="active">',
        '<div class="hours">{hoursToday}: <span>{businesshours}</span></div>',
        '</tpl>',
        '<tpl if="!active">',
        '<div class="callToOrder">{callToOrder}</div>',
        '</tpl>',
        '</div>',
        '<ul class="actions">',
        '<li><a class="viewMenu" target="_top" href="{viewMenuURL}">{viewMenu}</a>',
        '<tpl if="active">',
        '<li><a class="startOrder" target="_top" href="{startOrderURL}">{startOrder}</a>',
        '</tpl>',
        '<tpl if="!active">',
        '<li class="disabledStartOrder">{startOrder}</li>',
        '</tpl>',
        '</ul>',
        '</div>').compile();

    var createInfoElement = function (rest) {
        var viewMenuURL = 'http://' +
            document.location.host.replace(/^api\./, '') +
            '/mp/pub/menu?restid=' + rest.restaurantid;
        var startOrderURL = 'http://' +
            document.location.host.replace(/^api\./, '') +
            '/mp/pub/start?restid=' + rest.restaurantid;
        return infoElementTemplate.apply({
            name: cleanRestaurantName(rest.restaurantname),
            address1: rest.address1,
            address2: rest.address2,
            city: rest.city,
            statecode: rest.statecode,
            zipcode: rest.zipcode,
            phone: rest.phone,
            hoursToday: _('Hours Today'),
            businesshours: rest.businesshours,
            active: rest.active && (rest.deliveryavailable || rest.pickupavailable),
            viewMenu: _('View menu'),
            viewMenuURL: viewMenuURL,
            startOrder: _('Start an order'),
            startOrderURL: startOrderURL,
            callToOrder: _(
                'Online ordering is not available at this location.' +
                '<br>Please call the store to place your order.')
        });
    };



    var createMarker = function (point, index, rest) {
        var marker, letter, baseIcon, letteredIcon;

        // Create a base icon for all of our markers that specifies the
        // shadow, icon dimensions, etc.
        baseIcon = new google.maps.Icon(G_DEFAULT_ICON);
        baseIcon.shadow = "http://www.google.com/mapfiles/shadow50.png";
        baseIcon.iconSize = new google.maps.Size(20, 34);
        baseIcon.shadowSize = new google.maps.Size(37, 34);
        baseIcon.iconAnchor = new google.maps.Point(9, 34);
        baseIcon.infoWindowAnchor = new google.maps.Point(9, 2);

        // Creates a marker whose info window displays the letter
        // corresponding to the given index.
        letteredIcon = new google.maps.Icon(baseIcon);
        if (index !== false && index < 26) {
            letter = String.fromCharCode("A".charCodeAt(0) + index);
            letteredIcon.image =
                "http://www.google.com/mapfiles/marker" + letter + ".png";
        }

        marker = new google.maps.Marker(point, {icon: letteredIcon});

        return marker;
    };


    var selectRestaurant = function (rest) {
        Ext.select("#resultsContainer .selected").removeClass("selected");
        rest.box.addClass("selected");
        rest.box.scrollIntoView(Ext.get('resultsContainer'), false);

        map.panTo(rest.point);
        map.openInfoWindowHtml(rest.point, createInfoElement(rest));

        if (window._gaq) {
            _gaq.push([
                '_trackEvent',
                'Location Search',
                'Restaurant Selected',
                'RestID ' + rest.restid,
                rest.index
            ]);
        }
    };


    var showSearchMessage = function (messageHTML) {
        var html =
            '<div class="restaurantbox selected">' +
            '  <div class="message">' + messageHTML + '</div>' +
            '</div>';
        Ext.get('resultsContainer').update(html);
    };

    var updateSearchResults = function (data) {
        updateSearchResults_really(data, false);
    };

    var updateSearchResults_bulk = function (data) {
        updateSearchResults_really(data, false);
    };

    var updateSearchResults_really = function (data, selectFirst) {
        var container = Ext.get('resultsContainer');
        var useIndex;

        if (!(data.length && data.length > 0)) {
            showSearchMessage(
                _("No stores were found matching your search." +
                    " Please check to make sure you entered" +
                    " everything correctly."));

            if (window._gaq) {
                _gaq.push([
                    '_trackEvent',
                    'Location Search',
                    'No Restaurants Found'
                ]);
            }

            return;
        }

        if (shouldPreferActive) {
            data = sortActiveToTop(data);
        }

        if (window._gaq) {
            var deliveryCount = 0, pickupCount = 0, totalCount = 0;
            Ext.each(data, function (r) {
                totalCount++;
                if (r.active && r.deliveryavailable) {
                    deliveryCount++;
                }
                if (r.active && r.pickupavailable) {
                    pickupCount++;
                }
            });
            _gaq.push([
                '_trackEvent',
                'Location Search',
                'Restaurants Found',
                null,
                totalCount
            ], [
                '_trackEvent',
                'Location Search',
                'Pick-Up Restaurants Found',
                null,
                pickupCount
            ], [
                '_trackEvent',
                'Location Search',
                'Delivery Restaurants Found',
                null,
                deliveryCount
            ]);
        }

        container.update('');
        useIndex = data.length <= 26;
        Ext.each(data, function (rest, index) {
            var point, marker, box;

            // log("restaurant:", rest);

            rest.index = index;

            point = new google.maps.LatLng(rest.latitude, rest.longitude);
            marker = createMarker(point, useIndex && index, rest);
            google.maps.Event.addListener(marker, "click", function () {
                selectRestaurant(rest);
            });
            map.addOverlay(marker);
            rest.point = point;
            rest.marker = marker;

            box = container.createChild(
                createRestaurantBox(useIndex && index, rest));
            rest.box = box;
            rest.loaded = false;
            box.on('click', function () {
                selectRestaurant(rest);
            });
            box.select('.ordernow').on('click', function () {
                startOrder(rest.restaurantid);
            });
        });

        if (selectFirst) {
            selectRestaurant(data[0]);
        }
    };


    var sortCityToTop = function (data, cityName, stateCode) {
        var top = [], bottom = [];
        Ext.each(data, function (rest, index) {
            if (rest.city == cityName && rest.statecode == stateCode) {
                top.push(rest);
            } else {
                bottom.push(rest);
            }
        });

        return top.concat(bottom);
    };

    var sortActiveToTop = function (data) {
        var top = [], bottom = [];
        Ext.each(data, function (r) {
            if (r.active && (r.deliveryavailable || r.pickupavailable)) {
                top.push(r);
            } else {
                bottom.push(r);
            }
        });
        return top.concat(bottom);
    };


    var search = function (latitude, longitude, place) {
        var geocoder;
        var point;
        var marker;
        var accuracy;
        var postalCode;
        var cityName;
        var stateCode;
        var t;
        var zoomLevels = {
            0: 6,
            1: 6,
            2: 6,
            3: 11,
            4: 11,
            5: 12,
            6: 13,
            7: 13,
            8: 13,
            9: 13
        };

        showSearchMessage(_("Searching..."));

        // log("Place", place);

        t = place && place.AddressDetails;
        accuracy = t && t.Accuracy;
        t = t && t.Country;
        t = t && t.AdministrativeArea;
        stateCode = t && t.AdministrativeAreaName;
        if (t && !t.Locality && t.SubAdministrativeArea) {
            t = t.SubAdministrativeArea;
        }
        t = t && t.Locality;
        cityName = t && t.LocalityName;
        t = t && t.PostalCode;
        postalCode = t && t.PostalCodeNumber;

        point = new google.maps.LatLng(latitude, longitude);
        map.setCenter(point, zoomLevels[accuracy || 5] || zoomLevels[1]);

        if (accuracy == 5 && postalCode) {
            if (window._gaq) {
                _gaq.push([
                    '_trackEvent',
                    'Location Search',
                    'Search for Postal Code',
                    postalCode
                ]);
            }
            Ext.Ajax.request({
                url: "/mp/ndXTAL/searchByPostalCode_JSON",
                params: {
                    postalCode: "'" + postalCode + "'",
                    distanceInMiles: 25,
                    limit: 26
                },
                scope: this,
                success: function (response) {
                    var data = Ext.decode(response.responseText);
                    updateSearchResults(data);
                },
                failure: function (response) {
                    showSearchMessage(
                        _("There was an error searching for locations." +
                            " Please try again later."));
                }
            });
        }
        else if (accuracy == 4 && stateCode && cityName) {
            if (window._gaq) {
                _gaq.push([
                    '_trackEvent',
                    'Location Search',
                    'Search for City',
                    cityName + ', ' + stateCode
                ]);
            }
            Ext.Ajax.request({
                url: "/mp/ndXTAL/searchByGeoCode_JSON",
                params: {
                    latitude: point.lat(),
                    longitude: point.lng(),
                    distanceInMiles: 25,
                    limit: 26
                },
                scope: this,
                success: function (response) {
                    var data = Ext.decode(response.responseText);
                    data = sortCityToTop(data, cityName, stateCode);
                    updateSearchResults(data);
                },
                failure: function (response) {
                    showSearchMessage(
                        _("There was an error searching for locations." +
                            " Please try again later."));
                }
            });
        }
        else if (accuracy == 2 && stateCode) {
            showSearchMessage(_("Fetching all stores in " + stateCode + ", stand by..."));
            if (window._gaq) {
                _gaq.push([
                    '_trackEvent',
                    'Location Search',
                    'Search for State',
                    stateCode
                ]);
            }
            Ext.Ajax.request({
                url: "/mp/ndXTAL/searchByStateCode_JSON",
                params: {
                    stateCode: "'" + stateCode + "'"
                },
                scope: this,
                success: function (response) {
                    var data = Ext.decode(response.responseText);
                    updateSearchResults_bulk(data);
                },
                failure: function (response) {
                    showSearchMessage(
                        _("There was an error searching for locations." +
                            " Please try again later."));
                }
            });
        }
        else {
            if (window._gaq) {
                _gaq.push([
                    '_trackEvent',
                    'Location Search',
                    'Search for Geo Code'
                ]);
            }
            Ext.Ajax.request({
                url: "/mp/ndXTAL/searchByGeoCode_JSON",
                params: {
                    latitude: point.lat(),
                    longitude: point.lng(),
                    distanceInMiles: 25,
                    limit: 26
                },
                scope: this,
                success: function (response) {
                    var data = Ext.decode(response.responseText);
                    updateSearchResults(data);
                },
                failure: function (response) {
                    showSearchMessage(
                        _("There was an error searching for locations." +
                            " Please try again later."));
                }
            });
        }
    };


    var handleEmptySearch = function (message) {
        var box, point;

        message = message || _("Enter your location to find a Quiznos near you.");
        showSearchMessage(message);

        point = new google.maps.LatLng(37.0625, -95.677068);
        map.setCenter(point, 4);

        Ext.get('searchBox').focus();
    };


    var freeFormSearch = function () {
        Ext.get('resultsContainer').update('');

        address = Ext.get('searchBox').getValue();
        if (!address) {
            handleEmptySearch();
            return false;
        }

        geocoder = new google.maps.ClientGeocoder();
        geocoder.getLocations(
            address,
            function (response) {
                var place;
                var point;
                var marker;

                if (!response || response.Status.code != 200) {
                    // log("error response", response);
                    //FIXME: message wording
                    handleEmptySearch(
                        _("<p>We were not able to find a location matching" +
                            " your request.</p>" +
                            "<p>Please check your search.</p>"));
                    return;
                }

                place = response.Placemark[0];
                // log('found place: ', place);
                Ext.get('searchBox').set({
                    value: place.address.replace(/, USA$/, '')
                });
                search(place.Point.coordinates[1],
                       place.Point.coordinates[0],
                       place);
            }
        );

        return false;
    };


    return {
        init: function () {
            var params = Ext.urlDecode(window.location.search.substring(1));
            var location = "", userInfo = {};

            var enableTouch = function () {
                var pane = Ext.get('resultsContainer').dom;
                var offset;
                pane.ontouchstart = function (e) {
                    if (e.touches.length == 1) {
                        touch = e.touches[0];
                        offset = pane.scrollTop + touch.pageY;
                    } else {
                        offset = null;
                    }
                };
                pane.ontouchmove = function (e) {
                    var touch;
                    if (e.touches.length == 1 && offset !== null) {
                        e.preventDefault();
                        touch = e.touches[0];
                        pane.scrollTop = offset - touch.pageY;
                    }
                };
            };
            if (Ext.isWebKit) {
                enableTouch();
            }

            map = new google.maps.Map2(document.getElementById("map"));
            map.addControl(new google.maps.SmallZoomControl3D());
            map.addControl(new google.maps.ScaleControl());

            google.maps.Event.addListener(map, 'infowindowopen', function () {
                var containers = map.getInfoWindow().getContentContainers();
                Ext.each(containers, function (c) {
                    var el = Ext.get(c, true);
                    el.select('.startOrder').on('click', function (e) {
                        var href = e.getTarget().href;
                        var m = /restid=(\d+)/.exec(href);
                        if (m) {
                            e.preventDefault();
                            startOrder(m[1]);
                        }
                    });

                    var link = el.select('.disabledStartOrder', true);
                    var callToOrder = el.select('.callToOrder', true);
                    link.on('mouseenter', function (e) {
                        callToOrder.addClass('callToOrderHighlighted');
                    });
                    link.on('mouseout', function () {
                        callToOrder.removeClass('callToOrderHighlighted');
                    });
                });
            });

            if (params.prefer_active) {
                shouldPreferActive = params.prefer_active;
            }

            if (params.latitude && params.longitude) {
                search(params.latitude, params.longitude);
                return;
            }

            if (params.location) {
                location = params.location.replace(/^City, [A-Z][A-Z] /, '');
            } else {
                if (params.address) {
                    location += ", " + params.address;
                }
                if (params.city) {
                    location += ", " + params.city;
                }
                if (params.state) {
                    location += ", " + params.state;
                }
                if (params.zipCode) {
                    location += ", " + params.zipCode;
                }
                location = location.substring(2);
            }

            if (!location && window.returningUserInfo) {
                userInfo = window.returningUserInfo;
                if (userInfo.latitude && userInfo.longitude) {
                    search(userInfo.latitude, userInfo.longitude);
                    return;
                }
            }

            if (!location && google.loader.ClientLocation) {
                search(google.loader.ClientLocation.latitude,
                       google.loader.ClientLocation.longitude);
                return;
            }

            if (location) {
                Ext.get('searchBox').set({value: location});
            }

            freeFormSearch();
        }
    };
}();

