package testslbmjava;

import gov.sandia.gnem.slbmjni.GridProfile;
import gov.sandia.gnem.slbmjni.Point;
import gov.sandia.gnem.slbmjni.SLBMException;
import gov.sandia.gnem.slbmjni.SlbmInterface;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import static java.lang.Math.*;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

public class TestSLBMFormats
{

	private static SlbmInterface slbm;

	private static int verbosity = 1;

	private static final double dtr = 3.1415926535897932384626 / 180.;
	private static final double rtd = 180. / 3.1415926535897932384626;
	
	private static HashMap<Point, GridProfile> profiles;

	@BeforeClass
	public static void setUpBeforeClass() throws Exception
	{
		// Load the c++ SLBM library libslbm.so into memory.
		System.loadLibrary("slbmjni");
		System.out.println("setUpBeforeClass()  slbmjni loaded");
		slbm = new SlbmInterface();

		System.out.println("SlbmInterface version " + slbm.getVersion());

		slbm.loadVelocityModel("../rstt.2.3");
		
		profiles = new HashMap<Point, GridProfile>(slbm.getNGridNodes());
		
		for (int i=0; i<slbm.getNGridNodes(); ++i)
		{
			GridProfile profile = slbm.getGridData(i);
			profiles.put(new Point(profile), profile);
		}
		
		System.out.println("Profiles.size = "+profiles.size());
		
	}

	@AfterClass
	public static void tearDownAfterClass() throws Exception
	{
		slbm.close();
		if (verbosity > 0) System.out.println("Done");
	}

	@Test
	public void testGetVersion()
	{
		if (verbosity > 0)
			System.out.println("testGetVersion()");
		assert (slbm.getVersion().equals("3.0.0b"));
	}

	@Test
	public void testFormat1() throws SLBMException, IOException
	{
		if (verbosity > 0)
			System.out.println("testFormat1()");

		File f = new File("format1.txt");
		f.delete();
		slbm.saveVelocityModel(f.getCanonicalPath(), 1);
		assert(f.exists());
		
		SlbmInterface fmt = new SlbmInterface();		
		fmt.loadVelocityModel(f.getCanonicalPath());

		boolean eql = compareProfiles(fmt);
		assert(eql);

		f = new File("format12");
		f.delete();
		f.mkdir();
		fmt.saveVelocityModel(f.getCanonicalPath(), 2);
		File target = new File(f, "geostacks");
		assert(target.exists());

		SlbmInterface fmt2 = new SlbmInterface();
		fmt2.loadVelocityModel(f.getCanonicalPath());
		eql = compareProfiles(fmt2);
		assert(eql);
		
		fmt.close();
		fmt2.close();
	}
	
	@Test
	public void testFormat2() throws SLBMException, IOException
	{
		if (verbosity > 0)
			System.out.println("testFormat2()");

		File f = new File("format2");
		f.delete();
		f.mkdir();
		slbm.saveVelocityModel(f.getCanonicalPath(), 2);
		File target = new File(f, "geostacks");
		assert(target.exists());
		
		SlbmInterface fmt = new SlbmInterface();
		fmt.loadVelocityModel(f.getCanonicalPath());
		
		boolean eql = compareProfiles(fmt);
		assert(eql);
		
		f = new File("format22");
		f.delete();
		f.mkdir();
		fmt.saveVelocityModel(f.getCanonicalPath(), 2);
		target = new File(f, "geostacks");
		assert(target.exists());

		SlbmInterface fmt2 = new SlbmInterface();
		fmt2.loadVelocityModel(f.getCanonicalPath());
		eql = compareProfiles(fmt2);
		assert(eql);
		
		fmt.close();
		fmt2.close();
	}

	@Test
	public void testFormat3() throws SLBMException, IOException
	{
		if (verbosity > 0)
			System.out.println("testFormat3()");

		// slbm was loaded from main model directory rstt.2.3
		
		// save the model in format 3 (version 3 directory format)
		// in a directory called 'format3'
		File f = new File("format3");
		f.delete();
		f.mkdir();
		slbm.saveVelocityModel(f.getCanonicalPath(), 3);
		File target = new File(f, "geotessmodel");
		assert(target.exists());
		
		// make a new SlbmInterface and load the model from
		// format3 (version 3 directory format).
		SlbmInterface fmt = new SlbmInterface();
		fmt.loadVelocityModel(f.getCanonicalPath());
		boolean eql = compareProfiles(fmt);
		assert(eql);
		
		// save the model loaded from format3 to a new 
		// directory in format 2 (version 2 binary directory format)
		f = new File("format32");
		f.delete();
		f.mkdir();
		fmt.saveVelocityModel(f.getCanonicalPath(), 2);
		target = new File(f, "geostacks");
		assert(target.exists());

		// load it back in.  This model will have originated from
		// rstt.2.3, been saved in format3, loaded from format 3,
		// saved in format 2, loaded from format 2.
		SlbmInterface fmt2 = new SlbmInterface();
		fmt2.loadVelocityModel(f.getCanonicalPath());
		// compare it to the original.
		eql = compareProfiles(fmt2);
		assert(eql);
		
		fmt.close();
		fmt2.close();
	}

	@Test
	public void testFormat4binary() throws SLBMException, IOException
	{
		if (verbosity > 0)
			System.out.println("testFormat4binary()");

		File f = new File("format4.binary");
		f.delete();
		slbm.saveVelocityModel(f.getCanonicalPath(), 4);
		assert(f.exists());
		
		SlbmInterface fmt = new SlbmInterface();		
		fmt.loadVelocityModel(f.getCanonicalPath());
		
		boolean eql = compareProfiles(fmt);
		assert(eql);

		f = new File("format42b");
		f.delete();
		f.mkdir();
		fmt.saveVelocityModel(f.getCanonicalPath(), 2);
		File target = new File(f, "geostacks");
		assert(target.exists());

		SlbmInterface fmt2 = new SlbmInterface();
		fmt2.loadVelocityModel(f.getCanonicalPath());
		eql = compareProfiles(fmt2);
		assert(eql);
		
		fmt.close();
		fmt2.close();
	}

	@Test
	public void testFormat4ascii() throws SLBMException, IOException
	{
		if (verbosity > 0)
			System.out.println("testFormat4ascii()");

		File f = new File("format4.ascii");
		f.delete();
		slbm.saveVelocityModel(f.getCanonicalPath(), 4);
		assert(f.exists());
		
		SlbmInterface fmt = new SlbmInterface();		
		fmt.loadVelocityModel(f.getCanonicalPath());

		boolean eql = compareProfiles(fmt);
		assert(eql);

		f = new File("format42a");
		f.delete();
		f.mkdir();
		fmt.saveVelocityModel(f.getCanonicalPath(), 2);
		File target = new File(f, "geostacks");
		assert(target.exists());

		SlbmInterface fmt2 = new SlbmInterface();
		fmt2.loadVelocityModel(f.getCanonicalPath());
		eql = compareProfiles(fmt2);
		assert(eql);
		
		fmt.close();
		fmt2.close();
	}
	
	private boolean compareProfiles(SlbmInterface slbm2) throws SLBMException
	{
		boolean passed = true;
		int nmissing = 0;
		int notEqual=0;
		
		if (slbm2.getNGridNodes() != slbm.getNGridNodes())
		{
			System.out.printf("NGridNodes are not equal  %d != %d%n",
					slbm2.getNGridNodes(), slbm.getNGridNodes());
			return false;
		}
		
		for (int i=0; i<slbm2.getNGridNodes(); ++i)
		{
			GridProfile p2 = slbm2.getGridData(i);
			GridProfile profile = profiles.get(new Point(p2));
			
			//if (i < 50) System.out.println(p2.getLatLon());
			
			if (profile == null)
			{
				System.out.printf("Missing profile[%d] at %s%n", i, p2.getLatLon());
				passed = false;
				++nmissing;
			}
			else if (!p2.equals(profile))
			{
				System.out.println("Profiles are not equal "+profile.getLatLon());
				System.out.println(profile);
				System.out.println(p2);
				passed = false;
				++notEqual;				
			}
			if (nmissing > 10 || notEqual > 10)
				return false;
		}
		//System.out.println("nmissing = "+nmissing);
		
		
//		GridProfile p2 = slbm2.getGridData(40948);
//		GridProfile profile = slbm.getGridData(40347);
//		
//		Point x1 = new Point(profile);
//		Point x2 = new Point(p2);
//		
//		System.out.println(String.format("%1.12f %1.12f", toDegrees(p2.lat), toDegrees(p2.lon)));
//		System.out.println(String.format("%1.12f %1.12f", toDegrees(profile.lat), toDegrees(profile.lon)));
//		
//		System.out.println(String.format("%1.7f %1.7f %1.7f", x1.u[0], x1.u[1], x1.u[2]));
//		System.out.println(String.format("%1.7f %1.7f %1.7f", x2.u[0], x2.u[1], x2.u[2]));
//		
//		System.out.printf("%1.15f%n", Point.dot(x1.u, x2.u));
//		
//		System.out.println(p2);
//		System.out.println(profile);

		
		return passed;
	}

}
