/*
 * Copyright 2021 MobilityData IO
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.mobilitydata.gtfsvalidator.validator;

import java.util.HashMap;
import java.util.Map;
import javax.inject.Inject;
import org.mobilitydata.gtfsvalidator.annotation.GtfsValidator;
import org.mobilitydata.gtfsvalidator.notice.DuplicateFareRuleZoneIdFieldsNotice;
import org.mobilitydata.gtfsvalidator.notice.NoticeContainer;
import org.mobilitydata.gtfsvalidator.table.GtfsFareRule;
import org.mobilitydata.gtfsvalidator.table.GtfsFareRuleTableContainer;

/**
 * Validates: unique combination of `fare_rules.route_id`, `fare_rules.origin_id`,
 * `fare_rules.contains_id` and `fare_rules.destination_id` fields in GTFS file `fare_rules.txt`
 *
 * <p>Generated notice:
 *
 * <ul>
 *   <li>{@link DuplicateFareRuleZoneIdFieldsNotice}
 * </ul>
 */
@GtfsValidator
public class DuplicateFareRuleZoneIdFieldsValidator extends FileValidator {
  @Inject GtfsFareRuleTableContainer fareRuleTable;

  @Override
  public void validate(NoticeContainer noticeContainer) {
    final Map<String, GtfsFareRule> fareRuleByZoneIdFieldsCombination =
        new HashMap<>(fareRuleTable.entityCount());
    fareRuleTable
        .getEntities()
        .forEach(
            fareRule -> {
              String fieldsCombination =
                  fareRule.routeId()
                      + fareRule.originId()
                      + fareRule.containsId()
                      + fareRule.destinationId();
              if (fareRuleByZoneIdFieldsCombination.containsKey(fieldsCombination)) {
                noticeContainer.addValidationNotice(
                    new DuplicateFareRuleZoneIdFieldsNotice(
                        fareRule.csvRowNumber(),
                        fareRule.fareId(),
                        fareRuleByZoneIdFieldsCombination.get(fieldsCombination).csvRowNumber(),
                        fareRuleByZoneIdFieldsCombination.get(fieldsCombination).fareId()));
              } else {
                fareRuleByZoneIdFieldsCombination.put(fieldsCombination, fareRule);
              }
            });
  }
}

@@ -684,24 +684,50 @@
 a.util.Map;%0A
+import java.util.Objects;%0A
 import javax
@@ -1121,17 +1121,17 @@
 tion of 
-%60
+%22
 fare_rul
@@ -1145,12 +1145,12 @@
 e_id
-%60, %60
+%22, %22
 fare
@@ -1169,15 +1169,15 @@
 n_id
-%60
+%22
 ,%0A * 
-%60
+%22
 fare
@@ -1198,15 +1198,15 @@
 s_id
-%60
+%22
  and 
-%60
+%22
 fare
@@ -1226,17 +1226,17 @@
 ation_id
-%60
+%22
  fields 
@@ -1248,17 +1248,17 @@
 FS file 
-%60
+%22
 fare_rul
@@ -1267,9 +1267,9 @@
 .txt
-%60
+%22
 %0A *%0A
@@ -1597,22 +1597,23 @@
 nal Map%3C
-String
+Integer
 , GtfsFa
@@ -1811,32 +1811,34 @@
     
-String fieldsCombination
+GtfsFareRule otherFareRule
  =%0A 
@@ -1866,156 +1866,73 @@
 Rule
-.routeId()%0A                      + fareRule.originId()%0A                      + fareRule.containsId()%0A                      + fareRule.destinationId(
+ByZoneIdFieldsCombination.putIfAbsent(getHash(fareRule), fareRule
 );%0A 
@@ -1952,72 +1952,29 @@
 if (
-f
+otherF
 areRule
-ByZoneIdFieldsCombination.containsKey(fieldsCombination)
+ != null
 ) %7B%0A
@@ -2207,64 +2207,21 @@
     
-f
+otherF
 areRule
-ByZoneIdFieldsCombination.get(fieldsCombination)
 .csv
@@ -2261,213 +2261,588 @@
     
-f
+otherF
 areRule
-ByZoneIdFieldsCombination.get(fieldsCombination).fareId()));%0A              %7D else %7B%0A                
+.fareId()));%0A              %7D%0A            %7D);%0A  %7D%0A%0A  /**%0A   * Returns the hashcode associated to the combination of %22
 fare
-RuleByZoneIdFieldsCombination.put(fieldsCombination, fareRule);%0A 
+_rules.origin_id%22,%0A   * %22fare_rules.contains_id%22 and %22fare_rules.destination_id%22.%0A   *%0A   * @param fareRule the %7B@code GtfsFareRule%7D to generate the hash from%0A   * @return the hashcode associated to the combination of this %7B@code GtfsFareRule%7D %22origin_id%22,%0A
    
+*
      
-     %7D%0A            %7D
+%22contains_id%22 and %22destination_id%22.%0A   */%0A  private int getHash(GtfsFareRule fareRule) %7B%0A    return Objects.hash(fareRule.originId(), fareRule.containsId(), fareRule.destinationId()
 );%0A 

improve efficiency of DuplicateFareRuleZoneIdFieldsValidator (#811)