package com.github.florent37.carpaccio.mapping;
import android.view.View;
import com.github.florent37.carpaccio.CarpaccioHelper;
import com.github.florent37.carpaccio.CarpaccioLogger;
import com.github.florent37.carpaccio.model.CarpaccioAction;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created by florentchampigny on 23/07/15.
*/
public class MappingManager {
private static final String TAG = "CarpaccioMappingManager";
protected Map<String, Object> mappedObjects = new HashMap<>();
protected Map<String, List> mappedLists = new HashMap<>();
protected Map<String, List<MappingWaiting>> mappingWaitings = new HashMap<>();
public interface MappingManagerCallback {
void callActionOnView(CarpaccioAction action, View view);
}
protected MappingManagerCallback mappingManagerCallback;
public MappingManager() {
}
/**
* All mapping call must start with $
* ex : function($user) function($user.getText())
* CAN ONLY MAP 1 OBJECT, function($user1,$user2) will be rejected
*/
public static boolean isCallMapping(String[] args) {
return args.length == 1 && args[0].startsWith("$");
}
//object.image.getUrl()
public String evaluate(Object object, String call) {
if (!call.contains(".")) { //"object"
CarpaccioLogger.d(TAG, "call " + call + " on " + object.getClass().getName());
return object.toString();
} else {
String function = call.substring(call.indexOf('.') + 1); //image.getUrl(); or //image
String callToGetObject;
if (function.contains(".")) {
callToGetObject = function.substring(0, function.indexOf('.')); //image
} else {
callToGetObject = function; //image
}
String realCallToGetObject = getFunctionName(callToGetObject);
Object newObject = CarpaccioHelper.callFunction(object, realCallToGetObject);
if (newObject != null) {
CarpaccioLogger.d(TAG, "call " + realCallToGetObject + " return =" + newObject.getClass().getName());
if (newObject instanceof String) {
return (String) newObject;
} else if (newObject instanceof Number) {
return String.valueOf(newObject);
} else
return evaluate(newObject, function);
} else {
CarpaccioLogger.d(TAG, "call " + realCallToGetObject + " return = NULL");
return null;
}
}
}
/**
* Add an object to the mapper
* When the object is added, call all the mappingWaitings (views which need this object)
*
* @param name the mapped object name, ex : for function($user), the name will be "user"
* @param object the mapped object
*/
public void mapObject(String name, Object object) {
mappedObjects.put(name, object);
CarpaccioLogger.d(TAG, "map object [" + name + "," + object.getClass().getName() + "]");
//call the waiting objects
List<MappingWaiting> waitingsForThisName = mappingWaitings.get(name);
if (waitingsForThisName != null) {
for (MappingWaiting mappingWaiting : waitingsForThisName) {
CarpaccioLogger.d(TAG, "call waiting mapped " + mappingWaiting.getCarpaccioAction().getCompleteCall());
String value = evaluate(object, mappingWaiting.getCall());
CarpaccioLogger.d(TAG, "call waiting value = " + value);
if (value != null && mappingManagerCallback != null) {
mappingWaiting.getCarpaccioAction().setValues(new String[]{value}); //TODO
mappingManagerCallback.callActionOnView(mappingWaiting.getCarpaccioAction(), mappingWaiting.getView());
}
}
//remove all waitings for this name
waitingsForThisName.clear();
mappingWaitings.remove(name);
}
}
public void mapList(String name, List list) {
CarpaccioLogger.d(TAG, "map list " + name + " size=" + list.size());
mappedLists.put(name, list);
}
public void appendList(String mappedName, List list) {
List savedList = mappedLists.get(mappedName);
if (savedList == null) {
CarpaccioLogger.e(TAG, "No list found for [" + mappedName + "]");
} else {
savedList.addAll(list);
}
}
public List getMappedList(String name) {
return mappedLists.get(name);
}
/**
* From getName() return getName()
* From name return getName()
*/
protected static String getFunctionName(String call) {
if (call.contains("(") && call.contains(")"))
return call.replace("()", "");
else {
String firstLetter = call.substring(0, 1).toUpperCase();
String lastLetters = call.substring(1, call.length());
return "get" + firstLetter + lastLetters;
}
}
/**
* Called when a view loaded and call a mapping function
*
* @param view the calling view
* @param mappedObject If available, the object to map with the view. Else add the view to mappingWaitings
*/
public void callMappingOnView(CarpaccioAction action, View view, Object mappedObject) {
if (action.isCallMapping()) {
CarpaccioLogger.d(TAG, "callMappingOnView mapping=" + mappedObject + " action=" + action.getCompleteCall() + " view=" + view.getClass().getName());
String arg = action.getArgs()[0]; //only map the first argument
String objectName = null;
String call;
if (arg.contains(".")) { //"$user.getName()"
call = arg.substring(1, arg.length()); // "user.getName()"
objectName = call.substring(0, arg.indexOf(".") - 1); // "user"
} else {
objectName = arg.substring(1, arg.length()); // "user"
call = objectName; // "user"
}
//if you already have the object
if (mappedObject != null) {
String value = evaluate(mappedObject, call);
CarpaccioLogger.d(TAG, "callMappingOnView evaluate(" + call + ")" + " on " + mappedObject.getClass().getName() + " returned " + value);
action.setValues(new String[]{value}); //TODO
mappingManagerCallback.callActionOnView(action, view);
} else {
//add to waiting
List<MappingWaiting> waitings = mappingWaitings.get(objectName); //["user"] = List<MappingWaiting>
if (waitings == null)
waitings = new ArrayList<>();
waitings.add(new MappingWaiting(view, action, call, objectName));
CarpaccioLogger.d(TAG, "added to waiting " + call + " for " + view.getClass().getName());
mappingWaitings.put(objectName, waitings);
}
}
}
public MappingManagerCallback getMappingManagerCallback() {
return mappingManagerCallback;
}
public void setMappingManagerCallback(MappingManagerCallback mappingManagerCallback) {
this.mappingManagerCallback = mappingManagerCallback;
}
public Object getMappedListsObject(String name, int position) {
return mappedLists.get(name).get(position);
}
public Object getMappedObject(String name) {
return mappedObjects.get(name);
}
}