package com.ftinc.scoop;
import android.app.Activity;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
import android.util.Log;
import android.util.SparseArray;
import android.view.View;
import android.view.animation.Interpolator;
import com.ftinc.scoop.binding.IBinding;
import com.ftinc.scoop.binding.StatusBarBinding;
import com.ftinc.scoop.binding.ViewBinding;
import com.ftinc.scoop.adapters.ColorAdapter;
import com.ftinc.scoop.internal.ToppingBinder;
import com.ftinc.scoop.util.BindingUtils;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* This class is not deprecated, please use {@link Scoop} class to bind everything
*
* Package: com.ftinc.scoop
* Created by drew.heavner on 6/17/16.
*/
@Deprecated
public class SugarCone {
private static final String TAG = "SugarCone";
static final Map<Class<?>, ToppingBinder<Object>> BINDERS = new LinkedHashMap<>();
static final ToppingBinder<Object> NOP_VIEW_BINDER = new ToppingBinder<Object>() {
@Override
public List<IBinding> bind(Object target) {
return new ArrayList<>();
}
};
/***********************************************************************************************
*
* Variables
*
*/
private SparseArray<Topping> mToppings = new SparseArray<>();
private HashMap<Class, Set<IBinding>> mBindings = new HashMap<>();
private static boolean debug = false;
/***********************************************************************************************
*
* Api Methods
*
*/
public void bind(Activity activity){
List<IBinding> bindings = getViewBinder(activity).bind(activity);
// add to system
Set<IBinding> _bindings = getBindings(activity.getClass());
_bindings.addAll(bindings);
}
public SugarCone bind(Object obj, int toppingId, View view){
return bind(obj, toppingId, view, null);
}
public SugarCone bind(Object obj, int toppingId, View view, @Nullable ColorAdapter colorAdapter){
return bind(obj, toppingId, view, colorAdapter, null);
}
public SugarCone bind(Object obj, int toppingId, View view, @Nullable ColorAdapter colorAdapter, @Nullable Interpolator interpolator){
// Get a default color adapter if not supplied
if(colorAdapter == null){
colorAdapter = BindingUtils.getColorAdapter(view.getClass());
}
// Generate Binding
IBinding binding = new ViewBinding(toppingId, view, colorAdapter, interpolator);
// Bind
return bind(obj, toppingId, binding);
}
public SugarCone bindStatusBar(Activity activity, int toppingId){
return bindStatusBar(activity, toppingId, null);
}
public SugarCone bindStatusBar(Activity activity, int toppingId, @Nullable Interpolator interpolator){
IBinding binding = new StatusBarBinding(toppingId, activity, interpolator);
return bind(activity, toppingId, binding);
}
public SugarCone bind(Object obj, int toppingId, IBinding binding){
// Find Topping
Topping topping = mToppings.get(toppingId);
if(topping != null){
// Store binding
Set<IBinding> bindings = getBindings(obj.getClass());
bindings.add(binding);
return this;
}else{
throw new InvalidParameterException("No Topping for the given id (" + toppingId + ") was found.");
}
}
public void unbind(Object obj){
Set<IBinding> bindings = getBindings(obj.getClass());
for (IBinding binding : bindings) {
binding.unbind();
}
// Clear the bindings out of the map
mBindings.remove(obj.getClass());
}
public SugarCone update(int toppingId, @ColorInt int color){
// Get the topping
Topping topping = mToppings.get(toppingId);
if(topping != null){
topping.updateColor(color);
// Update bindings
Collection<Set<IBinding>> bindings = mBindings.values();
for (Set<IBinding> bindingSet : bindings) {
for (IBinding binding : bindingSet) {
if(binding.getToppingId() == toppingId) {
binding.update(topping);
}
}
}
}else{
throw new InvalidParameterException("No Topping for the given id (" + toppingId + ") was found.");
}
return this;
}
/***********************************************************************************************
*
* Helper Methods
*
*/
@NonNull @UiThread
static ToppingBinder<Object> getViewBinder(@NonNull Object target) {
Class<?> targetClass = target.getClass();
if (debug) Log.d(TAG, "Looking up topping binder for " + targetClass.getName());
return findViewBinderForClass(targetClass);
}
@NonNull @UiThread
private static ToppingBinder<Object> findViewBinderForClass(Class<?> cls) {
ToppingBinder<Object> viewBinder = BINDERS.get(cls);
if (viewBinder != null) {
if (debug) Log.d(TAG, "HIT: Cached in topping binder map.");
return viewBinder;
}
String clsName = cls.getName();
if (clsName.startsWith("android.") || clsName.startsWith("java.")) {
if (debug) Log.d(TAG, "MISS: Reached framework class. Abandoning search.");
return NOP_VIEW_BINDER;
}
//noinspection TryWithIdenticalCatches Resolves to API 19+ only type.
try {
Class<?> viewBindingClass = Class.forName(clsName + "_ToppingBinder");
//noinspection unchecked
viewBinder = (ToppingBinder<Object>) viewBindingClass.newInstance();
if (debug) Log.d(TAG, "HIT: Loaded topping binder class.");
} catch (ClassNotFoundException e) {
if (debug) Log.d(TAG, "Not found. Trying superclass " + cls.getSuperclass().getName());
viewBinder = findViewBinderForClass(cls.getSuperclass());
} catch (InstantiationException e) {
throw new RuntimeException("Unable to create topping binder for " + clsName, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Unable to create topping binder for " + clsName, e);
}
BINDERS.put(cls, viewBinder);
return viewBinder;
}
Set<IBinding> getBindings(Class clazz){
Set<IBinding> bindings = mBindings.get(clazz);
if(bindings == null){
bindings = new HashSet<>();
mBindings.put(clazz, bindings);
}
return bindings;
}
public SugarCone addTopping(Topping... topping) {
return addToppings(Arrays.asList(topping));
}
public SugarCone addToppings(Collection<Topping> toppings){
for (Topping topping : toppings) {
mToppings.put(topping.getId(), topping);
}
return this;
}
public SparseArray<Topping> getToppings(){
return mToppings;
}
}