public final class

MediaBucketList

extends Object
/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * 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 com.cooliris.media;

import java.util.ArrayList;
import java.util.HashMap;

public final class MediaBucketList {
    private static final Boolean TRUE = new Boolean(true);
    private static final Boolean FALSE = new Boolean(false);

    private ArrayList<MediaBucket> mBuckets = new ArrayList<MediaBucket>(1024);
    private boolean mDirtyCount;
    private boolean mDirtyAcceleratedLookup;
    private int mCount;
    private HashMap<MediaItem, Boolean> mCachedItems = new HashMap<MediaItem, Boolean>(1024);

    // If only albums are selected, a bucket contains mediaSets.
    // If items are selected, a bucket contains mediaSets and mediaItems.

    // Returns the first item selection (ignoring items within set selections).
    public static MediaItem getFirstItemSelection(ArrayList<MediaBucket> buckets) {
        MediaItem item = null;
        if (buckets != null) {
            int numBuckets = buckets.size();
            for (int i = 0; i < numBuckets; i++) {
                MediaBucket bucket = buckets.get(0);
                if (bucket != null && !isSetSelection(bucket)) {
                    ArrayList<MediaItem> items = bucket.mediaItems;
                    if (items != null && items.size() > 0) {
                        item = items.get(0);
                        break;
                    }
                }
            }
        }
        return item;
    }

    // Returns the first set selection (ignoring sets corresponding to item
    // selections).
    public static MediaSet getFirstSetSelection(ArrayList<MediaBucket> buckets) {
        MediaSet set = null;
        if (buckets != null) {
            int numBuckets = buckets.size();
            for (int i = 0; i < numBuckets; i++) {
                MediaBucket bucket = buckets.get(0);
                if (bucket != null && isSetSelection(bucket)) {
                    set = bucket.mediaSet;
                }
            }
        }
        return set;
    }

    public ArrayList<MediaBucket> get() {
        return mBuckets;
    }

    public int size() {
        if (mDirtyCount) {
            ArrayList<MediaBucket> buckets = mBuckets;
            int numBuckets = buckets.size();
            int count = 0;
            for (int i = 0; i < numBuckets; ++i) {
                MediaBucket bucket = buckets.get(i);
                int numItems = 0;
                if (bucket.mediaItems == null && bucket.mediaSet != null) {
                    numItems = bucket.mediaSet.getNumItems();
                    // This selection reflects the bucket itself, and not the
                    // items inside the bucket (which is 0).
                    if (numItems == 0) {
                        numItems = 1;
                    }
                } else if (bucket.mediaItems != null && bucket.mediaItems != null) {
                    numItems = bucket.mediaItems.size();
                }
                count += numItems;
            }
            mCount = count;
            mDirtyCount = false;
        }
        return mCount;
    }

    public void add(int slotId, MediaFeed feed, boolean removeIfAlreadyAdded) {
        if (slotId == Shared.INVALID) {
            return;
        }
        setDirty();
        final ArrayList<MediaBucket> selectedBuckets = mBuckets;
        final int numSelectedBuckets = selectedBuckets.size();
        MediaSet mediaSetToAdd = null;
        ArrayList<MediaItem> selectedItems = null;
        MediaBucket bucket = null;
        final boolean hasExpandedMediaSet = feed.hasExpandedMediaSet();
        if (!hasExpandedMediaSet) {
            ArrayList<MediaSet> mediaSets = feed.getMediaSets();
            if (slotId >= mediaSets.size()) {
                return;
            }
            mediaSetToAdd = mediaSets.get(slotId);
        } else {
            int numSlots = feed.getNumSlots();
            if (slotId < numSlots) {
                MediaSet set = feed.getSetForSlot(slotId);
                if (set != null) {
                    ArrayList<MediaItem> items = set.getItems();
                    if (set.getNumItems() > 0) {
                        mediaSetToAdd = items.get(0).mParentMediaSet;
                    }
                }
            }
        }

        // Search for the bucket for this media set
        for (int i = 0; i < numSelectedBuckets; ++i) {
            final MediaBucket bucketCompare = selectedBuckets.get(i);
            if (bucketCompare != null && bucketCompare.mediaSet != null
                && mediaSetToAdd != null && bucketCompare.mediaSet == mediaSetToAdd) {
                // We found the MediaSet.
                if (!hasExpandedMediaSet) {
                    // Remove this bucket from the list since this bucket was
                    // already selected.
                    if (removeIfAlreadyAdded) {
                        selectedBuckets.remove(bucketCompare);
                    }
                    return;
                } else {
                    bucket = bucketCompare;
                    break;
                }
            }
        }
        if (bucket == null) {
            // Did not find the media bucket.
            bucket = new MediaBucket();
            bucket.mediaSet = mediaSetToAdd;
            bucket.mediaItems = selectedItems;
            selectedBuckets.add(bucket);
        }
        if (hasExpandedMediaSet) {
            int numSlots = feed.getNumSlots();
            if (slotId < numSlots) {
                MediaSet set = feed.getSetForSlot(slotId);
                if (set != null) {
                    ArrayList<MediaItem> items = set.getItems();
                    int numItems = set.getNumItems();
                    selectedItems = bucket.mediaItems;
                    if (selectedItems == null) {
                        selectedItems = new ArrayList<MediaItem>(numItems);
                        bucket.mediaItems = selectedItems;
                    }
                    for (int i = 0; i < numItems; ++i) {
                        MediaItem item = items.get(i);
                        // We see if this item has already been added.
                        int numPresentItems = selectedItems.size();
                        boolean foundIndex = false;
                        for (int j = 0; j < numPresentItems; ++j) {
                            final MediaItem selectedItem = selectedItems.get(j);
                            if (selectedItem != null && item != null && selectedItem == item) {
                                // This index was already present, we need to
                                // remove it.
                                foundIndex = true;
                                if (removeIfAlreadyAdded) {
                                    selectedItems.remove(j);
                                }
                                break;
                            }
                        }
                        if (foundIndex == false) {
                            selectedItems.add(item);
                        }
                    }
                }
            }
        }
        setDirty();
    }

    public boolean find(MediaItem item) {
        HashMap<MediaItem, Boolean> cachedItems = mCachedItems;
        if (mDirtyAcceleratedLookup) {
            cachedItems.clear();
            mDirtyAcceleratedLookup = false;
        }
        Boolean itemAdded = cachedItems.get(item);
        if (itemAdded == null) {
            ArrayList<MediaBucket> selectedBuckets = mBuckets;
            int numSelectedBuckets = selectedBuckets.size();
            for (int i = 0; i < numSelectedBuckets; ++i) {
                MediaBucket bucket = selectedBuckets.get(i);
                ArrayList<MediaItem> mediaItems = bucket.mediaItems;
                if (mediaItems == null) {
                    MediaSet parentMediaSet = item.mParentMediaSet;
                    if (parentMediaSet != null && parentMediaSet.equals(bucket.mediaSet)) {
                        cachedItems.put(item, TRUE);
                        return true;
                    }
                } else {
                    int numMediaItems = mediaItems.size();
                    for (int j = 0; j < numMediaItems; ++j) {
                        MediaItem itemCompare = mediaItems.get(j);
                        if (itemCompare == item) {
                            cachedItems.put(item, TRUE);
                            return true;
                        }
                    }
                }
            }
            cachedItems.put(item, FALSE);
            return false;
        } else {
            return itemAdded.booleanValue();
        }
    }

    public void clear() {
        mBuckets.clear();
        setDirty();
    }

    private void setDirty() {
        mDirtyCount = true;
        mDirtyAcceleratedLookup = true;
    }

    // Assumption: No item and set selection combinations.
    protected static boolean isSetSelection(ArrayList<MediaBucket> buckets) {
        if (buckets != null) {
            int numBuckets = buckets.size();
            if (numBuckets == 0) {
                return false;
            } else if (numBuckets == 1) {
                return isSetSelection(buckets.get(0));
            } else {
                // If there are multiple sets, must be a set selection.
                return true;
            }
        }
        return false;
    }

    protected static boolean isSetSelection(MediaBucket bucket) {
        return (bucket.mediaSet != null && bucket.mediaItems == null) ? true : false;
    }

    // Assumption: If multiple items are selected, they must all be in the first
    // bucket.
    protected static boolean isMultipleItemSelection(ArrayList<MediaBucket> buckets) {
        if (buckets != null) {
            int numBuckets = buckets.size();
            if (numBuckets == 0) {
                return false;
            } else {
                return isMultipleSetSelection(buckets.get(0));
            }
        }
        return false;
    }

    protected static boolean isMultipleSetSelection(MediaBucket bucket) {
        return (bucket.mediaItems != null && bucket.mediaItems.size() > 1) ? true : false;
    }
}