

    var SpecialOffer = makeClass();
	
	function setGlobalSpecialOfferVars(){
		
		if (typeof window.BOOKING_FORM_HTML === "undefined") {
			window.BOOKING_FORM_HTML = $('#BookingContainerDiv').html();
			$('#BookingContainerDiv').empty();
		}
		
		if (typeof window.CURRENT_SO === "undefined") {
			window.CURRENT_SO = {};
		}

	}
	
	function bookNow() {
		
		// -- when the user hits 'book now'
        var airportDD = $("#sOfferDepartureAirport");
        var errorTxt = $("#noSelectedAirport");

        if (airportDD !== null && airportDD.val() == "-") {
            errorTxt.html("<span>Please select an airport.</span>");
            errorTxt.show();
            return false;
        }
        return true;

	};
	
	/**
	 * SpecialOffer - reusable class that controls a single special offer 
	 * 
	 * requires ;
	 * 		- jquery.js
	 * 		- vh.util.js
	 */
	
    SpecialOffer.prototype = {
		
		_data : {}, // JSON object that holds all Special Offer Data
		appended : false // flag if we've already appended the booking form
		
    };
    
	SpecialOffer.prototype.init = function( SpecialOfferJSON ) {
		
		// ref
		var self = this;
		
		// guard
		if (VH.UTIL.isUndefinedOrNull(SpecialOfferJSON)) {
			return;
		}
		
		// set the data for this instance	
		self._data = SpecialOfferJSON;

		self.InitControls();

	};

	SpecialOffer.prototype.InitControls = function() {

	    var so = this;
	    var openBtn = $(so._data.offerCellId + " td.book a.moreinfo");

	    // set href, click and show button
	    if (!VH.UTIL.isUndefinedOrNull(so._data.useAnchor)) {
	        openBtn.attr("href", so._data.offerCellId)
	    }

	    // click and show button
	    openBtn.click(function(e) {
	   
	        if (VH.UTIL.isUndefinedOrNull(so._data.useAnchor)) {
	            e.preventDefault();
	        }
	        // is there a form open?
	        if (!VH.UTIL.isUndefinedOrNull(CURRENT_SO.UnloadBookingForm)) {
	            CURRENT_SO.UnloadBookingForm();
	        }
	        CURRENT_SO = so;
	        so.LoadBookingForm();

	      
	    }).show();

	};

	SpecialOffer.prototype.UnloadBookingForm = function() {

	    var so = this;
	    var formCell = $(so._data.bookingFormCellId);
	    var offerCell = $(so._data.offerCellId);

	    // do we need to close the hotel info? (/special_offers/)
	    if (so._data.hotelInfoCellId !== '') {
	        $(so._data.hotelInfoCellId).hide();
	    }

	    formCell.hide();
	    formCell.empty();

	    offerCell.removeClass("CurrentOffer");
	    offerCell.find("td:first").css({ "border-left": "none" });
	    offerCell.find("td:last").css({ "border-right": "none" });

	    var closeBtn = null;

	    if (so._data.mainSo) { // is /special_offers/
	        closeBtn = offerCell.find("td.book a.moreinfo");
	        closeBtn.find("img").attr("src", "/_assets/images/special_offers/more_info.gif");
	    } else { // is /special_offers/carribean/
	        closeBtn = formCell.find(".shrink a");
	    }

	    closeBtn.unbind();
	    closeBtn.click(function(e) {
	        if (VH.UTIL.isUndefinedOrNull(so._data.useAnchor)) {
	            e.preventDefault();
	        }
	        // is there a form open?
	        if (!VH.UTIL.isUndefinedOrNull(CURRENT_SO.UnloadBookingForm)) {
	            CURRENT_SO.UnloadBookingForm();
	        }
	        CURRENT_SO = so;
	        so.LoadBookingForm();
	    }).show();


	    so.appended = false;

	};

	SpecialOffer.prototype.LoadBookingForm = function() {

	    var so = this;

	    // get the right table cell id and append the booking form 
	    var formCell = $(so._data.bookingFormCellId);
	    var offerCell = $(so._data.offerCellId);
	    if (!so.appended) {
	        formCell.append('<td colspan="9" style="padding:0;">' + BOOKING_FORM_HTML + '</td>');
	        so.appended = true;
	    }

	    // set up close btn
	    var closeBtn = null;

	    if (so._data.mainSo) { // is /special_offers/
	        closeBtn = offerCell.find("td.book a.moreinfo");
	        closeBtn.find("img").attr("src", "/_assets/images/special_offers/less_info.gif");
	    } else { // is /special_offers/carribean/
	        closeBtn = formCell.find(".shrink a");
	    }

	    closeBtn.unbind();
	    closeBtn.click(function(e) {
	        e.preventDefault();
	        so.UnloadBookingForm();
	    });

	    // set up book now btn 
	    var bookBtn = formCell.find(".OfferButton");
	    bookBtn.click(function(e) {
	        return (bookNow());
	    });

	    // do we need to show the hotel info? (/special_offers/)
	    if (so._data.hotelInfoCellId !== '') {
	        $(so._data.hotelInfoCellId).show();
	    }

	    // init form
	    so.InitAirports();
	    so.WriteOfferDetails();
	    so.RenderCalendar();
	    so.UpdateHiddenFields();

	    offerCell.addClass("CurrentOffer");
	    offerCell.find("td:first").css({ "border-left": "1px solid #C00" });
	    offerCell.find("td:last").css({ "border-right": "1px solid #C00" });

	    formCell.show();
	    
	    //find and call the Coremetrics tag
	    var cmTag;
	    if (so._data.hotelInfoCellId !== '') {

	        var cmTag = so._data.hotelInfoCellId.replace('#hotel_', 'cmTag_offer_');

	        if (!VH.UTIL.isUndefinedOrNull(cmTag)) {
	            var evalTag = window[cmTag];

	            if (!VH.UTIL.isUndefinedOrNull(evalTag)) {
	                eval(window[cmTag]);
	            }
	        }
	    }

	};
	
	// -- returns an <option> for dropdowns
  	SpecialOffer.prototype.CreateOption = function(value, text, selected) {
         return '<option value="' + value + '">' + text + '</option>';
    };
	
	// -- takes a date string in the form  DD/MM/YYYY and returns a date object
	SpecialOffer.prototype.GetDate = function( date ) {
			var dateStr = date.split("/");
			return new Date(dateStr[2], dateStr[1] - 1, dateStr[0]);
    };

    SpecialOffer.prototype.GetInt = function(str) {
        var no = parseInt(str);
        return isNaN(no) ? 0 : no;
    };

	// -- fills in details in the <ul />
	SpecialOffer.prototype.WriteOfferDetails = function() {

	    var so = this;

	    var hotelInfo = $(so._data.hotelInfoCellId);

	    var hotelName = hotelInfo.find(".title h2").text();

	    if (hotelName.length == 0) {
	        hotelName = $('#a_name_' + so._data.mainAccom).find("span").text();
	    }

	    // small text at bottom
	    $("#txtDestinationName").html("<br />" + hotelName);
	    $("#txtDuration").text(so._data.duration);
	    $("#txtDepartureDates").text(so._data.bookableFrom + " - " + so._data.bookableTo);
	    var occupancy = so.GetInt(so._data.occupancy);
	    $("#txtOccupancy").text(occupancy > 0 ? occupancy : 2);

	    var tempAirports = so._data.origins.split("|");
	    var airportTxt = "";
	    for (var i = 0; i < tempAirports.length; i++) {
	        airportTxt += tempAirports[i].split("^")[1];
	        if (i + 1 < tempAirports.length) {
	            airportTxt += " or ";
	        }
	    }

	    $("#txtDepartureAirports").text(airportTxt);
	    $("#txtBoardBasis").text(so._data.board);
	    $("#Pax2who .adult").find("select").val("2");

	}; 
	
	// -- populates hidden booking form fields
	SpecialOffer.prototype.UpdateHiddenFields = function() {
		
		var so = this;
		var hotelName = $('#a_name_' + so._data.mainAccom).find("span").text();
		$("#sOfferMainAccom").val(so._data.mainAccom);
        $("#sOfferDestination").val(so._data.destination);
        $("#sOfferProgram").val(so._data.programId);
        $("#sOfferCompany").val(so._data.company);
        $("#sOfferDuration").val(so._data.duration);
        $("#sOfferHotelName").val(hotelName);
	};

    // -- populates the departure airport dropdown
    SpecialOffer.prototype.InitAirports = function() {
		
		var so = this;
        var arr = so._data.origins.split("|");
		var airportDD = $("#sOfferDepartureAirport");

        airportDD.empty();
 
		// more than one airport?
		if ( arr.length > 1 ){
			airportDD.append('<option value="-">Please select</option>');
		} 
		
		for (var i = 0; i < arr.length; i++) {
        	airportDD.append(so.CreateOption(arr[i].split("^")[0], arr[i].split("^")[1]));
   	 	}
		
    };
	
	// -- render the calendar 	
	SpecialOffer.prototype.RenderCalendar = function (){

	    var so = this;

	    $("#staticCal").data("bookableFrom", so._data.bookableFrom);
	    $("#staticCal").data("bookableTo", so._data.bookableTo);

		$("#staticCal").datepicker({
		
			// basic options
            rangeSelect: false, // no date range selection
            yearRange: '-0:+2', // sets to current year + 2
            firstDay: 1, // sets to Monday

            // min, max and formatting
            minDate: so.GetDate(so._data.hotelBookableFrom), // earliest selectable date 
            maxDate: so.GetDate(so._data.hotelBookableTo), // latest selectable date 
            setDate: so.GetDate(so._data.bookableFrom), // default selected date
            dateFormat: 'D d M yy',
            dayNamesMin: ['S', 'M', 'T', 'W', 'T', 'F', 'S'],

            // callbacks
            onRender: so.FixDisplay, // custom Zolv callback
            onSelect: so.UpdateForm,
            beforeShowDay: so.highlightOfferDates
        });

        $('#staticCal').datepicker('setDate', so.GetDate(so._data.bookableFrom)); 
 
		
		$("#sOfferDepartureDate").val(
			$.datepicker.formatDate('D d M yy', so.GetDate(so._data.bookableFrom))
		);
						
	};

	SpecialOffer.prototype.UpdateForm = function(date){
		$("#sOfferDepartureDate").val(date);
    };

    SpecialOffer.prototype.highlightOfferDates = function(date) {

        var cal = $("#staticCal");

        var dateStr = cal.data("bookableFrom").split("/");
        var soBookableFrom = new Date(dateStr[2], dateStr[1] - 1, dateStr[0]);

        dateStr = cal.data("bookableTo").split("/");
        var soBookableTo = new Date(dateStr[2], dateStr[1] - 1, dateStr[0]);
        
        soBookableFrom.setDate(soBookableFrom.getDate() - 1);
        soBookableTo.setDate(soBookableTo.getDate() + 1); 

        if (VH.UTIL.CompareDate(date, soBookableFrom) && VH.UTIL.CompareDate(soBookableTo, date)) {
            return [true, "soDate"];
        }
        return [true, ""];
    };

	SpecialOffer.prototype.FixDisplay = function() {

	    var calendar = $("#staticCal");
	    var selects = calendar.find("select");
	    selects.eq(0).css({ "width": "100px" }); // month
	    selects.eq(1).css({ "width": "60px" }); // year

	    // prev/next labels
	    calendar.find(".ui-datepicker-prev label:empty").hide();
	    calendar.find(".ui-datepicker-next label:empty").hide();
	};
	
	

