POP.ToolTip = function(targets, config) {
	
	var self = this;	
	self.config = $.extend({
		tooltipContainerId: 'tooltip-container', 
		tooltipType: 'calendar',
		animateInTime: 200,  
		animateOutTime: 200,
        delay: 400 ,
		offsetLeft: 0,
		offsetTop: 0
    }, config || {}); 

	self.__init(targets); 
};
 
POP.ToolTip.prototype = {
	
	/**
	*	'Private' methods
	**/
	__init: function(targets) {	
		var self = this;
		//POP.CalendarToolTipCache.init();
		self.targetEls = targets;
		self.targetObj = $(self.targetEls);
		self.tooltipContainer = $('.' + self.config.tooltipContainerClass);
		self.animate = (jQuery.support.opacity) ? true : false;
		if(self.tooltipContainer.length < 1) {
			self.__create();
		}else {
			self.tooltipContent = self.tooltipContainer.find('.tt-content');
		}
		self.__addEventListeners();
	},
	
	__addEventListeners: function() {
		var self = this;
		
		$('body').delegate(self.targetEls, 'mouseenter', function(e) {
			//console.log('target: ', self);
			self.close(true);
			self.__stopTimer();
			self.__startTimer($(this), true);
		});
		$('body').delegate(self.targetEls, 'mouseleave', function(e) {
			self.__stopTimer();
			self.__startTimer($(this));
		});
	},
	
	__create: function() {
		var self = this,
			html = '';
		html += '<div id="'+ self.config.tooltipContainerId +'">';
		html += '	<div class="tt-top"></div>';
		html += '	<div class="tt-wrapper">';
		html += '		<div class="tt-content"></div>';
		html += '	</div>';
		html += '	<div class="tt-btm"></div>';
		html += '	<div class="tt-arr"></div>';
		html += '</div>';
		self.tooltipContainer = $(html);
		self.tooltipContainer.css({
			'display': 'none',
			'position': 'absolute',
			'z-index': 2
		});
		self.tooltipContent = self.tooltipContainer.find('.tt-content');		
		$('body').append(self.tooltipContainer);
	},
	
	__getTooltip: function(element) {
		var self = this,
			tooltipType = '', 
			tooltip = {};
		tooltipType = element.data('type') || self.config.tooltipType; 
		tooltip = POP.ToolTipType.factory(tooltipType);
		tooltip.view(self, element);
	},
	
	__startTimer: function(element, doOpen) {
		var self = this;
		self.showTooltipTimer = setTimeout(function() {
			self.__stopTimer();
			if(doOpen) {
				self.__getTooltip(element);
			}else {
				self.close();
			}
		}, self.config.delay); 
	},
	
	__stopTimer: function() {
		var self = this;
		clearTimeout(self.showTooltipTimer);  
	},
	
	__getPosition: function(element) {
		
        var self = this,
			ttPos = {},
            vertical = '',
            horizontal = '',
            quadrant = '',
            targetObjWidth = element.innerWidth(),
            targetObjHeight = element.innerHeight(),
            ttHeight = self.tooltipContainer.innerHeight(),
            ttWidth = self.tooltipContainer.innerWidth(),
            targetObjPosition = element.offset(),
            winWidth = $(window).width(),
            winHeight = $(window).height(),
            winLeft = $(window).scrollLeft(),
            winTop = $(window).scrollTop(),
            left = targetObjPosition.left - winLeft,
            top = targetObjPosition.top - winTop,
            realWidth = winWidth - left,
            realHeight = winHeight - top, 
			defaultPosition = false;
        if (top - ttHeight / 2 < 0) {
            vertical = 'u';
        } else if (top + ttHeight / 2 > realHeight) {
            vertical = 'l';
        } else {
            vertical = 'm';
        }
        if (left - ttWidth / 2 < 0 && left + ttWidth < realWidth) {
            horizontal = 'l';
        } else if (ttWidth > realWidth && (winLeft - ttWidth) > 0 || realWidth < ttWidth / 2) {
            horizontal = 'r';
        } else {
            horizontal = 'm';
        }

        /*
		TODO: finish positing override...
		defaultPositionVert = element.attr('data-positionvert');
		defaultPositionHor = element.attr('data-positionhor');
        
		vertical = defaultPositionVert || vertical;
		horizontal = defaultPositionHor || horizontal;*/
		quadrant = vertical + horizontal;
  
        switch (quadrant) {
            case 'ul':
                ttPos.left = 0;
                ttPos.top = targetObjHeight;
                break;

            case 'um':
                ttPos.left = targetObjWidth / 2 - ttWidth / 2;
                ttPos.top = targetObjHeight;
                break;

            case 'ur':
                ttPos.left = targetObjWidth - ttWidth;
                ttPos.top = targetObjHeight;
                break;

            case 'ml':
                ttPos.left = targetObjWidth;
                ttPos.top = targetObjHeight / 2 - ttHeight / 2;
                break;

            case 'mm':
                ttPos.left = targetObjWidth / 2 - ttWidth / 2;
                ttPos.top = 0 - ttHeight;
                break;

            case 'mr':
                ttPos.left = 0 - ttWidth;
                ttPos.top = targetObjHeight / 2 - ttHeight / 2;
                break;

            case 'll':
                ttPos.left = 0;
                ttPos.top = 0 - ttHeight;
                break;

            case 'lm':
                ttPos.left = targetObjWidth / 2 - ttWidth / 2;
                ttPos.top = 0 - ttHeight;
                break;

            case 'lr':
                ttPos.left = targetObjWidth - ttWidth;
                ttPos.top = 0 - ttHeight;
                break;
        }

        ttPos.quadrant = quadrant;
        ttPos.left += self.config.offsetLeft;
        ttPos.top += self.config.offsetTop;
		//console.log('Top: ', ttPos.top, 'height: ', ttHeight, 'element h: ', targetObjHeight);
		
        return ttPos;
    },

	__positionTooltip: function(element) {
		var self = this, 
			oldClass, 
			tooltipPosition = {};
		//make sure element on top of other targets
		element.css({ 'position': 'relative', 'z-index': 11 });	
		//make sure a tags are clickable
		element.find('> a').css({'position': 'relative', 'z-index': 10});
		element.append(self.tooltipContainer);
		//get rid of any previously added arrow classes
        oldClass = self.tooltipContainer.attr('data-arrow');
        if (oldClass) {
            self.tooltipContainer.removeClass(oldClass);
        }
		tooltipPosition = self.__getPosition(element);
		self.tooltipContainer.attr('data-arrow', tooltipPosition.quadrant);
		self.tooltipContainer.addClass(tooltipPosition.quadrant);
		self.tooltipContainer.css({
            'left': tooltipPosition.left + 'px',
            'top': tooltipPosition.top + 'px'
        });
	},
	
	/**
	*	Public Methods
	**/
	open: function(content, element, options) {
		var self = this;
		
		if(content) {
			self.addContent(content, element);
		}else {
			self.clearContent(self.tooltipContent);
			self.addLoader(element, options);
		}
		if (self.animate) {
            self.tooltipContainer.css({
                'opacity': 0
            }).show();
            self.tooltipContainer.stop().animate({
                	'opacity': 1,
	                'top': '-=5'
	            }, self.config.animateInTime, 
				function () {
					//animated in
            });
        } else {
            self.tooltipContainer.show();
        }
	},
	close: function(doHide) {
		//return; //testing
		var self = this;
		//make sure nothing is above the current target;
		self.targetObj.css({'z-index': 1});
		self.targetObj.find('> a').css({'z-index': 1});
        if (self.animate && !doHide) {
            self.tooltipContainer.stop().animate({
            	    'opacity': 0,
	                'top': '-=5'
	            },
	            self.config.animateOutTime,
	            function () {
	                self.tooltipContainer.hide(); // hide, just in case
	                self.clearContent(self.tooltipContent);
            });
        } else {
            self.tooltipContainer.hide();
            self.clearContent(self.tooltipContent);
        }
	},
	addContent: function(content, element) {
		var self = this;
		self.tooltipContent.html(content);
		Cufon.refresh();
		self.__positionTooltip(element);
		//Cufon.refresh();
	},
	clearContent: function(element) {
		element.empty();
	},
	addLoader: function(element, options) {
		var self = this, loader = {};
		if(POP.loadingMsg !== undefined) {
			loader = new POP.loadingMsg(self.tooltipContent, {top: options.top});
		    loader.show();
			self.__positionTooltip(element);
		}
	}
}

/**
*   Tooltip factory methods
**/
POP.ToolTipType = function () { };

POP.ToolTipType.prototype = {
    model: function (obj, element) { },
    view: function (obj, element) { }
};

POP.ToolTipType.factory = function (type) {
    var constr = type,
        newToolTip;

    if (typeof POP.ToolTipType[constr] !== "function") {
        throw {
            name: "Error",
            message: constr + " doesn\'t exist."
        };
    }

    if (typeof POP.ToolTipType[constr].prototype.model !== 'function') {
        POP.ToolTipType[constr].prototype = new POP.ToolTipType.ToolTip();
    }

    newToolTip = new POP.ToolTipType[constr]();
    return newToolTip;
}

/**
*   Default Tooltip 
**/
POP.ToolTipType.defaultTooltip = function () { }

POP.ToolTipType.defaultTooltip.prototype.model = function (obj, element) {
    var data = {};
    
    data = 'default tooltip data';
    return data;
};

/**
*   @param obj - tooltip controller object
**/
POP.ToolTipType.defaultTooltip.prototype.view = function (obj, element) {
    var data = {},
    html = '', interval;

    data = this.model(obj, element);
    if (!data) { return; }

    html = data;

	//open tooltip with loading message
	obj.open('', element, true);
	//wait a sec and load data
	interval = setInterval(function() {
		clearInterval(interval);
		obj.addContent(html);
	}, 1000);
};

/**
*   Calendar Tooltip - displays info about specific performances
**/
POP.ToolTipType.calendar = function () { };

POP.ToolTipType.calendar.prototype.model = function (obj, element) {
    var data = {};
    data.pid = element.data('pid');
    data.date = element.data('date');
    return data;
};

/**
*   @param obj - tooltip controller object
**/
POP.ToolTipType.calendar.prototype.view = function (obj, element) {

    var data = {},
        ajaxURL,
        pid,
        date,
        html = '', 
		loader = {},
		cached = '',
		key = '';
        
    data = this.model(obj, element);
    if (!data) { return; }

	key = String(data.pid + data.date);
	cached = POP.CalendarToolTipCache.getItem(key);
	
	if(cached) {
		obj.open(cached, element);
	}else {
		obj.open(null, element, {top: '40px'});

	    ajaxURL = POP.CONFIG.root + '/calendar/detail.aspx?pid=' + data.pid + '&date=' + data.date;

	    $.ajax({
	        url: ajaxURL,
			context: element,
	        success: function(results) {
				var tt = this.find('.tt-content');
				POP.CalendarToolTipCache.add(key, results);
				if(tt.length > 0) {
					html = results;
		            obj.addContent(html, element);
				}
	        },
	        error: function(results) {
	            if ($(window).unload) {
	                return;
	            } else {
	                html = '<div class="errors"><p>Sorry. Ajax request failed.</p></div>';
					obj.addContent(html, element);
	            }       
	        }
	    });
	}
	
};

/**
*	Donate Tooltip - displays info about specific performances
**/
POP.ToolTipType.donate = function () { };

POP.ToolTipType.donate.prototype.model = function (obj, element) {
	var data = {};
	data = element.find('.benefits').clone().show();
	return data;
};

/**
*	@params obj - obj.el: hovered on element, obj.tt: tooltip object
**/
POP.ToolTipType.donate.prototype.view = function (obj, element) {
	var data = {},
	html = '';
	
	data = this.model(obj, element);
	if (!data) { return; }

	html = data;
	obj.open(html, element);
};

/**
*	Best Availability Tooltip - displays info about specific performances
**/
POP.ToolTipType.bestAvailability = function () { };

POP.ToolTipType.bestAvailability.prototype.model = function (obj, element) {
	var data = {};
	data = $('.best-availability-info').clone().html();
	return data;
};

/**
*	@params obj - obj.el: hovered on element, obj.tt: tooltip object
**/
POP.ToolTipType.bestAvailability.prototype.view = function (obj, element) {
	var data = {},
	html = '';
	
	this.addEventListeners(obj, element);
	
	data = this.model(obj, element);
	if (!data) { return; }

	html = data;
	obj.open(html, element);
	
};
POP.ToolTipType.bestAvailability.prototype.addEventListeners = function(obj, element) {
	element.click(function(e) {
		e.preventDefault();
	});
}; 

/**
*	Verification Code Tooltip - shows images of backs of credit cards
**/
POP.ToolTipType.verificationCode = function () { };

POP.ToolTipType.verificationCode.prototype.model = function (obj, element) {
	var data = {};
	
	data = element.find('div').html();
	return data;
};

/**
*	@params obj - obj.el: hovered on element, obj.tt: tooltip object
**/
POP.ToolTipType.verificationCode.prototype.view = function (obj, element) {
	var data = {},
	html = '';
	
	this.addEventListener(obj, element);
	data = this.model(obj, element);
	if (!data) { return; }

	html = data;
	obj.open(html, element);
	
};

POP.ToolTipType.verificationCode.prototype.addEventListener = function (obj, element) {
	element.bind('click', function(e) {
		e.preventDefault();
	});
};



















