package com.google.tripmeout.frontend.storage;

import com.google.tripmeout.frontend.TripModel;
import com.google.tripmeout.frontend.error.TripAlreadyExistsException;
import com.google.tripmeout.frontend.error.TripNotFoundException;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class InMemoryTripModelStorage {
  Map<String, TripModel> storage = new ConcurrentHashMap<>();

  public void addTrip(TripModel trip) throws TripAlreadyExistsException {
    if (storage.get(trip.id()) == null) {
      storage.put(trip.id(), trip);
    } else {
      throw new TripAlreadyExistsException("Trip with id: " + trip.id() + " already exisits");
    }
  }

  public void removeTrip(String tripId) throws TripNotFoundException {
    TripModel trip = storage.remove(tripId);
    if (trip == null) {
      throw new TripNotFoundException("Trip with id: " + tripId + " not found in storage");
    }
  }

  public void updateTripLocation(String tripId, double latitude, double longitude) 
      throws TripNotFoundException {
    TripModel trip = storage.get(tripId);
    if (trip == null) {
      throw new TripNotFoundException("Trip with id: " + tripId + " not found in storage");
    }
    TripModel updatedTrip = trip.toBuilder()
        .setLocationLat(latitude)
        .setLocationLong(longitude)
        .build();

    storage.put(tripId, updatedTrip);
  }

  public void updateTripName(String tripId, String name) throws TripNotFoundException {
    TripModel trip = storage.get(tripId);
    if (trip == null) {
      throw new TripNotFoundException("Trip with id: " + tripId + " not found in storage");
    }
    TripModel updatedTrip = trip.toBuilder()
        .setName(name)
        .build();

    storage.put(tripId, updatedTrip);
  }

  public TripModel getTrip(String tripId) throws TripNotFoundException {
    TripModel trip = storage.get(tripId);
    if (trip != null) {
      return trip;
    }
    throw new TripNotFoundException("Trip with id: " + tripId + " not found in storage");
  }

  public List<TripModel> getAllUserTrips(String userId) {
    List<TripModel> trips = new ArrayList<>();
    storage.forEach((tripId, trip) -> {
      if (userId.equals(trip.userId())) {
        trips.add(trip);
      }
    });
    return trips;
  }
}

@@ -520,24 +520,54 @@
 Exception %7B%0A
+    synchronized(storage) %7B%0A  
     if (stor
@@ -598,24 +598,26 @@
 ll) %7B%0A      
+  
 storage.put(
@@ -638,16 +638,18 @@
 p);%0A    
+ 
+ 
 %7D else %7B
@@ -649,16 +649,18 @@
  else %7B%0A
+  
       th
@@ -725,16 +725,29 @@
 .id() + 
+%0A            
 %22 alread
@@ -755,24 +755,32 @@
  exisits%22);%0A
+      %7D%0A
     %7D%0A  %7D%0A%0A 
@@ -976,32 +976,43 @@
 d: %22 + tripId + 
+%0A          
 %22 not found in s
@@ -1145,32 +1145,62 @@
 oundException %7B%0A
+    synchronized(storage) %7B%0A  
     TripModel tr
@@ -1217,32 +1217,34 @@
 ge.get(tripId);%0A
+  
     if (trip == 
@@ -1249,32 +1249,34 @@
 = null) %7B%0A      
+  
 throw new TripNo
@@ -1311,32 +1311,45 @@
 d: %22 + tripId + 
+%0A            
 %22 not found in s
@@ -1354,34 +1354,38 @@
  storage%22);%0A    
-%7D%0A
+  %7D%0A  
     TripModel up
@@ -1413,32 +1413,34 @@
 ilder()%0A        
+ 
+ 
 .setLocationLat(
@@ -1445,24 +1445,26 @@
 t(latitude)%0A
+  
         .set
@@ -1487,32 +1487,34 @@
 gitude)%0A        
+  
 .build();%0A%0A    s
@@ -1504,32 +1504,34 @@
  .build();%0A%0A    
+ 
+ 
 storage.put(trip
@@ -1540,32 +1540,38 @@
 , updatedTrip);%0A
+    %7D%0A
   %7D%0A%0A  public vo
@@ -1639,32 +1639,62 @@
 oundException %7B%0A
+    synchronized(storage) %7B%0A  
     TripModel tr
@@ -1715,32 +1715,34 @@
 et(tripId);%0A    
+  
 if (trip == null
@@ -1743,32 +1743,34 @@
 = null) %7B%0A      
+ 
+ 
 throw new TripNo
@@ -1805,32 +1805,45 @@
 d: %22 + tripId + 
+%0A            
 %22 not found in s
@@ -1856,22 +1856,26 @@
 %22);%0A    
+  
 %7D%0A    
+ 
+ 
 TripMode
@@ -1911,24 +1911,26 @@
 r()%0A        
+  
 .setName(nam
@@ -1932,32 +1932,34 @@
 e(name)%0A        
+  
 .build();%0A%0A    s
@@ -1953,24 +1953,26 @@
 ild();%0A%0A    
+ 
+ 
 storage.put(
@@ -1993,16 +1993,22 @@
 dTrip);%0A
+    %7D%0A
   %7D%0A%0A  p
@@ -2069,32 +2069,62 @@
 oundException %7B%0A
+    synchronized(storage) %7B%0A  
     TripModel tr
@@ -2145,32 +2145,34 @@
 et(tripId);%0A    
+  
 if (trip != null
@@ -2177,24 +2177,26 @@
 ll) %7B%0A      
+ 
+ 
 return trip;
@@ -2196,26 +2196,30 @@
 n trip;%0A    
-%7D%0A
+  %7D%0A  
     throw ne
@@ -2270,16 +2270,27 @@
 ripId + 
+%0A          
 %22 not fo
@@ -2307,16 +2307,23 @@
 rage%22);%0A
+    %7D %0A
   %7D%0A%0A  p

add synchronized blocks to storage implementation