package org.openpixi.pixi.ui;

import org.openpixi.pixi.physics.Settings;
import org.openpixi.pixi.physics.Simulation;
import org.openpixi.pixi.physics.fields.PoissonSolver;
import org.openpixi.pixi.physics.fields.PoissonSolverFFTPeriodic;
import org.openpixi.pixi.physics.fields.SimpleSolver;
import org.openpixi.pixi.physics.grid.ChargeConservingCIC;
import org.openpixi.pixi.physics.grid.Grid;
import org.openpixi.pixi.ui.util.WriteFile;

import java.io.File;

public class PoissonSolverCalculations {
	
	private Simulation s;
	private Grid g;
	private PoissonSolver poisolver;
	
	public PoissonSolverCalculations() {

		Settings stt = new Settings();
		stt.setSimulationWidth(100);
		stt.setSimulationHeight(100);

		stt.setGridCellsX(100);
		stt.setGridCellsY(100);
		stt.setGridSolver(new SimpleSolver());
		stt.setInterpolator(new ChargeConservingCIC());

		this.s = new Simulation(stt);
		this.g = s.grid;
		g.resetCurrent();
		
		this.poisolver = new PoissonSolverFFTPeriodic();
	}
	
	private double[][] pointChargeShifted(int numCellsX, int numCellsY) {
		double[][] rho = new double[numCellsX][numCellsY];
		int indexX = (int)(numCellsX/2);
		int indexY = (int) (numCellsY/2);
		rho[indexX][indexY] = 1;
		rho[indexX+1][indexY] = 1;
		rho[indexX][indexY+1] = 1;
		rho[indexX+1][indexY+1] = 1;
		return rho;
	}
	
	private double[][] dipole(int numCellsX, int numCellsY) {
		double[][] rho = new double[numCellsX][numCellsY];
		int indexX = (int)(numCellsX/2);
		int indexY = (int) (numCellsY/2);
		rho[indexX-2][indexY] = 10;
		rho[indexX+2][indexY] = -10;
		return rho;
	}
	
	private double[][] lineChargeOnEdge(int numCellsX, int numCellsY) {
		double[][] rho = new double[numCellsX][numCellsY];
		double charge = 1;
		for(int i = 0; i < numCellsX; i++) {
				rho[i][0] = charge;
				rho[i][numCellsY-1] = charge;				
		}
		
		for(int i = 0; i < numCellsY; i++) {
			rho[0][i] = charge;
			rho[numCellsX-1][i] = charge;				
		}
		return rho;
	}
	
	private double[][] lineChargeOnSide(int numCellsX, int numCellsY) {
		double[][] rho = new double[numCellsX][numCellsY];
		double charge = 1;		
		for(int i = 0; i < numCellsY; i++) {
				rho[0][i] = charge;			
		}
		return rho;
	}
	
	private double[][] randomChargeDistribution(int numCellsX, int numCellsY) {
		double[][] rho = new double[numCellsX][numCellsY];
		double charge = 10;
		if (Math.random() < 0.5) {
			charge = -charge;
		}
		for(int i = 0; i < numCellsX; i++) {
			for(int j = 0; j < numCellsY; j++) {
				g.setRho(i, j, charge * Math.random());
			}
		}
		
		return rho;
	}
	
	public static void output(Grid g) {
		
		double aspectratio = g.getCellHeight() * g.getNumCellsY() / g.getCellWidth() * g.getNumCellsX();
		//deletes the old files
		File file1 = new File("\\efeld.dat");
		file1.delete();
		File file2 = new File("\\potential.dat");
		file2.delete();
		
		//creates new file "efield.dat" in working directory and writes
		//field data to it
		WriteFile fieldFile = new WriteFile("efeld", "");
		for (int i = 0; i < g.getNumCellsX(); i++) {
			for(int j = 0; j < g.getNumCellsY(); j++) {
				fieldFile.writeLine(i*g.getCellWidth() + "\t" + j*g.getCellHeight() +
						"\t" + g.getEx(i, j) + "\t" + g.getEy(i, j));
			}
		}
		fieldFile.closeFstream();
		
		WriteFile potentialFile = new WriteFile("potential", "");
		for (int i = 0; i < g.getNumCellsX(); i++) {
			for(int j = 0; j < g.getNumCellsY(); j++) {
				potentialFile.writeLine(i*g.getCellWidth() + "\t" + j*g.getCellHeight()  + "\t" + g.getPhi(i, j));
			}
		}
		potentialFile.closeFstream();
		
		//YOU NEED GNUPLOT FOR THIS http://www.gnuplot.info/
		//NEEDS TO BE IN YOUR EXECUTION PATH (i.e. PATH variable on windows)
		//plots the above output as vector field
		try {
		Runtime gnuplotrt = Runtime.getRuntime();
		Process gnuplotpr = gnuplotrt.exec("gnuplot -e \"set term png; set size ratio " + aspectratio + "; set output 'D:\\efield.png'; plot 'D:\\efeld.dat' using 1:2:3:4 with vectors head filled lt 2\"");
		} catch (Exception e) {
			e.printStackTrace();
		}
		//plots potential
		try {
		Runtime gnuplotPotentialRt = Runtime.getRuntime();
		Process gnuplotPotentialPr = gnuplotPotentialRt.exec("gnuplot -e \"set term png; set size ratio " + aspectratio + "; set output 'D:\\potential.png'; plot 'D:\\potential.dat' using 1:2:3 with circles linetype palette \"");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		
		PoissonSolverCalculations pc = new PoissonSolverCalculations();
		//writes to g.rho
		pc.randomChargeDistribution(pc.g.getNumCellsX(), pc.g.getNumCellsY());
				
		long start = System.currentTimeMillis();
		pc.poisolver.solve(pc.g);				
		long elapsed = System.currentTimeMillis()-start;
		System.out.println("\nCalculation time: "+elapsed);
		
		PoissonSolverCalculations.output(pc.g);
		
		interpolatorAndPoissonsolver();
	}
	
	public static void interpolatorAndPoissonsolver() {

		Settings stt = new Settings();
		stt.setSimulationWidth(100);
		stt.setSimulationHeight(100);
		stt.setSpeedOfLight(Math.sqrt(stt.getSimulationWidth() * stt.getSimulationWidth() +
				stt.getSimulationHeight() * stt.getSimulationHeight())/5);

		stt.setNumOfParticles(1);
		stt.setParticleRadius(1);
		stt.setParticleMaxSpeed(stt.getSpeedOfLight());

		stt.setGridCellsX(100);
		stt.setGridCellsY(100);
		stt.setGridSolver(new SimpleSolver());
		stt.setInterpolator(new ChargeConservingCIC());

		Simulation s = new Simulation(stt);
		PoissonSolverCalculations.output(s.grid);
	}

}
