package net.osmand.plus.osmo;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import net.osmand.Location;
import net.osmand.data.LatLon;
import net.osmand.plus.OsmandSettings.OsmandPreference;
import net.osmand.plus.R;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.Context;
import android.graphics.Color;
public class OsMoGroupsStorage {
private static final String GROUPS = "groups";
private static final String USERS = "users";
private static final String TRACKS = "tracks";
private static final String SERVER_NAME = "serverName";
private static final String GROUP_ID = "group_id";
private static final String TRACKER_ID = "trackerId";
private static final String USER_NAME = "userName";
private static final String USER_COLOR = "userSetColor";
private static final String GEN_COLOR = "genColor";
private static final String SERVER_COLOR = "serverColor";
private static final String DESCRIPTION = "description";
private static final String POLICY = "policy";
private static final String NAME = "name";
private static final String ENABLED = "enabled";
private static final String EXPIRE_TIME = "expireTime";
private static final String DELETED = "deleted";
private OsmandPreference<String> pref;
private OsMoGroups service;
private ConcurrentHashMap<String, OsMoGroup> groups = new ConcurrentHashMap<String, OsMoGroup>();
public OsMoGroupsStorage(OsMoGroups service, OsmandPreference<String> pref) {
this.service = service;
this.pref = pref;
}
public Collection<OsMoGroup> getGroups() {
return groups.values();
}
public void load() {
String grp = pref.get();
try {
JSONObject obj = new JSONObject(grp);
if(!obj.has(GROUPS)) {
return;
}
JSONArray groups = obj.getJSONArray(GROUPS);
for (int i = 0; i < groups.length(); i++) {
JSONObject o = (JSONObject) groups.get(i);
OsMoGroup group = new OsMoGroup();
group.groupId = o.getString(GROUP_ID);
if(o.has(NAME)) {
group.name = o.getString(NAME);
}
if(o.has(EXPIRE_TIME)) {
group.expireTime = o.getLong(EXPIRE_TIME);
}
if(o.has(USER_NAME)) {
group.userName = o.getString(USER_NAME);
}
if(o.has(DESCRIPTION)) {
group.description = o.getString(DESCRIPTION);
}
if(o.has(POLICY)) {
group.policy = o.getString(POLICY);
}
if(o.has(ENABLED) && o.getBoolean(ENABLED)) {
group.enabled = true;
}
parseGroupUsers(group, o);
// parseGroupTracks(group, obj);
this.groups.put(group.groupId, group);
}
} catch (JSONException e) {
e.printStackTrace();
service.showErrorMessage(e.getMessage());
}
}
public void save() {
JSONObject mainObj = new JSONObject();
try {
JSONArray ar = new JSONArray();
for(OsMoGroup gr : groups.values()) {
if(gr.isMainGroup()) {
continue;
}
JSONObject obj = new JSONObject();
if (gr.userName != null) {
obj.put(USER_NAME, gr.userName);
}
if (gr.name != null) {
obj.put(NAME, gr.name);
}
if(gr.description != null) {
obj.put(DESCRIPTION, gr.description);
}
if(gr.policy != null) {
obj.put(POLICY, gr.policy);
}
if(gr.expireTime != 0) {
obj.put(EXPIRE_TIME, gr.expireTime);
}
if (gr.enabled) {
obj.put(ENABLED, true);
}
obj.put(GROUP_ID, gr.groupId);
ar.put(obj);
saveGroupUsers(gr, obj);
saveGroupTracks(gr, obj);
}
mainObj.put(GROUPS, ar);
} catch (JSONException e) {
e.printStackTrace();
service.showErrorMessage(e.getMessage());
}
pref.set(mainObj.toString());
}
private void saveGroupUsers(OsMoGroup gr, JSONObject grObj) throws JSONException {
JSONArray ar = new JSONArray();
for(OsMoDevice u : gr.users.values()) {
JSONObject obj = new JSONObject();
if (u.userName != null) {
obj.put(USER_NAME, u.userName);
}
if (u.serverName != null) {
obj.put(SERVER_NAME, u.serverName);
}
if (u.userColor != 0) {
obj.put(USER_COLOR, u.userColor);
}
if (u.genColor != 0) {
obj.put(GEN_COLOR, u.genColor);
}
if (u.serverColor != 0) {
obj.put(SERVER_COLOR, u.serverColor);
}
if (u.deleted != 0) {
obj.put(DELETED, u.deleted);
}
if(u.enabled) {
obj.put(ENABLED, u.enabled);
}
obj.put(TRACKER_ID, u.trackerId);
ar.put(obj);
}
grObj.put(USERS, ar);
}
private void saveGroupTracks(OsMoGroup gr, JSONObject grObj) throws JSONException {
if (gr.groupTracks.size() > 0) {
JSONArray ar = new JSONArray();
for (String u : gr.groupTracks) {
JSONObject obj = new JSONObject();
obj.put(NAME, u);
ar.put(obj);
}
grObj.put(TRACKS, ar);
}
}
protected void parseGroupUsers(OsMoGroup gr, JSONObject obj) throws JSONException {
if(!obj.has(USERS)) {
return;
}
JSONArray users = obj.getJSONArray(USERS);
for (int i = 0; i < users.length(); i++) {
JSONObject o = (JSONObject) users.get(i);
OsMoDevice user = new OsMoDevice();
user.group = gr;
if(o.has(SERVER_NAME)) {
user.serverName = o.getString(SERVER_NAME);
}
if(o.has(USER_NAME)) {
user.userName = o.getString(USER_NAME);
}
if(o.has(SERVER_COLOR)) {
user.serverColor = o.getInt(SERVER_COLOR);
}
if(o.has(USER_COLOR)) {
user.userColor = o.getInt(USER_COLOR);
}
if(o.has(GEN_COLOR)) {
user.genColor = o.getInt(GEN_COLOR);
}
if(o.has(DELETED)) {
user.deleted = o.getLong(DELETED);
}
if(o.has(ENABLED) && o.getBoolean(ENABLED)) {
user.enabled = true;
}
user.trackerId = o.getString(TRACKER_ID);
gr.users.put(user.trackerId, user);
}
}
protected void parseGroupTracks(OsMoGroup gr, JSONObject obj) throws JSONException {
if(!obj.has(TRACKS)) {
return;
}
JSONArray tracks = obj.getJSONArray(TRACKS);
for (int i = 0; i < tracks.length(); i++) {
JSONObject o = (JSONObject) tracks.get(i);
if(o.has(NAME)) {
gr.groupTracks.add(NAME);
}
}
}
public static class OsMoGroup {
protected String name;
protected String userName;
protected String description;
protected String policy;
protected String groupId;
protected boolean enabled;
protected long expireTime;
protected boolean active;
protected boolean deleted;
protected Map<String, OsMoDevice> users = new ConcurrentHashMap<String, OsMoDevice>();
protected List<String> groupTracks = new ArrayList<String>();
public List<OsMoDevice> getGroupUsers(String mygid) {
// filter deleted
List<OsMoDevice> dvs = new ArrayList<OsMoDevice>(users.size());
for(OsMoDevice d : users.values()) {
if(mygid != null && mygid.equals(d.trackerId)) {
continue;
}
if(d.getDeletedTimestamp() == 0) {
dvs.add(d);
}
}
return dvs;
}
public List<String> getGroupTracks() {
return groupTracks;
}
public List<OsMoDevice> getVisibleGroupUsers(String mygid) {
if(!isActive() && !isMainGroup()) {
return Collections.emptyList();
}
return getGroupUsers(mygid);
}
public boolean isDeleted() {
return deleted;
}
public String getDescription() {
return description;
}
public String getPolicy() {
return policy;
}
public long getExpireTime() {
return expireTime;
}
public boolean isMainGroup() {
return groupId == null;
}
public String getGroupId() {
return groupId;
}
public boolean isActive() {
return active;
}
public boolean isEnabled() {
return enabled;
}
public String getVisibleName(Context ctx){
if(isMainGroup()) {
return ctx.getString(R.string.osmo_connected_devices);
}
if(userName != null && userName.length() > 0) {
return userName;
}
if(name == null) {
return "";
}
return name;
}
public OsMoDevice updateLastLocation(String trackerId, Location location) {
OsMoDevice d = users.get(trackerId);
if(d != null) {
d.setLastLocation(location);
}
return d;
}
}
public static class OsMoMessage {
protected long timestamp;
protected LatLon location;
protected String text;
protected OsMoDevice user;
public String getText() {
return text;
}
public long getTimestamp() {
return timestamp;
}
public LatLon getLocation() {
return location;
}
public OsMoDevice getUser() {
return user;
}
}
public static class OsMoDevice {
protected String serverName;
protected String userName;
protected int serverColor;
protected int userColor;
protected int genColor;
protected String trackerId;
protected boolean enabled;
protected boolean active;
protected long deleted;
protected OsMoGroup group ;
protected ConcurrentLinkedQueue<Location> previousLocations = new java.util.concurrent.ConcurrentLinkedQueue<Location>();
protected List<OsMoMessage> messages = new ArrayList<OsMoMessage>();
protected long lastOnline;
protected Location lastLocation;
public List<OsMoMessage> getMessages() {
return messages;
}
public ConcurrentLinkedQueue<Location> getPreviousLocations(long threshold) {
while(!previousLocations.isEmpty() && previousLocations.peek().getTime() < threshold) {
previousLocations.poll();
}
return previousLocations;
}
public void setLastLocation(Location lastLocation) {
if(this.lastLocation != null) {
previousLocations.add(this.lastLocation);
}
this.lastLocation = lastLocation;
if (lastLocation != null) {
setLastOnline(lastLocation.getTime());
}
}
public Location getLastLocation() {
return lastLocation;
}
public void setLastOnline(long lastOnline) {
this.lastOnline = lastOnline;
}
public long getLastOnline() {
return lastOnline;
}
public boolean isEnabled() {
return enabled;
}
public boolean isActive() {
return active;
}
public long getDeletedTimestamp() {
return deleted;
}
public OsMoGroup getGroup() {
return group;
}
public String getTrackerId() {
return trackerId;
}
public int getColor() {
if(userColor != 0) {
return userColor;
}
if(serverColor != 0) {
return serverColor ;
}
return genColor;
}
public int getNonActiveColor() {
int color = getColor();
int alpha = Math.round(Color.alpha(color) * 0.3f);
int red = Color.red(color);
int green = Color.green(color);
int blue = Color.blue(color);
return Color.argb(alpha, red, green, blue);
}
public String getVisibleName(){
if(userName != null && userName.length() > 0) {
return userName;
}
if(serverName == null || serverName.length() == 0) {
return trackerId;
}
return serverName;
}
}
public OsMoGroup getGroup(String gid) {
return groups.get(gid);
}
public void deleteGroup(OsMoGroup gr) {
groups.remove(gr.groupId);
gr.deleted = true;
}
public void addGroup(OsMoGroup g) {
groups.put(g.groupId, g);
g.deleted = false;
}
public void mergeGroups(Map<String, OsMoGroup> groupsToMerge) {
Set<String> toDelete = new HashSet<String>(groups.keySet());
if (groupsToMerge != null) {
Set<String> toMerge = groupsToMerge.keySet();
for (String id: toMerge) {
if (toDelete.contains(id)) {
toDelete.remove(id);
} else {
addGroup(groupsToMerge.get(id));
}
}
}
for (String id: toDelete) {
OsMoGroup group = getGroup(id);
if (group != null) {
deleteGroup(group);
}
}
}
public void clearGroups() {
groups.clear();
}
}