1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.gallery3d.data;
18
19import com.android.gallery3d.app.GalleryApp;
20
21import android.content.Context;
22import android.net.Uri;
23
24import java.util.ArrayList;
25import java.util.HashSet;
26
27public class ClusterAlbumSet extends MediaSet implements ContentListener {
28    private static final String TAG = "ClusterAlbumSet";
29    private GalleryApp mApplication;
30    private MediaSet mBaseSet;
31    private int mKind;
32    private ArrayList<ClusterAlbum> mAlbums = new ArrayList<ClusterAlbum>();
33    private boolean mFirstReloadDone;
34
35    public ClusterAlbumSet(Path path, GalleryApp application,
36            MediaSet baseSet, int kind) {
37        super(path, INVALID_DATA_VERSION);
38        mApplication = application;
39        mBaseSet = baseSet;
40        mKind = kind;
41        baseSet.addContentListener(this);
42    }
43
44    @Override
45    public MediaSet getSubMediaSet(int index) {
46        return mAlbums.get(index);
47    }
48
49    @Override
50    public int getSubMediaSetCount() {
51        return mAlbums.size();
52    }
53
54    @Override
55    public String getName() {
56        return mBaseSet.getName();
57    }
58
59    @Override
60    public long reload() {
61        if (mBaseSet.reload() > mDataVersion) {
62            if (mFirstReloadDone) {
63                updateClustersContents();
64            } else {
65                updateClusters();
66                mFirstReloadDone = true;
67            }
68            mDataVersion = nextVersionNumber();
69        }
70        return mDataVersion;
71    }
72
73    public void onContentDirty() {
74        notifyContentChanged();
75    }
76
77    private void updateClusters() {
78        mAlbums.clear();
79        Clustering clustering;
80        Context context = mApplication.getAndroidContext();
81        switch (mKind) {
82            case ClusterSource.CLUSTER_ALBUMSET_TIME:
83                clustering = new TimeClustering(context);
84                break;
85            case ClusterSource.CLUSTER_ALBUMSET_LOCATION:
86                clustering = new LocationClustering(context);
87                break;
88            case ClusterSource.CLUSTER_ALBUMSET_TAG:
89                clustering = new TagClustering(context);
90                break;
91            case ClusterSource.CLUSTER_ALBUMSET_FACE:
92                clustering = new FaceClustering(context);
93                break;
94            default: /* CLUSTER_ALBUMSET_SIZE */
95                clustering = new SizeClustering(context);
96                break;
97        }
98
99        clustering.run(mBaseSet);
100        int n = clustering.getNumberOfClusters();
101        DataManager dataManager = mApplication.getDataManager();
102        for (int i = 0; i < n; i++) {
103            Path childPath;
104            String childName = clustering.getClusterName(i);
105            if (mKind == ClusterSource.CLUSTER_ALBUMSET_TAG) {
106                childPath = mPath.getChild(Uri.encode(childName));
107            } else if (mKind == ClusterSource.CLUSTER_ALBUMSET_SIZE) {
108                long minSize = ((SizeClustering) clustering).getMinSize(i);
109                childPath = mPath.getChild(minSize);
110            } else {
111                childPath = mPath.getChild(i);
112            }
113            ClusterAlbum album = (ClusterAlbum) dataManager.peekMediaObject(
114                        childPath);
115            if (album == null) {
116                album = new ClusterAlbum(childPath, dataManager, this);
117            }
118            album.setMediaItems(clustering.getCluster(i));
119            album.setName(childName);
120            album.setCoverMediaItem(clustering.getClusterCover(i));
121            mAlbums.add(album);
122        }
123    }
124
125    private void updateClustersContents() {
126        final HashSet<Path> existing = new HashSet<Path>();
127        mBaseSet.enumerateTotalMediaItems(new MediaSet.ItemConsumer() {
128            public void consume(int index, MediaItem item) {
129                existing.add(item.getPath());
130            }
131        });
132
133        int n = mAlbums.size();
134
135        // The loop goes backwards because we may remove empty albums from
136        // mAlbums.
137        for (int i = n - 1; i >= 0; i--) {
138            ArrayList<Path> oldPaths = mAlbums.get(i).getMediaItems();
139            ArrayList<Path> newPaths = new ArrayList<Path>();
140            int m = oldPaths.size();
141            for (int j = 0; j < m; j++) {
142                Path p = oldPaths.get(j);
143                if (existing.contains(p)) {
144                    newPaths.add(p);
145                }
146            }
147            mAlbums.get(i).setMediaItems(newPaths);
148            if (newPaths.isEmpty()) {
149                mAlbums.remove(i);
150            }
151        }
152    }
153}
154