/* ----------------------------------------
 * Origin  : Akkodis
 * Project : CDPP Propagation Tool 
 * ----------------------------------------
 * History 
 * Version : 30/11/2022 : LBE : V2.6
 * DM-ID : Redmine #l0481 : 30/11/2022 : Creation
 * Version : 05/08/2024 : LBE : V2.11
 * DM-ID : Redmine#l0763 : 05/08/2024 : Drawing improved
 * ----------------------------------------
 */
package fr.tlse.irap.pt.client.controller.tools.carrington;

import java.util.List;

import fr.tlse.irap.pt.client.controller.common.Position2D;
import fr.tlse.irap.fieldLine.FieldLine;
import fr.tlse.irap.fieldLine.FieldPoint;
import fr.tlse.irap.utils.CoordConverter;
import java.util.ArrayList;
import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.paint.CycleMethod;
import javafx.scene.paint.RadialGradient;
import javafx.scene.paint.Stop;
import javafx.scene.shape.Circle;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Shape;
import javafx.scene.shape.StrokeLineCap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Displays one or more field lines on carrington map
 *
 * @author frup47043
 */
public class CarringtonFieldLines {

    protected static final Logger log = LoggerFactory.getLogger(CarringtonFieldLines.class);
    private List<List<Shape>> fieldLinesPathes;
    private Group nodes = new Group();
    //private BooleanProperty hasChanged = new SimpleBooleanProperty();
    //private BooleanProperty visibilityChanged = new SimpleBooleanProperty();

    private boolean isValid = true;
    /**
     * List of field lines data
     */
    private List<FieldLine> fieldLines;

    public CarringtonFieldLines() {
        this(new ArrayList<FieldLine>());
    }

    public CarringtonFieldLines(List<FieldLine> pFieldLines) {

        fieldLines = pFieldLines;
        fieldLinesPathes = createPathLines(fieldLines);
        for (List<Shape> lShapes : fieldLinesPathes) {
            nodes.getChildren().addAll(lShapes);
        }


        // Listen for property visibility changed => swap visibility 
//        visibilityChanged.addListener(
//                new ChangeListener<Boolean>() {
//            @Override
//            public void changed(ObservableValue<? extends Boolean> observedBoolean, Boolean oldValue, Boolean newValue) {
//                if (newValue) {
//                    drawLines();
//                } else {
//                    clearLines();
//                }
//            }
//        });
    }

//    public void setColor(Color c) {
//        ((Path) nodes.getChildren().get(0)).setFill(c);
//        ((Path) nodes.getChildren().get(0)).setStroke(c);
//    }
    public List<Position2D> getPositions(FieldLine pFl) {
        List<Position2D> positions = new ArrayList<Position2D>();
        double x, y;

        if (!pFl.getPoints().isEmpty()) {
            for (FieldPoint lFp : pFl.getPoints()) {
                double[] lSphericCoords = CoordConverter.toSpheric(lFp.getX(), lFp.getY(), lFp.getZ());
                //log.info("**** Found foot point " + lSphericCoords[0] + " " + lSphericCoords[1] + " at " + lSphericCoords[2]);
                x = CarringtonHelper.longToX(lSphericCoords[0]);
                y = CarringtonHelper.latToY(lSphericCoords[1]);
                positions.add(new Position2D(x, y));
            }
        }
        return positions;
    }

    protected void drawLines() {
        //List<List<Position2D>> lPos = new ArrayList<List<Position2D>>();
        for (int i = 0; i < fieldLinesPathes.size() && i < fieldLines.size(); i++) {
            //log.debug("***Drawing field line "+i);
            updateLine(i);
        }
        show(true);
    }

    protected void clearLines() {
        fieldLinesPathes.clear();
//        for (List<Shape> lShapes : fieldLinesPathes) {
//            for (Shape lShape : lShapes) {
//                if (lShape instanceof Path) {
//                    ((Path)lShape).getElements().clear();
//                }
//                lShape.setVisible(true);
//            }
//        }
    }

    public void show(boolean pView) {
        for (List<Shape> lShapes : fieldLinesPathes) {
            for (Shape lShape : lShapes) {
                lShape.setVisible(pView);
            }
        }
    }

    public void hide() {
        show(false);
    }

//    public boolean isVisible() {
//        return hcs.isVisible();
//    }
    /**
     * field lines and redraw
     *
     * @param pLines new field lines
     */
    public void setFieldLines(List<FieldLine> pLines) {
        log.debug("Setting fieldLines " + pLines);
        fieldLines = pLines;
        if (fieldLines == null) {
            //Avoid null list, create empty list
            fieldLines = new ArrayList<FieldLine>();
        }
        fieldLinesPathes.clear();
        nodes.getChildren().clear();
        fieldLinesPathes = createPathLines(fieldLines);
        //nodes.getChildren().addAll(fieldLinesPathes);
        for (List<Shape> lShapes : fieldLinesPathes) {
            nodes.getChildren().addAll(lShapes);
        }
        if (pLines != null && !pLines.isEmpty()) {
            drawLines();
        } else {
            //nodes.getChildren().clear();
        }
    }

    
    /**
     * List of field lines data
     * @return the fieldLines
     */
    public List<FieldLine> getFieldLines() {
        return fieldLines;
    }
    
    public Group getNodes() {
        return nodes;
    }

    /**
     * Prepare the Field line draw properties. For each fieldLine,
     * set a dashed line , a plain line, a circle, then a square.
     */
    private static List<List<Shape>> createPathLines(List<FieldLine> pFLines) {
        List<List<Shape>> lAllPathes = new ArrayList<>();
        for (FieldLine lFl : pFLines) {
            Color c = Color.web(lFl.getColor());
            RadialGradient radialGradient = new RadialGradient(0, 0, 0.2, 0.3, 1,
                    true, CycleMethod.NO_CYCLE, new Stop[]{
                        new Stop(0, Color.rgb(250, 250, 255)), new Stop(1, c)});

            List<Shape> lFlPathes = new ArrayList<>();

            //then dashed line for parker points
            Path lPath = new Path();
            //lPath.setFill(Color.RED);
            lPath.setStroke(Color.web(lFl.getColor()));
            lPath.setStrokeWidth(2);
            lPath.setStrokeLineCap(StrokeLineCap.ROUND);
            lPath.getStrokeDashArray().addAll(4d);
            lPath.setId("FLine");
            lPath.setVisible(false);
            lFlPathes.add(lPath);
            //then pfss part in plain
            lPath = new Path();
            lPath.setStroke(Color.web(lFl.getColor()));
            lPath.setStrokeWidth(2);
            lPath.setStrokeLineCap(StrokeLineCap.ROUND);
            lPath.setId("FLinepfss");
            lPath.setVisible(false);
            lFlPathes.add(lPath);

            //sub-solar point as a circle
            lFlPathes.add(new Circle(8, radialGradient));
            //then transition point
            lFlPathes.add(new Rectangle(8.0, 8.0, radialGradient));
            
            lAllPathes.add(lFlPathes);
        }
        return lAllPathes;
    }

    /**
     * Update Lines with a list of position
     */
//    public static void updateLines(List<Path> pPathes, List<List<Position2D>> pPositions) {
//        for (int i = 0; i < pPathes.size() && i < pPositions.size(); i++) {
//            updateLine(pPathes.get(i), pPositions.get(i));
//        }
//    }
//
    /**
     * Update a Line with a list of position
     *
     * @param pIdx Line index to update
     */
    public void updateLine(int pIdx) {
        MoveTo moveTo;
        LineTo lineTo;
        Position2D lastPos = null;
        List<Shape> lShapes = fieldLinesPathes.get(pIdx);
        List<Position2D> lPositions = getPositions(fieldLines.get(pIdx));
        FieldLine lFl = fieldLines.get(pIdx);

        ((Path)lShapes.get(0)).getElements().clear();
        ((Path)lShapes.get(1)).getElements().clear();

        for (int i = 0; i < lPositions.size(); i++) {
            Position2D pos = lPositions.get(i);

            if(i==0) {//sub solar point
                ((Circle)lShapes.get(2)).setCenterX(pos.getX());
                ((Circle)lShapes.get(2)).setCenterY(pos.getY());
            }
            if (lFl.getPfssIdx() == i) { //square between pfss and parker part
                ((Rectangle)lShapes.get(3)).setX(pos.getX()-4);
                ((Rectangle)lShapes.get(3)).setY(pos.getY()-4);
                lastPos = null;
            }
 
            //if(pHcs.getElements().size()>1) {
            Path lLinePath = (Path)lShapes.get(0);
            if (lFl.getPfssIdx() <= i) {
                lLinePath = (Path)lShapes.get(1);
                //log.debug("Setting line to PFSS part");
            }
            //if first position or gap between new point, jump without line
            if (lastPos == null) {
                moveTo = new MoveTo(pos.getX(), pos.getY());
                lLinePath.getElements().add(moveTo);
            } else {
                //log.debug("Setting line to " + pos.getX() + " " + pos.getY());
                //moveTo = new MoveTo(pos.getX(), pos.getY());
                lineTo = new LineTo(pos.getX(), pos.getY());
                //moveTo = new MoveTo(pos.getX(), pos.getY());
                //
                lLinePath.getElements().add(lineTo);
            }
            //pHcs.getElements().add(moveTo);
            //}
            lastPos = pos;

        }
    }


}
