function Zappos() {
    this.initialize();
}

Zappos.prototype.initialize = function() {
    this.itor = 0;
    this.order = {};
    this.marker;
    this.heatSpots = false;
    this.voting = true;
    
    if(GBrowserIsCompatible()) {
        this.map = new GMap2(document.getElementById('map'));
        this.map.setMapType(G_NORMAL_MAP);
        this.map.removeMapType(G_SATELLITE_MAP);
        this.map.removeMapType(G_HYBRID_MAP);
        this.map.setCenter(new GLatLng(38.5825261593533, -95.5810546875), 5);
        this.map.disableDoubleClickZoom();
        
        this.prepopulateHotSpots();
        this.fetchVotedStyles();
        this.setupHelp();
        this.fetchData();
    }
}

Zappos.prototype.fetchVotedStyles = function() {
    $.get("/n/zappos_map_vote.cgi?fetch=5&order=asc&" + (new Date).getTime(), {}, function(styles) { 
        for(var i = 0; i < 5; i++) {
            var itemImage = $('<a href="http://www.zappos.com/product/' + styles[i].sku + '"><img src="/images/' + styles[i].image + '" alt="" /></a>');
            $('#bottom-styles').append(itemImage);
        }
    }, 'json');
    
    $.get("/n/zappos_map_vote.cgi?fetch=5&order=desc&" + (new Date).getTime(), {}, function(styles) { 
        for(var i = 0; i < 5; i++) {
            var itemImage = $('<a href="http://www.zappos.com/product/' + styles[i].sku + '"><img src="/images/' + styles[i].image + '" alt="" /></a>');
            $('#top-styles').append(itemImage);
        }
    }, 'json');
}

Zappos.prototype.prepopulateHotSpots = function() {
    var that = this;
    $.ajax({ url: '/n/zappos_maps.cgi?heatmap=1&' + (new Date).getTime(), type: 'GET', timeout: 10000, dataType: "json",
        success : function(orders) {
            var out = 0;
            for(var i = 0; i < orders.length; i++) {
                if(orders[i].location && orders[i].location.length > 0) {
                    var point = new GLatLng(orders[i].location[0], orders[i].location[1]);
                    that.map.addOverlay(new ZHeatSpot(point, orders[i].productType, that.heatSpots));
                    out++;
                }
            }
            
            $('#heat-map').text('heat map: off');
        },
        
        error : function() {
            that.prepopulateHotSpots();
        }
    });
}

Zappos.prototype.setupHelp = function() {
    var that = this;
    $('#about').click(function() {
    	var top = (that.map.getSize().height * 0.5) - ($('#about-box').height() * 0.6);
    	var left = (that.map.getSize().width/2) - 300;
    	$('#about-box').css({
    		'position': 'absolute',
    		'top': top,
    		'left': left
    	}).fadeIn("slow");
    });
    
    $('#about-box a').click(function() {
    	$('#about-box').fadeOut("slow");
    });
    
    $('#heat-map').toggle(
        function() {
            $('.spot').css({ display : 'block' });
        	that.heatSpots = true;
        	$('#heat-map').text('heat map: on');
        },
        function() {
            $('.spot').css({ display : 'none' });
        	that.heatSpots = false;
        	$('#heat-map').text('heat map: off');
        }
    );
    
    $('#voting').toggle(
        function() {
            $('.vote').css({ display : 'none' });
            that.voting = false;
            $('#voting').text('voting: off');
        },
        function() {
            $('.vote').css({ display : 'block' });
            that.voting = true;
            $('#voting').text('voting: on');
        }
    );
    
    $('#topstyles').toggle(
        function() {
            $('#top-styles').animate({ right : -10 });
            $('#bottom-styles').animate({ right : -10 });
            $('#topstyles').text('hide top styles');
        },
        function() {
            $('#top-styles').animate({ right : -510 });
            $('#bottom-styles').animate({ right : -510 });
            $('#topstyles').text('show top styles');
        }
    );
}

Zappos.prototype.fetchData = function() {
    var that = this;
    $.ajax({ url: '/n/zappos_maps.cgi?' + (new Date).getTime(), type: 'GET', timeout: 2500, dataType: "json",
        success : function(order) {  
            if(order.sku != that.order.sku && 
            order.location != that.order.location && 
            order.location.length != 0 && 
            order.location != [0,0]) {
                that.order = $.extend(true, {}, order);
                
                var point = new GLatLng(order.location[0], order.location[1]);
                that.map.panToInclude(point, 85, 85, 145, 85);
                var bubble = new ZBubble(point, order.image, order.sku, order.styleId, order.productType, order.name, order.brand, order.price, order.rating, that.voting);
                that.map.addOverlay(bubble);

                var remove = (function(marker, order, point, that) { return function() { 
                    marker.remove(); 
                    that.map.addOverlay(new ZHeatSpot(point, order.productType, that.heatSpots));
                } }(bubble, order, point, that)); 
                setTimeout(remove, 35000);
            }
                        
            var check = (function(that) { return function() { that.fetchData(); } }(that)); 
            setTimeout(check, 4250);
        },
        
        error : function() {
            that.fetchData();
        }
    });
}


GMap2.prototype.panToInclude = function(point, top, right, bottom, left) {
    point = this.fromLatLngToContainerPixel(point);
    var mapDimensions = this.getSize();
    var horizontal = 0;
    var vertical = 0;
        
    if(point.x - left < 0) 
        horizontal = Math.abs(point.x - left);
    
    if(point.x + right > mapDimensions.width)
        horizontal =  mapDimensions.width - (point.x + right);
    
    if(point.y - top < 0)
        vertical = Math.abs(point.y - top);
        
    if(point.y + bottom > mapDimensions.height)
        vertical = mapDimensions.height - (point.y + bottom);
                
    if(horizontal || vertical)
        this.panBy(new GSize(horizontal, vertical));
}

function ZBubble (latLng, image, sku, styleId, type, name, brand, price, rating, voting) {
    this.itemLatLng = latLng;
    this.image = image;
    this.sku = sku;
    this.styleId = styleId;
    this.type = type;
    this.name = name;
    this.brand = brand;
    this.price = price;
    this.rating = rating;
    this.voting = voting;
    this.prototype = new GOverlay();
    
    this.initialize = function(map) {
        var make = this.makeDiv();
        var notch = make[1];
        var div = make[0];
        var itemImage = $('<a href="http://www.zappos.com/product/' + this.sku + '"><img src="' + this.image + '" alt="" /></a>');
		var imageCopy = itemImage.clone()
		var moreInfo = this.getMoreInfo();
                
        if($('#queue a').length == 10) {
			var last = $('#queue a:first');
			last.remove();
			last = null;
		}
		$('#queue').append(imageCopy);
        
		imageCopy
		    .mouseenter(function(e) {
		        moreInfo
		            .appendTo($('body'))
		            .css({
		                display : 'block',
		                top : 60,
		                left : e.pageX - moreInfo.width()
		            });
		    })
		    .mouseleave(function() {
		        moreInfo
		            .css({
		                display : 'none'
		            })
		            .remove();
		    });
        
        div.css({
            background: '#fff',
            padding: 10
        }).append(itemImage);
        
        var that = this;
        var up = $('<div class="up"><a href="#"><img src="images/up.png" alt="Vote Up"/></a></div>')
            .css({ opacity: 0.05 })
            .click(function() {
                var click = this;
                $.get('/n/zappos_map_vote.cgi?style_id=' + that.styleId + '&vote=up', {}, function(stats) {
                    var parent = $(click).parent();
                    var grandparent = parent.parent();
                    parent.remove();
                        
                    if(parseInt(stats.up_count) > parseInt(stats.down_count)) {
                        var count = $('<div class="positive"><img src="images/up.png" alt="" /></div>');
                    } else {
                        var count = $('<div class="negative"><img src="images/down.png" alt="" /></div>');
                    }

                    count
                        .prepend($('<p class="total">Current Tally</p>'))
                        .append($('<p class="score">' + stats.score + '</p>'))
                        .appendTo(grandparent)
                        .fadeOut(3500);
                }, 'json');
            });
                    
        var down = $('<div class="down"><a href="#"><img src="images/down.png" alt="Vote down"/></a></div>')
            .css({ opacity: 0.05 })
            .click(function(){
                var click = this;
                $.get('/n/zappos_map_vote.cgi?style_id=' + that.styleId + '&vote=down', {}, function(stats) {
                    var parent = $(click).parent();
                    var grandparent = parent.parent();
                    parent.remove();
                    
                    if(parseInt(stats.up_count) > parseInt(stats.down_count)) {
                        var count = $('<div class="positive"><img src="images/up.png" alt="" /></div>');
                    } else {
                        var count = $('<div class="negative"><img src="images/down.png" alt="" /></div>');
                    }

                    count
                        .prepend($('<p class="total">Current Tally</p>'))
                        .append($('<p class="score">' + stats.score + '</p>'))
                        .appendTo(grandparent)
                        .fadeOut(3500);
                }, 'json');
            });        
        
        if(this.voting) {
            var vote = $('<div class="vote" />')
                .append(up)
                .append(down);
        } else {
            var vote = $('<div class="vote" style="display:none;" />')
                .append(up)
                .append(down);
        }
        
        var bubble = $('<div class="bubble" />')
            .css({
                position : 'absolute',
                display: 'none'
            })
            .append(div)
            .append(notch)
            .appendTo(map.getPane(G_MAP_FLOAT_PANE))
            .mouseenter(function(){
                $(this).css({ 'zIndex' : 1000 });
                $(this)
                    .children('div.vote')
                    .children()
                    .animate({
                        opacity: 0.5
                    }, 250);
            })
            .mouseleave(function(){
                down.stop().css({ opacity: 0.5 });
                up.stop().css({ opacity: 0.5 });
                $(this).css({ 'zIndex' : 500 });
                $(this)
                    .children('div.vote')
                    .children()
                    .animate({
                        opacity: 0.05
                    }, 10);
            })
            .mouseover(function(e){
                if($(e.target).closest('div').hasClass('up')) {
                    down.css({ opacity: 0.5 });
                    up.css({ opacity: 1 });
                }

                if($(e.target).closest('div').hasClass('down')) {
                    up.css({ opacity: 0.5 });
                    down.css({ opacity: 1 });
                }

                if(!$(e.target).closest('div').hasClass('down') &&
                !$(e.target).closest('div').hasClass('up')) {
                    up.css({ opacity: 0.5 });
                    down.css({ opacity: 0.5 });
                }
            });
        
        this.div = bubble;
        this.vote = vote;
        this.map = map;
        
        this.redraw(true);
    }
    
    this.makeDiv = function() {
        switch(this.type) {
            case 'Shoes' :
                var notch = $('<img src="images/notch-p.png" alt="" class="notch" />');        
                var div = $('<div class="purple" />');
                break;
            case 'Clothing' :
                var notch = $('<img src="images/notch-b.png" alt="" class="notch" />');        
                var div = $('<div class="blue" />');
                break;
            case 'Bags' :
                var notch = $('<img src="images/notch-g.png" alt="" class="notch" />');        
                var div = $('<div class="green" />');
                break;
            case 'Other' :
                var notch = $('<img src="images/notch-o.png" alt="" class="notch" />');        
                var div = $('<div class="orange" />');
                break;
        }
        return [div, notch];
    }
    
    this.getMoreInfo = function() {
        if(parseFloat(this.rating) > 4.5) { 
            var star = $('<span class="star"><img src="http://www.zappos.com/images/stars-5.gif" alt="" /></span>');
        } else if(parseFloat(this.rating) > 3.5) {
            var star = $('<span class="star"><img src="http://www.zappos.com/images/stars-4.gif" alt="" /></span>');
        } else if(parseFloat(this.rating) > 2.5) {
            var star = $('<span class="star"><img src="http://www.zappos.com/images/stars-3.gif" alt="" /></span>');
        } else if(parseFloat(this.rating) > 1.5) {
            var star = $('<span class="star"><img src="http://www.zappos.com/images/stars-2.gif" alt="" /></span>');
        } else if(parseFloat(this.rating) > 0.5) {
            var star = $('<span class="star"><img src="http://www.zappos.com/images/stars-1.gif" alt="" /></span>');
        } else {
            var star = "";
        }
        
        var info = $('<div class="more-info">')
            .append($('<span class="name">' + this.name + '</span>'))
            .append($('<span class="brand">' + this.brand + '</span>'))
            .append($('<span class="price">$' + this.price + '</span>'))
            .append(star);
        
        return info;
    }
    
    this.redraw = function(force) {
        if(!force) return;
        var point = this.map.fromLatLngToDivPixel(this.itemLatLng);
        
        var that = this;
        this.div.css({
            left : point.x - 50,
            top : point.y - 25,
            display: 'block',
            opacity: 0
        }).animate({
            top: point.y - 5,
            opacity: 1
        }, 500, function(){
            that.div.css({ filter: null });
            that.div.append(that.vote);
        });
    }
    
    this.remove = function() {
        var that = this;
        var position = this.div.position();
        
        $(this.div).animate({
            top: position.top + 20,
            opacity: 0
        }, 500, function() {
            that.div.remove();
            that.div = null;
        });
    }
}

function ZHeatSpot (latLng, type, heatSpots) {
    this.itemLatLng = latLng;
    this.type = type;
    this.heatSpots = heatSpots
    this.prototype = new GOverlay();
    
    this.initialize = function(map) {
        switch(this.type) {
            case 'Shoes' :
                var spot = $('<img src="images/spot-p.png" alt="" class="spot" />'); break;
            case 'Clothing' :
                var spot = $('<img src="images/spot-b.png" alt="" class="spot" />'); break;
            case 'Bags' :
                var spot = $('<img src="images/spot-g.png" alt="" class="spot" />'); break;
            case 'Other' :
                var spot = $('<img src="images/spot-o.png" alt="" class="spot" />'); break;
        }
        
        spot.css({
            position : 'absolute',
            display : 'none'
        }).appendTo(map.getPane(G_MAP_FLOAT_PANE));
        
        this.spot = spot;
        this.map = map;
        
        this.redraw(true);
    }
    
    this.redraw = function(force) {
        if(!force) return;
        var point = this.map.fromLatLngToDivPixel(this.itemLatLng);
        if(this.heatSpots) {
            this.spot.css({
                left : point.x - 5,
                top : point.y - 5,
                display: 'block'
            });
        } else {
            this.spot.css({
                left : point.x - 5,
                top : point.y - 5
            });
        }
    }
}

$(document).ready(function(){
    new Zappos();
});

$(window).unload(function() { GUnload(); });
