package gem.kevin.provider; import gem.kevin.widget.MutualAdapter; import java.util.HashMap; import java.util.HashSet; import android.util.Log; public class MutualSourceProvider { public interface MutualSourceCallback { public void onMutualSourceChanged(MutualSourceProvider provider); } private static final String TAG = "MutualSourceProvider"; public static final int ACTION_TYPE_UNKNOWN = -1; public static final int ACTION_TYPE_WRITE_SOURCE = 1; public static final int ACTION_TYPE_READ_SOURCE = 2; public static final float OP_SUCCESS = 0; public static final float SOURCE_LOCKED = 27f; public static final float SOURCE_EMPTY = 37f; public static final float DEFAULT_LOCK_PURPOSE = SOURCE_LOCKED; public static final void deMutualize(MutualSourceProvider provider, HashSet<MutualSourceProvider> mutualProviderPool) { mutualProviderPool.remove(provider); } public static final void mutualize(MutualSourceProvider provider, HashSet<MutualSourceProvider> mutualProviderPool) { mutualProviderPool.add(provider); } private HashSet<Object> mMutualSources; private boolean mSourcesInUse = false; private float mSourcesLockedPurpose = 0f; private HashSet<MutualSourceProvider> mMutualProviderPool; private HashSet<MutualAdapter> mBoundAdapters = new HashSet<MutualAdapter>(); private int mActionType; private final HashSet<MutualSourceCallback> mMutualSourceCallbacks = new HashSet<MutualSourceCallback>(); public MutualSourceProvider(int actionType, HashSet<MutualSourceProvider> mutualProviderPool) { if (mutualProviderPool == null) { throw new ExceptionInInitializerError( "Null mutual provider pool found, " + "stop initialize mutual source provider."); } else if (actionType != ACTION_TYPE_READ_SOURCE && actionType != ACTION_TYPE_WRITE_SOURCE) { throw new ExceptionInInitializerError( "Invalid read/write type found, " + "stop initialize mutual source provider."); } mMutualSources = new HashSet<Object>(); mActionType = actionType; mutualize(this, mutualProviderPool); mMutualProviderPool = mutualProviderPool; } public void bindMutualAdapter(MutualAdapter adapter) { if (adapter == null) { return; } if (!mBoundAdapters.contains(adapter)) { mBoundAdapters.add(adapter); adapter.setMutualSourceProvider(this); updateBoundAdapterData(adapter); } } public void clearMutualSources() { this.mMutualSources.clear(); updateBoundAdapterData(); onMutualSourceChanged(); } public boolean containMutualSource(Object source) { return this.mMutualSources.contains(source); } public int getActionType() { return mActionType; } public HashSet<MutualAdapter> getBoundMutualAdapters() { return mBoundAdapters; } public int getMutualSourceCount() { return mMutualSources.size(); } public HashSet<Object> getMutualSources() { return mMutualSources; } public void lockMutualSources() { lockMutualSources(DEFAULT_LOCK_PURPOSE); } public void lockMutualSources(float externalPurposeCode) { mSourcesInUse = true; mSourcesLockedPurpose = externalPurposeCode; } public void registerMutualSourceCallback(MutualSourceCallback... callbacks) { if (!mMutualSourceCallbacks.isEmpty()) { mMutualSourceCallbacks.clear(); } Log.i("ActionSourceProvider", "register callbacks size: " + callbacks.length); for (int i = 0; i < callbacks.length; i++) { mMutualSourceCallbacks.add(callbacks[i]); } } public float removeMutualSource(Object source) { if (!mSourcesInUse) { Log.i(TAG, "remove source"); this.mMutualSources.remove(source); updateBoundAdapterData(); onMutualSourceChanged(); return OP_SUCCESS; } else { Log.i(TAG, "Can't remove source: " + source.toString()); return mSourcesLockedPurpose; } } public void setMutualSources(HashSet<Object> sources, HashMap<Object, Float> out_failToSet) { if (sources == null) { return; } HashSet<MutualSourceProvider> otherProviders = new HashSet<MutualSourceProvider>(); otherProviders.addAll(mMutualProviderPool); otherProviders.remove(this); for (Object source : sources) { float setResult = takeMutualSource(source, otherProviders); if (setResult != OP_SUCCESS && out_failToSet != null) { out_failToSet.put(source, Float.valueOf(setResult)); } } } public float takeMutualSource(Object source, HashSet<MutualSourceProvider> mutuals) { if (source == null || containMutualSource(source)) { return SOURCE_EMPTY; } boolean canTake = true; float takeResult = OP_SUCCESS; /* * If action will do write operations to the source, try to make the * source exclusively owned by current provider or previous provider who * already lock the source */ if (mActionType == ACTION_TYPE_WRITE_SOURCE) { for (MutualSourceProvider provider : mutuals) { if (provider != null && provider.containMutualSource(source)) { float ret = provider.removeMutualSource(source); if (ret != OP_SUCCESS) { canTake = false; takeResult = ret; } } } } else if (mActionType == ACTION_TYPE_READ_SOURCE) { /* * If action do read operations to the source, try to make previous * provider which will do write operations give up the source if not * locked */ for (MutualSourceProvider provider : mutuals) { if (provider != null && (provider.getActionType() == ACTION_TYPE_WRITE_SOURCE) && provider.containMutualSource(source)) { float ret = provider.removeMutualSource(source); if (ret != OP_SUCCESS) { canTake = false; takeResult = ret; } } } } if (canTake) { addMutualSource(source); } return takeResult; } public void unbindMutualAdapter(MutualAdapter adapter) { if (mBoundAdapters.contains(adapter)) { mBoundAdapters.remove(adapter); adapter.setMutualSourceProvider(null); } } public void unLockMutualSources() { mSourcesInUse = false; mSourcesLockedPurpose = 0; } public void updateBoundAdapterData() { for (MutualAdapter adapter : mBoundAdapters) { adapter.updateData(mMutualSources); } } public void updateBoundAdapterData(MutualAdapter adapter) { if (mBoundAdapters.contains(adapter)) { adapter.updateData(mMutualSources); } } protected void addMutualSource(Object source) { this.mMutualSources.add(source); updateBoundAdapterData(); onMutualSourceChanged(); } @Override protected void finalize() { unLockMutualSources(); deMutualize(this, mMutualProviderPool); } protected void onMutualSourceChanged() { for (MutualSourceCallback callback : mMutualSourceCallbacks) { callback.onMutualSourceChanged(this); } } }