"use strict";
/**
 * Router /WEB LAYER/: maps routes to specific controller functions, passes request parameters and handles responses.
 * Handles web logic (http request, response). Sets response headers, handles error responses.
 */
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.v2GtfsRouter = exports.V2GTFSRouter = void 0;
const ParamValidatorManager_1 = require("../../../pid/helpers/ParamValidatorManager");
const models_1 = require("../../models");
const shared_1 = require("../../../shared");
const constants_1 = require("../../../shared/constants");
const AbstractRouter_1 = require("@golemio/core/dist/helpers/routing/AbstractRouter");
const Geo_1 = require("@golemio/core/dist/output-gateway/Geo");
const Validation_1 = require("@golemio/core/dist/output-gateway/Validation");
const ioc_1 = require("@golemio/core/dist/output-gateway/ioc");
const express_1 = require("@golemio/core/dist/shared/express");
const express_validator_1 = require("@golemio/core/dist/shared/express-validator");
const golemio_errors_1 = require("@golemio/core/dist/shared/golemio-errors");
const moment_timezone_1 = __importDefault(require("@golemio/core/dist/shared/moment-timezone"));
class V2GTFSRouter extends AbstractRouter_1.AbstractRouter {
    constructor() {
        super(constants_1.RouteVersion.v2, "gtfs");
        // Assign router to the express.Router() instance
        this.router = (0, express_1.Router)();
        // Reg-ex to match a valid daytime format (ex. 21:43:56)
        this.timeRegex = /(([0-1][0-9])|(2[0-3])):[0-5][0-9]:[0-5][0-9]/;
        this.tripInclusions = [
            (0, express_validator_1.query)("includeShapes").optional().isBoolean().not().isArray(),
            (0, express_validator_1.query)("includeStops").optional().isBoolean().not().isArray(),
            (0, express_validator_1.query)("includeStopTimes").optional().isBoolean().not().isArray(),
            (0, express_validator_1.query)("includeService").optional().isBoolean().not().isArray(),
            (0, express_validator_1.query)("includeRoute").optional().isBoolean().not().isArray(),
            (0, express_validator_1.query)("date").optional().isISO8601().custom(ParamValidatorManager_1.ParamValidatorManager.getDateValidator()).not().isArray(),
        ];
        this.stopTimesHandlers = [
            (0, express_validator_1.param)("stopId").exists().not().isArray(),
            (0, express_validator_1.query)("from").optional().matches(this.timeRegex).not().isArray(),
            (0, express_validator_1.query)("to").optional().matches(this.timeRegex).not().isArray(),
            (0, express_validator_1.query)("date").optional().isISO8601().custom(ParamValidatorManager_1.ParamValidatorManager.getDateValidator()).not().isArray(),
            (0, express_validator_1.query)("includeStop").optional().isBoolean().not().isArray(),
        ];
        this.GetAllServices = async (req, res, next) => {
            try {
                const queryData = (0, express_validator_1.matchedData)(req);
                const data = await this.serviceModel.GetAll({
                    date: queryData.date || undefined,
                    limit: Number(queryData.limit) || undefined,
                    offset: Number(queryData.offset) || undefined,
                });
                res.status(200).send(data);
            }
            catch (err) {
                next(err);
            }
        };
        this.GetAllStopTimes = async (req, res, next) => {
            try {
                const queryData = (0, express_validator_1.matchedData)(req);
                const data = await this.stopTimeModel.GetAll({
                    date: queryData.date || undefined,
                    from: queryData.from || undefined,
                    limit: Number(queryData.limit) || undefined,
                    offset: Number(queryData.offset) || undefined,
                    stop: !!queryData.includeStop,
                    stopId: req.params.stopId,
                    to: queryData.to || undefined,
                });
                res.status(200).send(data);
            }
            catch (err) {
                next(err);
            }
        };
        this.GetAllTrips = async (req, res, next) => {
            try {
                const queryData = (0, express_validator_1.matchedData)(req);
                const data = await this.tripModel.GetAll({
                    date: queryData.date || undefined,
                    limit: Number(queryData.limit) || undefined,
                    offset: Number(queryData.offset) || undefined,
                    stopId: queryData.stopId,
                });
                res.status(200).send(data);
            }
            catch (err) {
                next(err);
            }
        };
        this.GetOneTrip = async (req, res, next) => {
            try {
                const queryData = (0, express_validator_1.matchedData)(req);
                const id = req.params.id;
                const data = await this.tripModel.GetOne(id, {
                    date: queryData.date || undefined,
                    route: !!queryData.includeRoute,
                    service: !!queryData.includeService,
                    shapes: !!queryData.includeShapes,
                    stopTimes: !!queryData.includeStopTimes,
                    stops: !!queryData.includeStops,
                });
                if (!data) {
                    throw new golemio_errors_1.GeneralError("not_found", "GTFSRouter", undefined, 404);
                }
                res.status(200).send(data);
            }
            catch (err) {
                next(err);
            }
        };
        this.GetAllStops = async (req, res, next) => {
            const queryData = (0, express_validator_1.matchedData)(req);
            const names = shared_1.RopidRouterUtils.convertParamToArray(queryData.names);
            const aswIds = shared_1.RopidRouterUtils.convertParamToArray(queryData.aswIds);
            const cisIds = shared_1.RopidRouterUtils.convertParamToArray(queryData.cisIds);
            const gtfsIds = shared_1.RopidRouterUtils.convertParamToArray(queryData.ids);
            try {
                const coords = await (0, Geo_1.parseCoordinates)(queryData.latlng, queryData.range);
                const data = await this.stopModel.GetAll({
                    aswIds,
                    cisIds,
                    gtfsIds,
                    lat: coords.lat,
                    limit: Number(queryData.limit) || undefined,
                    lng: coords.lng,
                    names,
                    offset: Number(queryData.offset) || undefined,
                    range: coords.range,
                });
                res.status(200).send(data);
            }
            catch (err) {
                next(err);
            }
        };
        this.GetOneStop = async (req, res, next) => {
            try {
                const id = req.params.id;
                const data = await this.stopModel.GetOne(id);
                if (!data) {
                    throw new golemio_errors_1.GeneralError("not_found", "GTFSRouter", undefined, 404);
                }
                res.status(200).send(data);
            }
            catch (err) {
                next(err);
            }
        };
        this.GetAllRoutes = async (req, res, next) => {
            try {
                const queryData = (0, express_validator_1.matchedData)(req);
                const data = await this.routeModel.GetAll({
                    limit: Number(queryData.limit) || undefined,
                    offset: Number(queryData.offset) || undefined,
                });
                res.status(200).send(data);
            }
            catch (err) {
                next(err);
            }
        };
        this.GetOneRoute = async (req, res, next) => {
            try {
                const id = req.params.id;
                const data = await this.routeModel.GetOne(id);
                if (!data) {
                    throw new golemio_errors_1.GeneralError("not_found", "GTFSRouter", undefined, 404);
                }
                res.status(200).send(data);
            }
            catch (err) {
                next(err);
            }
        };
        this.GetAllShapes = async (req, res, next) => {
            try {
                const queryData = (0, express_validator_1.matchedData)(req);
                const data = await this.shapeModel.GetAll({
                    id: req.params.id,
                    limit: Number(queryData.limit) || undefined,
                    offset: Number(queryData.offset) || undefined,
                });
                if (!data) {
                    throw new golemio_errors_1.GeneralError("not_found", "GTFSRouter", undefined, 404);
                }
                res.status(200).send(data);
            }
            catch (err) {
                next(err);
            }
        };
        /**
         * Initiates all routes. Should respond with correct data to a HTTP requests to all routes.
         */
        this.initRoutes = () => {
            const maxAge = 4 * 60 * 60; // 4 hours
            const staleWhileRevalidate = 60; // 1 minute
            this.initTripsEndpoints(maxAge, staleWhileRevalidate);
            this.initStopsEndpoints(maxAge, staleWhileRevalidate);
            this.initStopTimesEndpoints(maxAge, staleWhileRevalidate);
            this.initRoutesEndpoints(maxAge, staleWhileRevalidate);
            this.initShapesEndpoints(maxAge, staleWhileRevalidate);
            this.initServicesEndpoints(maxAge, staleWhileRevalidate);
        };
        this.initRoutesEndpoints = (maxAge, staleWhileRevalidate) => {
            this.router.get("/routes", (0, Validation_1.paginationLimitMiddleware)("GTFSRouter"), Validation_1.checkErrors, this.cacheHeaderMiddleware.getMiddleware(maxAge, staleWhileRevalidate), this.GetAllRoutes);
            this.router.get("/routes/:id", (0, express_validator_1.param)("id").exists(), Validation_1.checkErrors, this.cacheHeaderMiddleware.getMiddleware(maxAge, staleWhileRevalidate), this.GetOneRoute);
        };
        this.initServicesEndpoints = (maxAge, staleWhileRevalidate) => {
            this.router.get("/services", (0, express_validator_1.query)("date").optional().isISO8601().custom(ParamValidatorManager_1.ParamValidatorManager.getDateValidator()).not().isArray(), (0, Validation_1.paginationLimitMiddleware)("GTFSRouter"), Validation_1.checkErrors, this.cacheHeaderMiddleware.getMiddleware(maxAge, staleWhileRevalidate), this.GetAllServices);
        };
        this.initShapesEndpoints = (maxAge, staleWhileRevalidate) => {
            this.router.get("/shapes/:id", (0, Validation_1.paginationLimitMiddleware)("GTFSRouter"), Validation_1.checkErrors, (0, express_validator_1.param)("id").exists(), this.cacheHeaderMiddleware.getMiddleware(maxAge, staleWhileRevalidate), this.GetAllShapes);
        };
        this.initTripsEndpoints = (maxAge, staleWhileRevalidate) => {
            this.router.get("/trips", (0, express_validator_1.query)("stopId").optional().not().isArray(), this.tripInclusions, (0, Validation_1.paginationLimitMiddleware)("GTFSRouter"), Validation_1.checkErrors, this.cacheHeaderMiddleware.getMiddleware(maxAge, staleWhileRevalidate), this.GetAllTrips);
            this.router.get("/trips/:id", (0, express_validator_1.param)("id").exists(), this.tripInclusions, Validation_1.checkErrors, this.cacheHeaderMiddleware.getMiddleware(maxAge, staleWhileRevalidate), this.GetOneTrip);
        };
        this.initStopsEndpoints = (maxAge, staleWhileRevalidate) => {
            this.router.get("/stops", [
                (0, express_validator_1.query)("latlng").optional().isLatLong().not().isArray(),
                (0, express_validator_1.query)("range").optional().isNumeric().not().isArray(),
                (0, express_validator_1.query)("names").optional().not().isEmpty({ ignore_whitespace: true }),
                (0, express_validator_1.query)("aswIds").optional().not().isEmpty({ ignore_whitespace: true }),
                (0, express_validator_1.query)("cisIds").optional().isInt(),
                (0, express_validator_1.query)("ids").optional().not().isEmpty({ ignore_whitespace: true }),
            ], (0, Validation_1.paginationLimitMiddleware)("GTFSRouter"), Validation_1.checkErrors, this.cacheHeaderMiddleware.getMiddleware(maxAge, staleWhileRevalidate), this.GetAllStops);
            this.router.get("/stops/:id", [(0, express_validator_1.param)("id").exists()], Validation_1.checkErrors, this.cacheHeaderMiddleware.getMiddleware(maxAge, staleWhileRevalidate), this.GetOneStop);
        };
        this.initStopTimesEndpoints = (maxAge, staleWhileRevalidate) => {
            this.router.get("/stoptimes/:stopId", this.stopTimesHandlers, (0, Validation_1.paginationLimitMiddleware)("GTFSRouter"), Validation_1.checkErrors, (req, res, next) => {
                const queryData = (0, express_validator_1.matchedData)(req);
                if (queryData.from &&
                    queryData.to &&
                    (0, moment_timezone_1.default)(queryData.from, "H:mm:ss").isAfter((0, moment_timezone_1.default)(queryData.to, "H:mm:ss"))) {
                    throw new golemio_errors_1.GeneralError("Validation error", "GTFSRouter", new Error("'to' cannot be later than 'from'"), 400);
                }
                return next();
            }, this.cacheHeaderMiddleware.getMiddleware(maxAge, staleWhileRevalidate), this.GetAllStopTimes);
        };
        this.cacheHeaderMiddleware = ioc_1.OutputGatewayContainer.resolve(ioc_1.ContainerToken.CacheHeaderMiddleware);
        this.tripModel = models_1.models.GTFSTripsModel;
        this.stopModel = models_1.models.GTFSStopModel;
        this.stopTimeModel = models_1.models.GTFSStopTimesModel;
        this.routeModel = models_1.models.GTFSRoutesModel;
        this.shapeModel = models_1.models.GTFSShapesModel;
        this.serviceModel = models_1.models.GTFSCalendarModel;
        this.initRoutes();
    }
}
exports.V2GTFSRouter = V2GTFSRouter;
const v2GtfsRouter = new V2GTFSRouter();
exports.v2GtfsRouter = v2GtfsRouter;
//# sourceMappingURL=V2GTFSRouter.js.map