/* ----------------------------------------
 * Origin  : Akkodis
 * Project : CDPP Propagation Tool 
 * ----------------------------------------
 * History 
 * Version : V2.13
 * DM-ID : redmine#12279 : 10/09/2025 : LBE : Add field lines in 3d panel
 * ----------------------------------------
 */
package fr.tlse.irap.pt.client.controller.drawing3d;

import fr.tlse.irap.fieldLine.FieldLine;
import fr.tlse.irap.fieldLine.FieldPoint;
import fr.tlse.irap.pos.Position;
import fr.tlse.irap.pt.client.controller.common.SpaceElementCollection;
import fr.tlse.irap.pt.client.services.ServiceFactory;
import fr.tlse.irap.spaceElement.SpaceElement;
import fr.tlse.irap.utils.CoordConverter;
import java.util.ArrayList;
import java.util.List;
import javafx.scene.paint.Color;
import org.fxyz3d.geometry.Point3D;
import org.fxyz3d.shapes.composites.PolyLine3D;

/**
 * Manage Field lines objects in 2D panel
 *
 * @author Laurent.BEIGBEDER
 */
public class FieldLine3d {

    private Xform tg;
    private PolyLine3D shape;
    private Color color;
    /**
     * lineWidth in km
     */
    private float lineWidth=100;
    
    
    /**
     * Solar wind speed in km/s
     */
    private double solarWindSpeed = 400;
    /**
     * relates object if any
     */
    private SpaceElement spaceElement = null;

    
    public FieldLine3d(FieldLine pFl, double pVsw, float pLineWidth, Color pColor) {
        solarWindSpeed = pVsw;
        lineWidth = pLineWidth;
        color = pColor;
        tg = new Xform();
        shape = generateShape(pFl, pLineWidth, pColor);
        shape.setUserData(this);
        tg.getChildren().add(shape);
    }

    /**
     * generate polyline shape from field line points
     * @param pFl
     * @param pWidth
     * @param pColor
     * @return 
     */
    private PolyLine3D generateShape(FieldLine pFl, float pWidth, Color pColor) {
        List<Point3D> lPts = new ArrayList<>();
        for (FieldPoint lFp : pFl.getPoints()) {
            lPts.add(new Point3D((float) lFp.getX(), (float) lFp.getY(), (float) lFp.getZ()));
        }
        return new PolyLine3D(lPts, pWidth, pColor, PolyLine3D.LineType.RIBBON);
    }
    
    /**
     * Change line shape with object properties
     */
    public Xform setNewPoints(FieldLine pFl, float pLineWidth) {
        lineWidth = pLineWidth;
        tg.getChildren().clear();
        shape = generateShape(pFl, pLineWidth, color);
        shape.setUserData(this);
        tg.getChildren().add(shape);
        return tg;
    }
    

    /**
     * Get projection from parker spiral from an element position
     *
     * @param pSe Element fo start position in (HAE/EclipJ2000) in km
     * @param pSWSpeed Solar wind speed in km.s-1 Sun attitude to convert
     * EclipJ2000 to IAU
     * @return List of fieldLines in carrington/IAU_SUN
     */
    public static FieldLine getParkerFieldLine(SpaceElement pSe, double pSWSpeed) {
        //get parker spiral

        final double RSun = 696340;
        final double RSourceFactor = 1;
        final double lSolRot = 25.38;
        //get rot angle per second
        final double lAngularSpeed = 2 * Math.PI / (lSolRot * 24 * 60 * 60);
        final double rSource = RSourceFactor * RSun;
        FieldLine lFl = new FieldLine();
        Position lStartPos = pSe.getPosition();

        double[] lSunAtt = ServiceFactory.getPositionService().getPositionElement(
                SpaceElementCollection.getSpaceElementWrapper().getSun(),
                SpaceElementCollection.getCurrentStartDate()).getAttitude();

        double[] lP = CoordConverter.toSpheric(lStartPos.getX(), lStartPos.getY(), lStartPos.getZ());
        //System.out.println("pointToFollow = " + pointToFollow);
        double lRange = pSe.getPosition().length();
        double lRangeMax = lRange;
        //if max range set on followed target
        double lPhi = Math.toRadians(lP[0]);
        double lTheta = Math.toRadians(lP[1]);
        //System.out.println("lRange = "+lRange+" Phi="+lP[0]+" theta="+lP[1]);
//            //convert thta to angle from Z axis

        double lPhi0 = lPhi + (lAngularSpeed * (lRange - rSource)) / pSWSpeed;

        //LOGGER.info("pRadius=" + pRadius + " pSolarwspeed=" + pSolarwspeed + " lAngularSpeed=" + lAngularSpeed);
        //LOGGER.info("Range=" + lRange + " Phi=" + lPhi + " lPhi0=" + lPhi0);
        List<FieldPoint> lPts = new ArrayList<FieldPoint>();

        //System.out.println("Build line " + i + " Phi0=" + Math.toDegrees(lPhi0) + " theta=" + Math.toDegrees(lTheta));
        //logger.info("Parker spiral point Build "+lSe.getName()+": ("+lStartPos.getX()+"/"+lStartPos.getY()+"/"+lStartPos.getZ()+") - Att:"+pSunAtt[0]+" - "+lP[0]+" lat="+lP[1]+" r="+ lRange);
        //Build line
        for (lRange = rSource; lRange < lRangeMax; lRange += RSun) {

            /**
             * **** CRAVENS 3D with no simplification ****
             */
            lPhi = lPhi0 - (lAngularSpeed * (lRange - rSource)) / pSWSpeed;

            //lRange = pRadius + (pSolarwspeed * (lPhi - lPhi0)) / lAngularSpeed;
            //logger.info("**********Using sun attitude "+pSunAtt[0]+"/"+pSunAtt[1]);
            //convert to carrington(IAU) spheric coords then spheric
            double[] lPt = CoordConverter.toCartesian(Math.toDegrees(lPhi) - lSunAtt[0], Math.toDegrees(lTheta) - lSunAtt[1], lRange);
            //logger.info("Parker spiral point (Eclip)"+lSe.getName()+": "+(Math.toDegrees(lPhi))+" lat="+ (Math.toDegrees(lTheta))+" r="+ lRange);
            //logger.info("Parker spiral point (IAU)"+lSe.getName()+": "+(Math.toDegrees(lPhi)-pSunAtt[0])+" lat="+ (Math.toDegrees(lTheta)-pSunAtt[1])+" r="+ lRange);
            //CoordConverter.rectangularToCarrington(lPt[0], lPt[1], lPt[2], pSunAtt);
            FieldPoint lFp = new FieldPoint(lPt[0], lPt[1], lPt[2], 0, 0, 0);
            lPts.add(lFp);
            //lList.add(lPoint);
        }
        //Add all parker spiral line points to field line from start point to surface
        for (int i = lPts.size() - 1; i >= 0; i--) {
            lFl.getPoints().add(lPts.get(i));
        }
        return lFl;
    }

    /**
     * Display hide 3d object in scene
     * @param pShow 
     */
    public void setVisible(boolean pShow) {
        if(shape==null) return;
        shape.setVisible(pShow);
    }
    
    public boolean isVisible() {
        if(shape==null) return false;
        return shape.isVisible();
    }
    
    
    /**
     * @return the color
     */
    public Color getColor() {
        return color;
    }

    /**
     * @param color the color to set
     */
    public void setColor(Color color) {
        this.color = color;
    }

    /**
     * Solar wind speed in km/s
     * @return the solarWindSpeed
     */
    public double getSolarWindSpeed() {
        return solarWindSpeed;
    }

    /**
     * Solar wind speed in km/s
     * @param solarWindSpeed the solarWindSpeed to set
     */
    public void setSolarWindSpeed(double solarWindSpeed) {
        this.solarWindSpeed = solarWindSpeed;
    }

    /**
     * relates object if any
     * @return the spaceElement
     */
    public SpaceElement getSpaceElement() {
        return spaceElement;
    }

    /**
     * relates object if any
     * @param spaceElement the spaceElement to set
     */
    public void setSpaceElement(SpaceElement spaceElement) {
        this.spaceElement = spaceElement;
    }

    /**
     * @return the shape behind a xform
     */
    public Xform getTg() {
        return tg;
    }

    /**
     * lineWidth in km
     * @return the lineWidth
     */
    public float getLineWidth() {
        return lineWidth;
    }

    /**
     * lineWidth in km
     * @param lineWidth the lineWidth to set
     */
    public void setLineWidth(float lineWidth) {
        this.lineWidth = lineWidth;
    }

}
