window.eviivo = window.eviivo ? window.eviivo : {};
window.eviivo.availabilitySearch = window.eviivo.availabilitySearch ? window.eviivo.availabilitySearch : {};

window.eviivo.availabilitySearch = function ($) {

    var defaultOptions = {
        isDefaultReferrer: true,
        defaultNightsServiced: 0,
        roomsLimit: 3,   //default room limit is 3 if not overriden by external settings
        eviivoSearchBoxId: "#eviivo-availability-search",   //default serach box id is "eviivo-availability-search" if not overriden by external settings
        cultureLanguageCode: "en-GB",
        baseSearchUrl: "",
        resources: {
            adults: "Adults",
            children: "Children",
            rooms: "Room(s)",
            room: "Room"
        },
        //have this search criteria as a default for easier way to parse the query string and easier way to customize the search if properties want to
        criteria:
        {
            startDate: null,
            endDate: null,
            occupancy: [{ adults: 2, children: 0 }]
        }
    };
    var options;
    var occupancySelectionHtmlClone;
    var roomsRow;
    var currentDate;
    var simpleVersion;

    var $tooltip;
    var $addButton;
    var $removeButton;
    var $searchButton;
    var $startDate;
    var $endDate;
    var $doneButton;
    var $occupancySelectors;
    var $firstAdultsOccupancy;
    var $showPricesButtons;
    var $searchBar;
    var $datePicker;
    var $viewportWidth;
    var $safariBrowser;
    var $isChannelSearch;
    var querystringHelper;
    var $formFieldSet;
    var $datePickerSelectionToolTip;
    var $infoTooltip;

    ///<summary>extend Date javascript object and add extra function "addHours"</summary>
    Date.prototype.addHours = function (hours) {
        this.setHours(this.getHours() + hours);
        return this;
    };

    ///<summary>Main init method of the eviivo.availabilitySearch object</summary>
    ///<param name="settings">external settings</param>
    function init(settings) {
        //extend internal settings with external ones
        options = $.extend(defaultOptions, settings);

        //cache jquerySelectors either as jQuery objects or just as simple text selectors
        occupancySelectionHtmlClone = $(options.eviivoSearchBoxId + " div.column-outer").html();
        roomsRow = options.eviivoSearchBoxId + " div.column-inner";

        //cache jquery objects
        $tooltip = $(options.eviivoSearchBoxId + " div.cp-tooltip");
        $addButton = $(options.eviivoSearchBoxId + " #btn-addRoom");
        $removeButton = $(options.eviivoSearchBoxId + " #btn-removeRoom");
        $searchButton = $(options.eviivoSearchBoxId + " button.cp-button-price");
        $showPricesButtons = $("#mod-results div.results-price button.cp-button-showprices");
        $startDate = $(options.eviivoSearchBoxId + " input#eviivo-start-date");
        $endDate = $(options.eviivoSearchBoxId + " input#eviivo-end-date");
        $doneButton = $(options.eviivoSearchBoxId + " .actions button");
        $firstAdultsOccupancy = $(options.eviivoSearchBoxId + " div.column-inner:first-child span.column-adult span.ui-selectmenu-button");
        $searchBar = $("#eviivo-availability-search");
        $datePicker = $("#ui-datepicker-div");
        $isChannelSearch = $("#submit-reservation #cbe");
        $formFieldSet = $('.column-outer');
        $viewportWidth = $(window).width();
        //use this array to cache the occupancy selector menus for easier manipulation
        $occupancySelectors = [];
        $safariBrowser = false;
        $datePickerSelectionToolTip = $('#datepicker-tooltip');
        $infoTooltip = $(".cp-tooltip-info");
        querystringHelper = eviivo.utils.queryStringHelper;
        if (typeof querystringHelper === "undefined") {
            console.log("eviivo.utils.queryStringHelper was not loaded therefore this page might not work properly");
        }

        //init datepicker (set culture and min date - not in the past)
        var minDate = new Date();
        if (options.defaultNightsServiced == null || options.isDefaultReferrer === false) {
            options.defaultNightsServiced = 0;
        }
        minDate.setDate(minDate.getDate() + options.defaultNightsServiced);

        var dtFormat = eviivo.webcore.formatting.datetime.evGetDateDisplayFormat(options.cultureLanguageCode, "medium");

        //setup culture and get users current culture
        var culture = "en-gb";
        if (options.selectedCultureLanguageCode != null) {
            culture = options.selectedCultureLanguageCode;
        }
        
        //Date has been extended via eviivo.webcore.formatting.js, this function takes the current users culture as a parameter and then determines what first day of the week should be, returning it as an offset used with date pickers
        var d = new Date();
        var firstDayOffset = d.evStandardFirstDayCalendarOffset(culture);

        $.datepicker.setDefaults(
            $.extend(
            {
                'dateFormat': dtFormat,
                'altFormat': dtFormat,
                'showOtherMonths': true,
                'selectOtherMonths': true,
                'minDate': minDate,
                'firstDay': firstDayOffset
            }
            )
        );

        $startDate.datepicker({
            onSelect: startDateSelectHandler
        });

        $endDate.datepicker({
            onSelect: endDateSelectHandler
        });

        //init end datepicker with culture specifics, min date as current date and onSelect custom handler
        $endDate.datepicker();

        //attach click handler for add room button
        $addButton.on("click", addRoomClickHandler);
        //attach click handler for remove room button
        $removeButton.on("click", removeRoomClickHandler);
        $datePickerSelectionToolTip.on("click", clearDatePickerTooltip);
        //attach click handler for hiding the occupancy tooltip (to "done" button and to DOM document)
        $doneButton.on("click", tooltipHide).on("blur", tooltipHide);
        $(document).on('keydown', tooltipHideEscape);

        //attach click handler for showing the occupancy tooltip
        $(options.eviivoSearchBoxId + " .icon-guest").on("click", tooltipShow);
        $(options.eviivoSearchBoxId + " .icon-guest a").on("click", tooltipShow);

        //initialize the first row of occupancy selectors in the occupancy tooltip
        initSelectMenu($(options.eviivoSearchBoxId + " div.column-inner:first-child select.cp-select"));

        //handle the click outside the occupancy tooltip (close the tooltip and focus on the search price button)
        $(document).on("click", tooltipOutsideClick);

        //action for search button
        $searchButton.on("click", triggerSearch);

        //action for show prices button
        $showPricesButtons.on("click", showStartDateCalendar);

        //first try to extract search criteria from query string
        extractCriteria();
        //init search criteria (either from extracted query string keys or from default values)
        initSearchForm();

        $infoTooltip.on("click", hideInfoToolTip);


        validate(true);


    }


    ///<summary>Initialize occupancy selectors in the occupancy tooltip</summary>
    ///<param name="selector">the dropdown jquery selector</param>
    function initSelectMenu(selector) {
        var selectors = selector.selectmenu({
            change: highlightOccupancy
        });

        $occupancySelectors.push({ adults: selectors[0], children: selectors[1] });
    }

    ///<summary>Occupancy selector onChange handler</summary>
    function occupancySelectHandler() {
        var totalAdults = 0;
        $(options.eviivoSearchBoxId + " div.column-inner span.column-adult .ui-selectmenu-text").each(function (i, e) {
            totalAdults += extractNumber($(e));
        });

        var totalChildren = 0;
        $(options.eviivoSearchBoxId + " div.column-inner span.column-child .ui-selectmenu-text").each(function (i, e) {
            totalChildren += extractNumber($(e));
        });

        var numberOfRooms = $(roomsRow).length;
        var searchBoxText = $(options.eviivoSearchBoxId + " .cp-inputValues a span");
        var roomText = "";
        if (numberOfRooms > 1) {
            roomText = options.resources.rooms;
        } else {
            roomText = options.resources.room;
        }
        searchBoxText.html(totalAdults + " " + options.resources.adults + " " + totalChildren + " " + options.resources.children + " " + numberOfRooms + " " + roomText);
    }

    ///<summary>highlight the occupancy text when switching values</summary>
    function highlightOccupancy() {
        occupancySelectHandler();
        var searchBoxText = $(options.eviivoSearchBoxId + " .cp-inputValues a");
        searchBoxText.fadeIn("slow", function () {
            searchBoxText.css("color", "#000");
        });
    }

    ///<summary>Give each room added a number</summary>
    function numberRoomTitle() {
        var count = 1;
        $(".column-outer .column-inner").each(function () {
            var countTitle = options.resources.room + " " + count;

            $(this).find(".room").html(countTitle);

            count++;
        });
    }

    //<summary>Change number of rooms selected in helper text</summary>
    function numberRoomHelper() {
        var roomTotal = $(".column-outer .column-inner").length;
        var roomRow = $(".room-counter");
        var resource;
        if (roomTotal > 1) {
            resource = options.resources.roomsAdded;
        } else {
            resource = options.resources.roomAdded;
        }
        var roomHtml = resource.replace(new RegExp('\\{' + 0 + '\\}', 'gm'), roomTotal);
        roomRow.html(roomHtml);
        roomRow.addClass('pulse');

        var newRow = roomRow.clone(true);
        roomRow.before(newRow);
        $(".room-counter:last").remove();
    }

    ///<summary>Add room onClick handler</summary>
    function addRoomClickHandler() {
        var numberOfRooms = $(roomsRow).length;
        if (numberOfRooms < options.roomsLimit) {
            $(options.eviivoSearchBoxId + " div.column-outer").append(occupancySelectionHtmlClone).addClass("cloned");
            initSelectMenu($(options.eviivoSearchBoxId + " div.column-inner:last-child select.cp-select"));
            occupancySelectHandler();
            numberRoomTitle();
            numberRoomHelper();
        }
        setTooltipButtonsStatus();
    }

    ///<summary>Remove room onClick handler</summary>
    function removeRoomClickHandler() {
        var numberOfRooms = $(roomsRow).length;
        if (numberOfRooms > 1) {
            $(options.eviivoSearchBoxId + " div.column-inner:last").remove();
            occupancySelectHandler();
            numberRoomHelper();
        }
        setTooltipButtonsStatus();
    }

    ///<summary>Set the disabled status of the add and remove room buttons in the occupancy tooltip</summary>
    function setTooltipButtonsStatus() {
        var numberOfRooms = $(roomsRow).length;
        if (numberOfRooms > 1) {
            $removeButton.removeAttr("disabled");
        } else {
            $removeButton.attr("disabled", "disabled");
            //once disabled the "remove button" we focus on the "add button" for better interaction
            $addButton.focus();
        }
        if (numberOfRooms < options.roomsLimit) {
            $addButton.removeAttr("disabled");
        } else {
            $addButton.attr("disabled", "disabled");
            //once disabled the "add button" we focus on the "remove button" for better interaction
            $removeButton.focus();
        }
        $(options.eviivoSearchBoxId + " div.column-outer").removeClass("overflow");
        if (numberOfRooms > 2) {
            $(options.eviivoSearchBoxId + " div.column-outer").addClass("overflow");
        }
    }

    ///<summary>Hide tooltip when clicking outside the tooltip area</summary>
    function tooltipOutsideClick(e) {
        if (!$(e.target).hasClass("ui-menu-item-wrapper") && !$(e.target).hasClass("ui-menu-item") && !$(e.target).hasClass("cp-tooltip") && $(e.target).parents("div.cp-tooltip").length === 0) {
            tooltipHide(e, true);
        }
    }

    ///<summary>Hide tooltip handler on escape key</summary>
    function tooltipHideEscape(e) {
        if (e.keyCode === 27) {
            tooltipHide(e, true);
        }
    }

    ///<summary>Hide tooltip handler</summary>
    function tooltipHide(e, bypassFocus) {
        if ($tooltip.is(":visible")) {
            $tooltip.hide();

            //we check if we bypass focus for search button
            if (!bypassFocus) {
                $searchButton.focus();
            }
        }
    }

    ///<summary>Show tooltip handler</summary>
    function tooltipShow(e) {
        if (e !== null) {
            e.stopPropagation();
        }
        if (($tooltip).is(":hidden")) {
            $tooltip.show('fast');
            //when showing tooltip we focus on first select input element
            $firstAdultsOccupancy.focus();
        }
    }

    function hideInfoToolTip() {
        //hide info tooltip if visible
        if ($infoTooltip.is(":visible")) {
            $infoTooltip.hide();
        }
    }

    ///<summary>Performs a validation on all the fields necessary to make the autocomplete / location result valid</summary>
    function validate(isOnLoadValidation) {
        // if both dates fields are empty
        if ($startDate.val() === "" && $endDate.val() === "") {
            if (isOnLoadValidation) {
                $datePickerSelectionToolTip.addClass("infotip");
            } else {
                $startDate.addClass("invalid");
                $endDate.addClass("invalid");
            }
            $datePickerSelectionToolTip.show();
            return false;
        }
        // if start date field is empty
        if ($startDate.val() === "") {
            if (isOnLoadValidation) {
                $datePickerSelectionToolTip.addClass("infotip");
            } else {
                $startDate.addClass("invalid");
            }
            $datePickerSelectionToolTip.show();
            return false;
        }
        // if end date field is empty
        if ($endDate.val() === "") {
            if (isOnLoadValidation) {
                $datePickerSelectionToolTip.addClass("infotip");
            } else {
                $endDate.addClass("invalid");
            }
            $datePickerSelectionToolTip.show();
            return false;
        }
        clearDatePickerTooltip();
        return true;

    }


    function clearDatePickerTooltip() {
        $startDate.removeClass("invalid");
        $endDate.removeClass("invalid");
        $datePickerSelectionToolTip.removeClass("infotip");
        $datePickerSelectionToolTip.hide();
    }


    ///<summary>Extract search criteria from querystring and populate search form</summary>
    function extractCriteria() {
        var criteria = options.criteria;
        var src = window.location.href;
        var isRoomCount = false;

        //extract all query string keys by using reg exp
        var qsJson = querystringHelper.getAllKeys(src);

        //set start and end dates
        if (qsJson["startdate"] !== null) {
            criteria.startDate = new Date(qsJson["startdate"]);
        }
        if (qsJson["enddate"] !== null) {
            criteria.endDate = new Date(qsJson["enddate"]);
        }

        //in case we had number of nights from legacy URL formats
        if (qsJson["nights"] !== null) {
            var nights = parseInt(qsJson["nights"]);
            //in case we had number of nights from legacy URL formats
            if (!isNaN(nights)) {
                //we have to re-construct the date object due to fact it will change the original is we only assign
                criteria.endDate = new Date(criteria.startDate.getFullYear(), criteria.startDate.getMonth(), criteria.startDate.getDate(), 0, 0, 0);
                criteria.endDate.addHours(24 * nights);
            }
        }

        //make sure to persist the display format
        if (qsJson["simpleversion"] !== null) {
            simpleVersion = qsJson["simpleversion"];
        }

        if (qsJson["noofrooms"] !== null) {
            isRoomCount = qsJson["noofrooms"] >= 0;
        }

        criteria.occupancy = [];

        //pass through all query string keys and construct the occupancy selectors
        $.each(qsJson, function (key, value) {
            //check for existance of adults and/or children params
            var isAdults = key.indexOf("adults") >= 0;
            var isChildren = key.indexOf("children") >= 0;

            if (isAdults || isChildren > 0) {
                //check to see which is the occupancy group the query string key refers to
                var occupancyRegEx = new RegExp("[a-zA-Z]+([0-9]+)");
                // extract the "index" of the adults or children (eg. adults1) - we need to consider them as being 0 base even though they come as 1 based in the URL
                var index = parseInt(occupancyRegEx.exec(key)[1]) - 1;

                // if room count is used exit loop if the "index" of the adults or children is greater than the noofrooms query string value
                if (isRoomCount && (index + 1) > parseInt(qsJson["noofrooms"]))
                    return false;

                //construct extra occupancy groups (in case it's needed)
                while (index > options.criteria.occupancy.length - 1) {
                    criteria.occupancy.push({ adults: 0, children: 0 });
                }

                //based on key, set the appropriate field for occupancy
                if (isAdults) {
                    criteria.occupancy[index].adults = value;

                } else if (isChildren) {
                    criteria.occupancy[index].children = value;
                }
            }
        });

        return criteria;
    }

    ///<summary>Construct the search URL base on the base URL and the selected parameters</summary>
    function triggerSearch() {

        if (!validate()) {
            return;
        }

        var searchUrl = options.baseSearchUrl;
        var src = window.location.href;
        var originalQueryString = querystringHelper.getAllKeys(src);
        var queryStrings = jQuery.extend({}, originalQueryString);

        var startDate = $startDate.datepicker("getDate");
        var endDate = $endDate.datepicker("getDate");

        if (startDate !== null) {
            querystringHelper.addKey(queryStrings, "startdate", startDate.evStandardIso8601DateExtended());
        }
        if (endDate !== null) {
            querystringHelper.addKey(queryStrings, "enddate", endDate.evStandardIso8601DateExtended());
        }

        querystringHelper.deleteKeyWithRegex(queryStrings, "adults");
        querystringHelper.deleteKeyWithRegex(queryStrings, "children");
        querystringHelper.deleteKeyWithRegex(queryStrings, "noofrooms");
        $(options.eviivoSearchBoxId + " div.column-inner").each(function (i, e) {
            querystringHelper.addKey(queryStrings, "adults" + (i + 1), extractNumber($(e).find("span.column-adult .ui-selectmenu-text")));
            querystringHelper.addKey(queryStrings, "children" + (i + 1), extractNumber($(e).find("span.column-child .ui-selectmenu-text")));
        });

        if (simpleVersion !== null && simpleVersion !== "" && simpleVersion !== undefined) {
            querystringHelper.addKey(queryStrings, "simpleversion", simpleVersion);
        }

        //This is necessary in order to cater for situations where the booking pages are being served via the SearchSystem
        if ($("#ref").length > 0 && $("#ref").val().length > 0) {
            querystringHelper.addKey(queryStrings, "ref", $("#ref").val());
        }

        handlePromotionsRequestParameters(originalQueryString, queryStrings);

        querystringHelper.addRandomizer(queryStrings);

        searchUrl += querystringHelper.toString(queryStrings);

        //reload browser to the search url
        window.location.href = searchUrl;
    }

    function handlePromotionsRequestParameters(originalQueryString, queryStrings) {
        //clear the promo code parameter
        querystringHelper.deleteKey(queryStrings, "pce");
        //see if promo code has to be submited fresh
        var promotionCodeElement = $("#pce");
        if (promotionCodeElement.length > 0) {
            querystringHelper.addKey(queryStrings, "pce", promotionCodeElement.val());
        }

        //clear the promo instant deal parameter
        querystringHelper.deleteKey(queryStrings, "peid");
        //see if promo instant deal has to be submited fresh
        var promotionEnableDealsElement = $("#peid");
        if (promotionEnableDealsElement.length > 0 && promotionEnableDealsElement.val() != null && promotionEnableDealsElement.val() !== "") {
            querystringHelper.addKey(queryStrings, "peid", promotionEnableDealsElement.val());
        }
    }

    ///<summary>Construct the search URL base on the base URL and the selected parameters</summary>
    function showStartDateCalendar(e) {
        if (!$viewportWidth < 768) {
            //smaller than ipad
            eviivo.smoothScrolling.smoothScrollHandler(e, function () {
                $startDate.datepicker("show");
            }, this);
        }
    }

    ///<summary>initialize the serach form based on criteria options we have (either from query string, from property setup or from our own defaults)</summary>
    function initSearchForm() {

        //pass through all occupancy groups
        $.each(options.criteria.occupancy, function (index, value) {
            //construct extra occupancy group selectors in case it's needed
            while (index > 0 && index > $occupancySelectors.length - 1) {
                addRoomClickHandler();
            }
            $($occupancySelectors[index].adults).val(value.adults);
            $($occupancySelectors[index].adults).selectmenu("refresh");
            $($occupancySelectors[index].children).val(value.children);
            $($occupancySelectors[index].children).selectmenu("refresh");
        });

        occupancySelectHandler();
    }

    ///<summary>Datepicker select handler for start date</summary>
    function startDateSelectHandler(date, instance) {
        //grab selected date and add extra 24 hours
        var selectedDate = new Date(instance.selectedYear, instance.selectedMonth, parseInt(instance.selectedDay), 0, 0, 0, 0);
        var minEndDate = new Date(selectedDate).addHours(24);

        //set the minDate for the endDate calendar
        $endDate.datepicker("option", { "minDate": minEndDate });

        //auto show the end date calendar (delay of 100ms because of jquery show effects on datepicker)
        setTimeout(function () {
            $endDate.datepicker("show");
            $endDate.datepicker("setDate", minEndDate);
        }, 100);

        // If yellow tooltip exists & it's visible
        if ($datePickerSelectionToolTip.length > 0 && $datePickerSelectionToolTip.is(':visible')) {
            clearDatePickerTooltip();
        }
    }

    ///<summary>Datepicker select handler for end date</summary>
    function endDateSelectHandler(date, instance) {
        if ($startDate.val() === "") {
            //auto show the end date calendar (delay of 100ms because of jquery show effects on datepicker)
            setTimeout(function () {
                $startDate.datepicker("show");
            }, 100);
        } else {
            //focus on done button
            $firstAdultsOccupancy.focus();
        }
        // If yellow tooltip exists & it's visible
        if ($datePickerSelectionToolTip.length > 0 && $datePickerSelectionToolTip.is(':visible')) {
            clearDatePickerTooltip();
        }

    }

    ///<summary>helper function to extract number from occupancy selector text (adult or child)</summary>
    function extractNumber(selector) {
        return parseInt(selector.text().slice(0, 2).trim());
    }

    ///<summary>extend Date javascript object and add extra function "addHours"</summary>
    Date.prototype.addHours = function (hours) {
        this.setHours(this.getHours() + hours);
        return this;
    };

    ///<summary>Expose the internal "private" methods for external use (make them public)</summary>
    return {
        init: init,
        triggerSearch: triggerSearch
    };
}(jQuery);
