package charactermanaj.ui.model;

import java.util.AbstractList;
import java.util.ArrayList;
import java.util.List;

import javax.swing.ComboBoxModel;
import javax.swing.event.EventListenerList;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;

/**
 * コンボボックスのリストへの追加によって自動的に現在選択が設定されないシンプルな動きをするコンボボックスのモデル。
 * リストの削除時に現在選択中のものが削除される場合は、現在選択は解除される。
 *
 * @param <S>
 */
public class SimpleComboBoxModel<S> extends AbstractList<S> implements ComboBoxModel {

	private EventListenerList listeners = new EventListenerList();

	private List<S> items;

	private Object selectedItem;

	public SimpleComboBoxModel() {
		this(new ArrayList<S>());
	}

	public SimpleComboBoxModel(List<S> items) {
		this.items = items;
	}

	public void setAll(List<S> items) {
		this.items.clear();
		if (items != null) {
			this.items.addAll(items);
		}

		ListDataListener[] ls = listeners.getListeners(ListDataListener.class);
		if (ls.length > 0) {
			ListDataEvent evt = new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, 0, this.items.size());
			for (ListDataListener l : ls) {
				l.contentsChanged(evt);
			}
		}
	}

	@Override
	public S get(int index) {
		return items.get(index);
	}

	@Override
	public int size() {
		return items.size();
	}

	@Override
	public int getSize() {
		return size();
	}

	@Override
	public Object getElementAt(int index) {
		return get(index);
	}

	@SuppressWarnings("unchecked")
	public boolean add(S element) {
		int found = -1;

		// 自然ソート順で挿入位置を求める
		int len = items.size();
		for (int idx = 0; idx < len; idx++) {
			S v = items.get(idx);
			int comp = ((Comparable<S>) element).compareTo(v);
			if (comp < 0) {
				break;
			}
			found = idx;
		}
		add(found + 1, element);

		return true;
	}

	@Override
	public void add(int index, S element) {
		items.add(index, element);

		ListDataListener[] ls = listeners.getListeners(ListDataListener.class);
		if (ls.length > 0) {
			ListDataEvent evt = new ListDataEvent(this, ListDataEvent.INTERVAL_ADDED, index, index);
			for (ListDataListener l : ls) {
				l.intervalAdded(evt);
			}
		}
	}

	@Override
	public S set(int index, S element) {
		S old = items.set(index, element);

		ListDataListener[] ls = listeners.getListeners(ListDataListener.class);
		if (ls.length > 0) {
			ListDataEvent evt = new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, index, index);
			for (ListDataListener l : ls) {
				l.contentsChanged(evt);
			}
		}
		return old;
	}

	@Override
	public S remove(int index) {
		S old = items.remove(index);

		ListDataListener[] ls = listeners.getListeners(ListDataListener.class);
		if (ls.length > 0) {
			ListDataEvent evt = new ListDataEvent(this, ListDataEvent.INTERVAL_REMOVED, index, index);
			for (ListDataListener l : ls) {
				l.intervalRemoved(evt);
			}
		}

		if (old != null && old.equals(selectedItem)) {
			setSelectedItem(null);
		}

		return old;
	}

	@Override
	public void addListDataListener(ListDataListener l) {
		listeners.add(ListDataListener.class, l);
	}

	@Override
	public void removeListDataListener(ListDataListener l) {
		listeners.remove(ListDataListener.class, l);
	}

	@Override
	public void setSelectedItem(Object anItem) {
		this.selectedItem = anItem;
		ListDataListener[] ls = listeners.getListeners(ListDataListener.class);
		if (ls.length > 0) {
			ListDataEvent evt = new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, -1, -1);
			for (ListDataListener l : ls) {
				l.contentsChanged(evt);
			}
		}
	}

	@Override
	public Object getSelectedItem() {
		return selectedItem;
	}
}