/*
 * Copyright (C) 2008-2015 by Holger Arndt
 *
 * This file is part of the Universal Java Matrix Package (UJMP).
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership and licensing.
 *
 * UJMP is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * UJMP 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with UJMP; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA  02110-1301  USA
 */

package org.ujmp.core.mapmatrix;

import java.io.Closeable;
import java.io.IOException;
import java.util.AbstractCollection;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.ujmp.core.Coordinates;
import org.ujmp.core.collections.list.FastArrayList;
import org.ujmp.core.objectmatrix.stub.AbstractDenseObjectMatrix2D;
import org.ujmp.core.util.MathUtil;
import org.ujmp.core.util.StringUtil;

public abstract class AbstractMapMatrix extends AbstractDenseObjectMatrix2D implements
		MapMatrix {
	private static final long serialVersionUID = 5571429371462164416L;

	private volatile boolean isIndexUpToDate = false;
	private final List keyIndexList = new FastArrayList();

	public AbstractMapMatrix() {
		super(0, 2);
	}

	public synchronized final long[] getSize() {
		size[ROW] = size();
		return size;
	}

	public synchronized final Object getObject(long row, long column) {
		return getObject(MathUtil.longToInt(row), MathUtil.longToInt(column));
	}

	public synchronized final int indexOfKey(Object key) {
		return keyIndexList.indexOf(key);
	}

	public synchronized final Object getObject(int row, int column) {
		Object mapKey = getKey(row);
		if (column == 0) {
			return mapKey;
		} else if (column == 1) {
			return (mapKey == null ? null : get(mapKey));
		} else {
			return null;
		}
	}

	@SuppressWarnings("unchecked")
	public synchronized final void setObject(Object value, int row, int column) {
		if (column == 0) {
			// remove old key and add new key with old value
			K key = getKey(row);
			V oldValue = get(key);
			remove(key);
			put((K) value, oldValue);
		} else if (column == 1) {
			K key = getKey(row);
			put(key, (V) value);
		}
	}

	public synchronized final void setObject(Object value, long row, long column) {
		setObject(value, MathUtil.longToInt(row), MathUtil.longToInt(column));
	}

	public synchronized MapMatrix clone() {
		buildIndexIfNecessary();
		MapMatrix clone = new DefaultMapMatrix();
		clone.putAll(this);
		for (K key : keyIndexList) {
			V value = get(key);
			clone.put(key, value);
		}
		return clone;
	}

	public String getAsString(Object key) {
		return StringUtil.convert(get(key));
	}

	private synchronized final K getKey(int index) {
		buildIndexIfNecessary();
		K k = null;
		if (index >= 0 && index < keyIndexList.size()) {
			k = keyIndexList.get(index);
		}
		return k;
	}

	private synchronized void buildIndexIfNecessary() {
		if (!isIndexUpToDate) {
			Iterator it = keySet().iterator();
			while (it.hasNext()) {
				keyIndexList.add(it.next());
			}
			if (it instanceof Closeable) {
				try {
					((Closeable) it).close();
				} catch (IOException e) {
					throw new RuntimeException(e);
				}
			}
			isIndexUpToDate = true;
		}
	}

	public synchronized boolean containsKey(Object key) {
		buildIndexIfNecessary();
		return keyIndexList.contains(key);
	}

	public synchronized boolean containsValue(Object value) {
		buildIndexIfNecessary();
		for (K key : keyIndexList) {
			if (value.equals(get(key))) {
				return true;
			}
		}
		return false;
	}

	public synchronized Set> entrySet() {
		final AbstractMapMatrix map = this;
		return new AbstractSet>() {

			@Override
			public Iterator> iterator() {
				return new Iterator>() {

					Iterator it = keySet().iterator();

					public boolean hasNext() {
						return it.hasNext();
					}

					public java.util.Map.Entry next() {
						final K k = it.next();
						final V v = get(k);
						return new java.util.Map.Entry() {

							public K getKey() {
								return k;
							}

							public V getValue() {
								return v;
							}

							public V setValue(V value) {
								throw new UnsupportedOperationException();
							}
						};
					}

					public void remove() {
						throw new UnsupportedOperationException();
					}
				};
			}

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

	public final synchronized boolean isEmpty() {
		return size() == 0;
	}

	public synchronized final V put(K key, V value) {
		keyIndexList.clear();
		isIndexUpToDate = false;
		V v = putIntoMap(key, value);
		if (v != null) {
			fireValueChanged(Coordinates.wrap(indexOfKey(key), 1), value);
		} else {
			fireValueChanged();
		}
		return v;
	}

	public synchronized final void putAll(Map map) {
		for (K k : map.keySet()) {
			putIntoMap(k, map.get(k));
		}
		fireValueChanged();
	}

	public synchronized final V remove(Object key) {
		keyIndexList.clear();
		isIndexUpToDate = false;
		V v = removeFromMap(key);
		fireValueChanged();
		return v;
	}

	public synchronized final Collection values() {
		buildIndexIfNecessary();
		final AbstractMapMatrix map = this;
		return new AbstractCollection() {
			@Override
			public Iterator iterator() {
				return new Iterator() {
					Iterator it = keyIndexList.iterator();

					public boolean hasNext() {
						return it.hasNext();
					}

					public V next() {
						return get(it.next());
					}

					public void remove() {
						throw new UnsupportedOperationException();
					}
				};
			}

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

	public final void clear() {
		keyIndexList.clear();
		isIndexUpToDate = false;
		clearMap();
	}

	protected abstract void clearMap();

	protected abstract V removeFromMap(Object key);

	protected abstract V putIntoMap(K key, V value);
}

 

Ads help maintain this website.