Index: DefaultFeatureSelection.java
===================================================================
--- DefaultFeatureSelection.java	(revision 43088)
+++ DefaultFeatureSelection.java	(revision 43089)
@@ -3,23 +3,22 @@
  *
  * Copyright (C) 2007-2013 gvSIG Association.
  *
- * 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 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.
+ * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA  02110-1301, USA.
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
- * For any additional information, do not hesitate to contact us
- * at info AT gvsig.com, or visit our website www.gvsig.com.
+ * For any additional information, do not hesitate to contact us at info AT
+ * gvsig.com, or visit our website www.gvsig.com.
  */
 package org.gvsig.fmap.dal.feature.impl;
 
@@ -41,18 +40,19 @@
 import org.gvsig.fmap.dal.feature.FeatureStore;
 import org.gvsig.fmap.dal.feature.FeatureType;
 import org.gvsig.fmap.dal.feature.exception.ReversedSelectionIteratorException;
-import org.gvsig.fmap.dal.feature.impl.dynobjectutils.DynObjectSetFeatureSetFacade;
+import org.gvsig.fmap.dal.feature.impl.DefaultFeatureReferenceSelection.SelectionData;
+import org.gvsig.fmap.dal.feature.impl.featureset.AbstractFeatureSet;
+import org.gvsig.fmap.dal.feature.impl.undo.FeatureCommandsStack;
 import org.gvsig.tools.ToolsLocator;
 import org.gvsig.tools.dispose.DisposableIterator;
 import org.gvsig.tools.dispose.DisposeUtils;
-import org.gvsig.tools.dynobject.DynObjectSet;
 import org.gvsig.tools.dynobject.DynStruct;
 import org.gvsig.tools.exception.BaseException;
+import org.gvsig.tools.observer.Observable;
+import org.gvsig.tools.observer.Observer;
 import org.gvsig.tools.persistence.PersistenceManager;
 import org.gvsig.tools.persistence.PersistentState;
 import org.gvsig.tools.persistence.exception.PersistenceException;
-import org.gvsig.tools.visitor.VisitCanceledException;
-import org.gvsig.tools.visitor.Visitor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -65,602 +65,669 @@
  *
  * @author <a href="mailto:cordin@disid.com">Cèsar Ordiñana</a>
  */
-public class DefaultFeatureSelection extends DefaultFeatureReferenceSelection
-		implements FeatureSelection {
+public class DefaultFeatureSelection extends AbstractFeatureSet
+        implements FeatureSelection {
 
-	private static final Logger LOG = LoggerFactory
-			.getLogger(DefaultFeatureSelection.class);
+    private static final Logger LOG = LoggerFactory
+            .getLogger(DefaultFeatureSelection.class);
 
-	private Map featureTypeCounts = new HashMap(1);
-	private Map<Feature,Iterator> featureIterators = new HashMap<>();
+    public class RemoveFromFeatureSelectionException extends DataRuntimeException {
 
-	/**
-	 * Creates a DefaultFeatureSelection, with a FeatureStore.
-	 *
-	 * @param featureStore
-	 *            the FeatureStore to load Features from
-	 * @throws DataException
-	 *             if there is an error while getting the total number of
-	 *             Features of the Store.
-	 * @see AbstractSetBasedDataSelection#DefaultSelection(int)
-	 */
-	public DefaultFeatureSelection(DefaultFeatureStore featureStore)
-			throws DataException {
-		super(featureStore);
-	}
+        /**
+         *
+         */
+        private static final long serialVersionUID = 2636692469445838928L;
+        private final static String MESSAGE_FORMAT = "Can't remove feature from reversed selection.";
+        private final static String MESSAGE_KEY = "_RemoveFromFeatureSelectionException";
 
-	/**
-	 * Creates a new Selection with the total size of Features from which the
-	 * selection will be performed.
-	 *
-	 * @param featureStore
-	 *            the FeatureStore of the selected FeatureReferences
-	 * @param helper
-	 *            to get some information of the Store
-	 * @throws DataException
-	 *             if there is an error while getting the total number of
-	 *             Features of the Store.
-	 */
-	public DefaultFeatureSelection(FeatureStore featureStore,
-			FeatureSelectionHelper helper) throws DataException {
-		super(featureStore, helper);
-	}
+        public RemoveFromFeatureSelectionException(Throwable cause) {
+            super(MESSAGE_FORMAT, cause, MESSAGE_KEY, serialVersionUID);
+            //setValue("store", store);
+        }
+    }
 
-	/**
-	 * Constructor used by the persistence manager. Don't use directly. After to
-	 * invoke this method, the persistence manager calls the the method
-	 * {@link #loadFromState(PersistentState)} to set the values of the internal
-	 * attributes that this class needs to work.
-	 */
-	public DefaultFeatureSelection() {
-		super();
-	}
+    /**
+     * Facade over a Iterator of FeatureReferences, to return Features instead.
+     *
+     * @author <a href="mailto:cordin@disid.com">Cèsar Ordiñana</a>
+     */
+    private class FeatureIteratorFacade implements DisposableIterator {
 
-	public boolean select(Feature feature) {
-		return select(feature, true);
-	}
+        private final Logger LOGGER = LoggerFactory
+                .getLogger(FeatureIteratorFacade.class);
 
-	/**
-	 * @see #select(Feature)
-	 * @param undoable
-	 *            if the action must be undoable
-	 */
-	public boolean select(Feature feature, boolean undoable) {
-		// TODO: should we check if the feature is from the same FeatureStore??
-		if (feature == null) {
-			return false;
-		}
+        private java.util.Iterator refIterator;
 
-		// LOGGER.debug("Selected feature: {}", feature);
+        private FeatureStore featureStore;
+        private Feature currentFeature = null;
 
-		if (isReversed()) {
-			removeFeatureTypeCount(feature.getType());
-		} else {
-			addFeatureTypeCount(feature.getType());
-		}
-		return select(feature.getReference(), undoable);
-	}
+        public FeatureIteratorFacade(java.util.Iterator iter,
+                FeatureStore featureStore) {
+            this.refIterator = iter;
+            this.featureStore = featureStore;
+        }
 
-	public boolean select(FeatureSet features) throws DataException {
-		return select(features, true);
-	}
+        @Override
+        public boolean hasNext() {
+            return refIterator.hasNext();
+        }
 
-	/**
-	 * @see #select(FeatureSet)
-	 * @param undoable
-	 *            if the action must be undoable
-	 */
-	public boolean select(FeatureSet features, boolean undoable)
-			throws DataException {
-		boolean change = false;
-		boolean inComplex = false;
-		if (undoable && getFeatureStore().isEditing()
-				&& !getCommands().inComplex()) {
+        @Override
+        public Object next() {
+            FeatureReference ref = nextFeatureReference();
+            try {
+                currentFeature = featureStore.getFeatureByReference(ref);
+                return currentFeature;
+            } catch (DataException ex) {
+                LOGGER.error(
+                        "Error loading the Feature with FeatureReference: "
+                        + ref, ex);
+                return null;
+            }
+        }
 
-			getCommands().startComplex("_selectionSelectFeatureSet");
-			inComplex = getCommands().inComplex();
-		}
+        /**
+         * Returns the next FeatureReference.
+         *
+         * @return the next FeatureReference
+         */
+        public FeatureReference nextFeatureReference() {
+            return (FeatureReference) refIterator.next();
+        }
 
-		disableNotifications();
-		DisposableIterator iter = null;
-		try {
-			for (iter = features.fastIterator(); iter.hasNext();) {
-				change |= select((Feature) iter.next(), undoable);
-			}
-		} finally {
-			dispose(iter);
-		}
-		enableNotifications();
-		if (undoable && getFeatureStore().isEditing() && inComplex) {
-			getCommands().endComplex();
-		}
-		if (change) {
-			notifyObservers(DataStoreNotification.SELECTION_CHANGE);
-		}
-		return change;
-	}
+        @Override
+        public void remove() {
+            try {
+                featureStore.delete(currentFeature);
+                refIterator.remove();
+            } catch (DataException e) {
+                throw new RemoveFromFeatureSelectionException(e);
+            }
+        }
 
-	public boolean deselect(Feature feature) {
-		return deselect(feature, true);
-	}
+        public class RemoveFromFeatureSelectionException extends DataRuntimeException {
 
-	/**
-	 * @see #deselect(Feature)
-	 * @param undoable
-	 *            if the action must be undoable
-	 */
-	public boolean deselect(Feature feature, boolean undoable) {
-		if (feature == null) {
-			return false;
-		}
+            /**
+             *
+             */
+            private static final long serialVersionUID = 2636692469445838928L;
+            private final static String MESSAGE_FORMAT = "Can't remove feature from selection.";
+            private final static String MESSAGE_KEY = "_RemoveFromFeatureSelectionException";
 
-		LOG.debug("Deselected feature: {}", feature);
+            public RemoveFromFeatureSelectionException(Throwable cause) {
+                super(MESSAGE_FORMAT, cause, MESSAGE_KEY, serialVersionUID);
+                //setValue("store", store);
+            }
+        }
 
-		if (isReversed()) {
-			addFeatureTypeCount(feature.getType());
-		} else {
-			removeFeatureTypeCount(feature.getType());
-		}
-		return deselect(feature.getReference(), undoable);
-	}
+        @Override
+        public void dispose() {
+            if (refIterator instanceof DisposableIterator) {
+                ((DisposableIterator) refIterator).dispose();
+            }
+            refIterator = null;
+            featureStore = null;
+        }
+    }
 
-	public boolean deselect(FeatureSet features) throws DataException {
-		return deselect(features, true);
-	}
+    /**
+     * Facade over a Iterator of FeatureReferences, to return Features instead,
+     * when the Selection is reversed
+     *
+     * @author <a href="mailto:cordin@disid.com">Cèsar Ordiñana</a>
+     */
+    private class ReversedFeatureIteratorFacade implements DisposableIterator {
 
-	/**
-	 * @see #deselect(FeatureSet)
-	 * @param undoable
-	 *            if the action must be undoable
-	 */
-	public boolean deselect(FeatureSet features, boolean undoable)
-			throws DataException {
-		boolean change = false;
-		if (undoable && getFeatureStore().isEditing()) {
-			getCommands().startComplex("_selectionDeselectFeatureSet");
-		}
-		disableNotifications();
-		DisposableIterator iter = null;
-		try {
-			for (iter = features.fastIterator(); iter.hasNext();) {
-				change |= deselect((Feature) iter.next(), undoable);
-			}
-		} finally {
-			dispose(iter);
-		}
-		enableNotifications();
-		if (undoable && getFeatureStore().isEditing()) {
-			getCommands().endComplex();
-		}
-		if (change) {
-			notifyObservers(DataStoreNotification.SELECTION_CHANGE);
-		}
-		return change;
-	}
+        private SelectionData selectionData;
 
-	public boolean isSelected(Feature feature) {
-		if (feature == null) {
-			return false;
-		}
+        private DisposableIterator iterator;
 
-        // Use the selection data size as a small optimization for the most
-        // common case, when nothing is selected and every feature is checked
-        // while drawing or painting the table document.
-        if (selectionData.isReversed()) {
-            return selectionData.getSize() == 0
-                || !selectionData.contains(feature.getReference());
-        } else {
-            return selectionData.getSize() > 0
-                && selectionData.contains(feature.getReference());
-        }
-	}
+        private Feature nextFeature = null;
+        private Feature currentFeature = null;
 
-	public FeatureType getDefaultFeatureType() {
-		try {
-			return getFeatureStore().getDefaultFeatureType();
-		} catch (DataException ex) {
-			LOG.error("Error getting the default feature type "
-					+ "of the FeatureStore: " + getFeatureStore(), ex);
-		}
-		return null;
-	}
+        private FeatureSet featureSet;
 
-	public List getFeatureTypes() {
-		// Go through the map of FeatureTypes, and return only the ones that
-		// have at least a Feature.
-		List types = new ArrayList();
-		for (java.util.Iterator iterator = featureTypeCounts.entrySet()
-				.iterator(); iterator.hasNext();) {
-			Map.Entry entry = (Entry) iterator.next();
-			FeatureType type = (FeatureType) entry.getKey();
-			Long count = (Long) entry.getValue();
+        public ReversedFeatureIteratorFacade(SelectionData selectionData,
+                FeatureStore featureStore, boolean fastIterator) {
+            this.selectionData = selectionData;
 
-			if (count.longValue() > 0) {
-				types.add(type);
-			}
-		}
+            // Load a Set with all the store features
+            try {
+                featureSet = featureStore.getFeatureSet();
+                //if (fastIterator) {
+                iterator = featureSet.fastIterator();
+//				} else {
+//					iterator = featureSet.iterator();
+//				}
+            } catch (DataException ex) {
+                throw new ReversedSelectionIteratorException(ex);
+            }
 
-		return types;
-	}
+            // Filter the features not selected and position in the next
+            // selected feature
+            positionInNextElement();
+        }
 
-	public long getSize() throws DataException {
-		return getSelectedCount();
-	}
+        @Override
+        public boolean hasNext() {
+            return nextFeature != null;
+        }
 
-	public boolean isEmpty() throws DataException {
-		return getSelectedCount() == 0;
-	}
+        @Override
+        public Object next() {
+            featureIterators.remove(currentFeature);
+            currentFeature = nextFeature.getCopy();
+            featureIterators.put(currentFeature, this);
+            positionInNextElement();
+            return currentFeature;
+        }
 
-	/**
-	 * Returns the list of selected values, or the deselected ones if the
-	 * selection has been reversed.
-	 */
-	public DisposableIterator iterator() {
-		return iterator(0);
-	}
+        @Override
+        public void remove() {
+            try {
+                featureSet.delete(currentFeature);
+            } catch (DataException e) {
+                throw new RemoveFromFeatureSelectionException(e);
 
-	/**
-	 * Returns the list of selected values, or the deselected ones if the
-	 * selection has been reversed.
-	 *
-	 * WARN: not very good performance implementation.
-	 */
-	public DisposableIterator iterator(long index) {
-		return iterator(index, false);
-	}
+            }
+        }
 
-	/**
-	 * Returns the list of selected values, or the deselected ones if the
-	 * selection has been reversed.
-	 *
-	 * WARN: not really a fast implementation.
-	 */
-	public DisposableIterator fastIterator() {
-		return fastIterator(0);
-	}
-        
-        @Override
-        public Feature first() {
-            DisposableIterator it = null;
-            try {
-                it = this.iterator();
-                if( it == null ) {
-                    return null;
+        private void positionInNextElement() {
+            nextFeature = null;
+            while (iterator.hasNext()) {
+                nextFeature = (Feature) iterator.next();
+                if (selectionData.contains(nextFeature.getReference())) {
+                    nextFeature = null;
+                } else {
+                    break;
                 }
-                Feature f = (Feature) it.next();
-                return f;
-            } finally {
-                DisposeUtils.disposeQuietly(it);
             }
         }
 
-	/**
-	 * Returns the list of selected values, or the deselected ones if the
-	 * selection has been reversed.
-	 *
-	 * WARN: not really a fast implementation.
-	 */
-	public DisposableIterator fastIterator(long index) {
-		return iterator(index, true);
-	}
+        @Override
+        public void dispose() {
+            this.featureSet.dispose();
+            this.iterator.dispose();
+            this.selectionData = null;
+            this.nextFeature = null;
+        }
+    }
 
-	protected void clearFeatureReferences() {
-		super.clearFeatureReferences();
-		featureTypeCounts.clear();
-	}
+    private Map featureTypeCounts = new HashMap(1);
+    private final Map<Feature, Iterator> featureIterators = new HashMap<>();
+    private final DefaultFeatureReferenceSelection featureReferenceSelection;
 
-	/**
-	 * Creates an iterator for the Selection.
-	 */
-	private DisposableIterator iterator(long index, boolean fastIterator) {
-		if (isReversed()) {
-			DisposableIterator iter = new ReversedFeatureIteratorFacade(
-					getData(), getFeatureStore(), fastIterator);
-			for (long l = 0; l < index && iter.hasNext(); l++) {
-				iter.next();
-			}
-			return iter;
+    /**
+     * Creates a DefaultFeatureSelection, with a FeatureStore.
+     *
+     * @param featureStore the FeatureStore to load Features from
+     * @throws DataException if there is an error while getting the total number
+     * of Features of the Store.
+     * @see AbstractSetBasedDataSelection#DefaultSelection(int)
+     */
+    public DefaultFeatureSelection(DefaultFeatureStore featureStore)
+            throws DataException {
+        this.featureReferenceSelection = new DefaultFeatureReferenceSelection(featureStore);
+    }
 
-		} else {
-			// TODO: maybe we could add a new referenceIterator(int index)
-			// method that could be implemented in a more performant way
+    /**
+     * Creates a new Selection with the total size of Features from which the
+     * selection will be performed.
+     *
+     * @param featureStore the FeatureStore of the selected FeatureReferences
+     * @param helper to get some information of the Store
+     * @throws DataException if there is an error while getting the total number
+     * of Features of the Store.
+     */
+    public DefaultFeatureSelection(FeatureStore featureStore,
+            FeatureSelectionHelper helper) throws DataException {
+        this.featureReferenceSelection = new DefaultFeatureReferenceSelection(featureStore, helper);
+    }
 
-			java.util.Iterator iter = selectionData.getSelected().iterator();
-			for (long l = 0; l < index && iter.hasNext(); l++) {
-				iter.next();
-			}
-			return new FeatureIteratorFacade(iter, getFeatureStore());
-		}
-	}
+    /**
+     * Constructor used by the persistence manager. Don't use directly. After to
+     * invoke this method, the persistence manager calls the the method
+     * {@link #loadFromState(PersistentState)} to set the values of the internal
+     * attributes that this class needs to work.
+     */
+    public DefaultFeatureSelection() {
+        this.featureReferenceSelection = new DefaultFeatureReferenceSelection();
+    }
 
-	private Long removeFeatureTypeCount(FeatureType featureType) {
-		Long count = (Long) featureTypeCounts.get(featureType);
-		if (count == null) {
-			count = new Long(-1);
-		} else {
-			count = new Long(count.longValue() - 1);
-		}
-		featureTypeCounts.put(featureType, count);
-		return count;
-	}
+    @Override
+    public FeatureStore getFeatureStore() {
+        return this.featureReferenceSelection.getFeatureStore();
+    }
 
-	private Long addFeatureTypeCount(FeatureType featureType) {
-		Long count = (Long) featureTypeCounts.get(featureType);
-		if (count == null) {
-			count = new Long(1);
-		} else {
-			count = new Long(count.longValue() + 1);
-		}
-		featureTypeCounts.put(featureType, count);
-		return count;
-	}
+    private void notifyObservers(String notificationType) {
+        this.featureReferenceSelection.notifyObservers(notificationType);
+    }
 
-	/**
-	 * Facade over a Iterator of FeatureReferences, to return Features instead.
-	 *
-	 * @author <a href="mailto:cordin@disid.com">Cèsar Ordiñana</a>
-	 */
-	private class FeatureIteratorFacade implements DisposableIterator {
+    public FeatureCommandsStack getCommands() {
+        return this.featureReferenceSelection.getCommands();
+    }
 
-		private final Logger LOGGER = LoggerFactory
-				.getLogger(FeatureIteratorFacade.class);
+    @Override
+    public void enableNotifications() {
+        this.featureReferenceSelection.enableNotifications();
+    }
 
-		private java.util.Iterator refIterator;
+    @Override
+    public void disableNotifications() {
+        this.featureReferenceSelection.disableNotifications();
+    }
 
-		private FeatureStore featureStore;
-		private Feature currentFeature = null;
+    public boolean isReversed() {
+        return this.featureReferenceSelection.isReversed();
+    }
 
-		public FeatureIteratorFacade(java.util.Iterator iter,
-				FeatureStore featureStore) {
-			this.refIterator = iter;
-			this.featureStore = featureStore;
-		}
+    @Override
+    public long getSelectedCount() {
+        return this.featureReferenceSelection.getSelectedCount();
+    }
 
-		public boolean hasNext() {
-			return refIterator.hasNext();
-		}
+    public DefaultFeatureReferenceSelection.SelectionData getData() {
+        return this.featureReferenceSelection.getData();
+    }
 
-		public Object next() {
-			FeatureReference ref = nextFeatureReference();
-			try {
-			    currentFeature = featureStore.getFeatureByReference(ref);
-				return currentFeature;
-			} catch (DataException ex) {
-				LOGGER.error(
-						"Error loading the Feature with FeatureReference: "
-								+ ref, ex);
-				return null;
-			}
-		}
+    @Override
+    public boolean select(FeatureReference reference) {
+        return this.featureReferenceSelection.select(reference);
+    }
 
-		/**
-		 * Returns the next FeatureReference.
-		 *
-		 * @return the next FeatureReference
-		 */
-		public FeatureReference nextFeatureReference() {
-			return (FeatureReference) refIterator.next();
-		}
+    public boolean select(FeatureReference reference, boolean undoable) {
+        return this.featureReferenceSelection.select(reference, undoable);
+    }
 
-		public void remove() {
-		    try {
-                featureStore.delete(currentFeature);
-                refIterator.remove();
-            } catch (DataException e) {
-                throw new RemoveFromFeatureSelectionException(e);
-            }
-		}
+    @Override
+    public boolean deselect(FeatureReference reference) {
+        return this.featureReferenceSelection.deselect(reference);
+    }
 
-        public class RemoveFromFeatureSelectionException extends DataRuntimeException {
+    public boolean deselect(FeatureReference reference, boolean undoable) {
+        return this.featureReferenceSelection.deselect(reference, undoable);
+    }
 
-            /**
-             *
-             */
-            private static final long serialVersionUID = 2636692469445838928L;
-            private final static String MESSAGE_FORMAT = "Can't remove feature from selection.";
-            private final static String MESSAGE_KEY = "_RemoveFromFeatureSelectionException";
+    @Override
+    public Iterator referenceIterator() {
+        return this.featureReferenceSelection.referenceIterator();
+    }
 
-            public RemoveFromFeatureSelectionException(Throwable cause) {
-                super(MESSAGE_FORMAT, cause, MESSAGE_KEY, serialVersionUID);
-                //setValue("store", store);
-            }
-        }
+    @Override
+    public void selectAll() throws DataException {
+        this.featureReferenceSelection.selectAll();
+    }
 
-		public void dispose() {
-			if (refIterator instanceof DisposableIterator) {
-				((DisposableIterator) refIterator).dispose();
-			}
-			refIterator = null;
-			featureStore = null;
-		}
-	}
+    @Override
+    public void deselectAll() throws DataException {
+        this.featureReferenceSelection.deselectAll();
+    }
+    
+    public void deselectAll(boolean undoable) throws DataException {
+        this.featureReferenceSelection.deselectAll(undoable);
+    }
+    
+    @Override
+    public boolean isSelected(FeatureReference reference) {
+        return this.featureReferenceSelection.isSelected(reference);
+    }
 
-	/**
-	 * Facade over a Iterator of FeatureReferences, to return Features instead,
-	 * when the Selection is reversed
-	 *
-	 * @author <a href="mailto:cordin@disid.com">Cèsar Ordiñana</a>
-	 */
-	private class ReversedFeatureIteratorFacade implements DisposableIterator {
+    @Override
+    public void reverse() {
+        this.featureReferenceSelection.reverse();
+    }
 
-		private SelectionData selectionData;
+    @Override
+    public void dispose() {
+        this.featureReferenceSelection.dispose();
+    }
 
-		private DisposableIterator iterator;
+    @Override
+    public void update(Observable o, Object o1) {
+        this.featureReferenceSelection.update(o, o1);
+    }
 
-        private Feature nextFeature = null;
-        private Feature currentFeature = null;
+    @Override
+    public void addObserver(Observer obsrvr) {
+        this.featureReferenceSelection.addObserver(obsrvr);
+    }
 
-		private FeatureSet featureSet;
+    @Override
+    public void deleteObserver(Observer obsrvr) {
+        this.featureReferenceSelection.deleteObserver(obsrvr);
+    }
 
-		public ReversedFeatureIteratorFacade(SelectionData selectionData,
-				FeatureStore featureStore, boolean fastIterator) {
-			this.selectionData = selectionData;
+    @Override
+    public void deleteObservers() {
+        this.featureReferenceSelection.deleteObservers();
+    }
 
-			// Load a Set with all the store features
-			try {
-				featureSet = featureStore.getFeatureSet();
-				//if (fastIterator) {
-					iterator = featureSet.fastIterator();
-//				} else {
-//					iterator = featureSet.iterator();
-//				}
-			} catch (DataException ex) {
-				throw new ReversedSelectionIteratorException(ex);
-			}
+    @Override
+    public void beginComplexNotification() {
+        this.featureReferenceSelection.beginComplexNotification();
+    }
 
-			// Filter the features not selected and position in the next
-			// selected feature
-			positionInNextElement();
-		}
+    @Override
+    public void endComplexNotification() {
+        this.featureReferenceSelection.endComplexNotification();
+    }
 
-		public boolean hasNext() {
-			return nextFeature != null;
-		}
+    @Override
+    public void saveToState(PersistentState ps) throws PersistenceException {
+        this.featureReferenceSelection.saveToState(ps);
+    }
 
-		public Object next() {
-            featureIterators.remove(currentFeature);
-		    currentFeature = nextFeature.getCopy();
-		    featureIterators.put(currentFeature, this);
-			positionInNextElement();
-			return currentFeature ;
-		}
+    @Override
+    public boolean select(Feature feature) {
+        return select(feature, true);
+    }
 
-		public void remove() {
-			try {
-                featureSet.delete(currentFeature);
-            } catch (DataException e) {
-                throw new RemoveFromFeatureSelectionException(e);
+    /**
+     * @param feature
+     * @return
+     * @see #select(Feature)
+     * @param undoable if the action must be undoable
+     */
+    public boolean select(Feature feature, boolean undoable) {
+        // TODO: should we check if the feature is from the same FeatureStore??
+        if (feature == null) {
+            return false;
+        }
 
+        // LOGGER.debug("Selected feature: {}", feature);
+        if (isReversed()) {
+            removeFeatureTypeCount(feature.getType());
+        } else {
+            addFeatureTypeCount(feature.getType());
+        }
+        return select(feature.getReference(), undoable);
+    }
+
+    @Override
+    public boolean select(FeatureSet features) throws DataException {
+        return select(features, true);
+    }
+
+    /**
+     * @param features
+     * @return
+     * @throws org.gvsig.fmap.dal.exception.DataException
+     * @see #select(FeatureSet)
+     * @param undoable if the action must be undoable
+     */
+    public boolean select(FeatureSet features, boolean undoable)
+            throws DataException {
+        boolean change = false;
+        boolean inComplex = false;
+        if (undoable && this.featureReferenceSelection.getFeatureStore().isEditing()
+                && !this.featureReferenceSelection.getCommands().inComplex()) {
+
+            this.featureReferenceSelection.getCommands().startComplex("_selectionSelectFeatureSet");
+            inComplex = this.featureReferenceSelection.getCommands().inComplex();
+        }
+
+        disableNotifications();
+        DisposableIterator iter = null;
+        try {
+            for (iter = features.fastIterator(); iter.hasNext();) {
+                change |= select((Feature) iter.next(), undoable);
             }
-		}
+        } finally {
+            DisposeUtils.disposeQuietly(iter);
+        }
+        enableNotifications();
+        if (undoable && getFeatureStore().isEditing() && inComplex) {
+            getCommands().endComplex();
+        }
+        if (change) {
+            notifyObservers(DataStoreNotification.SELECTION_CHANGE);
+        }
+        return change;
+    }
 
-    	public class RemoveFromFeatureSelectionException extends DataRuntimeException {
+    @Override
+    public boolean deselect(Feature feature) {
+        return deselect(feature, true);
+    }
 
-    	    /**
-             *
-             */
-            private static final long serialVersionUID = 2636692469445838928L;
-            private final static String MESSAGE_FORMAT = "Can't remove feature from reversed selection.";
-    	    private final static String MESSAGE_KEY = "_RemoveFromFeatureSelectionException";
+    /**
+     * @param feature
+     * @return
+     * @see #deselect(Feature)
+     * @param undoable if the action must be undoable
+     */
+    public boolean deselect(Feature feature, boolean undoable) {
+        if (feature == null) {
+            return false;
+        }
 
-    	    public RemoveFromFeatureSelectionException(Throwable cause) {
-    	        super(MESSAGE_FORMAT, cause, MESSAGE_KEY, serialVersionUID);
-    	        //setValue("store", store);
-    	    }
-    	}
+        LOG.debug("Deselected feature: {}", feature);
 
+        if (isReversed()) {
+            addFeatureTypeCount(feature.getType());
+        } else {
+            removeFeatureTypeCount(feature.getType());
+        }
+        return deselect(feature.getReference(), undoable);
+    }
 
-		private void positionInNextElement() {
-			nextFeature = null;
-			while (iterator.hasNext()) {
-				nextFeature = (Feature) iterator.next();
-				if (selectionData.contains(nextFeature.getReference())) {
-					nextFeature = null;
-				} else {
-					break;
-				}
-			}
-		}
+    @Override
+    public boolean deselect(FeatureSet features) throws DataException {
+        return deselect(features, true);
+    }
 
-		public void dispose() {
-			this.featureSet.dispose();
-			this.iterator.dispose();
-			this.selectionData = null;
-			this.nextFeature = null;
-		}
-	}
+    /**
+     * @param features
+     * @return
+     * @throws org.gvsig.fmap.dal.exception.DataException
+     * @see #deselect(FeatureSet)
+     * @param undoable if the action must be undoable
+     */
+    public boolean deselect(FeatureSet features, boolean undoable)
+            throws DataException {
+        boolean change = false;
+        if (undoable && getFeatureStore().isEditing()) {
+            getCommands().startComplex("_selectionDeselectFeatureSet");
+        }
+        disableNotifications();
+        DisposableIterator iter = null;
+        try {
+            for (iter = features.fastIterator(); iter.hasNext();) {
+                change |= deselect((Feature) iter.next(), undoable);
+            }
+        } finally {
+            DisposeUtils.disposeQuietly(iter);
+        }
+        enableNotifications();
+        if (undoable && getFeatureStore().isEditing()) {
+            getCommands().endComplex();
+        }
+        if (change) {
+            notifyObservers(DataStoreNotification.SELECTION_CHANGE);
+        }
+        return change;
+    }
 
-	public void delete(Feature feature) throws DataException {
-	    Iterator it = this.featureIterators.get(feature);
-	    if( it!=null ) {
-	        it.remove();
-	        return;
-	    }
-	    feature.getStore().delete(feature);
-	}
+    @Override
+    public boolean isSelected(Feature feature) {
+        if (feature == null) {
+            return false;
+        }
 
-	public void insert(EditableFeature feature) throws DataException {
-        feature.getStore().insert(feature);
+        // Use the selection data size as a small optimization for the most
+        // common case, when nothing is selected and every feature is checked
+        // while drawing or painting the table document.
+        if (getData().isReversed()) {
+            return getData().getSize() == 0
+                    || !getData().contains(feature.getReference());
+        } else {
+            return getData().getSize() > 0
+                    && getData().contains(feature.getReference());
+        }
     }
 
-	public void update(EditableFeature feature) throws DataException {
-        feature.getStore().update(feature);
+    @Override
+    public FeatureType getDefaultFeatureType() {
+        try {
+            return getFeatureStore().getDefaultFeatureType();
+        } catch (DataException ex) {
+            LOG.error("Error getting the default feature type "
+                    + "of the FeatureStore: " + getFeatureStore(), ex);
+        }
+        return null;
     }
 
-	/*
-	 * (non-Javadoc)
-	 *
-	 * @seeorg.gvsig.fmap.dal.feature.impl.DefaultFeatureReferenceSelection#
-	 * loadFromState(org.gvsig.tools.persistence.PersistentState)
-	 */
-	public void loadFromState(PersistentState state)
-			throws PersistenceException {
-		super.loadFromState(state);
+    @Override
+    public List getFeatureTypes() {
+        // Go through the map of FeatureTypes, and return only the ones that
+        // have at least a Feature.
+        List types = new ArrayList();
+        for (java.util.Iterator iterator = featureTypeCounts.entrySet()
+                .iterator(); iterator.hasNext();) {
+            Map.Entry entry = (Entry) iterator.next();
+            FeatureType type = (FeatureType) entry.getKey();
+            Long count = (Long) entry.getValue();
 
-	}
+            if (count > 0) {
+                types.add(type);
+            }
+        }
 
-	public void accept(Visitor visitor) throws BaseException {
-		accept(visitor, 0);
-	}
+        return types;
+    }
 
-	public final void accept(Visitor visitor, long firstValueIndex)
-			throws BaseException {
-		try {
-			doAccept(visitor, firstValueIndex);
-		} catch (VisitCanceledException ex) {
-			// The visit has been cancelled by the visitor, so we finish here.
-			LOG.debug(
-					"The visit, beggining on position {}, has been cancelled "
-							+ "by the visitor: {}", new Long(firstValueIndex),
-					visitor);
-		}
-	}
+    @Override
+    public long getSize() throws DataException {
+        return getSelectedCount();
+    }
 
-	private void doAccept(Visitor visitor, long firstValueIndex)
-			throws BaseException {
-		DisposableIterator iterator = fastIterator(firstValueIndex);
+    /**
+     * Returns the list of selected values, or the deselected ones if the
+     * selection has been reversed.
+     *
+     * WARN: not very good performance implementation.
+     */
+    @Override
+    public DisposableIterator iterator(long index) {
+        return iterator(index, false);
+    }
 
-		if (iterator != null) {
-			try {
-				while (iterator.hasNext()) {
-					Feature feature = (Feature) iterator.next();
-					visitor.visit(feature);
-				}
-			} finally {
-				iterator.dispose();
-			}
-		}
-	}
+    /**
+     * Returns the list of selected values, or the deselected ones if the
+     * selection has been reversed.
+     *
+     * WARN: not really a fast implementation.
+     */
+    @Override
+    public DisposableIterator fastIterator(long index) {
+        return iterator(index, true);
+    }
 
-	protected void doDispose() throws BaseException {
-		super.doDispose();
-		featureTypeCounts.clear();
-	}
+    protected void clearFeatureReferences() {
+        this.featureReferenceSelection.clearFeatureReferences();
+        featureTypeCounts.clear();
+    }
 
-	public static void registerPersistent() {
-		PersistenceManager manager = ToolsLocator.getPersistenceManager();
-		DynStruct definition = manager.addDefinition(
-				DefaultFeatureSelection.class, "DefaultFeatureSelection",
-				"DefaultFeatureSelection Persistent definition", null, null);
+    /**
+     * Creates an iterator for the Selection.
+     */
+    private DisposableIterator iterator(long index, boolean fastIterator) {
+        if (isReversed()) {
+            DisposableIterator iter = new ReversedFeatureIteratorFacade(
+                    getData(), getFeatureStore(), fastIterator);
+            for (long l = 0; l < index && iter.hasNext(); l++) {
+                iter.next();
+            }
+            return iter;
 
-		definition.extend(manager.getDefinition(DefaultFeatureReferenceSelection.DYNCLASS_PERSISTENT_NAME));
-		definition.addDynFieldMap("featureTypeCounts")
-				.setClassOfItems(Long.class).setMandatory(false);
+        } else {
+            // TODO: maybe we could add a new referenceIterator(int index)
+            // method that could be implemented in a more performant way
 
-	}
+            java.util.Iterator iter = getData().getSelected().iterator();
+            for (long l = 0; l < index && iter.hasNext(); l++) {
+                iter.next();
+            }
+            return new FeatureIteratorFacade(iter, getFeatureStore());
+        }
+    }
 
-	public Object clone() throws CloneNotSupportedException {
-		DefaultFeatureSelection clone = (DefaultFeatureSelection) super.clone();
-		clone.featureTypeCounts = new HashMap(featureTypeCounts);
-		return clone;
-	}
+    private Long removeFeatureTypeCount(FeatureType featureType) {
+        Long count = (Long) featureTypeCounts.get(featureType);
+        if (count == null) {
+            count = new Long(-1);
+        } else {
+            count = count - 1;
+        }
+        featureTypeCounts.put(featureType, count);
+        return count;
+    }
 
-    public DynObjectSet getDynObjectSet() {
-        return new DynObjectSetFeatureSetFacade(this, getFeatureStore());
+    private Long addFeatureTypeCount(FeatureType featureType) {
+        Long count = (Long) featureTypeCounts.get(featureType);
+        if (count == null) {
+            count = new Long(1);
+        } else {
+            count = count + 1;
+        }
+        featureTypeCounts.put(featureType, count);
+        return count;
     }
 
-    public DynObjectSet getDynObjectSet(boolean fast) {
-        return new DynObjectSetFeatureSetFacade(this, getFeatureStore(), fast);
+    @Override
+    public void delete(Feature feature) throws DataException {
+        Iterator it = this.featureIterators.get(feature);
+        if (it != null) {
+            it.remove();
+            return;
+        }
+        feature.getStore().delete(feature);
     }
 
+    @Override
+    public void insert(EditableFeature feature) throws DataException {
+        feature.getStore().insert(feature);
+    }
+
+    @Override
+    public void update(EditableFeature feature) throws DataException {
+        feature.getStore().update(feature);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @seeorg.gvsig.fmap.dal.feature.impl.DefaultFeatureReferenceSelection#
+     * loadFromState(org.gvsig.tools.persistence.PersistentState)
+     */
+    @Override
+    public void loadFromState(PersistentState state)
+            throws PersistenceException {
+        this.featureReferenceSelection.loadFromState(state);
+    }
+
+    protected void doDispose() throws BaseException {
+        this.featureReferenceSelection.doDispose();
+        featureTypeCounts.clear();
+    }
+
+    public static void registerPersistent() {
+        PersistenceManager manager = ToolsLocator.getPersistenceManager();
+        DynStruct definition = manager.addDefinition(
+                DefaultFeatureSelection.class, "DefaultFeatureSelection",
+                "DefaultFeatureSelection Persistent definition", null, null);
+
+        definition.extend(manager.getDefinition(DefaultFeatureReferenceSelection.DYNCLASS_PERSISTENT_NAME));
+        definition.addDynFieldMap("featureTypeCounts")
+                .setClassOfItems(Long.class).setMandatory(false);
+
+    }
+
+    @Override
+    public Object clone() throws CloneNotSupportedException {
+        DefaultFeatureSelection clone = (DefaultFeatureSelection) super.clone();
+        clone.featureTypeCounts = new HashMap(featureTypeCounts);
+        return clone;
+    }
+
 }
