package seed.minerva.apps.imse;

import jafama.FastMath;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import cache.common.Cache;
import cache.randomAccessCache.RACacheService;

import binaryMatrixFile.AsciiMatrixFile;
import binaryMatrixFile.BinaryMatrixFile;
import binaryMatrixFile.BinaryMatrixWriter;

import otherSupport.ColorMaps;
import otherSupport.StatusOutput;


import oneLiners.OneLiners;

import seed.minerva.MinervaOpticsSettings;
import seed.minerva.aug.mse.AugFaroNov2013;
import seed.minerva.aug.mse.AugMSESystem;
import seed.minerva.aug.mse.AugMseFaroData;
import seed.minerva.imse.IMSEOptics105_35;
import seed.minerva.imse.IMSEOptics135_50;
import seed.minerva.imse.IMSEOptics135_50_rescaled;
import seed.minerva.imse.IMSEOptics180_50;
import seed.minerva.imse.IMSEOptics75_25;
import seed.minerva.imse.IMSEOptics75_25_expanded_filter;
import seed.minerva.imse.IMSEOptics75_25_imgFielded;
import seed.minerva.imse.IMSEOptics75_25_imgFielded_fibreFielded;
import seed.minerva.imse.IMSEOptics75_25_rescaled;
import seed.minerva.imse.IMSEOptics75_25_silly_second_diag;
import seed.minerva.optics.Util;
import seed.minerva.optics.collection.HitsCollector;
import seed.minerva.optics.collection.ImageCollector;
import seed.minerva.optics.collection.IntensityInfo;
import seed.minerva.optics.collection.LensDepolarisationInfoCollector;
import seed.minerva.optics.collection.PlaneAngleInfo;
import seed.minerva.optics.drawing.SVGCylindricalProjection;
import seed.minerva.optics.drawing.SVGRayDrawing;
import seed.minerva.optics.drawing.VRMLDrawer;
import seed.minerva.optics.interfaces.NullInterface;
import seed.minerva.optics.optics.Box;
import seed.minerva.optics.optics.SimpleDoubleConvexLens;
import seed.minerva.optics.optimisation.OptimiseLensCurvature;
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.surfaces.Square;
import seed.minerva.optics.tracer.Tracer;
import seed.minerva.optics.types.Element;
import seed.minerva.optics.types.Intersection;
import seed.minerva.optics.types.Optic;
import seed.minerva.optics.types.Pol;
import seed.minerva.optics.types.RaySegment;
import seed.minerva.optics.types.Surface;


/** Generates ray tracing of the FARO (nov2013) MSE LOS points.
 * 
 * 
 * @author oliford
 *
 */
public class DrawMSELosTracing {
	
	final static String outPath = MinervaOpticsSettings.getAppsOutputPath() + "/rayTracing/augImse/mseLOSRays/";
	final static int nRays = 50;
	
	/** What rays to trace */
	public static double minIntensity = 0.01;
	public static boolean traceReflections = false;
	
	/** Optical system setup */
	public static AugMSESystem sys = new AugMSESystem(new IMSEOptics135_50_rescaled());
	
	//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.imseOptics.ccd;
	public static Plane polarisationPlane = sys.tubeOptics.PEMsFront;
	public static Element initRaysTarget = sys.mainMirror; //sys.mirrorBox.holeGlassFront;
	
	/** Don't draw rays that don't hit these elements */
	public static Surface mustHitToDraw = sys.tubeOptics.fibreEnds;
	
	final static double wavelen = 653e-9;
	
	public static void main(String[] args) {
		drawMSELosRays();
	}
	
	public static void drawMSELosRays(){
		
		VRMLDrawer vrmlOut = new VRMLDrawer(outPath + "/pictures.vrml", 0.005);
		vrmlOut.setDrawPolarisationFrames(false);
		vrmlOut.addVRML(AugMSESystem.vrmlScaleToAUGDDD);
		
		sys.setupForPulse(351); //Jan2013 setup
		
		double c[] = sys.tubeOptics.fibreEnds.getCentre();
		double n[] = sys.tubeOptics.fibreEnds.getNormal();
		
		AugFaroNov2013 faro = new AugFaroNov2013();
		
		double cols[][] = ColorMaps.jet(10);
		
		StatusOutput stat = new StatusOutput(DrawMSELosTracing.class, 10*6*nRays);		
		for(int ch=0; ch < 10; ch++){ //channel
			for(int f=0; f < 6; f++){ //fibre
			 	//mse-hb-6-5 = hinter beam = between beam and back wall
				//kanal-vb7-06 = vor beam = between beam and mirror box 
			
				double startPos[] = faro.getPos("mse-hb-" + (ch+1) + "-" + (f+1));
							
				int nAttempts = 0, nHit = 0;
				
				for(int i=0; i < nRays; i++){
					 do{
						 stat.doStatus((ch*6 + f)*nRays + i);
							
						Pol.recoverAll();
						
						RaySegment ray = new RaySegment();
						ray.startPos =  startPos.clone();
						ray.dir = Tracer.generateRandomRayTowardSurface(ray.startPos, initRaysTarget);
						
						ray.length = Double.POSITIVE_INFINITY;
						ray.up = Util.cross(Util.reNorm(Util.cross(ray.dir, new double[]{0,0,1})), ray.dir);
						
						ray.E0 = PointSpreadFunction.getInputStatesForMuellerCalc();
						ray.wavelength = wavelen;
						
						Tracer.trace(sys, ray, 100, minIntensity, traceReflections);
						
						List<Intersection> hits = ray.getIntersections(mustHitToDraw); 
										
						if(hits.size() > 0){
							vrmlOut.drawRay(ray, cols[ch]);
							
							nHit++;
							break;
						}
						if(nAttempts > 10000){
							break;
						}
						nAttempts++;
					}while(true);
					 
					System.out.println("\n--------------------------------------- "+ch+" "+f+" ----------------------------------------");
					System.out.println("(ch=" + ch + ", f="+f+"):\t" + nAttempts + "\t" + nHit);
					 
				}
			}
			
			
		}
		
		vrmlOut.drawOptic(sys);
		vrmlOut.addVRML("}"); //end of rotate/transform
		vrmlOut.destroy();
		stat.done();
				
	}

	
		
}
