package io.github.contractautomata.catapp.actions;

import java.awt.Point;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.IntStream;

import javax.swing.AbstractAction;

import com.mxgraph.model.mxCell;
import com.mxgraph.model.mxGeometry;
import com.mxgraph.swing.mxGraphComponent;
import com.mxgraph.util.mxPoint;
import com.mxgraph.view.mxGraph;

public class AddHandleAction extends AbstractAction
{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	private final Point pt;
	
	public AddHandleAction(Point pt)
	{
		this.pt=pt;
	}

	/**
	 * 
	 */
	public void actionPerformed(ActionEvent e)
	{
		if (e.getSource() instanceof mxGraphComponent)
		{
			mxGraphComponent graphComponent = (mxGraphComponent) e
					.getSource();
			mxGraph graph = graphComponent.getGraph();

			if (!graph.isSelectionEmpty())
			{
				mxCell edge = (mxCell) graph.getSelectionCell();
				mxGeometry eg = edge.getGeometry();				
				List<mxPoint> l = eg.getPoints()!=null
						? new ArrayList<>(eg.getPoints())
						: new ArrayList<>();
						
//				System.out.println(eg.getSourcePoint());
//				System.out.println(l);
//				System.out.println(eg.getTargetPoint());
//				System.out.println("You clicked on point "+pt);
				
				if (l.size()==0)
					l.add(new mxPoint(pt.x,pt.y));
				else {
					int ind = findIndex(l,eg.getSourcePoint(),eg.getTargetPoint());
					l.add(ind, new mxPoint(pt.x,pt.y));
				}
				eg.setPoints(l);
				graphComponent.refresh();
			}
		}
	}
	
	private int findIndex(List<mxPoint> l, mxPoint source, mxPoint target) {
		return IntStream.rangeClosed(0, l.size())
				.mapToObj(i-> new Object() {final int index=i;
				final int d= (int) ((i==0)?liesIn(source,l.get(0))
						:(i==l.size())?liesIn(l.get(l.size()-1),target)
						:liesIn(l.get(i-1),l.get(i)));
				})
				.sorted(Comparator.comparingInt(x -> x.d))
				.mapToInt(o->o.index)
				.findFirst().orElse(0);

	}
	
	//using the equation of a line passing from two points
	private double liesIn(mxPoint p2, mxPoint p1) {
		if (p1.getY()==p2.getY())
			return Math.abs(pt.y-p1.getY());
		else {
			double lies = ((pt.y - p1.getY())/(p2.getY()-p1.getY()))*(p2.getX()-p1.getX())+p1.getX();
			//.out.println(Math.abs(pt.x-lies));
			return Math.abs(pt.x - lies);
		}
	}


}
