1////////////////////////////////////////////////////////////////////////////////
2//
3//  ADOBE SYSTEMS INCORPORATED
4//  Copyright 2009 Adobe Systems Incorporated
5//  All Rights Reserved.
6//
7//  NOTICE: Adobe permits you to use, modify, and distribute this file
8//  in accordance with the terms of the license agreement accompanying it.
9//
10////////////////////////////////////////////////////////////////////////////////
11
12package spark.effects
13{
14import flash.utils.Dictionary;
15
16/**
17 * This internal class is a utility used by AnimateTransform to
18 * store, retrieve, and remove shared objects. The class uses a
19 * Dictionary of Dictionaries internally to store the shared
20 * objects and keeps a reference count for the entries to know
21 * when it is okay to remove the top level dictionary entry.
22 *
23 * The reason this is needed by AnimateTransform is that we want
24 * to share transform instances per top-level Parallel effect.
25 * But rather than keep the Dictionary-of-Dictionaries at that level,
26 * we keep it in this utility class. We add the reference count
27 * to the upper-level dictionary to know when we can delete it
28 * (Dictionary lacks any useful isEmpty() capability).
29 *
30 * The top level Dictionary elements are stored in sharedObjectMaps
31 * by the mapKey passed into storeSharedObject(). The items in
32 * sharedObjectMaps are Dictionaries using the target argument passed
33 * into storeSharedObject() to store their entries.
34 */
35internal class SharedObjectDepot
36{
37    /**
38     * The upper level Dictionary object. This will store our
39     * lower level Dictionaries that we create on the fly
40     */
41    private var sharedObjectMaps:Dictionary = new Dictionary(true);
42
43    /**
44     * The refcount per key in sharedObjectMaps. When the refcount
45     * for any map dips to zero, we delete it from sharedObjectMaps.
46     */
47    private var sharedObjectRefcounts:Dictionary = new Dictionary(true);
48
49    public function SharedObjectDepot()
50    {
51    }
52
53    /**
54     * Returns a shared object if it exists. The top level map is
55     * searched to see if there is an entry (another map) for the key
56     * 'mapKey'. If that exists, that map is searched to see if there
57     * is an entry with the key 'target'. mapKey must be non-null.
58     *
59     * @return Object the shared object, if it exists, or null otherwise.
60     */
61    public function getSharedObject(mapKey:Object, target:Object):Object
62    {
63        if (mapKey != null)
64        {
65            var sharedObjectMap:Dictionary =
66                Dictionary(sharedObjectMaps[mapKey]);
67            if (sharedObjectMap != null)
68                return sharedObjectMap[target];
69        }
70        return null;
71    }
72
73    /**
74     * Stores a new entry in the shared object map. First, the
75     * top level map is searched to see if there is an existing
76     * map entry (also a map) with the key 'mapKey'. If not, a
77     * new map is created and stored with this key in the top level
78     * map. Then the lower level map is queried to see if there
79     * is an entry with the key 'target'. If not, the refcount for
80     * mapKey is incremented. Finally, an entry is stored in the lower
81     * level map with the key 'target'. mapKey must be non-null.
82     *
83     */
84    public function storeSharedObject(mapKey:Object, target:Object,
85        instance:Object):void
86    {
87        if (mapKey != null)
88        {
89            var sharedObjectMap:Dictionary = sharedObjectMaps[mapKey];
90            if (!sharedObjectMap)
91            {
92                sharedObjectMap = new Dictionary();
93                sharedObjectMaps[mapKey] = sharedObjectMap;
94            }
95            if (!sharedObjectMap[target])
96            {
97                if (!sharedObjectRefcounts[mapKey])
98                    sharedObjectRefcounts[mapKey] = 1;
99                else
100                    sharedObjectRefcounts[mapKey] += 1;
101            }
102            sharedObjectMap[target] = instance;
103        }
104    }
105
106    /**
107     * Removes the entry accessed with the upper level key of mapKey and
108     * lower level key of target. If the refcount for mapKey reaches zero,
109     * that entry is deleted from the upper level map. mapKey must be
110     * non-null
111     */
112    public function removeSharedObject(mapKey:Object, target:Object):void
113    {
114        if (mapKey != null)
115        {
116            var sharedObjectMap:Dictionary = sharedObjectMaps[mapKey];
117            if (!sharedObjectMap)
118                return;
119            if (sharedObjectMap[target])
120            {
121                delete sharedObjectMap[target];
122                sharedObjectRefcounts[mapKey] -= 1;
123                if (sharedObjectRefcounts[mapKey] <= 0)
124                {
125                    delete sharedObjectMaps[mapKey];
126                    delete sharedObjectRefcounts[mapKey];
127                }
128            }
129        }
130    }
131}
132}