package fr.orsay.lri.varna.models;
import java.awt.Point;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import javax.swing.undo.AbstractUndoableEdit;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoableEdit;
import fr.orsay.lri.varna.VARNAPanel;
import fr.orsay.lri.varna.applications.templateEditor.GraphicalTemplateElement;
import fr.orsay.lri.varna.applications.templateEditor.TemplatePanel;
import fr.orsay.lri.varna.applications.templateEditor.TemplateEdits.ElementEdgeMoveTemplateEdit;
import fr.orsay.lri.varna.exceptions.ExceptionNAViewAlgorithm;
import fr.orsay.lri.varna.models.rna.ModeleBase;
import fr.orsay.lri.varna.models.rna.ModeleBP;
import fr.orsay.lri.varna.models.rna.RNA;
public class VARNAEdits {
public static final double MAX_DISTANCE= 55.0;
public static class BasesShiftEdit extends AbstractUndoableEdit
{
private ArrayList<Integer> _indices;
private double _dx;
private double _dy;
private VARNAPanel _vp;
public BasesShiftEdit(ArrayList<Integer> indices, double dx, double dy, VARNAPanel p)
{
_indices = indices;
_dx = dx;
_dy = dy;
_vp = p;
}
public void undo() throws CannotUndoException {
for (int index: _indices)
{
ModeleBase mb = _vp.getRNA().getBaseAt(index);
_vp.getRNA().setCoord(index,new Point2D.Double(mb.getCoords().x-_dx,mb.getCoords().y-_dy));
_vp.getRNA().setCenter(index,new Point2D.Double(mb.getCenter().x-_dx,mb.getCenter().y-_dy));
}
_vp.repaint();
}
public void redo() throws CannotRedoException {
for (int index: _indices)
{
ModeleBase mb = _vp.getRNA().getBaseAt(index);
_vp.getRNA().setCoord(index,new Point2D.Double(mb.getCoords().x+_dx,mb.getCoords().y+_dy));
_vp.getRNA().setCenter(index,new Point2D.Double(mb.getCenter().x-_dx,mb.getCenter().y-_dy));
}
_vp.repaint();
}
public boolean canUndo() { return true; }
public boolean canRedo() { return true; }
public String getPresentationName() { return "Base #"+_indices+" shifted"; }
public boolean addEdit(UndoableEdit anEdit)
{
if (anEdit instanceof BasesShiftEdit)
{
BasesShiftEdit e = (BasesShiftEdit) anEdit;
if (e._indices.equals(_indices))
{
Point2D.Double tot = new Point2D.Double(_dx+e._dx,_dy+e._dy);
if (tot.distance(0.0, 0.0)<MAX_DISTANCE)
{
_dx = _dx+e._dx;
_dy = _dy+e._dy;
return true;
}
}
}
return false;
}
};
public static class HelixRotateEdit extends AbstractUndoableEdit
{
private double _delta;
private double _base;
private double _pLimL;
private double _pLimR;
private Point _h;
private Point _ml;
private VARNAPanel _vp;
public HelixRotateEdit(double delta, double base, double pLimL, double pLimR, Point h, Point ml, VARNAPanel vp)
{
_delta = delta;
_base = base;
_pLimL = pLimL;
_pLimR = pLimR;
_h = h;
_ml = ml;
_vp = vp;
}
public void undo() throws CannotUndoException {
_vp.getVARNAUI().UIRotateEverything(-_delta, _base, _pLimL, _pLimR, _h, _ml);
_vp.repaint();
}
public void redo() throws CannotRedoException {
_vp.getVARNAUI().UIRotateEverything(_delta, _base, _pLimL, _pLimR, _h, _ml);
_vp.repaint();
}
public boolean canUndo() { return true; }
public boolean canRedo() { return true; }
public String getPresentationName() { return "Helix #"+_h+" rotated angle:"+_delta; }
public boolean addEdit(UndoableEdit anEdit)
{
if (anEdit instanceof HelixRotateEdit)
{
HelixRotateEdit e = (HelixRotateEdit) anEdit;
if (e._h.equals(_h))
{
double totAngle = e._delta+_delta;
while (totAngle>Math.PI)
{ totAngle -= 2.0*Math.PI; }
if (Math.abs(totAngle)<Math.PI/8.0)
{
_delta=totAngle;
return true;
}
}
}
return false;
}
};
public static class SingleBaseMoveEdit extends AbstractUndoableEdit
{
private int _index;
private double _ox;
private double _oy;
private double _nx;
private double _ny;
private VARNAPanel _vp;
public SingleBaseMoveEdit(int index, double nx, double ny, VARNAPanel p)
{
_index = index;
ModeleBase mb = p.getRNA().getBaseAt(index);
_ox = mb.getCoords().x;
_oy = mb.getCoords().y;
_nx = nx;
_ny = ny;
_vp = p;
}
public void undo() throws CannotUndoException {
_vp.getRNA().setCoord(_index,new Point2D.Double(_ox,_oy));
_vp.repaint();
}
public void redo() throws CannotRedoException {
_vp.getRNA().setCoord(_index,new Point2D.Double(_nx,_ny));
_vp.repaint();
}
public boolean canUndo() { return true; }
public boolean canRedo() { return true; }
public String getPresentationName() { return "Base #"+_index+" moved"; }
public boolean addEdit(UndoableEdit anEdit)
{
if (anEdit instanceof SingleBaseMoveEdit)
{
SingleBaseMoveEdit e = (SingleBaseMoveEdit) anEdit;
if (e._index==_index)
{
Point2D.Double po1 = new Point2D.Double(_ox,_oy);
Point2D.Double pn1 = new Point2D.Double(_nx,_ny);
Point2D.Double po2 = new Point2D.Double(e._ox,e._oy);
Point2D.Double pn2 = new Point2D.Double(e._nx,e._ny);
if ((pn1.equals(po2))&&(po1.distance(pn2)<MAX_DISTANCE))
{
_nx = e._nx;
_ny = e._ny;
return true;
}
}
}
return false;
}
};
public static class HelixFlipEdit extends AbstractUndoableEdit
{
private Point _h;
private VARNAPanel _vp;
public HelixFlipEdit(Point h, VARNAPanel vp)
{
_h = h;
_vp = vp;
}
public void undo() throws CannotUndoException {
_vp.getVARNAUI().UIFlipHelix(_h);
_vp.repaint();
}
public void redo() throws CannotRedoException {
_vp.getVARNAUI().UIFlipHelix(_h);
_vp.repaint();
}
public boolean canUndo() { return true; }
public boolean canRedo() { return true; }
public String getPresentationName() { return "Helix #"+_h+" flipped";}
public boolean addEdit(UndoableEdit anEdit)
{
return false;
}
};
public static class AddBPEdit extends AbstractUndoableEdit
{
private ModeleBP _msbp;
private int _i;
private int _j;
private VARNAPanel _vp;
public AddBPEdit(int i, int j, ModeleBP msbp, VARNAPanel vp)
{
_msbp = msbp;
_i = i;
_j = j;
_vp = vp;
}
public void undo() throws CannotUndoException {
_vp.getRNA().removeBP(_msbp);
_vp.repaint();
}
public void redo() throws CannotRedoException {
_vp.getRNA().addBPToStructure(_i,_j,_msbp);
_vp.repaint();
}
public boolean canUndo() { return true; }
public boolean canRedo() { return true; }
public String getPresentationName() { return "Add BP ("+_i+","+_j+")";}
public boolean addEdit(UndoableEdit anEdit)
{
return false;
}
};
public static class RemoveBPEdit extends AbstractUndoableEdit
{
private ModeleBP _msbp;
private int _i;
private int _j;
private VARNAPanel _vp;
public RemoveBPEdit( int i, int j,ModeleBP msbp, VARNAPanel vp)
{
_msbp = msbp;
_i = i;
_j = j;
_vp = vp;
}
public void undo() throws CannotUndoException {
_vp.getRNA().addBPToStructure(_i,_j,_msbp);
_vp.repaint();
}
public void redo() throws CannotRedoException {
_vp.getRNA().removeBP(_msbp);
_vp.repaint();
}
public boolean canUndo() { return true; }
public boolean canRedo() { return true; }
public String getPresentationName() { return "Remove BP ("+_i+","+_j+")";}
public boolean addEdit(UndoableEdit anEdit)
{
return false;
}
};
public static class RotateRNAEdit extends AbstractUndoableEdit
{
private double _angle;
private VARNAPanel _vp;
public RotateRNAEdit( double angle, VARNAPanel vp)
{
_angle = angle;
_vp = vp;
}
public void undo() throws CannotUndoException {
_vp.getRNA().globalRotation(-_angle);
_vp.repaint();
}
public void redo() throws CannotRedoException {
_vp.getRNA().globalRotation(_angle);
_vp.repaint();
}
public boolean canUndo() { return true; }
public boolean canRedo() { return true; }
public String getPresentationName() { return "Rotate RNA angle:"+_angle+"";}
public boolean addEdit(UndoableEdit anEdit)
{
if (anEdit instanceof RotateRNAEdit)
{
RotateRNAEdit e = (RotateRNAEdit) anEdit;
if (Math.abs(_angle+e._angle)<30)
{
_angle += e._angle;
return true;
}
}
return false;
}
};
public static class RedrawEdit extends AbstractUndoableEdit
{
private int _prevMode;
private int _newMode;
private boolean _prevFlat;
private boolean _newFlat;
private ArrayList<Point2D.Double> _backupCoords = new ArrayList<Point2D.Double>();
private ArrayList<Point2D.Double> _backupCenters = new ArrayList<Point2D.Double>();
private VARNAPanel _vp;
public RedrawEdit(VARNAPanel vp,boolean newFlat)
{
this(vp.getRNA().getDrawMode(),vp,newFlat);
}
public RedrawEdit(int newMode, VARNAPanel vp)
{
this(newMode,vp,vp.getFlatExteriorLoop());
}
public RedrawEdit(int newMode, VARNAPanel vp, boolean newFlat)
{
_vp = vp;
_newMode = newMode;
_newFlat = newFlat;
_prevFlat = _vp.getFlatExteriorLoop();
for (ModeleBase mb: _vp.getRNA().get_listeBases())
{
_backupCoords.add(new Point2D.Double(mb.getCoords().x,mb.getCoords().y));
_backupCenters.add(new Point2D.Double(mb.getCenter().x,mb.getCenter().y));
}
_prevMode = _vp.getDrawMode();
}
public void undo() throws CannotUndoException {
RNA r = _vp.getRNA();
_vp.setFlatExteriorLoop(_prevFlat);
r.setDrawMode(_prevMode);
for (int index =0;index<_vp.getRNA().get_listeBases().size();index++)
{
Point2D.Double oldCoord = _backupCoords.get(index);
Point2D.Double oldCenter = _backupCenters.get(index);
r.setCoord(index, oldCoord);
r.setCenter(index, oldCenter);
}
_vp.repaint();
}
public void redo() throws CannotRedoException {
try {
_vp.setFlatExteriorLoop(_newFlat);
_vp.getRNA().drawRNA(_newMode,_vp.getConfig());
} catch (ExceptionNAViewAlgorithm e) {
e.printStackTrace();
}
_vp.repaint();
}
public boolean canUndo() { return true; }
public boolean canRedo() { return true; }
public String getPresentationName() { return "Redraw whole RNA";}
public boolean addEdit(UndoableEdit anEdit)
{
return false;
}
};
}