package seed.minerva.apps.imse;

import binaryMatrixFile.BinaryMatrixFile;
import binaryMatrixFile.BinaryMatrixWriter;
import otherSupport.ColorMaps;
import otherSupport.StatusOutput;
import jafama.FastMath;
import oneLiners.OneLiners;

import seed.minerva.MinervaOpticsSettings;
import seed.minerva.aug.mse.AugMSESystem;
import seed.minerva.optics.Util;
import seed.minerva.optics.collection.ImageCollector;
import seed.minerva.optics.collection.IntersectionProcessor;
import seed.minerva.optics.collection.LensDepolarisationInfoCollector;
import seed.minerva.optics.drawing.SVGCylindricalProjection;
import seed.minerva.optics.drawing.SVGRayDrawing;
import seed.minerva.optics.drawing.VRMLDrawer;
import seed.minerva.optics.pointSpread.DualGaussianPSF;
import seed.minerva.optics.pointSpread.PSFGrid;
import seed.minerva.optics.pointSpread.PointSpreadBuilder;
import seed.minerva.optics.pointSpread.PointSpreadFunction;
import seed.minerva.optics.pointSpread.PointsPSF;
import seed.minerva.optics.surfaces.Cylinder;
import seed.minerva.optics.surfaces.Plane;
import seed.minerva.optics.tracer.Tracer;
import seed.minerva.optics.types.Element;
import seed.minerva.optics.types.Intersection;
import seed.minerva.optics.types.Pol;
import seed.minerva.optics.types.RaySegment;


/** Fire rays from a single point will all the polarisations through the AUG imse system
 * to see what happens to the polarisation.
 *  
 * @author oliford
 *
 */
public class SinglePSF {
	final static String outPath = MinervaOpticsSettings.getAppsOutputPath() + "/rayTracing/augImse/singlePSF/calibLamp/";
	final static int nRays = 10000;
	final static double posOnBeamAxis = 0.6; // 0.4 to 0.8 ish
	
	/** What rays to trace */
	public static double minIntensity = 0.01;
	public static boolean traceReflections = false;
	
	/** Optical system setup */
	public static AugMSESystem sys = new AugMSESystem();
	
	private static final double svgRayWidth = 0.0001;
	private static final double svgOpticWidth = 0.0003;
	
	//we require three optics;
	// 1) The imaging plane, which will collect the light INTENSITY.
	// 2) The polarisation sensitive plane, which collects the light polarisation.
	// 3) The inital target to fire rays at.
	// e.g. for the normal MSE system, 1 is thee fibre plane, 2 is the PEMs and 3 is the main mirror:		
	public static Plane imagePlane = sys.tubeOptics.fibreEnds;
	public static Plane polarisationPlane = sys.tubeOptics.PEMsFront;
	public static Element initRaysTarget = sys.mirrorBox.protectionCoverFront;
	
	final static double wavelen = 593e-9;
	
	public static void main(String[] args) {
		
		PointSpreadBuilder psfBuild = new PointSpreadBuilder(polarisationPlane);
		psfBuild.setMaxCoherentIntegrationRadius(0.005);
		
		/*double startPos[] = new double[]{ //-1.3, -1.3, 0.1 };
				sys.nbiStart[0] + posOnBeamAxis * sys.nbiUnit[0],
				sys.nbiStart[1] + posOnBeamAxis * sys.nbiUnit[1],
				sys.nbiStart[2] + posOnBeamAxis * sys.nbiUnit[2],
		};//*/		
		double startPos[] = sys.calibLampPos[1];

		psfBuild.startNewPSF(startPos, new PointsPSF());
		
		VRMLDrawer vrmlOut = new VRMLDrawer(outPath + "/singlePSF.vrml", 0.005);
		vrmlOut.setDrawPolarisationFrames(true);
		vrmlOut.setSkipRays(nRays/99);
		
		//One svg drawer in cartesian x/y/z and one in the mirror normal plane
		double rot[][] = new double[3][];
		rot[0] = sys.tubeOptics.fibreEnds.getNormal();
		rot[2] = Util.reNorm(Util.cross(rot[0], sys.mainMirror.getNormal()));
		rot[1] = Util.reNorm(Util.cross(rot[2], rot[0]));
		SVGRayDrawing svgOutCart = new SVGRayDrawing(outPath + "/raysCart", new double[]{ -2, -4, -1, 1, 0, 1 }, true);
		SVGRayDrawing svgOutFlat = new SVGRayDrawing(outPath + "/raysFlat", new double[]{ -2, -4, -1, 1, 0, 1 }, true, rot);
		SVGCylindricalProjection svgPol = new SVGCylindricalProjection(outPath + "/rayPol.svg", 5, -2, 2, true);
		double cols[][] = ColorMaps.jet(nRays);
		svgOutCart.generateLineStyles(cols, svgRayWidth, svgOpticWidth);
		svgOutFlat.generateLineStyles(cols, svgRayWidth, svgOpticWidth);
		svgPol.generateLineStyles(cols, svgRayWidth, svgOpticWidth);
		svgOutCart.setSkipRays(500);
		svgOutFlat.setSkipRays(500);
		svgPol.setSkipRays(500);
		
		
		//sys.mirrorBox.holeGlassFront.setUp(new double[]{ -3,10,2 });
		
		LensDepolarisationInfoCollector lensDepol = new LensDepolarisationInfoCollector(sys.tubeOptics.window1Front, sys.tubeOptics.PEMsFront, new double[]{ 0,0,1 }, 50, 0, outPath + "/polInf");
		
		sys.addElement(sys.makeBeamCylds());
		StatusOutput stat = new StatusOutput(SinglePSF.class, nRays);
		for(int i=0; i < nRays; i++){
			do {
				stat.doStatus(i);
				
				Pol.recoverAll();
				
				RaySegment ray = new RaySegment();
				ray.startPos =  startPos.clone();
				
				ray.dir = Tracer.generateRandomRayTowardSurface(ray.startPos, initRaysTarget);
				ray.up = Tracer.generateRayFanConsistentPolarisationDefinition(ray.startPos, ray.dir, initRaysTarget.getBoundarySphereCentre(), new double[]{ 0, 0, 1 });
								
				
				ray.length = Double.POSITIVE_INFINITY;
				
				ray.E0 = PointSpreadFunction.getInputStatesForMuellerCalc();
				ray.wavelength = wavelen;
				
				Tracer.trace(sys, ray, 100, minIntensity, traceReflections);
				
				int nPrev = psfBuild.getNPointsCollected();
				ray.processIntersections(imagePlane, psfBuild, lensDepol);
				psfBuild.nextCoherentSet();
				
				stat.doStatus(i);
								
				if(psfBuild.getNPointsCollected() > nPrev){
					vrmlOut.drawRay(ray);
					svgOutCart.drawRay(ray, i);
					svgOutFlat.drawRay(ray, i);
					svgPol.drawRay(ray, i);
					
					break;
				}

			}while(true);
		}
		stat.done();

		lensDepol.write();
		
		vrmlOut.drawOptic(sys);
		svgOutCart.drawElement(sys);
		svgOutFlat.drawElement(sys);
		svgPol.drawElement(sys);
		
		PointSpreadFunction psf = psfBuild.psfDone(false);
		/*
		RaySegment ray = new RaySegment();
		ray.startPos = startPos;
		ray.dir = psf.getMeanSourceDir();
		ray.length = 3;
		ray.up = psf.getMeanSourceUp();
		ray.E0 = new double[][]{ { 1,0,0,0 } };
		ray.E1 = ray.E0.clone();
		ray.wavelength = wavelen;
		ray.endHit = null;
		OneLiners.dumpArray(ray.dir);
		vrmlOut.setSmallLineLength(3);
		vrmlOut.drawRay(ray);
		*/
		
		System.out.println("nCollected = " + psfBuild.getNPointsCollected() + "\nFull Mueller:");
		psf.dumpMueller();
		
		double m[] = psf.getMeanMueller();
		for(int i=1; i < m.length; i++){
			m[i] /= m[0];
		}
		m[0] = 1;
		
		System.out.println("Normalised Mueller:");
		PointSpreadFunction.dumpMueller(m);

		vrmlOut.destroy();
		svgOutCart.destroy();
		svgOutFlat.destroy();
		svgPol.destroy();
	
	}
		
}
