/**
* Copyright 2014-present Liquid Data Intelligence S.A.
*
* 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 io.lqd.sdk.model;
import android.content.Context;
import android.content.SharedPreferences;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
import io.lqd.sdk.LQLog;
import io.lqd.sdk.LiquidTools;
public abstract class LQModel implements Serializable {
private static final long serialVersionUID = 1L;
private static final String PREF_FILE_NAME = "LQPrefs";
/**
* Generate a random unique id
* @return
*/
public static String newIdentifier() {
String uid = UUID.randomUUID().toString().toUpperCase(Locale.ENGLISH);
String epoch = LiquidTools.tenCharEpoch(Calendar.getInstance().getTimeInMillis());
return uid + "-" + epoch;
}
/*
* *******************
* Attributes Assertion
* *******************
*/
/**
* Check if the key have invalid chars: { $ . \0 } are the invalid attributes
* @param key key that will be checked
* @param raiseException if true will raise IllegalArgumentException, otherwise will Log
* @return true if the key is valid, false otherwise
*/
public static boolean validKey(String key, boolean raiseException) {
boolean isValid = (!key.contains("$") && !key.contains(".") && !key.contains("\0"));
if(!isValid) {
LiquidTools.exceptionOrLog(raiseException, "Key: (" + key + ") contains invalid chars: (. $ \\0)");
}
return isValid;
}
/**
* Check if the attribute type is valid: {null, String, Number, Boolean, Date} are the valid attributes
* @param attribute attribute that will be checked
* @param raiseException if true will raise IllegalArgumentException, otherwise will Log
* @return true if the attribute is valid, false otherwise
*/
public static boolean validValue(Object attribute, boolean raiseException) {
boolean isValid = ((attribute == null) || (attribute instanceof String) ||
(attribute instanceof Number) || (attribute instanceof Boolean) ||
(attribute instanceof Date));
if(!isValid) {
LiquidTools.exceptionOrLog(raiseException, "Value (" + attribute + ") with unsupported type. Supported: (String, Number, Boolean, Date)");
}
return isValid;
}
public static HashMap<String, Object> sanitizeAttributes(Map<String, Object> attributes, boolean raiseException) {
if (attributes == null) {
return null;
}
HashMap<String, Object> attrs = new HashMap<String, Object>();
for (String key : attributes.keySet()) {
if (LQModel.validKey(key, raiseException) && LQModel.validValue(attributes.get(key), raiseException)) {
attrs.put(key, attributes.get(key));
}
}
return attrs;
}
public void save(Context context, String path) {
String serializedObject = toJSON().toString();
SharedPreferences preferences = context.getSharedPreferences(PREF_FILE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor prefsEditor = preferences.edit();
String[] split = path.split("\\.");
prefsEditor.putString(split[1], serializedObject);
LQLog.infoVerbose("Saving " + split[1] + " to shared prefs");
prefsEditor.apply();
}
public static JSONObject retriveFromFile(Context context, String path) {
String retrivedData;
SharedPreferences preferences = context.getSharedPreferences(PREF_FILE_NAME, Context.MODE_PRIVATE);
String[] split = path.split("\\.");
retrivedData = preferences.getString(split[1], "");
try {
return new JSONObject(retrivedData);
} catch (JSONException e) {
LQLog.infoVerbose("Couldn't retrieve " + split[1] + " from file, probably new user");
}
return new JSONObject();
}
protected static HashMap<String, Object> attributesFromJSON(JSONObject object, String[] excludedKeys) {
HashMap<String, Object> hashMap = new HashMap<>();
if(object != JSONObject.NULL)
hashMap = toHashMap(object, excludedKeys);
return hashMap;
}
private static HashMap<String, Object> toHashMap(JSONObject object, String[] excludedKeys) {
HashMap<String, Object> hashmap = new HashMap<>();
Iterator<String> keysItr = object.keys();
while(keysItr.hasNext()) {
String key = keysItr.next();
if (!Arrays.asList(excludedKeys).contains(key)) {
Object value = null;
try {
value = object.get(key);
} catch (JSONException e) {
e.printStackTrace();
}
if (value instanceof JSONArray) {
value = toList((JSONArray) value, excludedKeys);
} else if (value instanceof JSONObject) {
value = toHashMap((JSONObject) value, excludedKeys);
}
hashmap.put(key, value);
}
}
return hashmap;
}
public static List<Object> toList(JSONArray array, String[] excludedKeys) {
List<Object> list = new ArrayList<>();
for(int i = 0; i < array.length(); i++) {
Object value = null;
try {
value = array.get(i);
} catch (JSONException e) {
e.printStackTrace();
}
if(value instanceof JSONArray) {
value = toList((JSONArray) value, excludedKeys);
}
else if(value instanceof JSONObject) {
value = toHashMap((JSONObject) value, excludedKeys);
}
list.add(value);
}
return list;
}
public abstract JSONObject toJSON();
}