/*
* Copyright (C) 2013 Chen Hui <calmer91@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package master.flame.danmaku.danmaku.model.android;
import master.flame.danmaku.danmaku.model.BaseDanmaku;
import master.flame.danmaku.danmaku.model.Danmaku;
import master.flame.danmaku.danmaku.model.IDanmakuIterator;
import master.flame.danmaku.danmaku.model.IDanmakus;
import master.flame.danmaku.danmaku.util.DanmakuUtils;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
public class Danmakus implements IDanmakus {
public static final int ST_BY_TIME = 0;
public static final int ST_BY_YPOS = 1;
public static final int ST_BY_YPOS_DESC = 2;
/**
* this type is used to iterate/remove/insert elements, not support sub/subnew
*/
public static final int ST_BY_LIST = 4;
public Collection<BaseDanmaku> items;
private Danmakus subItems;
private BaseDanmaku startItem, endItem;
private BaseDanmaku endSubItem;
private BaseDanmaku startSubItem;
private DanmakuIterator iterator;
private int mSize = 0;
private int mSortType = ST_BY_TIME;
private BaseComparator mComparator;
private boolean mDuplicateMergingEnabled;
public Danmakus() {
this(ST_BY_TIME, false);
}
public Danmakus(int sortType) {
this(sortType, false);
}
public Danmakus(int sortType, boolean duplicateMergingEnabled) {
BaseComparator comparator = null;
if (sortType == ST_BY_TIME) {
comparator = new TimeComparator(duplicateMergingEnabled);
} else if (sortType == ST_BY_YPOS) {
comparator = new YPosComparator(duplicateMergingEnabled);
} else if (sortType == ST_BY_YPOS_DESC) {
comparator = new YPosDescComparator(duplicateMergingEnabled);
}
if(sortType == ST_BY_LIST) {
items = new LinkedList<BaseDanmaku>();
} else {
mDuplicateMergingEnabled = duplicateMergingEnabled;
comparator.setDuplicateMergingEnabled(duplicateMergingEnabled);
items = new TreeSet<BaseDanmaku>(comparator);
mComparator = comparator;
}
mSortType = sortType;
mSize = 0;
iterator = new DanmakuIterator(items);
}
public Danmakus(Collection<BaseDanmaku> items) {
setItems(items);
}
public Danmakus(boolean duplicateMergingEnabled) {
this(ST_BY_TIME, duplicateMergingEnabled);
}
public void setItems(Collection<BaseDanmaku> items) {
if (mDuplicateMergingEnabled && mSortType != ST_BY_LIST) {
this.items.clear();
this.items.addAll(items);
items = this.items;
}
else {
this.items = items;
}
if (items instanceof List) {
mSortType = ST_BY_LIST;
}
mSize = (items == null ? 0 : items.size());
if (iterator == null) {
iterator = new DanmakuIterator(items);
} else {
iterator.setDatas(items);
}
}
public IDanmakuIterator iterator() {
iterator.reset();
return iterator;
}
@Override
public boolean addItem(BaseDanmaku item) {
if (items != null) {
try {
if (items.add(item)) {
mSize++;
return true;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return false;
}
@Override
public boolean removeItem(BaseDanmaku item) {
if (item == null) {
return false;
}
if (item.isOutside()) {
item.setVisibility(false);
}
if (items.remove(item)) {
mSize--;
return true;
}
return false;
}
private Collection<BaseDanmaku> subset(long startTime, long endTime) {
if (mSortType == ST_BY_LIST || items == null || items.size() == 0) {
return null;
}
if (subItems == null) {
subItems = new Danmakus(mDuplicateMergingEnabled);
}
if (startSubItem == null) {
startSubItem = createItem("start");
}
if (endSubItem == null) {
endSubItem = createItem("end");
}
startSubItem.time = startTime;
endSubItem.time = endTime;
return ((SortedSet<BaseDanmaku>) items).subSet(startSubItem, endSubItem);
}
@Override
public IDanmakus subnew(long startTime, long endTime) {
Collection<BaseDanmaku> subset = subset(startTime, endTime);
return new Danmakus(subset);
}
@Override
public IDanmakus sub(long startTime, long endTime) {
if (mSortType == ST_BY_LIST || items == null || items.size() == 0) {
return null;
}
if (subItems == null) {
subItems = new Danmakus(mDuplicateMergingEnabled);
}
if (startItem == null) {
startItem = createItem("start");
}
if (endItem == null) {
endItem = createItem("end");
}
if (subItems != null) {
long dtime = startTime - startItem.time;
if (dtime >= 0 && endTime <= endItem.time) {
return subItems;
}
}
startItem.time = startTime;
endItem.time = endTime;
subItems.setItems(((SortedSet<BaseDanmaku>) items).subSet(startItem, endItem));
return subItems;
}
private BaseDanmaku createItem(String text) {
return new Danmaku(text);
}
public int size() {
return mSize;
}
@Override
public void clear() {
if (items != null){
items.clear();
mSize = 0;
}
if (subItems != null) {
subItems.clear();
}
}
@Override
public BaseDanmaku first() {
if (items != null && !items.isEmpty()) {
if (mSortType == ST_BY_LIST) {
return ((LinkedList<BaseDanmaku>) items).getFirst();
}
return ((SortedSet<BaseDanmaku>) items).first();
}
return null;
}
@Override
public BaseDanmaku last() {
if (items != null && !items.isEmpty()) {
if (mSortType == ST_BY_LIST) {
return ((LinkedList<BaseDanmaku>) items).getLast();
}
return ((SortedSet<BaseDanmaku>) items).last();
}
return null;
}
private class DanmakuIterator implements IDanmakuIterator{
private Collection<BaseDanmaku> mData;
private Iterator<BaseDanmaku> it;
private boolean mIteratorUsed;
public DanmakuIterator(Collection<BaseDanmaku> datas){
setDatas(datas);
}
public synchronized void reset() {
if (!mIteratorUsed && it != null) {
return;
}
if (mData != null && mSize > 0) {
it = mData.iterator();
} else {
it = null;
}
}
public synchronized void setDatas(Collection<BaseDanmaku> datas){
if (mData != datas) {
mIteratorUsed = false;
it = null;
}
mData = datas;
}
@Override
public synchronized BaseDanmaku next() {
mIteratorUsed = true;
return it != null ? it.next() : null;
}
@Override
public synchronized boolean hasNext() {
return it != null && it.hasNext();
}
@Override
public synchronized void remove() {
mIteratorUsed = true;
if (it != null) {
it.remove();
}
}
}
private class BaseComparator implements Comparator<BaseDanmaku> {
protected boolean mDuplicateMergingEnable;
public BaseComparator(boolean duplicateMergingEnabled) {
setDuplicateMergingEnabled(duplicateMergingEnabled);
}
public void setDuplicateMergingEnabled(boolean enable) {
mDuplicateMergingEnable = enable;
}
@Override
public int compare(BaseDanmaku obj1, BaseDanmaku obj2) {
if (mDuplicateMergingEnable && DanmakuUtils.isDuplicate(obj1, obj2)) {
return 0;
}
return DanmakuUtils.compare(obj1, obj2);
}
}
private class TimeComparator extends BaseComparator {
public TimeComparator(boolean duplicateMergingEnabled) {
super(duplicateMergingEnabled);
}
@Override
public int compare(BaseDanmaku obj1, BaseDanmaku obj2) {
return super.compare(obj1, obj2);
}
}
private class YPosComparator extends BaseComparator {
public YPosComparator(boolean duplicateMergingEnabled) {
super(duplicateMergingEnabled);
}
@Override
public int compare(BaseDanmaku obj1, BaseDanmaku obj2) {
if (mDuplicateMergingEnable && DanmakuUtils.isDuplicate(obj1, obj2)) {
return 0;
}
int result = Float.compare(obj1.getTop(), obj2.getTop());
if (result != 0) {
return result;
}
return DanmakuUtils.compare(obj1, obj2);
}
}
private class YPosDescComparator extends BaseComparator {
public YPosDescComparator(boolean duplicateMergingEnabled) {
super(duplicateMergingEnabled);
}
@Override
public int compare(BaseDanmaku obj1, BaseDanmaku obj2) {
if (mDuplicateMergingEnable && DanmakuUtils.isDuplicate(obj1, obj2)) {
return 0;
}
int result = Float.compare(obj2.getTop(), obj1.getTop());
if (result != 0) {
return result;
}
return DanmakuUtils.compare(obj1, obj2);
}
}
@Override
public boolean contains(BaseDanmaku item) {
return this.items != null && this.items.contains(item);
}
@Override
public boolean isEmpty() {
return this.items == null || this.items.isEmpty();
}
private void setDuplicateMergingEnabled(boolean enable) {
mComparator.setDuplicateMergingEnabled(enable);
mDuplicateMergingEnabled = enable;
}
@Override
public void setSubItemsDuplicateMergingEnabled(boolean enable) {
mDuplicateMergingEnabled = enable;
startItem = endItem = null;
if (subItems == null) {
subItems = new Danmakus(enable);
}
subItems.setDuplicateMergingEnabled(enable);
}
}