1f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin/* 2f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Copyright (C) 2010 The Android Open Source Project 3f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 4f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Licensed under the Apache License, Version 2.0 (the "License"); 5f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * you may not use this file except in compliance with the License. 6f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * You may obtain a copy of the License at 7f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 8f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * http://www.apache.org/licenses/LICENSE-2.0 9f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 10f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Unless required by applicable law or agreed to in writing, software 11f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * distributed under the License is distributed on an "AS IS" BASIS, 12f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * See the License for the specific language governing permissions and 14f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * limitations under the License. 15f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 16f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 17f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpackage com.android.gallery3d.app; 18f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 19f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.R; 20f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.MediaObject; 21f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.Path; 22f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 23f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// This class handles filtering and clustering. 24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// 25f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// We allow at most only one filter operation at a time (Currently it 26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// doesn't make sense to use more than one). Also each clustering operation 27f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// can be applied at most once. In addition, there is one more constraint 28f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// ("fixed set constraint") described below. 29f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// 30f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// A clustered album (not including album set) and its base sets are fixed. 31f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// For example, 32f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// 33f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// /cluster/{base_set}/time/7 34f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// 35f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// This set and all sets inside base_set (recursively) are fixed because 36f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// 1. We can not change this set to use another clustering condition (like 37f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// changing "time" to "location"). 38f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// 2. Neither can we change any set in the base_set. 39f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// The reason is in both cases the 7th set may not exist in the new clustering. 40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// --------------------- 41f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// newPath operation: create a new path based on a source path and put an extra 42f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// condition on top of it: 43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// 44f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// T = newFilterPath(S, filterType); 45f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// T = newClusterPath(S, clusterType); 46f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// 47f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// Similar functions can be used to replace the current condition (if there is one). 48f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// 49f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// T = switchFilterPath(S, filterType); 50f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// T = switchClusterPath(S, clusterType); 51f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// 52f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// For all fixed set in the path defined above, if some clusterType and 53f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// filterType are already used, they cannot not be used as parameter for these 54f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// functions. setupMenuItems() makes sure those types cannot be selected. 55f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// 56f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic class FilterUtils { 57f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final String TAG = "FilterUtils"; 58f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int CLUSTER_BY_ALBUM = 1; 60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int CLUSTER_BY_TIME = 2; 61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int CLUSTER_BY_LOCATION = 4; 62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int CLUSTER_BY_TAG = 8; 63f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int CLUSTER_BY_SIZE = 16; 64f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int CLUSTER_BY_FACE = 32; 65f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int FILTER_IMAGE_ONLY = 1; 67f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int FILTER_VIDEO_ONLY = 2; 68f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int FILTER_ALL = 4; 69f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 70f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // These are indices of the return values of getAppliedFilters(). 71f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // The _F suffix means "fixed". 72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int CLUSTER_TYPE = 0; 73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int FILTER_TYPE = 1; 74f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int CLUSTER_TYPE_F = 2; 75f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int FILTER_TYPE_F = 3; 76f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int CLUSTER_CURRENT_TYPE = 4; 77f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int FILTER_CURRENT_TYPE = 5; 78f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 79f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static void setupMenuItems(GalleryActionBar model, Path path, boolean inAlbum) { 80f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int[] result = new int[6]; 81f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin getAppliedFilters(path, result); 82f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int ctype = result[CLUSTER_TYPE]; 83f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int ftype = result[FILTER_TYPE]; 84f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int ftypef = result[FILTER_TYPE_F]; 85f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int ccurrent = result[CLUSTER_CURRENT_TYPE]; 86f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int fcurrent = result[FILTER_CURRENT_TYPE]; 87f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 88f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setMenuItemApplied(model, CLUSTER_BY_TIME, 89f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin (ctype & CLUSTER_BY_TIME) != 0, (ccurrent & CLUSTER_BY_TIME) != 0); 90f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setMenuItemApplied(model, CLUSTER_BY_LOCATION, 91f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin (ctype & CLUSTER_BY_LOCATION) != 0, (ccurrent & CLUSTER_BY_LOCATION) != 0); 92f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setMenuItemApplied(model, CLUSTER_BY_TAG, 93f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin (ctype & CLUSTER_BY_TAG) != 0, (ccurrent & CLUSTER_BY_TAG) != 0); 94f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setMenuItemApplied(model, CLUSTER_BY_FACE, 95f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin (ctype & CLUSTER_BY_FACE) != 0, (ccurrent & CLUSTER_BY_FACE) != 0); 96f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 97f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin model.setClusterItemVisibility(CLUSTER_BY_ALBUM, !inAlbum || ctype == 0); 98f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 99f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setMenuItemApplied(model, R.id.action_cluster_album, ctype == 0, 100f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ccurrent == 0); 101f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 102f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // A filtering is available if it's not applied, and the old filtering 103f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // (if any) is not fixed. 104f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setMenuItemAppliedEnabled(model, R.string.show_images_only, 105f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin (ftype & FILTER_IMAGE_ONLY) != 0, 106f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin (ftype & FILTER_IMAGE_ONLY) == 0 && ftypef == 0, 107f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin (fcurrent & FILTER_IMAGE_ONLY) != 0); 108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setMenuItemAppliedEnabled(model, R.string.show_videos_only, 109f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin (ftype & FILTER_VIDEO_ONLY) != 0, 110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin (ftype & FILTER_VIDEO_ONLY) == 0 && ftypef == 0, 111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin (fcurrent & FILTER_VIDEO_ONLY) != 0); 112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setMenuItemAppliedEnabled(model, R.string.show_all, 113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ftype == 0, ftype != 0 && ftypef == 0, fcurrent == 0); 114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 116f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Gets the filters applied in the path. 117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static void getAppliedFilters(Path path, int[] result) { 118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin getAppliedFilters(path, result, false); 119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 120f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static void getAppliedFilters(Path path, int[] result, boolean underCluster) { 122f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin String[] segments = path.split(); 123f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Recurse into sub media sets. 124f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = 0; i < segments.length; i++) { 125f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (segments[i].startsWith("{")) { 126f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin String[] sets = Path.splitSequence(segments[i]); 127f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int j = 0; j < sets.length; j++) { 128f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Path sub = Path.fromString(sets[j]); 129f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin getAppliedFilters(sub, result, underCluster); 130f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 131f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 132f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 134f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // update current selection 135f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (segments[0].equals("cluster")) { 136f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // if this is a clustered album, set underCluster to true. 137f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (segments.length == 4) { 138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin underCluster = true; 139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int ctype = toClusterType(segments[2]); 142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin result[CLUSTER_TYPE] |= ctype; 143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin result[CLUSTER_CURRENT_TYPE] = ctype; 144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (underCluster) { 145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin result[CLUSTER_TYPE_F] |= ctype; 146f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 149f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 150f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static int toClusterType(String s) { 151f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (s.equals("time")) { 152f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return CLUSTER_BY_TIME; 153f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else if (s.equals("location")) { 154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return CLUSTER_BY_LOCATION; 155f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else if (s.equals("tag")) { 156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return CLUSTER_BY_TAG; 157f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else if (s.equals("size")) { 158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return CLUSTER_BY_SIZE; 159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else if (s.equals("face")) { 160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return CLUSTER_BY_FACE; 161f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 162f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return 0; 163f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 164f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 165f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static void setMenuItemApplied( 166f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin GalleryActionBar model, int id, boolean applied, boolean updateTitle) { 167f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin model.setClusterItemEnabled(id, !applied); 168f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 169f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 170f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static void setMenuItemAppliedEnabled(GalleryActionBar model, int id, boolean applied, boolean enabled, boolean updateTitle) { 171f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin model.setClusterItemEnabled(id, enabled); 172f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 173f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 174f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Add a specified filter to the path. 175f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static String newFilterPath(String base, int filterType) { 176f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int mediaType; 177f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin switch (filterType) { 178f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case FILTER_IMAGE_ONLY: 179f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mediaType = MediaObject.MEDIA_TYPE_IMAGE; 180f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin break; 181f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case FILTER_VIDEO_ONLY: 182f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mediaType = MediaObject.MEDIA_TYPE_VIDEO; 183f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin break; 184f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin default: /* FILTER_ALL */ 185f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return base; 186f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 187f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 188f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return "/filter/mediatype/" + mediaType + "/{" + base + "}"; 189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Add a specified clustering to the path. 192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static String newClusterPath(String base, int clusterType) { 193f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin String kind; 194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin switch (clusterType) { 195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case CLUSTER_BY_TIME: 196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin kind = "time"; 197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin break; 198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case CLUSTER_BY_LOCATION: 199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin kind = "location"; 200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin break; 201f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case CLUSTER_BY_TAG: 202f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin kind = "tag"; 203f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin break; 204f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case CLUSTER_BY_SIZE: 205f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin kind = "size"; 206f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin break; 207f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case CLUSTER_BY_FACE: 208f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin kind = "face"; 209f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin break; 210f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin default: /* CLUSTER_BY_ALBUM */ 211f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return base; 212f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 213f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 214f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return "/cluster/{" + base + "}/" + kind; 215f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 216f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 217f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Change the topmost filter to the specified type. 218f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static String switchFilterPath(String base, int filterType) { 219f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return newFilterPath(removeOneFilterFromPath(base), filterType); 220f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 221f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 222f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Change the topmost clustering to the specified type. 223f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static String switchClusterPath(String base, int clusterType) { 224f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return newClusterPath(removeOneClusterFromPath(base), clusterType); 225f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 226f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 227f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Remove the topmost clustering (if any) from the path. 228f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static String removeOneClusterFromPath(String base) { 229f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin boolean[] done = new boolean[1]; 230f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return removeOneClusterFromPath(base, done); 231f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 232f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 233f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static String removeOneClusterFromPath(String base, boolean[] done) { 234f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (done[0]) return base; 235f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 236f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin String[] segments = Path.split(base); 237f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (segments[0].equals("cluster")) { 238f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin done[0] = true; 239f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return Path.splitSequence(segments[1])[0]; 240f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 241f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 242f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin StringBuilder sb = new StringBuilder(); 243f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = 0; i < segments.length; i++) { 244f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin sb.append("/"); 245f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (segments[i].startsWith("{")) { 246f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin sb.append("{"); 247f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin String[] sets = Path.splitSequence(segments[i]); 248f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int j = 0; j < sets.length; j++) { 249f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (j > 0) { 250f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin sb.append(","); 251f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 252f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin sb.append(removeOneClusterFromPath(sets[j], done)); 253f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 254f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin sb.append("}"); 255f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 256f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin sb.append(segments[i]); 257f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 258f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 259f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return sb.toString(); 260f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 261f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 262f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Remove the topmost filter (if any) from the path. 263f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static String removeOneFilterFromPath(String base) { 264f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin boolean[] done = new boolean[1]; 265f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return removeOneFilterFromPath(base, done); 266f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 267f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 268f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static String removeOneFilterFromPath(String base, boolean[] done) { 269f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (done[0]) return base; 270f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 271f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin String[] segments = Path.split(base); 272f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (segments[0].equals("filter") && segments[1].equals("mediatype")) { 273f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin done[0] = true; 274f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return Path.splitSequence(segments[3])[0]; 275f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 276f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 277f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin StringBuilder sb = new StringBuilder(); 278f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = 0; i < segments.length; i++) { 279f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin sb.append("/"); 280f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (segments[i].startsWith("{")) { 281f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin sb.append("{"); 282f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin String[] sets = Path.splitSequence(segments[i]); 283f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int j = 0; j < sets.length; j++) { 284f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (j > 0) { 285f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin sb.append(","); 286f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 287f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin sb.append(removeOneFilterFromPath(sets[j], done)); 288f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 289f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin sb.append("}"); 290f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 291f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin sb.append(segments[i]); 292f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 293f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 294f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return sb.toString(); 295f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 296f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin} 297