summaryrefslogtreecommitdiff
path: root/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/CompositeStops.java
blob: 7e2ce94fe1db867ba6b69998027438b975b5ff0e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package com.mapbox.mapboxsdk.style.functions.stops;

import android.support.annotation.Keep;
import android.support.annotation.NonNull;
import android.support.annotation.Size;

import com.mapbox.mapboxsdk.style.functions.stops.Stop.CompositeValue;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * The {@link Stops} implementation for composite functions
 *
 * @param <Z> the zoom type (usually Float)
 * @param <I> the input type (the feature property type)
 * @param <O> the output type (the property type)
 * @param <S> the {@link Stops} implementation (eg CategoricalStops, {@link ExponentialStops} or {@link IntervalStops})
 */
public class CompositeStops<Z extends Number, I, O, S extends IterableStops<I, O, Stop<I, O>>>
  extends IterableStops<CompositeValue<Z, I>, O, Map.Entry<Z, S>> {

  private final Map<Z, S> stops;

  /**
   * JNI Constructor
   *
   * @param stops the stops {@link Map}
   */
  @Keep
  private CompositeStops(@NonNull @Size(min = 1) Map<Z, S> stops) {
    this.stops = stops;
  }

  /**
   * Create composite stops for {@link ExponentialStops}. Use
   * {@link com.mapbox.mapboxsdk.style.functions.Function#composite(String, ExponentialStops)}
   *
   * @param stops the stops
   */
  public CompositeStops(@NonNull ExponentialStops<Stop.CompositeValue<Z, I>, O> stops) {
    this.stops = new HashMap<>();

    for (Map.Entry<Z, List<Stop<I, O>>> entry : collect(stops).entrySet()) {
      // noinspection unchecked
      this.stops.put(entry.getKey(),
        (S) new ExponentialStops<>(stops.getBase(), entry.getValue().toArray(new Stop[0])));
    }
  }

  /**
   * Create composite stops for {@link IntervalStops}.
   * Use {@link com.mapbox.mapboxsdk.style.functions.Function#composite(String, IntervalStops)}
   *
   * @param stops the stops
   */
  public CompositeStops(@NonNull IntervalStops<Stop.CompositeValue<Z, I>, O> stops) {
    this.stops = new HashMap<>();

    for (Map.Entry<Z, List<Stop<I, O>>> entry : collect(stops).entrySet()) {
      // noinspection unchecked
      this.stops.put(entry.getKey(), (S) new IntervalStops<>(entry.getValue().toArray(new Stop[0])));
    }
  }

  /**
   * Create composite stops for {@link CategoricalStops}.
   * Use {@link com.mapbox.mapboxsdk.style.functions.Function#composite(String, CategoricalStops)}
   *
   * @param stops the stops
   */
  public CompositeStops(@NonNull CategoricalStops<CompositeValue<Z, I>, O> stops) {
    this.stops = new HashMap<>();

    for (Map.Entry<Z, List<Stop<I, O>>> entry : collect(stops).entrySet()) {
      // noinspection unchecked
      this.stops.put(entry.getKey(), (S) new CategoricalStops<>(entry.getValue().toArray(new Stop[0])));
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  protected String getTypeName() {
    return stops.values().iterator().next().getTypeName();
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public Map<String, Object> toValueObject() {
    Map<String, Object> map = super.toValueObject();

    // Flatten and toValueObjects stops
    // noinspection unchecked
    map.put("stops", toValueObjects(flatten(this.stops).toArray(new Stop[0])));

    return map;
  }

  @NonNull
  private List<Stop<CompositeValue<Z, I>, O>> flatten(Map<Z, S> stops) {
    List<Stop<CompositeValue<Z, I>, O>> flattenedStops = new ArrayList<>();
    for (Map.Entry<Z, S> entry : stops.entrySet()) {
      for (Stop<I, O> stop : entry.getValue()) {
        flattenedStops.add(new Stop<>(new CompositeValue<>(entry.getKey(), stop.in), stop.out));
      }
    }
    return flattenedStops;
  }

  @NonNull
  private Map<Z, List<Stop<I, O>>> collect(
    @NonNull IterableStops<CompositeValue<Z, I>, O, Stop<CompositeValue<Z, I>, O>> stops) {
    Map<Z, List<Stop<I, O>>> converted = new HashMap<>();

    for (Stop<CompositeValue<Z, I>, O> stop : stops) {
      List<Stop<I, O>> stopsForZ = converted.get(stop.in.zoom);
      if (stopsForZ == null) {
        stopsForZ = new ArrayList<>();
        converted.put(stop.in.zoom, stopsForZ);
      }

      stopsForZ.add(new Stop<>(stop.in.value, stop.out));
    }

    return converted;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public Iterator<Map.Entry<Z, S>> iterator() {
    return stops.entrySet().iterator();
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public int size() {
    return stops.size();
  }

}