001package com.hfg.util.collection;
002
003import java.util.HashMap;
004import java.util.HashSet;
005import java.util.Map;
006import java.util.Set;
007
008//------------------------------------------------------------------------------
009/**
010 * HashMap that keeps a dirty flag.
011 * @author J. Alex Taylor, hairyfatguy.com
012 */
013//------------------------------------------------------------------------------
014// com.hfg Library
015//
016// This library is free software; you can redistribute it and/or
017// modify it under the terms of the GNU Lesser General Public
018// License as published by the Free Software Foundation; either
019// version 2.1 of the License, or (at your option) any later version.
020//
021// This library is distributed in the hope that it will be useful,
022// but WITHOUT ANY WARRANTY; without even the implied warranty of
023// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
024// Lesser General Public License for more details.
025//
026// You should have received a copy of the GNU Lesser General Public
027// License along with this library; if not, write to the Free Software
028// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
029//
030// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com
031// jataylor@hairyfatguy.com
032//------------------------------------------------------------------------------
033
034public class DirtyMap<K, V> extends HashMap<K, V>
035{
036   private boolean mIsDirty;
037   private Set<K>  mDirtyKeySet;
038
039   //##########################################################################
040   // CONSTRUCTORS
041   //##########################################################################
042
043   //--------------------------------------------------------------------------
044   public DirtyMap()
045   {
046      super();
047   }
048
049   //--------------------------------------------------------------------------
050   public DirtyMap(int inInitialCapacity)
051   {
052      super(inInitialCapacity);
053   }
054
055   //--------------------------------------------------------------------------
056   public DirtyMap(int inInitialCapacity, float inLoadFactor)
057   {
058      super(inInitialCapacity, inLoadFactor);
059   }
060
061   //--------------------------------------------------------------------------
062   public DirtyMap(Map<? extends K,? extends V> inMap)
063   {
064      super(inMap);
065   }
066
067   //##########################################################################
068   // PUBLIC METHODS
069   //##########################################################################
070
071   //--------------------------------------------------------------------------
072   public void bless()
073   {
074      mIsDirty = false;
075      mDirtyKeySet = null;
076   }
077
078   //--------------------------------------------------------------------------
079   public boolean isDirty()
080   {
081      return mIsDirty;
082   }
083
084   //--------------------------------------------------------------------------
085   public Set<K> dirtyKeySet()
086   {
087      return CollectionUtil.hasValues(mDirtyKeySet) ? mDirtyKeySet : null;
088   }
089
090   //--------------------------------------------------------------------------
091   @Override
092   public void clear()
093   {
094      if (size() > 0)
095      {
096         mIsDirty = true;
097         super.clear();
098
099         mDirtyKeySet = null;
100      }
101   }
102
103   //--------------------------------------------------------------------------
104   @Override
105   public V put(K inKey, V inValue)
106   {
107      if (containsKey(inKey))
108      {
109         V currentValue = get(inKey);
110
111         boolean changed;
112         if (null == inValue)
113         {
114            changed = (currentValue != null);
115         }
116         else if (null == currentValue)
117         {
118            changed = true;
119         }
120         else
121         {
122            changed = !currentValue.equals(inValue);
123         }
124
125         if (changed)
126         {
127            if (null == mDirtyKeySet)
128            {
129               mDirtyKeySet = new HashSet<>(size());
130            }
131
132            mDirtyKeySet.add(inKey);
133
134            if (!isDirty())
135            {
136               mIsDirty = changed;
137            }
138         }
139      }
140      else
141      {
142         // New key
143         if (null == mDirtyKeySet)
144         {
145            mDirtyKeySet = new HashSet<>(size());
146         }
147
148         mDirtyKeySet.add(inKey);
149
150         mIsDirty = true;
151      }
152
153      return super.put(inKey, inValue);
154   }
155
156   //--------------------------------------------------------------------------
157   @Override
158   public void putAll(Map<? extends K,? extends V> m)
159   {
160      for (K key : m.keySet())
161      {
162         put(key, m.get(key));
163      }
164   }
165
166   //--------------------------------------------------------------------------
167   @Override
168   public V remove(Object inKey)
169   {
170      boolean containsKey = containsKey(inKey);
171      if (mDirtyKeySet != null
172          && containsKey)
173      {
174         mDirtyKeySet.remove(inKey);
175      }
176
177      if (! isDirty()
178          && containsKey)
179      {
180         mIsDirty = true;
181      }
182
183      return super.remove(inKey);
184   }
185
186}