1/*
2 * Copyright (C) 2007 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.resources;
18
19
20import java.util.ArrayList;
21import java.util.Collections;
22import java.util.HashMap;
23import java.util.List;
24import java.util.Map;
25
26/**
27 * This class gives access to the bidirectional relationship between {@link ResourceType} and
28 * {@link ResourceFolderType}.
29 */
30public final class FolderTypeRelationship {
31
32    private final static Map<ResourceType, List<ResourceFolderType>> mTypeToFolderMap =
33        new HashMap<ResourceType, List<ResourceFolderType>>();
34
35    private final static Map<ResourceFolderType, List<ResourceType>> mFolderToTypeMap =
36        new HashMap<ResourceFolderType, List<ResourceType>>();
37
38    static {
39        // generate the relationships in a temporary map
40        add(ResourceType.ANIM, ResourceFolderType.ANIM);
41        add(ResourceType.ANIMATOR, ResourceFolderType.ANIMATOR);
42        add(ResourceType.ARRAY, ResourceFolderType.VALUES);
43        add(ResourceType.ATTR, ResourceFolderType.VALUES);
44        add(ResourceType.BOOL, ResourceFolderType.VALUES);
45        add(ResourceType.COLOR, ResourceFolderType.VALUES);
46        add(ResourceType.COLOR, ResourceFolderType.COLOR);
47        add(ResourceType.DECLARE_STYLEABLE, ResourceFolderType.VALUES);
48        add(ResourceType.DIMEN, ResourceFolderType.VALUES);
49        add(ResourceType.DRAWABLE, ResourceFolderType.VALUES);
50        add(ResourceType.DRAWABLE, ResourceFolderType.DRAWABLE);
51        add(ResourceType.FRACTION, ResourceFolderType.VALUES);
52        add(ResourceType.ID, ResourceFolderType.VALUES);
53        add(ResourceType.INTEGER, ResourceFolderType.VALUES);
54        add(ResourceType.INTERPOLATOR, ResourceFolderType.INTERPOLATOR);
55        add(ResourceType.LAYOUT, ResourceFolderType.LAYOUT);
56        add(ResourceType.ID, ResourceFolderType.LAYOUT);
57        add(ResourceType.MENU, ResourceFolderType.MENU);
58        add(ResourceType.ID, ResourceFolderType.MENU);
59        add(ResourceType.MIPMAP, ResourceFolderType.MIPMAP);
60        add(ResourceType.PLURALS, ResourceFolderType.VALUES);
61        add(ResourceType.PUBLIC, ResourceFolderType.VALUES);
62        add(ResourceType.RAW, ResourceFolderType.RAW);
63        add(ResourceType.STRING, ResourceFolderType.VALUES);
64        add(ResourceType.STYLE, ResourceFolderType.VALUES);
65        add(ResourceType.STYLEABLE, ResourceFolderType.VALUES);
66        add(ResourceType.XML, ResourceFolderType.XML);
67
68        makeSafe();
69    }
70
71    /**
72     * Returns a list of {@link ResourceType}s that can be generated from files inside a folder
73     * of the specified type.
74     * @param folderType The folder type.
75     * @return a list of {@link ResourceType}, possibly empty but never null.
76     */
77    public static List<ResourceType> getRelatedResourceTypes(ResourceFolderType folderType) {
78        List<ResourceType> list = mFolderToTypeMap.get(folderType);
79        if (list != null) {
80            return list;
81        }
82
83        return Collections.emptyList();
84    }
85
86    /**
87     * Returns a list of {@link ResourceFolderType} that can contain files generating resources
88     * of the specified type.
89     * @param resType the type of resource.
90     * @return a list of {@link ResourceFolderType}, possibly empty but never null.
91     */
92    public static List<ResourceFolderType> getRelatedFolders(ResourceType resType) {
93        List<ResourceFolderType> list = mTypeToFolderMap.get(resType);
94        if (list != null) {
95            return list;
96        }
97
98        return Collections.emptyList();
99    }
100
101    /**
102     * Returns true if the {@link ResourceType} and the {@link ResourceFolderType} values match.
103     * @param resType the resource type.
104     * @param folderType the folder type.
105     * @return true if files inside the folder of the specified {@link ResourceFolderType}
106     * could generate a resource of the specified {@link ResourceType}
107     */
108    public static boolean match(ResourceType resType, ResourceFolderType folderType) {
109        List<ResourceFolderType> list = mTypeToFolderMap.get(resType);
110
111        if (list != null) {
112            return list.contains(folderType);
113        }
114
115        return false;
116    }
117
118    /**
119     * Adds a {@link ResourceType} - {@link ResourceFolderType} relationship. this indicates that
120     * a file in the folder can generate a resource of the specified type.
121     * @param type The resourceType
122     * @param folder The {@link ResourceFolderType}
123     */
124    private static void add(ResourceType type, ResourceFolderType folder) {
125        // first we add the folder to the list associated with the type.
126        List<ResourceFolderType> folderList = mTypeToFolderMap.get(type);
127        if (folderList == null) {
128            folderList = new ArrayList<ResourceFolderType>();
129            mTypeToFolderMap.put(type, folderList);
130        }
131        if (folderList.indexOf(folder) == -1) {
132            folderList.add(folder);
133        }
134
135        // now we add the type to the list associated with the folder.
136        List<ResourceType> typeList = mFolderToTypeMap.get(folder);
137        if (typeList == null) {
138            typeList = new ArrayList<ResourceType>();
139            mFolderToTypeMap.put(folder, typeList);
140        }
141        if (typeList.indexOf(type) == -1) {
142            typeList.add(type);
143        }
144    }
145
146    /**
147     * Makes the maps safe by replacing the current list values with unmodifiable lists.
148     */
149    private static void makeSafe() {
150        for (ResourceType type : ResourceType.values()) {
151            List<ResourceFolderType> list = mTypeToFolderMap.get(type);
152            if (list != null) {
153                // replace with a unmodifiable list wrapper around the current list.
154                mTypeToFolderMap.put(type, Collections.unmodifiableList(list));
155            }
156        }
157
158        for (ResourceFolderType folder : ResourceFolderType.values()) {
159            List<ResourceType> list = mFolderToTypeMap.get(folder);
160            if (list != null) {
161                // replace with a unmodifiable list wrapper around the current list.
162                mFolderToTypeMap.put(folder, Collections.unmodifiableList(list));
163            }
164        }
165    }
166}
167