"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const DepartureBoardMapper_1 = __importDefault(require("../../helpers/DepartureBoardMapper"));
const DepartureMode_1 = require("../../helpers/enums/DepartureMode");
const DepartureOrder_1 = require("../../helpers/enums/DepartureOrder");
const DepartureSkip_1 = require("../../helpers/enums/DepartureSkip");
const FilterHelper_1 = require("./FilterHelper");
const SkipHelper_1 = require("./SkipHelper");
class PIDDeparturesModel {
    constructor(departures, options) {
        this.toArray = () => {
            this.toArrayInternal();
            return DepartureBoardMapper_1.default.mapDepartures(this, this.options.timezone, this.options.mode);
        };
        this.toArrayInternal = (shouldIncludeDirections = true) => {
            this.skip();
            this.sort();
            this.filterAndLimit();
            this.sort();
            if (shouldIncludeDirections) {
                this.addDirections();
            }
        };
        /** Orders departures in special way by given options
         */
        this.filterAndLimit = () => {
            const finalDepartures = this.filterDepartures();
            if (FilterHelper_1.FilterHelper.isFillFilterType(this.options.filter)) {
                // return all once in limit and if still under limit fill it with others
                this.departures = finalDepartures.once
                    .slice(0, this.options.total)
                    .concat(finalDepartures.fill.slice(0, this.options.total - Math.min(finalDepartures.once.length, this.options.total)))
                    .slice(this.options.offset, this.options.offset + this.options.limit);
            }
            else {
                this.departures = finalDepartures.once
                    .slice(0, this.options.total)
                    .slice(this.options.offset, this.options.offset + this.options.limit);
            }
        };
        /** Skips departures by given options
         */
        this.skip = () => {
            this.departures = this.departures.filter((departure) => {
                if (this.options.skip.length === 0) {
                    return true;
                }
                let isSkipUntracked = false;
                let isSkipMissing = false;
                let isSkipCanceled = false;
                let isSkipAtStop = false;
                for (const skip of this.options.skip) {
                    if (skip === DepartureSkip_1.DepartureSkip.UNTRACKED) {
                        isSkipUntracked = true;
                    }
                    else if (skip === DepartureSkip_1.DepartureSkip.MISSING) {
                        isSkipMissing = true;
                    }
                    else if (skip === DepartureSkip_1.DepartureSkip.CANCELED) {
                        isSkipCanceled = true;
                    }
                    else if (skip === DepartureSkip_1.DepartureSkip.AT_STOP) {
                        isSkipAtStop = true;
                    }
                }
                return !((this.options.tripNumber && SkipHelper_1.SkipHelper.isMatchingTripNumber(departure, this.options.tripNumber)) ||
                    (isSkipUntracked && SkipHelper_1.SkipHelper.hasNoDelayInfo(departure)) ||
                    (!isSkipUntracked &&
                        isSkipMissing &&
                        SkipHelper_1.SkipHelper.isVehicleMissing(departure, this.options.runScheduleMap, this.options.untrackedTrips)) ||
                    (isSkipCanceled && SkipHelper_1.SkipHelper.isTripCanceled(departure)) ||
                    (isSkipAtStop && SkipHelper_1.SkipHelper.isVehicleAtStop(departure)));
            });
        };
        /** Sorts by proper datetime by given options
         */
        this.sort = () => {
            const datetimeToOrder = this.options.mode === DepartureMode_1.DepartureMode.ARRIVALS
                ? this.options.order === DepartureOrder_1.DepartureOrder.REAL
                    ? "arrival_datetime_real"
                    : "arrival_datetime"
                : this.options.order === DepartureOrder_1.DepartureOrder.REAL
                    ? "departure_datetime_real"
                    : "departure_datetime";
            this.departures = this.departures.sort((a, b) => a[datetimeToOrder].getTime() - b[datetimeToOrder].getTime());
        };
        /** Fills direction with proper value based on departure direction ruls
         */
        this.addDirections = () => {
            this.departures.forEach((departure) => {
                if (!("arrival_datetime" in departure)) {
                    return;
                }
                departure.direction = departure.direction || null;
                const thisStopDeparturesDirections = this.options.departuresDirections.filter((departuresDirection) => departuresDirection.departure_stop_id === departure.stop_id);
                if (thisStopDeparturesDirections.length > 0) {
                    for (const thisStopDeparturesDirection of thisStopDeparturesDirections) {
                        if (departure.stop_id === thisStopDeparturesDirection.departure_stop_id &&
                            departure.next_stop_id?.match(thisStopDeparturesDirection.next_stop_id_regexp)) {
                            departure.direction = thisStopDeparturesDirection.direction;
                        }
                    }
                }
            });
        };
        this.departures = departures;
        this.options = options;
    }
    processAndReturnTransfers() {
        this.toArrayInternal(false);
        // ITransferDeparture is a subset of IPIDDeparture
        return this.departures;
    }
    filterDepartures() {
        const filterCondition = PIDDeparturesModel.FilterConditionMap[this.options.filter];
        return filterCondition
            ? this.filterByCondition(filterCondition)
            : { once: this.departures, fill: [] };
    }
    filterByCondition(conditionFunction) {
        return this.departures.reduce((acc, currentDeparture) => {
            if (conditionFunction(acc, currentDeparture)) {
                acc.once.push(currentDeparture);
            }
            else {
                acc.fill.push(currentDeparture);
            }
            return acc;
        }, { once: [], fill: [] });
    }
}
PIDDeparturesModel.FilterConditionMap = {
    routeOnce: FilterHelper_1.FilterHelper.routeOnceCondition,
    routeOnceFill: FilterHelper_1.FilterHelper.routeOnceCondition,
    routeHeadingOnce: FilterHelper_1.FilterHelper.routeOnceHeadingCondition,
    routeHeadingOnceFill: FilterHelper_1.FilterHelper.routeOnceHeadingCondition,
    routeHeadingOnceNoGap: FilterHelper_1.FilterHelper.routeOnceHeadingNoGapCondition,
    routeHeadingOnceNoGapFill: FilterHelper_1.FilterHelper.routeOnceHeadingNoGapCondition,
    none: undefined,
};
exports.default = PIDDeparturesModel;
//# sourceMappingURL=PIDDepartureModel.js.map