/*******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2017 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package channel.metadata;
import alias.Alias;
import sample.Listener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class AttributeMonitor<T>
{
private Attribute mAttribute;
private Listener<AttributeChangeRequest> mListener;
private boolean mHeuristicsEnabled = true;
private Map<T,Integer> mOccurrenceCounts = new HashMap<>();
private T mCurrentValue;
private List<T> mIllegalValues = new ArrayList<>();
public AttributeMonitor(Attribute attribute, Listener<AttributeChangeRequest> listener)
{
mAttribute = attribute;
mListener = listener;
}
/**
* Processes the value and emits a change request if the value needs to be changed. If heuristics are enabled,
* an internal mapping of values to occurrence counts is updated and a change is emitted once a value that is
* different from the current value, has a higher occurrence count than the current value. If heuristics are
* disabled, then a change is emitted at each change in the value.
*
* @param t type
* @return true if the value was changed after processing
*/
public boolean process(T t)
{
boolean changed = false;
if(t != null && !mIllegalValues.contains(t))
{
if(mHeuristicsEnabled)
{
if(mOccurrenceCounts.containsKey(t))
{
mOccurrenceCounts.put(t, mOccurrenceCounts.get(t) + 1);
}
else
{
mOccurrenceCounts.put(t, 1);
}
}
if(mCurrentValue == null)
{
mCurrentValue = t;
changed = true;
}
else if(!mCurrentValue.equals(t))
{
if(mHeuristicsEnabled)
{
int count = mOccurrenceCounts.get(mCurrentValue);
for(Map.Entry<T,Integer> entry : mOccurrenceCounts.entrySet())
{
if(entry.getValue() > count)
{
count = entry.getValue();
mCurrentValue = entry.getKey();
changed = true;
}
}
}
else
{
mCurrentValue = t;
changed = true;
}
}
if(changed && mListener != null)
{
mListener.receive(new AttributeChangeRequest(mAttribute, getValue(), getAlias()));
}
}
return changed;
}
/**
* Alias for the current value. This class does not return an alias, but subclasses can return an alias that
* is appropriate for the monitored attribute value.
*
* @return an optional alias for the current value
*/
protected Alias getAlias()
{
return null;
}
/**
* Resets the attribute value to null and resets occurrence heuristics.
*/
public void reset()
{
mCurrentValue = null;
mOccurrenceCounts.clear();
}
/**
* Adds a value to the internal list of illegal values. The monitor will not allow the attribute to be changed to
* any values contained in this list.
*
* @param illegalValue to prevent for the monitored alias
*/
public void addIllegalValue(T illegalValue)
{
mIllegalValues.add(illegalValue);
}
/**
* Returns the current value or null if the monitor is newly started or reset.
*/
public T getValue()
{
return mCurrentValue;
}
/**
* Indicates if the current value is non-null
*/
public boolean hasValue()
{
return mCurrentValue != null;
}
}