<commit_before>package com.conveyal.analysis.models;

import com.conveyal.analysis.AnalysisServerException;
import com.conveyal.gtfs.GTFSFeed;
import com.conveyal.gtfs.error.GTFSError;
import com.fasterxml.jackson.annotation.JsonIgnore;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Represents a transport Bundle (GTFS and OSM).
 *
 * Previously the OSM was specified at the Region level, so every Bundle in the same Region used the same OSM data.
 *
 * All of the data is stored in S3, however some information is duplicated here for convenience.
 */
public class Bundle extends Model implements Cloneable {
    public String regionId;

    // Unique key that allows for linking new bundles to previously uploaded OSM.
    public String osmId;

    // Unique key that allows for linking new bundles to previously uploaded GTFS.
    public String feedGroupId;

    public double north;
    public double south;
    public double east;
    public double west;

    public LocalDate serviceStart;
    public LocalDate serviceEnd;

    public List<FeedSummary> feeds = new ArrayList<>();

    public Status status = Status.PROCESSING_OSM;
    public String statusText;

    public int feedsComplete;
    public int totalFeeds;

    public static String bundleScopeFeedId (String feedId, String feedGroupId) {
        return String.format("%s_%s", feedId, feedGroupId);
    }

    public Bundle clone () {
        try {
            return (Bundle) super.clone();
        } catch (CloneNotSupportedException e) {
            throw AnalysisServerException.unknown(e);
        }
    }

    /** Simplified model for storing the first N errors of each type in Mongo. */
    public static class GtfsErrorSummary {
        public String file;
        public Integer line;
        public String field;
        public String message;
        public GtfsErrorSummary () { /* For deserialization. */ }
        public GtfsErrorSummary (GTFSError error) {
            file = error.file;
            line = error.line > 0 ? (int)(error.line) : null;
            field = error.field;
            message = error.getMessage();
        }
    }

    /** Simplified model for storing the first N errors of each type in Mongo. */
    public static class GtfsErrorTypeSummary {
        public String type;
        public int count;
        public List<GtfsErrorSummary> someErrors = new ArrayList<>();
        public GtfsErrorTypeSummary () { /* For deserialization. */ }
        public GtfsErrorTypeSummary (String type) {
            this.type = type;
        }
    }

    /** Model for storing summany info in Mongo. Bundle contains one instance of FeedSummary per feed in the Bundle. */
    public static class FeedSummary implements Cloneable {
        public String feedId;
        public String name;
        public String originalFileName;
        public String fileName;

        /** The feed ID scoped with the bundle ID, for use as a unique identifier on S3 and in the GTFS API */
        public String bundleScopedFeedId;

        public LocalDate serviceStart;
        public LocalDate serviceEnd;
        public long checksum;
        public List<GtfsErrorTypeSummary> errors;

        /** Default empty constructor needed for JSON mapping. */
        public FeedSummary () { }

        public FeedSummary(GTFSFeed feed, String feedGroupId) {
            feedId = feed.feedId;
            bundleScopedFeedId = Bundle.bundleScopeFeedId(feed.feedId, feedGroupId);
            name = feed.agency.size() > 0 ? feed.agency.values().iterator().next().agency_name : feed.feedId;
            checksum = feed.checksum;
            setServiceDates(feed); // TODO expand to record hours per day by mode.
            summarizeErrors(feed);
        }<commit_msg>derive feed name from feedInfo and multiple agencies<commit_after>package com.conveyal.analysis.models;

import com.conveyal.analysis.AnalysisServerException;
import com.conveyal.gtfs.GTFSFeed;
import com.conveyal.gtfs.error.GTFSError;
import com.conveyal.gtfs.model.Agency;
import com.conveyal.gtfs.model.FeedInfo;
import com.fasterxml.jackson.annotation.JsonIgnore;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Represents a transport Bundle (GTFS and OSM).
 *
 * Previously the OSM was specified at the Region level, so every Bundle in the same Region used the same OSM data.
 *
 * All of the data is stored in S3, however some information is duplicated here for convenience.
 */
public class Bundle extends Model implements Cloneable {
    public String regionId;

    // Unique key that allows for linking new bundles to previously uploaded OSM.
    public String osmId;

    // Unique key that allows for linking new bundles to previously uploaded GTFS.
    public String feedGroupId;

    public double north;
    public double south;
    public double east;
    public double west;

    public LocalDate serviceStart;
    public LocalDate serviceEnd;

    public List<FeedSummary> feeds = new ArrayList<>();

    public Status status = Status.PROCESSING_OSM;
    public String statusText;

    public int feedsComplete;
    public int totalFeeds;

    public static String bundleScopeFeedId (String feedId, String feedGroupId) {
        return String.format("%s_%s", feedId, feedGroupId);
    }

    public Bundle clone () {
        try {
            return (Bundle) super.clone();
        } catch (CloneNotSupportedException e) {
            throw AnalysisServerException.unknown(e);
        }
    }

    /** Simplified model for storing the first N errors of each type in Mongo. */
    public static class GtfsErrorSummary {
        public String file;
        public Integer line;
        public String field;
        public String message;
        public GtfsErrorSummary () { /* For deserialization. */ }
        public GtfsErrorSummary (GTFSError error) {
            file = error.file;
            line = error.line > 0 ? (int)(error.line) : null;
            field = error.field;
            message = error.getMessage();
        }
    }

    /** Simplified model for storing the first N errors of each type in Mongo. */
    public static class GtfsErrorTypeSummary {
        public String type;
        public int count;
        public List<GtfsErrorSummary> someErrors = new ArrayList<>();
        public GtfsErrorTypeSummary () { /* For deserialization. */ }
        public GtfsErrorTypeSummary (String type) {
            this.type = type;
        }
    }

    /** Model for storing summany info in Mongo. Bundle contains one instance of FeedSummary per feed in the Bundle. */
    public static class FeedSummary implements Cloneable {
        public String feedId;
        public String name;
        public String originalFileName;
        public String fileName;

        /** The feed ID scoped with the bundle ID, for use as a unique identifier on S3 and in the GTFS API */
        public String bundleScopedFeedId;

        public LocalDate serviceStart;
        public LocalDate serviceEnd;
        public long checksum;
        public List<GtfsErrorTypeSummary> errors;

        /** Default empty constructor needed for JSON mapping. */
        public FeedSummary () { }

        public FeedSummary(GTFSFeed feed, String feedGroupId) {
            feedId = feed.feedId;
            bundleScopedFeedId = Bundle.bundleScopeFeedId(feed.feedId, feedGroupId);
            name = createFeedName(feed);
            checksum = feed.checksum;
            setServiceDates(feed); // TODO expand to record hours per day by mode.
            summarizeErrors(feed);
        }

        /** This seems to only be used for display purposes. */
        private static String createFeedName (GTFSFeed feed) {
            if (feed.feedInfo.size() == 1) {
                FeedInfo feedInfo = feed.feedInfo.values().iterator().next();
                String name = "";
                if (feedInfo.feed_id != null) {
                    name = feedInfo.feed_id;
                }
                if (feedInfo.feed_start_date != null) {
                    if (name.length() > 0) {
                        name += " starting ";
                    }
                    name += feedInfo.feed_start_date.toString(); // ISO-8601
                }
                if (name.length() > 0) {
                    return name;
                }
            }
            int nAgencies = feed.agency.size();
            if (nAgencies > 0) {
                final int limit = 3;
                String agencyNames = feed.agency.values().stream().limit(limit)
                        .map(a -> a.agency_name).collect(Collectors.joining(", "));
                if (nAgencies > limit) {
                    agencyNames += String.format(", +%d more", nAgencies - limit);
                }
                return agencyNames;
            }
            return "(unknown)";
        }
{'fraction_non_alphanumeric': 0.07971812376128606, 'fraction_numerical': 0.0017617264919621229, 'mean_word_length': 2.306516199490353, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5391842', 'n_tokens_mistral': 2439, 'n_tokens_neox': 2315, 'n_words': 804}