/*******************************************************************************
* Copyright (C) 2014 Travis Ralston (turt2live)
*
* 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 com.turt2live.antishare.configuration.groups;
import com.turt2live.antishare.collections.ArrayArrayList;
import com.turt2live.antishare.engine.list.RejectionList;
import com.turt2live.antishare.object.Rejectable;
import com.turt2live.antishare.object.attribute.TrackedState;
import java.util.ArrayList;
import java.util.List;
/**
* A block type list consisting of many rejection lists. This uses a
* voting-like system to determine what is tracked and what is not.
* <p/>
* It should be noted that this assumes all lists are of the same type,
* therefore a semi-random chosen list is used for {@link #getType()}
* where only the value of one list is considered for the return value.
* <p/>
* Internally when any getState() method is called a poll of all lists
* is activated to determine how many lists determine a location to be
* tracked and how many lists determine a list to be not tracked. An
* additional flag for "is tracked" is kept to ensure the correct return
* value is sent. If the flag is true and the "tracked" versus "negated"
* ratio is in favour of the tracked blocks then the return state is
* TRACKED. In the same scenario with the ratio in favour of negated,
* NEGATED is returned. In the event that the location is not tracked
* or that the negated and tracked counts are equal, NOT_PRESENT is
* returned.
*
* @author turt2live
*/
// TODO: Unit test
public class ConsolidatedRejectionList<T extends Rejectable> implements RejectionList<T> {
private List<RejectionList<T>> lists = new ArrayList<>();
/**
* Creates a new consolidated rejection list
*
* @param lists the lists to include. Cannot be null and must have at least one record
*/
public ConsolidatedRejectionList(List<RejectionList<T>> lists) {
if (lists == null || lists.isEmpty()) throw new IllegalArgumentException("lists cannot be null or empty");
this.lists.addAll(lists);
}
/**
* Creates a new consolidated rejection list
*
* @param lists the lists to include. Cannot be null and must have at least one record
*/
public ConsolidatedRejectionList(RejectionList<T>... lists) {
this(new ArrayArrayList<>(lists));
}
@Override
public boolean isBlocked(T item) {
return getState(item) == TrackedState.INCLUDED; // Tee hee
}
@Override
public TrackedState getState(T item) {
if (item == null) throw new IllegalArgumentException("location cannot be null");
int tracked = 0;
int negated = 0;
boolean included = false;
for (RejectionList<T> list : lists) {
TrackedState state = list.getState(item);
switch (state) {
case INCLUDED:
tracked++;
included = true;
break;
case NEGATED:
negated++;
included = true;
break;
default:
break;
}
}
return included && tracked != negated ? (tracked > negated ? TrackedState.INCLUDED : TrackedState.NEGATED) : TrackedState.NOT_PRESENT;
}
@Override
public ListType getType() {
return lists.get(0).getType();
}
}