001package com.gigya.android.sdk.api;
002
003import android.support.annotation.Nullable;
004
005import com.gigya.android.sdk.GigyaLogger;
006import com.gigya.android.sdk.utils.ObjectUtils;
007import com.google.gson.Gson;
008
009import org.json.JSONException;
010import org.json.JSONObject;
011
012import java.util.Map;
013
014/**
015 * Gigya generic response class.
016 */
017public class GigyaApiResponse {
018
019    private static final String LOG_TAG = "GigyaApiResponse";
020
021    public static final int INVALID_VALUE = -1;
022    public static final int OK = 200;
023
024    private String json;
025    private Map<String, Object> mapped;
026
027    // GSON Support.
028    private Gson gson = new Gson();
029
030    public Gson getGson() {
031        return gson;
032    }
033
034    public GigyaApiResponse(String json) {
035        this.json = json;
036        try {
037            JSONObject jo = new JSONObject(json);
038            mapped = ObjectUtils.toMap(jo);
039            GigyaLogger.debug(LOG_TAG, "json mapped!");
040        } catch (JSONException e) {
041            e.printStackTrace();
042        }
043    }
044
045    /**
046     * Get JSON formatted of the current response.
047     *
048     * @return JSON formatted String.
049     */
050    public String asJson() {
051        return this.json;
052    }
053
054    /**
055     * Optional parsing of the current response with generic given type. Uses GSON as the parsing engine.
056     *
057     * @param clazz Requested type for parsing.
058     * @return Parsed hard copy class according to provided type.
059     */
060    @Nullable
061    public <T> T parseTo(Class<T> clazz) {
062        try {
063            return getGson().fromJson(asJson(), clazz);
064        } catch (Exception ex) {
065            ex.printStackTrace();
066        }
067        return null;
068    }
069
070    /**
071     * Check if response parameters contains a specific key.
072     *
073     * @param key Required key for evaluation.
074     * @return TRUE of key is present.
075     */
076    @SuppressWarnings("LoopStatementThatDoesntLoop")
077    public boolean contains(String key) {
078        return mapped.containsKey(key);
079    }
080
081    /**
082     * Check if response parameters contains a specific nested key.
083     * Nested key example: profile.firstName
084     *
085     * @param key Required key for evaluation.
086     * @return TRUE of nested key is present.
087     */
088    public boolean containsNested(String key) {
089        String[] split = key.split("\\.");
090        if (split.length == 1) {
091            return mapped.containsKey(key);
092        } else {
093            Map map = mapped;
094            for (int i = 0; i < split.length; i++) {
095                Object obj = map.get(split[i]);
096                if (obj == null) {
097                    return false;
098                }
099                if (obj instanceof Map) {
100                    map = (Map) obj;
101                } else if (i < split.length - 1) {
102                    return false;
103                }
104            }
105            return true;
106        }
107    }
108
109    /**
110     * Type field optional getter.
111     * Allows fetching an parsed object from response parameters given required type.
112     * Uses GSON as the parsing engine.
113     *
114     * @param key   Requested parameter key.
115     * @param clazz Required  parsed object type.
116     * @return Parsed hard copy class according to provided key and type.
117     */
118    @SuppressWarnings("unchecked")
119    @Nullable
120    public <T> T getField(String key, Class<T> clazz) {
121        String[] split = key.split("\\.");
122        if (split.length == 1) {
123            if (mapped.containsKey(key)) {
124                final String json = gson.toJson(mapped.get(key));
125                return gson.fromJson(json, clazz);
126            }
127        }
128        if (containsNested(key)) {
129            Map map = mapped;
130            Object obj = null;
131            for (int i = 0; i < split.length; i++) {
132                obj = map.get(split[i]);
133                if (i < split.length - 1) {
134                    map = (Map) obj;
135                }
136            }
137            if (obj == null) {
138                return null;
139            }
140            if (obj.getClass() == clazz) {
141                return (T) obj;
142            }
143        } else {
144            return null;
145        }
146        return null;
147    }
148
149    //region ROOT ELEMENT GETTERS
150
151    /**
152     * Get response status code
153     *
154     * @return Integer status code.
155     */
156    public int getStatusCode() {
157        try {
158            return (int) mapped.get("statusCode");
159        } catch (Exception ex) {
160            ex.printStackTrace();
161            return INVALID_VALUE;
162        }
163    }
164
165    /**
166     * Get response error code.
167     *
168     * @return Integer error code.
169     */
170    public int getErrorCode() {
171        try {
172            return (int) mapped.get("errorCode");
173        } catch (Exception ex) {
174            ex.printStackTrace();
175            return INVALID_VALUE;
176        }
177    }
178
179    /**
180     * Get response error details if exists.
181     *
182     * @return String error details.
183     */
184    @Nullable
185    public String getErrorDetails() {
186        if (mapped.containsKey("errorDetails")) {
187            return (String) mapped.get("errorDetails");
188        }
189        return null;
190    }
191
192    /**
193     * Get response status reason if exists.
194     *
195     * @return String status reason.
196     */
197    @Nullable
198    public String getStatusReason() {
199        if (mapped.containsKey("statusReason")) {
200            return (String) mapped.get("statusReason");
201        }
202        return null;
203    }
204
205    /**
206     * Get response callId.
207     *
208     * @return String callId.
209     */
210    @Nullable
211    public String getCallId() {
212        if (mapped.containsKey("callId")) {
213            return (String) mapped.get("callId");
214        }
215        return null;
216    }
217
218    /**
219     * Get response time.
220     *
221     * @return String formatted timestamp.
222     */
223    @Nullable
224    public String getTime() {
225        if (mapped.containsKey("time")) {
226            return (String) mapped.get("time");
227        }
228        return null;
229    }
230
231    //endregion
232}