package se.oru.coordination.coordination_oru.util;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Scanner;
import java.util.TreeMap;

import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.JOptionPane;
import javax.swing.KeyStroke;

import org.metacsp.multi.spatioTemporal.paths.Pose;
import org.metacsp.multi.spatioTemporal.paths.PoseSteering;
import org.metacsp.utility.UI.JTSDrawingPanel;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.util.AffineTransformation;

import se.oru.coordination.coordination_oru.motionplanning.ompl.ReedsSheppCarPlanner;
import se.oru.coordination.coordination_oru.util.splines.Spline3D;
import se.oru.coordination.coordination_oru.util.splines.SplineFactory;

public class PathEditor {

	private static String PREFIX = null;
	private static int EMPTY_MAP_DIM = 10000;
	private static double OBSTACLE_SIZE = 2.0;
	private static double MAX_TURNING_RADIUS = 5.0;
	private static double MIN_DISTANCE_BETWEEN_PATH_POINTS = 0.4;
	private String pathFileName = null;
	private String mapFileName = null;
	private String mapImgFileName = null;
	private double mapRes = 1.0;
	private String posesFileName = null;
	private boolean selectionPathPointInputListen = false;
	private String selectionString = "";
	private ArrayList<Integer> selectedPathPointsInt = new ArrayList<Integer>();
	private boolean selectionObsInputListen = false;
	private ArrayList<Integer> selectedObsInt = new ArrayList<Integer>();
	private ArrayList<Geometry> obstacles = new ArrayList<Geometry>();
	private ArrayList<PoseSteering> path = null;
	private ArrayList<ArrayList<PoseSteering>> oldPaths = new ArrayList<ArrayList<PoseSteering>>(); 
	private JTSDrawingPanel panel = null;
	private double deltaX = 0.1;
	private double deltaY = 0.1;
	private double deltaT = 0.1;
	private double deltaTR = 0.1;
	private String newFileSuffix = ".new";
	private Coordinate[] obstacleFootprint = null;
	private ArrayList<Pose> obstacleCenters = new ArrayList<Pose>();
	private ArrayList<String> obstacleNames = new ArrayList<String>();
	private static boolean USE_MP = false; 
	
	private static String TEMP_MAP_DIR = ".tempMapsPathEditor";
	
	public void setObstacleFootprint(Coordinate[] footprint) {
		this.obstacleFootprint = new Coordinate[footprint.length+1];
		for (int i = 0; i < footprint.length; i++) {
			obstacleFootprint[i] = footprint[i];
		}
		obstacleFootprint[footprint.length] = footprint[0];
	}
	
	public void saveObstaclesToPoses(String fileName) {
        try {
            File file = new File(fileName);
            PrintWriter writer = new PrintWriter(file);
            for (int i = 0; i < obstacleCenters.size(); i++) {
            	writer.println(obstacleNames.get(i) + " " + obstacleCenters.get(i).getX() + " " + obstacleCenters.get(i).getY() + " " + obstacleCenters.get(i).getTheta());
            }
            writer.close();
        }
        catch (Exception e) { e.printStackTrace(); }
		
	}
	
	public void loadObstaclesFromPoses() {
		try {
			Scanner in = new Scanner(new FileReader(posesFileName));
			while (in.hasNextLine()) {
				String line = in.nextLine().trim();
				if (line.length() != 0 && !line.startsWith("#")) {
					String[] oneline = line.split(" |\t");
					if (oneline.length == 4) {
						Pose ps = null;
						String obsName = oneline[0];
						obstacleNames.add(obsName);
						ps = new Pose(
								new Double(oneline[1]).doubleValue(),
								new Double(oneline[2]).doubleValue(),
								new Double(oneline[3]).doubleValue());
						Geometry obs = makeObstacle(ps);
						int id = obstacles.size()-1;
						panel.addGeometry("obs_"+id, obs, false, false, true, "#cc3300");
						selectedObsInt.add(id);
					}
				}
			}
			in.close();
			clearPathPointSelection();
			highlightObstacles();
		}
		catch (FileNotFoundException e) { e.printStackTrace(); }
	}
	
	public PathEditor(String pathFileName, String mapFileName, String posesFileName, double deltaX, double deltaY, double deltaTheta, String newFileSuffix) {
		this.pathFileName = pathFileName;
		this.mapFileName = mapFileName;
		this.posesFileName = posesFileName;
		this.deltaX = deltaX;
		this.deltaY = deltaY;
		this.deltaT = deltaTheta;
		this.newFileSuffix = newFileSuffix;
		if (mapFileName != null) {
			this.mapImgFileName = PREFIX+File.separator+"maps"+File.separator+Missions.getProperty("image", this.mapFileName);
			this.mapRes = Double.parseDouble(Missions.getProperty("resolution", this.mapFileName));
		}
		this.setupGUI();
		if (pathFileName != null) this.readPath();
		if (mapFileName != null) panel.setMap(this.mapFileName);
		//if (posesFileName != null) this.loadObstaclesFromPoses();
		panel.updatePanel();
		this.deleteDir(new File(TEMP_MAP_DIR));
		new File(TEMP_MAP_DIR).mkdir();
	}
	
	public boolean deleteDir(File dir) {
	    if (dir.isDirectory()) {
	        String[] children = dir.list();
	        for (int i=0; i<children.length; i++) {
	            boolean success = deleteDir(new File(dir, children[i]));
	            if (!success) {
	                return false;
	            }
	        }
	    }
	    return dir.delete();
	}
	
	public PathEditor(String pathFileName) {
		this(pathFileName,null,null,0.1,0.1,0.1,".new");
	}

	public PathEditor(String pathFileName, String mapFileName) {
		this(pathFileName,mapFileName,null,0.1,0.1,0.1,".new");
	}

	public PathEditor(String pathFileName, String mapFileName, String posesFileName) {
		this(pathFileName,mapFileName,posesFileName,0.1,0.1,0.1,".new");
	}

	private double[] getMinXYMaxXY() {
		double maxX = -Double.MAX_VALUE;
		double maxY = -Double.MAX_VALUE;
		double minX = Double.MAX_VALUE;
		double minY = Double.MAX_VALUE;
		for (Geometry obs : this.obstacles) {
			// (minx miny, maxx miny, maxx maxy, minx maxy, minx miny)
			double oneMinX = obs.getEnvelope().getCoordinates()[0].x;
			double oneMinY = obs.getEnvelope().getCoordinates()[0].y;
			double oneMaxX = obs.getEnvelope().getCoordinates()[1].x;
			double oneMaxY = obs.getEnvelope().getCoordinates()[1].y;
			if (oneMinX < minX) minX = oneMinX;
			if (oneMinY < minY) minY = oneMinY;
			if (oneMaxX > maxX) maxX = oneMaxX;
			if (oneMaxY > maxY) maxY = oneMaxY;
		}
		for (PoseSteering ps : this.path) {
			if (ps.getX() < minX) minX = ps.getX();
			if (ps.getY() < minY) minY = ps.getY();
			if (ps.getX() > maxX) maxX = ps.getX();
			if (ps.getY() > maxY) maxY = ps.getY();
		}
		return new double[] {minX,minY,maxX,maxY};
	}
	
	private String getHelp() {
		String ret = "";
		TreeMap<String,String> helpText = new TreeMap<String, String>();
		for (KeyStroke key : panel.getInputMap().allKeys()) {
			if (key.equals(KeyStroke.getKeyStroke(KeyEvent.VK_0,0)) ||
					key.equals(KeyStroke.getKeyStroke(KeyEvent.VK_1,0)) ||
					key.equals(KeyStroke.getKeyStroke(KeyEvent.VK_2,0)) ||
					key.equals(KeyStroke.getKeyStroke(KeyEvent.VK_3,0)) ||
					key.equals(KeyStroke.getKeyStroke(KeyEvent.VK_4,0)) ||
					key.equals(KeyStroke.getKeyStroke(KeyEvent.VK_5,0)) ||
					key.equals(KeyStroke.getKeyStroke(KeyEvent.VK_6,0)) ||
					key.equals(KeyStroke.getKeyStroke(KeyEvent.VK_7,0)) ||
					key.equals(KeyStroke.getKeyStroke(KeyEvent.VK_8,0)) ||
					key.equals(KeyStroke.getKeyStroke(KeyEvent.VK_9,0)) ||
					key.equals(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS,0)) ||
					key.equals(KeyStroke.getKeyStroke(KeyEvent.VK_COMMA,0)))
				continue;
			if (key.getModifiers() != 0) helpText.put(key.toString().replaceAll("pressed ", "").replaceAll(" ", "-"), panel.getInputMap().get(key).toString());
			else helpText.put(key.toString().replaceAll("pressed ", ""), panel.getInputMap().get(key).toString());
		}
		for (Entry<String,String> en : helpText.entrySet()) {
			ret += en.getKey() + ": " + en.getValue() + "\n";
		}
		return ret;
	}
	
	private Geometry makeObstacle(Pose p) {
		GeometryFactory gf = new GeometryFactory();
		Geometry geom = null;
		if (obstacleFootprint == null) {
			geom = gf.createPolygon(new Coordinate[] { new Coordinate(0.0,0.0), new Coordinate(0.0,OBSTACLE_SIZE), new Coordinate(OBSTACLE_SIZE,OBSTACLE_SIZE), new Coordinate(OBSTACLE_SIZE,0.0), new Coordinate(0.0,0.0) });
		}
		else {
			geom = gf.createPolygon(obstacleFootprint);
		}		
		AffineTransformation at = new AffineTransformation();
		at.rotate(p.getTheta());
		at.translate(p.getX(), p.getY());
		Geometry transGeom = at.transform(geom);
		Pose center = new Pose(p.getX(), p.getY(), p.getTheta());
		obstacles.add(transGeom);
		obstacleCenters.add(center);
		return transGeom;
	}
	
	private void highlightPathPoints() {
		for (int selectedPathPointOneInt : selectedPathPointsInt) {
			if (selectedPathPointOneInt >= 0 && selectedPathPointOneInt < path.size()) {
				panel.addArrow(""+selectedPathPointOneInt, path.get(selectedPathPointOneInt).getPose(), Color.red);
			}
		}
		panel.updatePanel();
	}
	
	private void highlightObstacles() {
		for (int selectedObsOneInt : selectedObsInt) {
			if (selectedObsOneInt >= 0 && selectedObsOneInt < obstacles.size()) {
				panel.addGeometry("obs_"+selectedObsOneInt, obstacles.get(selectedObsOneInt), false, false, true, "#cc3300");
			}
		}
		panel.updatePanel();
	}
	
	private void clearObstacleSelection() {
		selectionString = "";
		selectedObsInt.clear();
		for (int i = 0; i < obstacles.size(); i++) panel.addGeometry("obs_"+i, obstacles.get(i), false, false, true, "#666699");
		panel.updatePanel();
	}
	
	private void clearPathPointSelection() {
		if (path != null) {
			selectionString = "";
			selectedPathPointsInt.clear();
			for (int i = 0; i < path.size(); i++) panel.addArrow(""+i, path.get(i).getPose(), Color.gray);
			panel.updatePanel();
		}
	}
	
	private void backupPath() {
		ArrayList<PoseSteering> backup = new ArrayList<PoseSteering>();
		for (PoseSteering ps : this.path) {
			PoseSteering newPS = new PoseSteering(ps.getX(), ps.getY(), ps.getTheta(), ps.getSteering());
			backup.add(newPS);
		}
		oldPaths.add(backup);
	}
	
	private void restorePath() {
		if (!oldPaths.isEmpty()) {
			for (int i = 0; i < path.size(); i++) panel.removeGeometry(""+i);
			path = oldPaths.get(oldPaths.size()-1);
			oldPaths.remove(oldPaths.size()-1);
			clearPathPointSelection();
		}
	}
	
	public void addAbstractAction(AbstractAction aa, int keyEvent, int modifiers, String description) {
		panel.getInputMap().put(KeyStroke.getKeyStroke(keyEvent,modifiers),description);
		panel.getActionMap().put(description,aa);
	}
	
	private void setupGUI() {
		panel = JTSDrawingPanel.makeEmpty("Path Editor");

		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_0,0),"Digit0");
		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_1,0),"Digit1");
		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_2,0),"Digit2");
		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_3,0),"Digit3");
		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_4,0),"Digit4");
		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_5,0),"Digit5");
		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_6,0),"Digit6");
		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_7,0),"Digit7");
		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_8,0),"Digit8");
		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_9,0),"Digit9");
		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS,0),"Digit-");
		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_COMMA,0),"Digit,");
		AbstractAction actInputSelection = new AbstractAction() {
			private static final long serialVersionUID = -1398168416006978350L;
			@Override
			public void actionPerformed(ActionEvent e) {
				selectionString += e.getActionCommand();
				System.out.println("Selection: " + selectionString);
			}
		};
		panel.getActionMap().put("Digit0",actInputSelection);
		panel.getActionMap().put("Digit1",actInputSelection);
		panel.getActionMap().put("Digit2",actInputSelection);
		panel.getActionMap().put("Digit3",actInputSelection);
		panel.getActionMap().put("Digit4",actInputSelection);
		panel.getActionMap().put("Digit5",actInputSelection);
		panel.getActionMap().put("Digit6",actInputSelection);
		panel.getActionMap().put("Digit7",actInputSelection);
		panel.getActionMap().put("Digit8",actInputSelection);
		panel.getActionMap().put("Digit9",actInputSelection);
		panel.getActionMap().put("Digit-",actInputSelection);
		panel.getActionMap().put("Digit,",actInputSelection);

		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_O,0),"Add obstacle(s) near selected pose(s)");
		AbstractAction actObs = new AbstractAction() {
			private static final long serialVersionUID = -1398168416006978750L;
			@Override
			public void actionPerformed(ActionEvent e) {
				if (!selectedPathPointsInt.isEmpty()) {
					for (int i = 0; i < obstacles.size(); i++) panel.addGeometry("obs_"+i, obstacles.get(i), false, false, true, "#666699");
					selectedObsInt.clear();
					for (int selectedPathPointOneInt : selectedPathPointsInt) {
						Geometry obs = makeObstacle(path.get(selectedPathPointOneInt).getPose());
						int id = obstacles.size()-1;
						panel.addGeometry("obs_"+id, obs, false, false, true, "#cc3300");
						selectedObsInt.add(id);
						obstacleNames.add("obs_"+id);
					}
					clearPathPointSelection();
					highlightObstacles();
				}
			}
		};
		panel.getActionMap().put("Add obstacle(s) near selected pose(s)",actObs);

		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE,0),"Cancel selection");
		AbstractAction actCancel = new AbstractAction() {
			private static final long serialVersionUID = -1398168416006978350L;
			@Override
			public void actionPerformed(ActionEvent e) {
				selectionPathPointInputListen = false;
				clearObstacleSelection();
				clearPathPointSelection();
			}
		};
		panel.getActionMap().put("Cancel selection",actCancel);

		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_P,0),"Add pose(s)");
		AbstractAction actInsert = new AbstractAction() {
			private static final long serialVersionUID = -8804517791543118334L;
			@Override
			public void actionPerformed(ActionEvent e) {
				if (!selectedPathPointsInt.isEmpty()) {
					backupPath();
					HashMap<Integer,PoseSteering> toAdd = new HashMap<Integer, PoseSteering>();
					for (int selectedPathPointOneInt : selectedPathPointsInt) {
						PoseSteering newPoseSteering = new PoseSteering(path.get(selectedPathPointOneInt).getPose().getX()+deltaX, path.get(selectedPathPointOneInt).getPose().getY()+deltaY, path.get(selectedPathPointOneInt).getPose().getTheta(), path.get(selectedPathPointOneInt).getSteering());
						toAdd.put(selectedPathPointOneInt, newPoseSteering);
					}
					for (int selectedPathPointOneInt : selectedPathPointsInt) {
						path.add(selectedPathPointsInt.get(0), toAdd.get(selectedPathPointOneInt));
					}
					clearPathPointSelection();
					highlightPathPoints();
				}
			}
		};
		panel.getActionMap().put("Add pose(s)",actInsert);

		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_Z,KeyEvent.CTRL_DOWN_MASK),"Undo");
		AbstractAction actUndo = new AbstractAction() {
			private static final long serialVersionUID = 5597593272769688561L;
			@Override
			public void actionPerformed(ActionEvent e) {
				restorePath();
			}
		};
		panel.getActionMap().put("Undo",actUndo);

		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_S,KeyEvent.CTRL_DOWN_MASK),"Save path");
		AbstractAction actSave = new AbstractAction() {
			private static final long serialVersionUID = 8788274388808789051L;
			@Override
			public void actionPerformed(ActionEvent e) {
				String newFileName = pathFileName+newFileSuffix;
				writePath(newFileName);
				System.out.println("Saved " + newFileName);
			}
		};
		panel.getActionMap().put("Save path",actSave);

		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_S,KeyEvent.SHIFT_DOWN_MASK),"Save obstacle poses");
		AbstractAction actSaveO = new AbstractAction() {
			private static final long serialVersionUID = 8788274388808783351L;
			@Override
			public void actionPerformed(ActionEvent e) {
				String newFileName = posesFileName+newFileSuffix;
				saveObstaclesToPoses(newFileName);
				System.out.println("Saved obstacle poses to " + newFileName);
			}
		};
		panel.getActionMap().put("Save obstacle poses",actSaveO);

		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_L,KeyEvent.SHIFT_DOWN_MASK),"Load obstacle poses");
		AbstractAction actLoadO = new AbstractAction() {
			private static final long serialVersionUID = 8788274388808983351L;
			@Override
			public void actionPerformed(ActionEvent e) {
				if (posesFileName != null) {
					loadObstaclesFromPoses();
				}
				System.out.println("Loaded obstacle poses from " + posesFileName);
			}
		};
		panel.getActionMap().put("Load obstacle poses",actLoadO);

		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_H,0),"Help");
		AbstractAction actHelp = new AbstractAction() {
			private static final long serialVersionUID = 8788274388808789053L;
			@Override
			public void actionPerformed(ActionEvent e) {
				JOptionPane.showMessageDialog(panel,getHelp());
//				System.out.println(getHelp());
			}
		};
		panel.getActionMap().put("Help",actHelp);

		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_S,0),"Select pose(s)");
		AbstractAction actSelect = new AbstractAction() {
			private static final long serialVersionUID = -4218195170958172222L;
			@Override
			public void actionPerformed(ActionEvent e) {
				if (!selectionPathPointInputListen) {
					clearPathPointSelection();
					System.out.println("Input selection (poses): " + selectionString);
				}
				else if (selectionPathPointInputListen) {
					for (int i = 0; i < path.size(); i++) panel.addArrow(""+i, path.get(i).getPose(), Color.gray);
					try {
						if (selectionString.contains("-")) {
							int first = Integer.parseInt(selectionString.substring(0,selectionString.indexOf("-")));
							int last = Math.min(path.size()-1,Integer.parseInt(selectionString.substring(selectionString.indexOf("-")+1)));
							for (int i = first; i <= last; i++) selectedPathPointsInt.add(i);
						}
						else if (selectionString.contains(",")) {
							String[] points = selectionString.split(",");
							for (String point : points) selectedPathPointsInt.add(Integer.parseInt(point));
						}
						else selectedPathPointsInt.add(Integer.parseInt(selectionString));
						clearObstacleSelection();
						highlightPathPoints();
						System.out.println("Current selection (poses): " + selectedPathPointsInt);
					}
					catch(NumberFormatException ex) { }
				}
				selectionPathPointInputListen = !selectionPathPointInputListen;
			}
		};
		panel.getActionMap().put("Select pose(s)",actSelect);

		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_G,0),"Select obstacle(s)");
		AbstractAction actObsSelect = new AbstractAction() {
			private static final long serialVersionUID = -4218195170858172222L;
			@Override
			public void actionPerformed(ActionEvent e) {
				if (!selectionObsInputListen) {
					clearObstacleSelection();
					System.out.println("Input selection (obstacles): " + selectionString);
				}
				else if (selectionObsInputListen) {
					for (int i = 0; i < obstacles.size(); i++) panel.addGeometry("obs_"+i, obstacles.get(i), false, false, true, "#666699");
					try {
						if (selectionString.contains("-")) {
							int first = Integer.parseInt(selectionString.substring(0,selectionString.indexOf("-")));
							int last = Integer.parseInt(selectionString.substring(selectionString.indexOf("-")+1));
							for (int i = first; i <= last; i++) selectedObsInt.add(i);
						}
						else if (selectionString.contains(",")) {
							String[] obss = selectionString.split(",");
							for (String obs : obss) selectedObsInt.add(Integer.parseInt(obs));
						}
						else selectedObsInt.add(Integer.parseInt(selectionString));
						highlightObstacles();
						System.out.println("Current selection (obstacles): " + selectedObsInt);
						clearPathPointSelection();
					}
					catch(NumberFormatException ex) { }
				}
				selectionObsInputListen = !selectionObsInputListen;
			}
		};
		panel.getActionMap().put("Select obstacle(s)",actObsSelect);

		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE,0),"Delete selected pose(s) and obstacle(s)");
		AbstractAction actDelete = new AbstractAction() {
			private static final long serialVersionUID = 4455373738365388356L;
			@Override
			public void actionPerformed(ActionEvent e) {
				if (!selectedPathPointsInt.isEmpty()) {
					for (int i = 0; i < path.size(); i++) panel.removeGeometry(""+i);
					backupPath();
					ArrayList<PoseSteering> toRemove = new ArrayList<PoseSteering>();
					for (int selectedPathPointOneInt : selectedPathPointsInt) {
						toRemove.add(path.get(selectedPathPointOneInt));
					}
					path.removeAll(toRemove);
					clearPathPointSelection();
				}
				if (!selectedObsInt.isEmpty()) {
					ArrayList<Geometry> toRemove = new ArrayList<Geometry>();
					ArrayList<Pose> toRemoveCenters = new ArrayList<Pose>();
					ArrayList<String> toRemoveNames = new ArrayList<String>();
					for (int i = 0; i < obstacles.size(); i++) panel.removeGeometry("obs_"+i);
					for (int selectedObsOneInt : selectedObsInt) {
						toRemove.add(obstacles.get(selectedObsOneInt));
						toRemoveCenters.add(obstacleCenters.get(selectedObsOneInt));
						toRemoveNames.add(obstacleNames.get(selectedObsOneInt));
					}
					obstacles.removeAll(toRemove);
					obstacleCenters.removeAll(toRemoveCenters);
					obstacleNames.removeAll(toRemoveNames);
					clearObstacleSelection();
				}
				panel.updatePanel();
			}
		};
		panel.getActionMap().put("Delete selected pose(s) and obstacle(s)",actDelete);

		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_P,KeyEvent.CTRL_DOWN_MASK),"Plan path between selected pair");
		AbstractAction actPlan = new AbstractAction() {
			private static final long serialVersionUID = -3238585469762752293L;
			@Override
			public void actionPerformed(ActionEvent e) {
				if (selectedPathPointsInt.size() >= 2) {
					PoseSteering startPose = path.get(selectedPathPointsInt.get(0));
					PoseSteering[] goalPoses = new PoseSteering[selectedPathPointsInt.size()-1];
					for (int i = 0; i < goalPoses.length; i++) {
						goalPoses[i] = path.get(selectedPathPointsInt.get(i+1));
					}
					PoseSteering[] newSubPath = computePath(startPose,goalPoses);
					if (newSubPath != null) {
						backupPath();
						TreeMap<Integer,PoseSteering> toAdd = new TreeMap<Integer, PoseSteering>();
						ArrayList<PoseSteering> toRemove = new ArrayList<PoseSteering>();
						for (int i = 1; i < selectedPathPointsInt.size()-1; i++) toRemove.add(path.get(selectedPathPointsInt.get(i)));
						if (!toRemove.isEmpty()) path.removeAll(toRemove);
						int selectedStart = selectedPathPointsInt.get(0)+1;
						for (int i = 1; i < newSubPath.length-1; i++) {
							PoseSteering newPoseSteering = new PoseSteering(newSubPath[i].getPose().getX(), newSubPath[i].getPose().getY(), newSubPath[i].getPose().getTheta(), newSubPath[i].getSteering());
							toAdd.put(i+selectedStart-1, newPoseSteering);
						}
						for (Entry<Integer,PoseSteering> en : toAdd.entrySet()) {
							path.add(en.getKey(), en.getValue());
						}
						clearPathPointSelection();
						for (Entry<Integer,PoseSteering> en : toAdd.entrySet()) {
							selectedPathPointsInt.add(en.getKey());
						}
						highlightPathPoints();
					}
				}
			}
		};
		panel.getActionMap().put("Plan path between selected pair",actPlan);
		
		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT,0),"Decrease X of selected pose(s)");
		AbstractAction actXMinus = new AbstractAction() {
			private static final long serialVersionUID = 1767256680398690970L;
			@Override
			public void actionPerformed(ActionEvent e) {
				if (!selectedPathPointsInt.isEmpty()) {
					backupPath();
					for (int selectedPathPointOneInt : selectedPathPointsInt) {
						double x = path.get(selectedPathPointOneInt).getPose().getX();
						double y = path.get(selectedPathPointOneInt).getPose().getY();
						double th = path.get(selectedPathPointOneInt).getPose().getTheta();
						x -= deltaX;
						PoseSteering newPoseSteering = new PoseSteering(x, y, th, path.get(selectedPathPointOneInt).getSteering());
						path.set(selectedPathPointOneInt, newPoseSteering);
					}
				}
				if (!selectedObsInt.isEmpty()) {
					for (int selectedObsOneInt : selectedObsInt) {
						Geometry obs = obstacles.get(selectedObsOneInt);
						Pose center = obstacleCenters.get(selectedObsOneInt);
						AffineTransformation at = new AffineTransformation();
						at.translate(-deltaX, 0);
						obstacles.set(selectedObsOneInt,at.transform(obs));
						obstacleCenters.set(selectedObsOneInt,new Pose(center.getX()-deltaX, center.getY(), center.getTheta()));
					}
				}
				highlightPathPoints();
				highlightObstacles();
			}
		};
		panel.getActionMap().put("Decrease X of selected pose(s)",actXMinus);
		
		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT,0),"Increase X of selected pose(s)");
		AbstractAction actXPlus = new AbstractAction() {
			private static final long serialVersionUID = 6900418766755234220L;
			@Override
			public void actionPerformed(ActionEvent e) {
				if (!selectedPathPointsInt.isEmpty()) {
					backupPath();
					for (int selectedPathPointOneInt : selectedPathPointsInt) {
						double x = path.get(selectedPathPointOneInt).getPose().getX();
						double y = path.get(selectedPathPointOneInt).getPose().getY();
						double th = path.get(selectedPathPointOneInt).getPose().getTheta();
						x += deltaX;
						PoseSteering newPoseSteering = new PoseSteering(x, y, th, path.get(selectedPathPointOneInt).getSteering());
						path.set(selectedPathPointOneInt, newPoseSteering);
					}
				}
				if (!selectedObsInt.isEmpty()) {
					for (int selectedObsOneInt : selectedObsInt) {
						Geometry obs = obstacles.get(selectedObsOneInt);
						Pose center = obstacleCenters.get(selectedObsOneInt);
						AffineTransformation at = new AffineTransformation();
						at.translate(deltaX, 0);
						obstacles.set(selectedObsOneInt,at.transform(obs));
						obstacleCenters.set(selectedObsOneInt,new Pose(center.getX()+deltaX, center.getY(), center.getTheta()));
					}
				}
				highlightPathPoints();
				highlightObstacles();
			}
		};
		panel.getActionMap().put("Increase X of selected pose(s)",actXPlus);

		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP,0),"Increase Y of selected pose(s)");
		AbstractAction actYPlus = new AbstractAction() {
			private static final long serialVersionUID = 2627197997139919535L;
			@Override
			public void actionPerformed(ActionEvent e) {
				if (!selectedPathPointsInt.isEmpty()) {
					backupPath();
					for (int selectedPathPointOneInt : selectedPathPointsInt) {
						double x = path.get(selectedPathPointOneInt).getPose().getX();
						double y = path.get(selectedPathPointOneInt).getPose().getY();
						double th = path.get(selectedPathPointOneInt).getPose().getTheta();
						y += deltaY;
						PoseSteering newPoseSteering = new PoseSteering(x, y, th, path.get(selectedPathPointOneInt).getSteering());
						path.set(selectedPathPointOneInt, newPoseSteering);
					}
				}
				if (!selectedObsInt.isEmpty()) {
					for (int selectedObsOneInt : selectedObsInt) {
						Geometry obs = obstacles.get(selectedObsOneInt);
						Pose center = obstacleCenters.get(selectedObsOneInt);
						AffineTransformation at = new AffineTransformation();
						at.translate(0, deltaY);
						obstacles.set(selectedObsOneInt,at.transform(obs));
						obstacleCenters.set(selectedObsOneInt,new Pose(center.getX(), center.getY()+deltaY, center.getTheta()));
					}
				}
				highlightPathPoints();
				highlightObstacles();			
			}
		};
		panel.getActionMap().put("Increase Y of selected pose(s)",actYPlus);
		
		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN,0),"Decrease Y of selected pose(s)");
		AbstractAction actYMinus = new AbstractAction() {
			private static final long serialVersionUID = 6487878455015786029L;
			@Override
			public void actionPerformed(ActionEvent e) {
				if (!selectedPathPointsInt.isEmpty()) {
					backupPath();
					for (int selectedPathPointOneInt : selectedPathPointsInt) {
						double x = path.get(selectedPathPointOneInt).getPose().getX();
						double y = path.get(selectedPathPointOneInt).getPose().getY();
						double th = path.get(selectedPathPointOneInt).getPose().getTheta();
						y -= deltaY;
						PoseSteering newPoseSteering = new PoseSteering(x, y, th, path.get(selectedPathPointOneInt).getSteering());
						path.set(selectedPathPointOneInt, newPoseSteering);
					}
				}
				if (!selectedObsInt.isEmpty()) {
					for (int selectedObsOneInt : selectedObsInt) {
						Geometry obs = obstacles.get(selectedObsOneInt);
						Pose center = obstacleCenters.get(selectedObsOneInt);
						AffineTransformation at = new AffineTransformation();
						at.translate(0, -deltaY);
						obstacles.set(selectedObsOneInt,at.transform(obs));
						obstacleCenters.set(selectedObsOneInt,new Pose(center.getX(), center.getY()-deltaY, center.getTheta()));
					}
				}
				highlightPathPoints();
				highlightObstacles();			
			}
		};
		panel.getActionMap().put("Decrease Y of selected pose(s)",actYMinus);
		
		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN,0),"Decrease theta of selected pose(s)");
		AbstractAction actTMinus = new AbstractAction() {
			private static final long serialVersionUID = -7391970411254721019L;
			@Override
			public void actionPerformed(ActionEvent e) {
				if (!selectedPathPointsInt.isEmpty()) {
					backupPath();
					for (int selectedPathPointOneInt : selectedPathPointsInt) {
						double x = path.get(selectedPathPointOneInt).getPose().getX();
						double y = path.get(selectedPathPointOneInt).getPose().getY();
						double th = path.get(selectedPathPointOneInt).getPose().getTheta();
						th -= deltaT;
						th = Missions.wrapAngle180(th);
						PoseSteering newPoseSteering = new PoseSteering(x, y, th, path.get(selectedPathPointOneInt).getSteering());
						path.set(selectedPathPointOneInt, newPoseSteering);
					}
				}
				if (!selectedObsInt.isEmpty()) {
					for (int selectedObsOneInt : selectedObsInt) {
						Geometry obs = obstacles.get(selectedObsOneInt);
						AffineTransformation at = new AffineTransformation();
						double toOriginX = obstacleCenters.get(selectedObsOneInt).getX();
						double toOriginY = obstacleCenters.get(selectedObsOneInt).getY();
						at.translate(-toOriginX,-toOriginY);
						at.rotate(-deltaT);
						at.translate(toOriginX,toOriginY);
						obstacles.set(selectedObsOneInt,at.transform(obs));
						Pose center = obstacleCenters.get(selectedObsOneInt);
						obstacleCenters.set(selectedObsOneInt, new Pose(center.getX(), center.getY(), center.getTheta()-deltaT));
					}
				}
				highlightPathPoints();
				highlightObstacles();			
			}
		};
		panel.getActionMap().put("Decrease theta of selected pose(s)",actTMinus);

		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN,KeyEvent.SHIFT_DOWN_MASK),"Speed decrease theta of selected pose(s)");
		AbstractAction actTMinusS = new AbstractAction() {
			private static final long serialVersionUID = -7391970411254721019L;
			@Override
			public void actionPerformed(ActionEvent e) {
				if (!selectedPathPointsInt.isEmpty()) {
					backupPath();
					for (int selectedPathPointOneInt : selectedPathPointsInt) {
						double x = path.get(selectedPathPointOneInt).getPose().getX();
						double y = path.get(selectedPathPointOneInt).getPose().getY();
						double th = path.get(selectedPathPointOneInt).getPose().getTheta();
						th -= (10*deltaT);
						th = Missions.wrapAngle180(th);
						PoseSteering newPoseSteering = new PoseSteering(x, y, th, path.get(selectedPathPointOneInt).getSteering());
						path.set(selectedPathPointOneInt, newPoseSteering);
					}
				}
				if (!selectedObsInt.isEmpty()) {
					for (int selectedObsOneInt : selectedObsInt) {
						Geometry obs = obstacles.get(selectedObsOneInt);
						AffineTransformation at = new AffineTransformation();
						double toOriginX = obstacleCenters.get(selectedObsOneInt).getX();
						double toOriginY = obstacleCenters.get(selectedObsOneInt).getY();
						at.translate(-toOriginX,-toOriginY);
						at.rotate(-10*deltaT);
						at.translate(toOriginX,toOriginY);
						obstacles.set(selectedObsOneInt,at.transform(obs));
						Pose center = obstacleCenters.get(selectedObsOneInt);
						obstacleCenters.set(selectedObsOneInt, new Pose(center.getX(), center.getY(), center.getTheta()-10*deltaT));
					}
				}
				highlightPathPoints();
				highlightObstacles();			
			}
		};
		panel.getActionMap().put("Speed decrease theta of selected pose(s)",actTMinusS);

		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP,0),"Increase theta of selected pose(s)");
		AbstractAction actTPlus = new AbstractAction() {
			private static final long serialVersionUID = 8414380724212398117L;
			@Override
			public void actionPerformed(ActionEvent e) {
				if (!selectedPathPointsInt.isEmpty()) {
					backupPath();
					for (int selectedPathPointOneInt : selectedPathPointsInt) {
						double x = path.get(selectedPathPointOneInt).getPose().getX();
						double y = path.get(selectedPathPointOneInt).getPose().getY();
						double th = path.get(selectedPathPointOneInt).getPose().getTheta();
						th += deltaT;
						th = Missions.wrapAngle180(th);
						PoseSteering newPoseSteering = new PoseSteering(x, y, th, path.get(selectedPathPointOneInt).getSteering());
						path.set(selectedPathPointOneInt, newPoseSteering);
					}
				}
				if (!selectedObsInt.isEmpty()) {
					for (int selectedObsOneInt : selectedObsInt) {
						Geometry obs = obstacles.get(selectedObsOneInt);
						AffineTransformation at = new AffineTransformation();
						double toOriginX = obstacleCenters.get(selectedObsOneInt).getX();
						double toOriginY = obstacleCenters.get(selectedObsOneInt).getY();
						at.translate(-toOriginX,-toOriginY);
						at.rotate(deltaT);
						at.translate(toOriginX,toOriginY);
						obstacles.set(selectedObsOneInt,at.transform(obs));
						Pose center = obstacleCenters.get(selectedObsOneInt);
						obstacleCenters.set(selectedObsOneInt, new Pose(center.getX(), center.getY(), center.getTheta()+deltaT));
					}
				}
				highlightPathPoints();
				highlightObstacles();			
			}
		};
		panel.getActionMap().put("Increase theta of selected pose(s)",actTPlus);

		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP,KeyEvent.SHIFT_DOWN_MASK),"Speed increase theta of selected pose(s)");
		AbstractAction actTPlusS = new AbstractAction() {
			private static final long serialVersionUID = 8414380724212398117L;
			@Override
			public void actionPerformed(ActionEvent e) {
				if (!selectedPathPointsInt.isEmpty()) {
					backupPath();
					for (int selectedPathPointOneInt : selectedPathPointsInt) {
						double x = path.get(selectedPathPointOneInt).getPose().getX();
						double y = path.get(selectedPathPointOneInt).getPose().getY();
						double th = path.get(selectedPathPointOneInt).getPose().getTheta();
						th += (10*deltaT);
						th = Missions.wrapAngle180(th);
						PoseSteering newPoseSteering = new PoseSteering(x, y, th, path.get(selectedPathPointOneInt).getSteering());
						path.set(selectedPathPointOneInt, newPoseSteering);
					}
				}
				if (!selectedObsInt.isEmpty()) {
					for (int selectedObsOneInt : selectedObsInt) {
						Geometry obs = obstacles.get(selectedObsOneInt);
						AffineTransformation at = new AffineTransformation();
						double toOriginX = obstacleCenters.get(selectedObsOneInt).getX();
						double toOriginY = obstacleCenters.get(selectedObsOneInt).getY();
						at.translate(-toOriginX,-toOriginY);
						at.rotate(10*deltaT);
						at.translate(toOriginX,toOriginY);
						obstacles.set(selectedObsOneInt,at.transform(obs));
						Pose center = obstacleCenters.get(selectedObsOneInt);
						obstacleCenters.set(selectedObsOneInt, new Pose(center.getX(), center.getY(), center.getTheta()+10*deltaT));
					}
				}
				highlightPathPoints();
				highlightObstacles();			
			}
		};
		panel.getActionMap().put("Speed increase theta of selected pose(s)",actTPlusS);

		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_I,0),"Info");
		AbstractAction actInfo = new AbstractAction() {
			private static final long serialVersionUID = 8424380724212398117L;
			@Override
			public void actionPerformed(ActionEvent e) {
				String obs = "Obstacles:";
				for (int i = 0; i < obstacles.size(); i++) obs += ("\n   obs_" + i + " pose (x,y,theta): " + obstacleCenters.get(i));
				System.out.println(obs);
			}
		};
		panel.getActionMap().put("Info",actInfo);
		
		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_M,KeyEvent.SHIFT_DOWN_MASK),"Increase minimum distance between path points for path planning");
		AbstractAction actMDPlus = new AbstractAction() {
			private static final long serialVersionUID = 8414380724212398117L;
			@Override
			public void actionPerformed(ActionEvent e) {
				MIN_DISTANCE_BETWEEN_PATH_POINTS += deltaX;
				System.out.println("Minimum distance between path points (>): " + MIN_DISTANCE_BETWEEN_PATH_POINTS);
			}
		};
		panel.getActionMap().put("Increase minimum distance between path points for path planning",actMDPlus);
		
		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_M,0),"Decrease minimum distance between path points for path planning");
		AbstractAction actMDMinus = new AbstractAction() {
			private static final long serialVersionUID = 8414380724212398117L;
			@Override
			public void actionPerformed(ActionEvent e) {
				if (MIN_DISTANCE_BETWEEN_PATH_POINTS-deltaX >= 0) MIN_DISTANCE_BETWEEN_PATH_POINTS -= deltaX;
				System.out.println("Minimum distance between path points (<): " + MIN_DISTANCE_BETWEEN_PATH_POINTS);
			}
		};
		panel.getActionMap().put("Decrease minimum distance between path points for path planning",actMDMinus);
		
		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_LESS,KeyEvent.SHIFT_DOWN_MASK),"Increase maximum turning radius");
		AbstractAction actTRPlus = new AbstractAction() {
			private static final long serialVersionUID = 8414380724212398117L;
			@Override
			public void actionPerformed(ActionEvent e) {
				MAX_TURNING_RADIUS += deltaTR;
				System.out.println("Turning radius (>): " + MAX_TURNING_RADIUS);
			}
		};
		panel.getActionMap().put("Increase maximum turning radius",actTRPlus);

		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_LESS,0),"Decrease maximum turning radius");
		AbstractAction actTRMinus = new AbstractAction() {
			private static final long serialVersionUID = 8414380724212398117L;
			@Override
			public void actionPerformed(ActionEvent e) {
				if (MAX_TURNING_RADIUS-deltaTR >= 0) MAX_TURNING_RADIUS -= deltaTR;
				System.out.println("Turning radius (<): " + MAX_TURNING_RADIUS);
			}
		};
		panel.getActionMap().put("Decrease maximum turning radius",actTRMinus);

		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_LESS,KeyEvent.SHIFT_DOWN_MASK | KeyEvent.CTRL_DOWN_MASK),"Increase obstacle size");
		AbstractAction actOSPlus = new AbstractAction() {
			private static final long serialVersionUID = 8414380724212398117L;
			@Override
			public void actionPerformed(ActionEvent e) {
				OBSTACLE_SIZE += deltaX;
				System.out.println("Obstacle size (>): " + OBSTACLE_SIZE);
			}
		};
		panel.getActionMap().put("Increase obstacle size",actOSPlus);

		panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_LESS,KeyEvent.CTRL_DOWN_MASK),"Decrease obstacle size");
		AbstractAction actOSMinus = new AbstractAction() {
			private static final long serialVersionUID = 8414380724212398117L;
			@Override
			public void actionPerformed(ActionEvent e) {
				if (OBSTACLE_SIZE-deltaX >= 0) OBSTACLE_SIZE -= deltaX;
				System.out.println("Osbtacle size (<): " + OBSTACLE_SIZE);
			}
		};
		panel.getActionMap().put("Decrease obstacle size",actOSMinus);

		panel.setFocusable(true);
		panel.setArrowHeadSizeInMeters(9.0);
		panel.setTextSizeInMeters(0.3);
	}
	
	
	private void writePath(String fileName) {
        try {
            File file = new File(fileName);
            PrintWriter writer = new PrintWriter(file);
            for (PoseSteering ps : path) {
            	writer.println(ps.getPose().getX() + " " + ps.getPose().getY() + " " + ps.getPose().getTheta() + " " + ps.getSteering());
            }
            writer.close();
        }
        catch (Exception e) { e.printStackTrace(); }
	}
	
	private void readPath() {
		ArrayList<PoseSteering> ret = new ArrayList<PoseSteering>();
		try {
			Scanner in = new Scanner(new FileReader(pathFileName));
			while (in.hasNextLine()) {
				String line = in.nextLine().trim();
				if (line.length() != 0 && !line.trim().startsWith("#")) {
					String[] oneline = line.split(" |\t");
					PoseSteering ps = null;
					if (oneline.length == 4) {
						ps = new PoseSteering(
								new Double(oneline[0]).doubleValue(),
								new Double(oneline[1]).doubleValue(),
								new Double(oneline[2]).doubleValue(),
								new Double(oneline[3]).doubleValue());
					}
					else {
						ps = new PoseSteering(
								new Double(oneline[0]).doubleValue(),
								new Double(oneline[1]).doubleValue(),
								new Double(oneline[2]).doubleValue(),
								0.0);					
					}
					ret.add(ps);
				}
			}
			in.close();
		}
		catch (FileNotFoundException e) { e.printStackTrace(); }
		this.path = ret;
		for (int i = 0; i < path.size(); i++) {
			Pose pose = path.get(i).getPose();
			panel.addArrow(""+i, pose, Color.gray);
		}
		panel.updatePanel();
	}
		
	private PoseSteering[] computePath(PoseSteering from, PoseSteering ... to) {
		if (USE_MP) {
			ReedsSheppCarPlanner rsp = new ReedsSheppCarPlanner();
			if (this.mapFileName != null && new File(mapImgFileName.substring(0,mapImgFileName.lastIndexOf("."))+".yaml").exists()) {
				rsp.setMap(mapImgFileName.substring(0,mapImgFileName.lastIndexOf("."))+".yaml");
			}
			else rsp.setMap("maps/map-empty.yaml");
			rsp.setRadius(3.0);
			rsp.setTurningRadius(MAX_TURNING_RADIUS);
			rsp.setDistanceBetweenPathPoints(MIN_DISTANCE_BETWEEN_PATH_POINTS);
			rsp.setStart(from.getPose());
			Pose[] goalPoses = new Pose[to.length];
			for (int i = 0; i < goalPoses.length; i++) goalPoses[i] = to[i].getPose();
			rsp.setGoals(goalPoses);
			rsp.addObstacles(obstacles.toArray(new Geometry[obstacles.size()]));
			if (!rsp.plan()) return null;
			PoseSteering[] ret = rsp.getPath();
			return ret;
		}
		Coordinate[] controlPoints = new Coordinate[4];
		controlPoints[0] = new Coordinate(from.getX(),from.getY(),0.0);
		double d = MAX_TURNING_RADIUS;
		controlPoints[1] = new Coordinate(from.getX()+d*Math.cos(from.getTheta()), from.getY()+d*Math.sin(from.getTheta()), 0.0);
		controlPoints[2] = new Coordinate(to[to.length-1].getX()-d*Math.cos(to[to.length-1].getTheta()), to[to.length-1].getY()-d*Math.sin(to[to.length-1].getTheta()), 0.0);
		controlPoints[3] = new Coordinate(to[to.length-1].getX(),to[to.length-1].getY(),0.0);
		Spline3D spline1 = SplineFactory.createBezier(controlPoints, 0.5);
		return spline1.asPoseSteerings();
	}

	public static void main(String[] args) {
		PREFIX = "";
		String pathFileName = "paths/path2.path";
		new PathEditor(pathFileName);
		
		//PREFIX = "/home/fpa/gitroot.gitlab/volvo_ce/coordination_oru_vce";
		//String pathFileName = PREFIX+File.separator+"paths/poses.txt";
		//String pathFileName = PREFIX+File.separator+"paths/elsite_smooth_paths/elsite_paths_left.path1_and_2_and_3.path.new";
		//String mapFileName = PREFIX+File.separator+"maps/elsite_1m.yaml";
		//String posesFileName = null;// PREFIX+File.separator+"paths/poses.txt";
		//new PathEditor(pathFileName,mapFileName,posesFileName);
		
	}

}