package com.conveyal.gtfs.model;

import com.google.common.collect.Maps;
import java.time.LocalDate;

import java.io.Serializable;
import java.util.Map;

/**
 * This table does not exist in GTFS. It is a join of calendars and calendar_dates on service_id.
 * There should only be one Calendar per service_id. There should only be one calendar_date per tuple of
 * (service_id, date), which means there can be many calendar_dates per service_id.
 */
public class Service implements Serializable {

    public String   service_id;
    public Calendar calendar;
    public Map<LocalDate, CalendarDate> calendar_dates = Maps.newHashMap();

    public Service(String service_id) {
        this.service_id = service_id;
    }

    /**
     * Is this service active on the specified date?
     * @param date
     * @return
     */
    public boolean activeOn (LocalDate date) {
        // first check for exceptions
        CalendarDate exception = calendar_dates.get(date);

        if (exception != null)
            return exception.exception_type == 1;

        else if (calendar == null)
            return false;

        else {
            int gtfsDate = date.getYear() * 10000 + date.getMonthValue() * 100 + date.getDayOfMonth();
            return calendar.end_date >= gtfsDate && calendar.start_date <= gtfsDate;
        }
    }
}

package com.conveyal.gtfs.model;

import com.google.common.collect.Maps;

import java.time.DayOfWeek;
import java.time.LocalDate;

import java.io.Serializable;
import java.util.Map;

/**
 * This table does not exist in GTFS. It is a join of calendars and calendar_dates on service_id.
 * There should only be one Calendar per service_id. There should only be one calendar_date per tuple of
 * (service_id, date), which means there can be many calendar_dates per service_id.
 */
public class Service implements Serializable {

    public String   service_id;
    public Calendar calendar;
    public Map<LocalDate, CalendarDate> calendar_dates = Maps.newHashMap();

    public Service(String service_id) {
        this.service_id = service_id;
    }

    /**
     * Is this service active on the specified date?
     * @param date
     * @return
     */
    public boolean activeOn (LocalDate date) {
        // first check for exceptions
        CalendarDate exception = calendar_dates.get(date);

        if (exception != null)
            return exception.exception_type == 1;

        else if (calendar == null)
            return false;

        else {
            int gtfsDate = date.getYear() * 10000 + date.getMonthValue() * 100 + date.getDayOfMonth();
            boolean withinValidityRange = calendar.end_date >= gtfsDate && calendar.start_date <= gtfsDate;

            if (!withinValidityRange) return false;

            switch (date.getDayOfWeek()) {
                case MONDAY:
                    return calendar.monday == 1;
                case TUESDAY:
                    return calendar.tuesday == 1;
                case WEDNESDAY:
                    return calendar.wednesday == 1;
                case THURSDAY:
                    return calendar.thursday == 1;
                case FRIDAY:
                    return calendar.friday == 1;
                case SATURDAY:
                    return calendar.saturday == 1;
                case SUNDAY:
                    return calendar.sunday == 1;
                default:
                    throw new IllegalArgumentException("unknown day of week constant!");
            }
        }
    }
}

fix #11 (service.activeOn returning false positives). also fixes conveyal/r5#107.