
$(function(){

    //BASIC SETUP
     window.baseUrl = $("#baseUrl").val();
    //window.baseUrl = "http://gc/";

    //the html element where we render the basket
    var basketInDOM = $("#basket_container");

    //location of the serverside controller that saves basket contents to session or gets from session.
    var basketController = window.baseUrl + "bookapi/basket";

    var currentBasketRequest = null;

    //the main object holding booking basket data
    window.bookingBasket = {
        bookings : [],
        show : 1
    };


    clearBasket = function() {
        window.bookingBasket = {
            bookings : [],
            show : 1
        };
        basketInDOM.slideUp(300, function(){
            renderBasket( saveBasket );
            $(this).slideDown(300);
        });
    }
    //CLICK EVENTS



    //adds a room to the booking basket when a 'book now' button is clicked
    $(".room_details a.book:not([class~=book_disabled])").live("click",function(evt) {
        evt.preventDefault();

        var totalRooms = 0;
        _(bookingBasket.bookings).each(function(booking){totalRooms += booking.rooms.length;});

        //only allow this if there are less than 9 rooms
        if (totalRooms < 9){

            var roomData = getRoomData(this);
            
            //is there not already a room in the basket for this hotel?
            var hotelPresent = bookingBasket.bookings[getHotelIndex(roomData.hotel.hotelId)];

            //a reference to the hotel that just had a room added to it
            var justAddedHotel;

            //if not, add this hotel and add the room to it, and flag it as newly added
            if ( !hotelPresent ){

                bookingBasket.bookings.push(
                    _(roomData.hotel).extend({rooms : [ roomData.room ], isNew : "isNew"})
                );

                justAddedHotel = bookingBasket.bookings.getLast();

            //if so, just add the room to this hotel, and flag it as newly added
            } else {

                _( bookingBasket.bookings ).each(function(booking, index){
                    if (booking.hotelId == roomData.hotel.hotelId){
                        justAddedHotel = bookingBasket.bookings[index];
                        booking.rooms.push( _(roomData.room).extend({isNew : "isNew"})  );
                        _.breakLoop();
                    }
                });
            }

            bookingBasket.show = 1;

            renderBasket(function(){

                //scroll to top before displaying
                $("html, body").animate({scrollTop : 0}, 500, function(){

                        //remove isNew flags, now they've rendered
                        if (!hotelPresent) delete justAddedHotel.isNew;
                        delete justAddedHotel.rooms.getLast().isNew;

                        saveBasket();

                        //animated reveal any newly added hotels or rooms
                        $(".isNew", basketInDOM).slideDown(500,function(){
                                                                        
                            //show tip that more rooms can be added (if one room)
                            if (totalRooms < 1) {
                                $("#tipMoreRooms").fadeIn(500);
                            }
                        });
                });
            });

        } else {
            alert("Basket is too full");
        }

    });

    //removes room from the basket
    $(".x_btn a").live("click",function(evt){

        evt.preventDefault();

        var context = getContext(this);

        var thisHotelIndex = getHotelIndex(context.hotelId);

        //target the hotel record in the basket
        var thisHotel = bookingBasket.bookings[thisHotelIndex];

        //remove room from hotel
        thisHotel.rooms.splice(context.roomIndex, 1);

        $(this).parents("ul").slideUp(200,function(){

            //if no rooms left, also delete the hotel in the basket
            if (thisHotel.rooms.length == 0) {

                bookingBasket.bookings.splice(thisHotelIndex,1);

                context.hotelContainer.slideUp(200,function(){

                    renderBasket( saveBasket );
                });
            } else {
                    renderBasket( saveBasket );
            }

        });

    });

    //put basket into hidden state
    $("#hideBasket").live("click",function(evt){

        evt.preventDefault();
        bookingBasket.show = 0;

        $("div[class='basket_bookings']", basketInDOM).slideUp(300,function(){
            //after animation:
            saveBasket( renderBasket );
        });
    });

    //put basket into shown state
    $(".showBasket").live("click",function(evt){

        evt.preventDefault();
        bookingBasket.show = 1;
        saveBasket(renderBasket, function(){

            $("div[class='basket_bookings']", basketInDOM).css("display","none").slideDown(300);

        });

    });

    //alter rate total for room when its addons altered
    $('input[class="addOn"]').live("click",function(evt){
        var context = getContext(this);

        var roomInDom = $(".roomRow", context.hotelContainer)[context.roomIndex];

        // target addOns in room dom element.
        var addOnsInDom = $(".addOnGroup .addOn", roomInDom );

        //target this room's record in basket object
        var thisRoom = bookingBasket.bookings[getHotelIndex(context.hotelId)].rooms[context.roomIndex];

        addOnsInDom.each(function(index){

                //update quantity and checked in basket object
                if ( $(this).attr('checked') ) {
                    thisRoom.addons[index].quantity =  1;
                    thisRoom.addons[index].checked =  "checked";
                } else {
                    thisRoom.addons[index].quantity = null;
                    delete thisRoom.addons[index].checked;
                }

        });

        //determine difference between previous and current total rate values
        thisRoom.prevRate = thisRoom.totalRate;
        thisRoom.totalRate = parseFloat(getTotalRate(thisRoom)).toFixed(2);

        //tag total display for increased / decreased animations after rendering
        if(thisRoom.prevRate < thisRoom.totalRate ){
            thisRoom.totalChanged = "increased";
        } else {
            thisRoom.totalChanged = "decreased";
        }

        //save, then render, then animate changes

        saveBasket( renderBasket, function(){

                var changed = $(".increased, .decreased", basketInDOM);

                changed.animate({"font-size" : "18px"},300,function(){
                        changed.animate({"font-size" : "12px"},300);
                });

                //remove increased or decreased flags
                delete thisRoom.totalChanged;

        });


    });

    $('.confirm_booking').live('click', function(evt){
            evt.preventDefault();
            $(this).parents('.basket_form').submit();
    });

    //UTILITY FUNCS

    //calculate total rate for a room (add extras with quantity != null to room price)
    var getTotalRate = function(room){
        
        var extra = 0.00;

        _(room.addons).each(function(addon){
            if (addon.quantity != null){
                //add to extra price
                extra += parseFloat(addon.quantity) * parseFloat(addon.Amount._);
            }
        });

        return parseFloat(room.initialTotalRate) + extra;

    };


    //supply total for all rooms in a hotel
    var withRoomsTotal = function(hotel){

         hotel.manyRooms = hotel.rooms.length > 1;

         hotel.roomsTotal = _(hotel.rooms).reduce(function(sum, room){
                                               return sum + parseFloat(room.totalRate); },0).toFixed(2);
         return hotel;
    };


    //get the positional index for a hotel record of a certain hotelId in the basket
    var getHotelIndex = function(hotelId){

             var hotelIndex = null;

             _(bookingBasket.bookings).each(function(booking,index){

                    if (booking.hotelId == hotelId){
                        hotelIndex = index;
                        _.breakLoop();
                    }
            });

             return hotelIndex;
    };



    //get parent container, hotel id, and room position for something that was clicked in a room row
    var getContext = function(clickedElement){

        var hotelContainer =  $(clickedElement).parents("div[class^='basket_inner']");

        return {    hotelContainer : hotelContainer,
                    hotelId : hotelContainer.get(0).getAttribute("data-hotelid"),
                    roomIndex : $(".roomRow", hotelContainer).index( $(clickedElement).parents("ul") )
        };
    };



    //gets room data from where 'book now' buttons are clicked
    var getRoomData = function(target){
        return {
                room : JSON.parse(decodeURIComponent(target.getAttribute("data-room"))),
                hotel : JSON.parse(
                   decodeURIComponent(
                        $(target).parents("div[class~=hotelData]").get(0).getAttribute("data-hotel")
                    )
               )
            };
    };



    //updates generated html from ICanHaz / Mustache template with 'bookingSet' id, using bookingBasket data
    var renderBasket = function(continuation){
        //use appropriate template depending on whether basket is shown or hidden
        var template = (bookingBasket.show == 1) ?  (bookingBasket.response == 'confirmBooking') ? "bookingConfirm" : "bookingSet" : "bookingSetMinimised";

        var basketToShow = bookingBasket;

        basketToShow.numRooms = _(bookingBasket.bookings).reduce(function(sum, booking){ return sum + booking.rooms.length }, 0);
        basketToShow.numHotels = bookingBasket.bookings.length;

        //apply room totals for each hotel
        basketToShow.bookings = _(basketToShow.bookings).map(withRoomsTotal);

        var basketHtml = (typeof bookingBasket.bookings != "undefined" && bookingBasket.bookings.length > 0) ? ich[template]( basketToShow ) : "";

        basketInDOM.html(basketHtml);
        enableEditor();

        (continuation) ? continuation() : null;
    };




    //AJAX FUNCTIONS




    //saves basket contents to session
    var saveBasket = function(continuation, continuationArg){

        if (currentBasketRequest != null) {
            currentBasketRequest.abort();
        }

        currentBasketRequest = $.post(
            basketController,
            {basket : bookingBasket},
            function(){
                (continuation) ? continuation(continuationArg) : null;
            },
            "json");
    };



    //gets basket contents from session
    var getBasket = function(continuation){

        if (!$('#emptyBasket') || $('#emptyBasket').val() != 1) {
            var hotelId = false;

            if ($('#confirmHotel') && $('#confirmHotel').val()) {
                        hotelId = $('#confirmHotel').val();
                    }
            if (currentBasketRequest != null) {
                currentBasketRequest.abort();
            }

            currentBasketRequest = $.get(
                basketController,
                            {hotelId: ""+hotelId+""},
                function(data) {
                    if (data != null && typeof data != "undefined" ){
                        $('#emptyBasket').val(data.emptyBasket);
                        window.bookingBasket = (data.response == "noBooking") ? {response: data.response, bookings : [], show : 1} : {response: data.response, bookings: data.contents.bookings, show: data.contents.show};
                        (continuation && data.response != "noBooking") ? continuation() : null;
                    }
                },
                "json");
        }
    };




    //ON PAGE LOAD



    //get basket from session and render on pageload
        if (window.scrollToResults) {
            ////scrolling
            getBasket(
                function(){
                    renderBasket(scrollToResults);
                }
            );
        }else {
            getBasket(renderBasket);
        }



});









