﻿var CriteriaSearch = function () {
    var cruiseLength = function (minLength, maxLength, selected, description) {
        var inner = {};

        inner.minLength = minLength;
        inner.maxLength = maxLength;
        inner.description = description;
        inner.selected = ko.observable(selected);
        inner.available = ko.observable(true);

        return inner;
    };

    var year = function (name, months) {
        var inner = {};

        inner.name = name;
        inner.months = months;

        return inner;
    };

    var port = function (name, code, geocode, selected, available, onSelectedChanged) {
        var inner = {};

        inner.name = name;
        inner.code = code;
        inner.geocode = geocode;
        inner.selected = ko.observable(selected);
        inner.available = ko.observable(available);

        inner.disabled = ko.dependentObservable(function () {
            return !inner.available();
        }, inner);

        var oldSelectedValue = selected;

        inner.selected.subscribe(function (newValue) {
            if (newValue !== oldSelectedValue && onSelectedChanged) {
                onSelectedChanged(newValue);
            }
            oldSelectedValue = newValue;
        });

        inner.available.subscribe(function (newValue) {
            if (newValue === false) {
                inner.selected(false);
            }
        });

        return inner;
    };

    var ship = function (name, code, classname, selected, available, onSelectedChanged) {
        var inner = {};

        inner.name = name;
        inner.code = code;
        inner.classname = classname;
        inner.selected = ko.observable(selected);
        inner.available = ko.observable(available);

        inner.disabled = ko.dependentObservable(function () {
            return !inner.available();
        }, inner);

        var oldSelectedValue = selected;

        inner.selected.subscribe(function (newValue) {
            if (newValue !== oldSelectedValue && onSelectedChanged) {
                onSelectedChanged(newValue);
            }
            oldSelectedValue = newValue;
        });

        inner.available.subscribe(function (newValue) {
            if (newValue === false) {
                inner.selected(false);
            }
        });

        return inner;
    };

    var destination = function (name, code, selected, available, onSelectedChanged) {
        var inner = {};

        inner.name = name;
        inner.code = code;
        inner.selected = ko.observable(selected);
        inner.available = ko.observable(available);

        inner.disabled = ko.dependentObservable(function () {
            return !inner.available();
        }, inner);

        var oldSelectedValue = selected;

        inner.selected.subscribe(function (newValue) {
            if (newValue !== oldSelectedValue && onSelectedChanged) {
                onSelectedChanged(newValue);
            }
            oldSelectedValue = newValue;
        });

        inner.available.subscribe(function (newValue) {
            if (newValue === false) {
                inner.selected(false);
            }
        });

        return inner;
    };

    var month = function (month, year, name, available, fromPrice, model, parent, onSelectedChanged) {
        var inner = {};

        inner.name = name;

        inner.month = month;

        inner.year = year;

        inner.available = ko.observable(available);

        inner.disabled = ko.dependentObservable(function () {
            return !inner.available();
        }, inner);

        inner.fromPrice = fromPrice;

        inner.selected = ko.observable(false);

        var oldSelectedValue = false;

        var runSubscription = true;
        inner.select = function (runSub) {
            if (!runSub && onSelectedChanged) {
                onSelectedChanged(true);
            }

            runSubscription = runSub;
            inner.selected(true);
            oldSelectedValue = true;
            runSubscription = true;
        };

        inner.notSelected = ko.dependentObservable(function () {
            return !inner.selected();
        }, inner);

        inner.available.subscribe(function (newValue) {
            if (newValue === false) {
                inner.selected(false);
            }
        });

        inner.selected.subscribe(function (newValue) {
            if (onSelectedChanged && oldSelectedValue !== newValue) {
                onSelectedChanged(newValue);
                oldSelectedValue = newValue;
            }

            if (shiftKeyPressed === true && runSubscription === true && newValue === true) {
                var firstFoundSelected = null;
                var startIndex = 0;
                var selectedFound = false;
                var endFound = false;
                var thisFound = false;
                var shouldContinue = true;

                $.each(parent.months(), function (i, v) {
                    if (shouldContinue === false) {
                        return;
                    }

                    if ((v.month === inner.month && v.year === inner.year) || endFound === true) {
                        if (selectedFound === true) {
                            endFound = true;
                        }
                        thisFound = true;
                        return;
                    }

                    if (v.selected()) {
                        if (thisFound === true) {
                            shouldContinue = false;
                        }
                        selectedFound = true;
                    } else if ((selectedFound === true || thisFound === true) && v.available() === true) {
                        v.select(false);
                    }
                });
            }
        });

        return inner;
    };

    var criteria = function (destinations, ships, ports, months, minNumberOfNights, maxNumberOfNights, numberOfAdults, numberOfChildren, useSeniorPrices, sysAdminId, searchFlight) {
        var inner = {};

        inner.destinations = destinations;
        inner.ships = ships;
        inner.ports = ports;
        inner.months = months;
        inner.minNumberOfNights = minNumberOfNights;
        inner.maxNumberOfNights = maxNumberOfNights;
        inner.numberOfAdults = numberOfAdults;
        inner.numberOfChildren = numberOfChildren;
        inner.useSeniorPrices = useSeniorPrices;
        inner.searchFlight = searchFlight;

        inner.getSearchCriteria = function (currentPage, sortOption) {
            var destinations = "";
            $(inner.destinations).each(function () {
                destinations += this.code + "|";
            });
            var ships = "";
            $(inner.ships).each(function () {
                ships += this.code + "|";
            });
            var ports = "";
            $(inner.ports).each(function () {
                ports += this.code + "|";
            });
            var months = "";
            $(inner.months).each(function () {
                months += this.month + "," + this.year + "|";
            });

            return { 'destinations': destinations, 'ships': ships, 'months': months, 'ports': ports, 'prices': '', 'minLength': inner.minNumberOfNights, 'maxLength': inner.maxNumberOfNights, 'numberOfAdults': inner.numberOfAdults, 'numberOfChildren': inner.numberOfChildren, 'useSeniorPrices': inner.useSeniorPrices, 'page': currentPage, 'searchFlight': inner.searchFlight };
        };

        inner.getQuerystring = function () {
            var destinations = "";
            $(inner.destinations).each(function () {
                destinations += this.code + "|";
            });
            var ships = "";
            $(inner.ships).each(function () {
                ships += this.code + "|";
            });
            var ports = "";
            $(inner.ports).each(function () {
                ports += this.code + "|";
            });
            var months = "";
            $(inner.months).each(function () {
                months += this.month + "," + this.year + "|";
            });

            destinations = destinations.substr(0, destinations.length - 1);
            ships = ships.substr(0, ships.length - 1);
            ports = ports.substr(0, ports.length - 1);
            months = months.substr(0, months.length - 1);

            return 's=' + sysAdminId + '&destinations=' + destinations + '&ships=' + ships + '&months=' + months + '&ports=' + ports + '&minLength=' + inner.minNumberOfNights + '&maxLength=' + inner.maxNumberOfNights + '&numberOfAdults=' + inner.numberOfAdults + '&numberOfChildren=' + inner.numberOfChildren + '&useSeniorPrices=' + inner.useSeniorPrices + "&searchFlight=" + inner.searchFlight;
        };

        return inner;
    };

    var searchAlternatives = function (model, maxNumberOfSearchCriteriaOptionChars, translations, searchFlight) {
        var inner = {};

        var maximumNumberOfPassengers = 4;
        var isFirstDestinations = true;
        var isFirstPorts = true;
        var isFirstMonths = true;
        var isFirstShips = true;
        var isFirstLengts = true;

        inner.currentGeoCode = "";
        inner.searchFlight = ko.observable(searchFlight);
        inner.notSearchFlight = ko.dependentObservable(function () {
            return !inner.searchFlight();
        });

        inner.searchFlight.subscribe(function () {
            filterSearchAlternatives();
        });

        inner.setCurrentGeoCode = function (value) {
            inner.currentGeoCode = value;
        };

        inner.isAllSelected = function (array, shouldBeAvailable) {
            var isAnySelected = true;
            $(array).each(function () {
                if (!isAnySelected) {
                    return;
                }
                if (shouldBeAvailable && this.available() === false) {
                    return;
                }

                if (this.selected() === true) {
                    isAnySelected = false;
                }
            });

            return isAnySelected;
        };

        maxNumberOfSearchCriteriaOptionChars = maxNumberOfSearchCriteriaOptionChars || 20;

        inner.availableDestinations = ko.observableArray([]);
        inner.showingDestinations = ko.observable(false);

        inner.availableShips = ko.observableArray([]);
        inner.showingShips = ko.observable(false);

        inner.availablePorts = ko.observableArray([]);
        inner.showingPorts = ko.observable(false);

        inner.availableCruiseLengths = ko.observableArray([]);
        inner.showingCruiseLengths = ko.observable(false);

        inner.useSeniorPrices = ko.observable(false);

        inner.showingNumberOfAdults = ko.observable(false);

        inner.showingNumberOfChildren = ko.observable(false);

        inner.months = ko.observableArray([]);

        inner.shipClasses = ko.dependentObservable(function () {
            var ships = inner.availableShips();
            return Enumerable.From(ships).GroupBy(function (x) { return x.classname; }).ToArray();
        });

        inner.allShipsSelected = ko.dependentObservable(function () {
            return inner.isAllSelected(inner.availableShips(), true);
        }, inner);

        inner.allDestinationsSelected = ko.dependentObservable(function () {
            return inner.isAllSelected(inner.availableDestinations(), true);
        }, inner);

        inner.allPortsSelected = ko.dependentObservable(function () {
            return inner.isAllSelected(inner.availablePorts(), true);
        }, inner);

        inner.allLengthsSelected = ko.dependentObservable(function () {
            return inner.isAllSelected(inner.availableCruiseLengths(), true);
        }, inner);

        inner.allMonthsSelected = ko.dependentObservable(function () {
            return inner.isAllSelected(inner.months(), true);
        }, inner);

        inner.selectAllShips = function () {
            //var select = !inner.isAllSelected(inner.availableShips(), true);

            $(inner.availableShips()).each(function () {
                //if (this.available() === true && select) {
                this.selected(false);
                //}
            });
        };

        inner.selectAllPorts = function () {
            //var select = !inner.isAllSelected(inner.availablePorts(), true);

            $(inner.availablePorts()).each(function () {
                //if (this.available() === true && select) {
                this.selected(false);
                //}
            });
        };
        inner.selectAllLengths = function () {
            //var select = !inner.isAllSelected(inner.availablePorts(), true);

            $(inner.availableCruiseLengths()).each(function () {
                //if (this.available() === true && select) {
                this.selected(false);
                //}
            });
        };

        inner.selectAllDestinations = function () {
            //var select = !inner.isAllSelected(inner.availableDestinations(), true);

            $(inner.availableDestinations()).each(function () {
                //if (this.available() === true && select) {
                this.selected(false);
                //}
            });
        };

        inner.selectAllMonths = function () {
            //var select = !inner.isAllSelected(inner.availableDestinations(), true);

            $(inner.months()).each(function () {
                // if (this.available() === true && select) {
                this.selected(false);
                // }
            });
        };

        inner.showMonthSelection = ko.dependentObservable(function () {
            return Enumerable.From(inner.months()).Count(function (item) { return item.selected() === true; }) < 2;
        }, inner);

        inner.selectableMonths = ko.dependentObservable(function () {
            return Enumerable.From(inner.months()).Where(function (item) { return item.available == true }).ToArray();
        }, inner);

        inner.availableYears = ko.dependentObservable(function () {
            return Enumerable.From(inner.months()).GroupBy(function (item) { return item.year; }, "", function (key, items) { return year(key, items.Where(function (item) { return item.year == key; }).ToArray()); }).ToArray();
        }, inner);

        inner.selectedDestinations = function () {
            if (inner.isAllSelected(inner.availableDestinations())) {
                if (isFirstDestinations === true) {
                    return translations.chooseDestination;
                } else {
                    return translations.anyDestination;
                }
            }

            isFirstDestinations = false;

            var destinations = getSelected(inner.availableDestinations());
            var str = '';
            if (destinations.length > 1) {
                str = translations.severalChoosen;
            } else {
                $.each(destinations, function (i, v) {
                    str += v.name + ',';
                });

                str = str.substr(0, str.length - 1);
            }

            if (str.length > maxNumberOfSearchCriteriaOptionChars) {
                str = str.substr(0, maxNumberOfSearchCriteriaOptionChars) + '...';
            } else {
                str = str.substr(0, str.length);
            }
            return str;
        };

        inner.selectedShips = function () {
            if (inner.isAllSelected(inner.availableShips())) {
                if (isFirstShips === true) {
                    return translations.chooseShip;
                } else {
                    return translations.anyShip;
                }
            }

            isFirstShips = false;

            var ships = getSelected(inner.availableShips());
            var str = '';

            if (ships.length > 1) {
                str = translations.severalChoosen;
            } else {
                $.each(ships, function (i, v) {
                    str += v.name + ',';
                });

                str = str.substr(0, str.length - 1);
            }

            if (str.length > maxNumberOfSearchCriteriaOptionChars) {
                str = str.substr(0, maxNumberOfSearchCriteriaOptionChars) + '...';
            } else {
                str = str.substr(0, str.length);
            }
            return str;
        };

        inner.selectedPorts = function () {
            if (inner.isAllSelected(inner.availablePorts())) {
                if (isFirstPorts === true) {
                    return translations.choosePort;
                }
                else
                    return translations.anyPort;
            }

            isFirstPorts = false;

            var ports = getSelected(inner.availablePorts());
            var str = '';

            if (ports.length > 1) {
                str = translations.severalChoosen;
            } else {
                $.each(ports, function (i, v) {
                    str += v.name + ',';
                });

                str = str.substr(0, str.length - 1);
            }

            if (str.length > maxNumberOfSearchCriteriaOptionChars)
                str = str.substr(0, maxNumberOfSearchCriteriaOptionChars) + '...';
            else
                str = str.substr(0, str.length);
            return str;
        };

        inner.selectedDates = function () {
            if (inner.isAllSelected(inner.months())) {
                if (isFirstMonths === true) {
                    return translations.chooseMonth;
                }
                else {
                    return translations.anyMonth;
                }
            }

            isFirstMonths = false;

            var selectedMonths = getSelected(inner.months());
            var str = '';

            if (selectedMonths.length > 1) {
                str = translations.severalChoosen;
            } else {
                $.each(selectedMonths, function (i, v) {
                    str += v.name + ' ' + v.year + ',';
                });

                str = str.substr(0, str.length - 1);
            }

            if (str.length > maxNumberOfSearchCriteriaOptionChars) {
                str = str.substr(0, maxNumberOfSearchCriteriaOptionChars) + '...';
            } else {
                str = str.substr(0, str.length);
            }
            return str;
        };





        inner.selectedCruiseLengths = function () {
            if (inner.isAllSelected(inner.availableCruiseLengths())) {
                return translations.severalChoosen;
            }

            var cruiseLengths = getSelected(inner.availableCruiseLengths());
            var str = '';

            if (cruiseLengths.length < 1)
                return translations.chooseLength;

            if (cruiseLengths.length > 1) {
                str = translations.severalChoosen;
            } else {
                $.each(cruiseLengths, function (i, v) {
                    str += v.description + ' ' + translations.nights + ',';
                });

                str = str.substr(0, str.length - 1);
            }

            if (str.length > maxNumberOfSearchCriteriaOptionChars)
                str = str.substr(0, maxNumberOfSearchCriteriaOptionChars) + '...';
            else
                str = str.substr(0, str.length);
            return str;
        };

        inner.numberOfAdults = ko.observable(2);
        inner.numberOfChildren = ko.observable(0);

        inner.availableAdults = ko.dependentObservable(function () {
            return maximumNumberOfPassengers - inner.numberOfChildren();
        }, inner);

        inner.availableChildren = ko.dependentObservable(function () {
            return maximumNumberOfPassengers - inner.numberOfAdults();
        }, inner);

        function getSelected(array) {
            return Enumerable.From(array).Where(function (item) { return item.selected() === true; }).ToArray();
        };

        function getMin(array, orderByFunc, defaultValue) {
            var min = Enumerable.From(array).OrderBy(orderByFunc).FirstOrDefault();
            if (min == null) {
                return defaultValue;
            }
            return orderByFunc(min);
        };

        function getMax(array, orderByFunc, defaultValue) {
            var max = Enumerable.From(array).OrderByDescending(orderByFunc).FirstOrDefault();
            if (max == null) {
                return defaultValue;
            }
            return orderByFunc(max);
        };

        inner.getCriteria = function () {
            var minNumberOfNights = getMin(getSelected(inner.availableCruiseLengths()), function (item) { return item.minLength; }, 0);
            var maxNumberOfNights = getMax(getSelected(inner.availableCruiseLengths()), function (item) { return item.maxLength; }, 100);

            var destinations = getSelected(inner.availableDestinations());
            if (destinations.length < 1) {
                destinations = inner.availableDestinations();
            }

            var ships = getSelected(inner.availableShips());
            if (ships.length < 1) {
                ships = inner.availableShips();
            }

            var ports = getSelected(inner.availablePorts());
            if (ports.length < 1) {
                ports = inner.availablePorts();
            }

            var months = getSelected(inner.months());
            if (months.length < 1) {
                months = inner.months();
            }

            return criteria(destinations, ships, ports, months, minNumberOfNights, maxNumberOfNights, inner.numberOfAdults(), inner.numberOfChildren(), inner.useSeniorPrices(), translations.sysAdminId, inner.searchFlight());
        };

        inner.showingMonthSelection = ko.observable(false);

        inner.hideAll = function () {
            inner.showingMonthSelection(false);
            inner.showingPorts(false);
            inner.showingShips(false);
            inner.showingCruiseLengths(false);
            inner.showingNumberOfChildren(false);
            inner.showingNumberOfAdults(false);
            inner.showingDestinations(false);
        };

        inner.toggleDestinations = function () {
            inner.showingMonthSelection(false);
            inner.showingPorts(false);
            inner.showingShips(false);
            inner.showingCruiseLengths(false);
            inner.showingNumberOfChildren(false);
            inner.showingNumberOfAdults(false);
            inner.showingDestinations(!inner.showingDestinations());
        };

        inner.toggleShips = function () {
            inner.showingDestinations(false);
            inner.showingMonthSelection(false);
            inner.showingPorts(false);
            inner.showingCruiseLengths(false);
            inner.showingNumberOfChildren(false);
            inner.showingNumberOfAdults(false);
            inner.showingShips(!inner.showingShips());
        };

        inner.togglePorts = function () {
            inner.showingDestinations(false);
            inner.showingMonthSelection(false);
            inner.showingShips(false);
            inner.showingCruiseLengths(false);
            inner.showingNumberOfChildren(false);
            inner.showingNumberOfAdults(false);
            inner.showingPorts(!inner.showingPorts());
        };

        inner.toggleMonthSelection = function () {
            inner.showingDestinations(false);
            inner.showingPorts(false);
            inner.showingShips(false);
            inner.showingCruiseLengths(false);
            inner.showingNumberOfChildren(false);
            inner.showingNumberOfAdults(false);
            inner.showingMonthSelection(!inner.showingMonthSelection());
        };

        inner.toggleCruiseLengthSelection = function () {
            inner.showingDestinations(false);
            inner.showingPorts(false);
            inner.showingShips(false);
            inner.showingMonthSelection(false);
            inner.showingNumberOfChildren(false);
            inner.showingNumberOfAdults(false);
            inner.showingCruiseLengths(!inner.showingCruiseLengths());
        };

        inner.toggleNumberOfAdults = function () {
            inner.showingDestinations(false);
            inner.showingPorts(false);
            inner.showingShips(false);
            inner.showingMonthSelection(false);
            inner.showingCruiseLengths(false);
            inner.showingNumberOfChildren(false);
            inner.showingNumberOfAdults(!inner.showingNumberOfAdults());
        };

        inner.toggleNumberOfChildren = function () {
            inner.showingDestinations(false);
            inner.showingPorts(false);
            inner.showingShips(false);
            inner.showingMonthSelection(false);
            inner.showingCruiseLengths(false);
            inner.showingNumberOfAdults(false);
            inner.showingNumberOfChildren(!inner.showingNumberOfChildren());
        };

        function filterSearchAlternatives() {
            model.filterSearchAlternatives(inner.getCriteria(), 1, null, function (data) {
                $(inner.availableDestinations()).each(function () {
                    var code = this.code;
                    var destination = Enumerable.From(data.Destinations).Where(function (item) { return item.Code === code; }).FirstOrDefault();
                    if (destination) {
                        this.available(destination.Available);
                    }
                });

                $(inner.availableShips()).each(function () {
                    var code = this.code;
                    var ship = Enumerable.From(data.Ships).Where(function (item) { return item.Code === code; }).FirstOrDefault();
                    if (ship) {
                        this.available(ship.Available);
                    }
                });

                $(inner.availablePorts()).each(function () {
                    var code = this.code;
                    var port = Enumerable.From(data.Ports).Where(function (item) { return item.Code === code; }).FirstOrDefault();
                    if (port) {
                        this.available(port.Available);
                    }
                });

                $(inner.availableYears()).each(function () {
                    $(this.months).each(function () {
                        var month = this.month;
                        var year = this.year;
                        var thisMonth = Enumerable.From(data.Months).Where(function (item) { return item.Month === month && item.Year === year; }).FirstOrDefault();
                        if (thisMonth) {
                            this.fromPrice = thisMonth.FromPrice;
                            this.available(thisMonth.Available);
                        }
                    });
                });
            });
        }

        model.getSearchAlternatives(function (data) {
            var months = [];
            $(data.Months).each(function () {
                var currentMonth = month(this.Month, this.Year, this.Name, this.Available, this.PriceFrom, model, inner, filterSearchAlternatives);
                months.push(currentMonth);
            });
            inner.months(months);

            $(data.Destinations).each(function () {
                inner.availableDestinations.push(destination(this.Name, this.Code, false, this.Available, filterSearchAlternatives));
            });

            $(data.Ships).each(function () {
                inner.availableShips.push(ship(this.Name, this.Code, this.ClassName, false, this.Available, filterSearchAlternatives));
            });

            $(data.Ports).each(function () {
                inner.availablePorts.push(port(this.Name, this.Code, this.GeoCode, false, this.Available, filterSearchAlternatives));
            });

            $(data.Lengths).each(function () {
                inner.availableCruiseLengths.push(cruiseLength(this.MinLength, this.MaxLength, this.Selected, this.Description));
            });

            filterSearchAlternatives();
        });

        return inner;
    };

    var cruisesViewModel = function (model, maxNumberOfSearchCriteriaOptionChars, translations) {
        var inner = {};

        inner.searchWithRedirect = function () {
            model.searchWithRedirect(inner.searchAlternatives.getCriteria());
        };

        inner.searchAlternatives = searchAlternatives(model, maxNumberOfSearchCriteriaOptionChars, translations, false);

        return inner;
    };

    var cruisesModel = function (translations) {
        var inner = {};

        inner.searchWithRedirect = function (criteria) {
            location.href = translations.secureDomain + "/Pages/BookingManager.aspx?" + criteria.getQuerystring();
        };

        inner.getSearchAlternatives = function (callback) {
            $.ajax({
                type: "POST",
                url: "/Webservices/CruiseResultService.asmx/GetSearchAlternatives",
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function (data) {
                    if (callback) {
                        callback(data.d);
                    }
                }
            });
        };

        inner.filterSearchAlternatives = function (criteria, currentPage, sortOption, callback) {
            $.ajax({
                type: "POST",
                url: "/Webservices/CruiseResultService.asmx/FilterSearchAlternatives",
                data: JSON.stringify(criteria.getSearchCriteria(currentPage, sortOption)),
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function (data) {
                    if (callback) {
                        callback(data.d);
                    }
                }
            });
        };

        return inner;
    };

    return { model: cruisesModel, viewModel: cruisesViewModel };
} ();
