content: package adder;
  
  import io.activej.crdt.primitives.CrdtMergable;
  import io.activej.serializer.BinaryInput;
  import io.activej.serializer.BinaryOutput;
  import io.activej.serializer.BinarySerializer;
  
  import java.util.HashMap;
  import java.util.Map;
  
  import static io.activej.serializer.BinarySerializers.*;
  
  public final class DetailedSumsCrdtState implements CrdtMergable<DetailedSumsCrdtState> {
  	public static final BinarySerializer<DetailedSumsCrdtState> SERIALIZER = new DetailedSumsCrdtState.Serializer();
  
  	private final Map<String, Float> sums;
  
  	public DetailedSumsCrdtState() {
  		this.sums = new HashMap<>();
  	}
  
  	public DetailedSumsCrdtState(Map<String, Float> sums) {
  		this.sums = new HashMap<>(sums);
  	}
  
  	public static DetailedSumsCrdtState of(String serverId, float sum) {
  		Map<String, Float> map = new HashMap<>();
  		map.put(serverId, sum);
  		return new DetailedSumsCrdtState(map);
  	}
  
  	public float getSumFor(String serverId) {
  		return sums.getOrDefault(serverId, 0f);
  	}
  
  	public float getSumExcept(String serverId) {
  		float sum = 0;
  		for (Map.Entry<String, Float> entry : sums.entrySet()) {
  			if (entry.getKey().equals(serverId)) continue;
  			sum += entry.getValue();
  		}
  		return sum;
  	}
  
  	public float getSum() {
  		return (float) sums.values().stream()
  			.mapToDouble(Float::doubleValue)
  			.sum();
  	}
  
  	@Override
  	public DetailedSumsCrdtState merge(DetailedSumsCrdtState other) {
  		DetailedSumsCrdtState newState = new DetailedSumsCrdtState();
  		newState.sums.putAll(this.sums);
  
  		other.sums.forEach((serverId, delta) -> newState.sums.merge(serverId, delta, Math::max));
  
  		return newState;
  	}
  
  	private static class Serializer implements BinarySerializer<DetailedSumsCrdtState> {
  		private static final BinarySerializer<Map<String, Float>> MAP_SERIALIZER = ofMap(ISO_88591_SERIALIZER, FLOAT_SERIALIZER);
  
  		@Override
  		public void encode(BinaryOutput out, DetailedSumsCrdtState item) {
  			MAP_SERIALIZER.encode(out, item.sums);
  		}
  
  		@Override
  		public DetailedSumsCrdtState decode(BinaryInput in) {
  			return new DetailedSumsCrdtState(MAP_SERIALIZER.decode(in));
  		}
  	}
  }
  