import { isTimestamp , now , days , inc , head , tail } from '@mds-core/mds-utils' ; import { UUID , CountMap , TripsStats , VEHICLE_EVENTS , VehicleEvent } from '@mds-core/mds-types' ; import cache from '@mds-core/mds-agency-cache' ; import logger from '@mds-core/mds-logger' ; export function asInt ( n ) { if ( n === undefined ) { return undefined ; } if ( typeof n === 'number' ) { return n ; } if ( typeof n === 'string' ) { return parseInt ( n ) ; } } export function startAndEnd ( params ) { const { start_time , end_time } = params ; const start_time_out = asInt ( start_time ) ; const end_time_out = asInt ( end_time ) ; if ( start_time_out !== undefined ) { if ( Number . isNaN ( start_time_out ) || ! isTimestamp ( start_time_out ) ) { throw new Error ( `invalid start_time ${ start_time }` ) ; } } if ( end_time_out !== undefined ) { if ( Number . isNaN ( end_time_out ) || ! isTimestamp ( end_time_out ) ) { throw new Error ( `invalid end_time ${ end_time }` ) ; } } if ( start_time_out !== undefined && end_time_out === undefined ) { if ( now ( ) - start_time_out > days ( 7 ) ) { throw new Error ( 'queries over 1 week not supported' ) ; } } if ( start_time_out !== undefined && end_time_out !== undefined ) { if ( end_time_out - start_time_out > days ( 7 ) ) { throw new Error ( 'queries over 1 week not supported' ) ; } } return { start_time : start_time_out , end_time : end_time_out } ; } export interface TripsData { [ s ] : { provider_id : UUID ; trip_id : UUID ; eventTypes : { [ n ] : string ; } ; } ; } export function categorizeTrips ( perTripId ) { const perProvider = { } ; Object . keys ( perTripId ) . map ( ( trip_id ) => { const trip = perTripId [ trip_id ] ; const pid = trip . provider_id ; perProvider [ pid ] = perProvider [ pid ] || { } ; const counts = { } ; const events = Object . keys ( trip . eventTypes ) . sort ( ) . map ( ( key ) => trip . eventTypes [ parseInt ( key ) ] ) ; if ( events . length === 1 ) { inc ( counts , 'single' ) ; perProvider [ pid ] . singles = perProvider [ pid ] . singles || { } ; inc ( perProvider [ pid ] . singles , head ( events ) ) ; } else if ( head ( events ) === VEHICLE_EVENTS . trip_start && tail ( events ) === VEHICLE_EVENTS . trip_end ) { inc ( counts , 'simple' ) ; } else if ( head ( events ) === VEHICLE_EVENTS . trip_start ) { if ( tail ( events ) === VEHICLE_EVENTS . trip_leave ) { inc ( counts , 'left' ) ; } else { inc ( counts , 'noEnd' ) ; } } else if ( tail ( events ) === VEHICLE_EVENTS . trip_end ) { if ( head ( events ) === VEHICLE_EVENTS . trip_enter ) { inc ( counts , 'entered' ) ; } else { inc ( counts , 'noStart' ) ; } } else if ( head ( events ) === VEHICLE_EVENTS . trip_enter && tail ( events ) === VEHICLE_EVENTS . trip_leave ) { inc ( counts , 'flyby' ) ; } else { inc ( counts , 'mystery' ) ; perProvider [ pid ] . mysteries = perProvider [ pid ] . mysteries || { } ; const key = events . map ( event => event . replace ( 'trip_' , '' ) ) . join ( '-' ) ; inc ( perProvider [ pid ] . mysteries , key ) ; perProvider [ pid ] . mystery_examples = perProvider [ pid ] . mystery_examples || { } ; perProvider [ pid ] . mystery_examples [ key ] = perProvider [ pid ] . mystery_examples [ key ] || [ ] ; if ( perProvider [ pid ] . mystery_examples [ key ] . length < 10 ) { perProvider [ pid ] . mystery_examples [ key ] . push ( trip_id ) ; } } Object . assign ( perProvider [ pid ] , counts ) ; } ) ; return perProvider ; } export async function getMaps ( ) { try { const events = await cache . readAllEvents ( ) ; logger . info ( 'read events' ) ; const eventSeed = { } ; const eventMap = events . reduce ( ( map , event ) => { return event ? Object . assign ( map , { [ event . device_id ] : event } ) : map ; } , eventSeed ) ; return Promise . resolve ( { eventMap } ) ; } catch ( err ) { return Promise . reject ( err ) ; } }