/**
 * @(#)UndoableSetGeometry.java	29.06.2004
 *
 * Copyright 2004 Edgar Soldin
 * 
 * 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 2 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package de.soldin.gt2jump;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import javax.swing.undo.AbstractUndoableEdit;

import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jump.feature.Feature;
import com.vividsolutions.jump.workbench.model.Layer;

/**
 * The <code>UndoableSetGeometry</code> is a implementation of a 
 * {@link java.util.Collection}, as well as a {@link 
 * javax.swing.undo.AbstractUndoableEdit}. The purpose is to have 
 * an undoable swing component for modifying geometries.
 * <p>
 * With these capabilities joined it can act as a container for multiple
 * <code>UndoableSetGeometry</code> objects, which can be executed in 
 * a batch and as a single action.
 * </p>
 */
public class UndoableSetGeometry 
	extends AbstractUndoableEdit
	implements Collection
	{
	private Collection actions = new Vector();
	private String name;
	private Layer layer;
			
	private HashMap proposed_geoms = new HashMap();
	private HashMap original_geoms = new HashMap();	
	
	public void redo() {
		execute();
		super.redo();
	}

	public void undo() {
		unexecute();
		super.undo();
	}
	
	public String getPresentationName(){
		return getName();
	}
	
	public String getUndoPresentationName(){
		return getName();
	}
	
	public String getRedoPresentationName(){
		return getName();
	}

	public UndoableSetGeometry(Layer layer, String name) {
		this.layer = layer;
		this.name = name+" (Layer: "+layer.getName()+")";
	}

	public UndoableSetGeometry(String name) {
		this.name = name;
	}

	public void execute() {
		//System.out.print("UT:execute() "+this+" ");
		if (layer!=null){
				
			List features = layer.getFeatureCollectionWrapper().getFeatures();
			ArrayList modifiedFeatures = new ArrayList();
			ArrayList modifiedFeaturesOldClones = new ArrayList();
			
			for (Iterator iter = proposed_geoms.keySet().iterator(); iter.hasNext();) {
				Feature feature = (Feature) iter.next();
				Geometry new_geom = (Geometry)proposed_geoms.get(feature);
				Geometry old_geom = feature.getGeometry();
				
				original_geoms.put(feature,old_geom);

				modifiedFeatures.add(feature);
				modifiedFeaturesOldClones.add(feature.clone());
				feature.setGeometry(new_geom);
			}
			
			refreshUI(modifiedFeatures,modifiedFeaturesOldClones);

		}else{
			//System.out.print("batch ");

			for (Iterator iter = this.iterator(); iter.hasNext();) {
				UndoableSetGeometry transformation = (UndoableSetGeometry) iter.next();
				transformation.execute();
			}

		}

	}

	public void unexecute() {
		//System.out.print("UT:unexecute() "+this+" ");
		if (layer!=null && original_geoms.size()>0){
	
			List features = layer.getFeatureCollectionWrapper().getFeatures();
			ArrayList modifiedFeatures = new ArrayList();
			ArrayList modifiedFeaturesOldClones = new ArrayList();
			
			for (Iterator iter = original_geoms.keySet().iterator(); iter.hasNext();) {
				Feature feature = (Feature) iter.next();
				Geometry new_geom = (Geometry)original_geoms.get(feature);

				modifiedFeatures.add(feature);
				modifiedFeaturesOldClones.add(feature.clone());
				feature.setGeometry(new_geom);
				
				//original_geoms.remove(feature);				
			}
			original_geoms.clear();
						
			refreshUI(modifiedFeatures,modifiedFeaturesOldClones);
			
		}else{
			//System.out.print("batch ");	
			for (Iterator iter = this.iterator(); iter.hasNext();) {
				UndoableSetGeometry transformation = (UndoableSetGeometry) iter.next();
				transformation.unexecute();
			}
		}
		//System.out.println();

	}
	
	private void refreshUI(ArrayList modifiedFeatures, ArrayList modifiedFeaturesOldClones){
		if (this.layer!=null) {
			Layer.tryToInvalidateEnvelope(this.layer);
			// fire the appropriate event, so everybody gets notified
			if (!modifiedFeatures.isEmpty()) {
				this.layer.getLayerManager().fireGeometryModified(
					modifiedFeatures,
					this.layer,
					modifiedFeaturesOldClones);
			}
		}	
	}	
	
	public String getName() {
		String out = "";
		if (layer==null){
			for (Iterator iter = actions.iterator(); iter.hasNext();) {
				out += (out.length()>0?", ":"")+((UndoableSetGeometry)iter.next()).getName();
			}
		}
		return name+": "+out;
	}
	
	public void setGeom(Feature feature, Geometry geom){
		proposed_geoms.put(feature,geom);
	}
	
	public Geometry getGeom(Feature in_feature){
		List features = layer.getFeatureCollectionWrapper().getFeatures();
		Feature feature = (Feature)features.get(features.indexOf(in_feature));
		return (Geometry)feature.getGeometry().clone();
	}

// Start of implementation of the collection methods 
	
	public boolean add(UndoableSetGeometry t){
		return actions.add(t);
	}

	public int size() {
		return actions.size();
	}

	public void clear() {
		actions.clear();
	}

	public boolean isEmpty() {
		return actions.isEmpty();
	}

	public Object[] toArray() {
		return actions.toArray();
	}

	public boolean add(Object o) {
		return actions.add(o);
	}

	public boolean contains(Object o) {
		return actions.contains(o);
	}

	public boolean remove(Object o) {
		return actions.remove(o);
	}

	public boolean addAll(Collection c) {
		return actions.addAll(c);
	}

	public boolean containsAll(Collection c) {
		return actions.containsAll(c);
	}

	public boolean removeAll(Collection c) {
		return actions.removeAll(c);
	}

	public boolean retainAll(Collection c) {
		return actions.retainAll(c);
	}


	public Iterator iterator() {
		return actions.iterator();
	}

	public Object[] toArray(Object[] a) {
		return actions.toArray(a);
	}

}
