package RSTT;

import gov.sandia.gnem.slbmjni.GridProfile;
import gov.sandia.gnem.slbmjni.SLBMException;
import gov.sandia.gnem.slbmjni.SlbmInterface;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
Copyright (c) 2012, Lawrence Livermore National Security, LLC.
Produced at the Lawrence Livermore National Laboratory
Written by Stephen Myers (myers30@llnl.gov).
LLNL-CODE-607696
All rights reserved.
This file is part of RSTT_NOGS.
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
• Redistributions of source code must retain the above copyright notice, this list of conditions and the disclaimer below.
• Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the disclaimer (as noted below) in the documentation and/or other materials provided with the distribution.
• Neither the name of the LLNS/LLNL nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Additional
 */
public class GetNodes {
        BufferedReader in;
        SlbmInterface slbm;
    
    public GetNodes() {
            System.loadLibrary("slbmjni");
            slbm = new SlbmInterface();
            slbm = new SlbmInterface();
    }
    
    public void makeActive (double latmin, double lonmin, double latmax, double lonmax) {
        //System.out.println(latmin+" "+lonmin+" "+latmax+" "+lonmax);
	slbm.initializeActiveNodes(Math.toRadians(latmin), Math.toRadians(lonmin), Math.toRadians(latmax), Math.toRadians(lonmax));
    }
    
     public void loadModel (String modelPath) {
        slbm.loadVelocityModelBinary(modelPath);
    }
     
     public void WriteActiveNodeInfo (String outFileName) throws FileNotFoundException, SLBMException {
         PrintWriter out = new PrintWriter(outFileName);
         GridProfile nodeModel;
         for (int i=0;i<slbm.getNActiveNodes(); i++) {
             nodeModel = slbm.getActiveNodeData(i);
             out.printf("node %6d %6d %7.3f %7.3f\n",this.slbm.getGridNodeId(nodeModel.nodeId),nodeModel.nodeId, Math.toDegrees(nodeModel.lat),Math.toDegrees(nodeModel.lon));
	   
             for (int j=0;j<nodeModel.getNIntervals();j++) {
		if (j==8) {
                 out.printf("        %2d %7.2f %6.2f %6.2f %9.5f %9.5f \n",
                         j, 
                         nodeModel.depth[j], 
                         nodeModel.velocity[0][j],
                         nodeModel.velocity[1][j],
                         nodeModel.gradient[0],
                         nodeModel.gradient[1]);
		} else {
                 out.printf("        %2d %7.2f %6.2f %6.2f\n",
                         j, 
                         nodeModel.depth[j], 
                         nodeModel.velocity[0][j],
                         nodeModel.velocity[1][j]);
		}
             }
	  }
         out.close();
     }


       public void WriteNodeInfo (int node, String outFileName) throws FileNotFoundException, SLBMException {
         PrintWriter out = new PrintWriter(outFileName);
         GridProfile nodeModel;
             nodeModel = slbm.getGridData(node);
	     WriteANode(nodeModel,out);
         out.close();
     }

       public static void WriteANode(GridProfile node, PrintWriter out) {
	     out.printf("node %6d %7.3f %7.3f\n",node.nodeId, Math.toDegrees(node.lat),Math.toDegrees(node.lon));
             for (int j=0;j<node.getNIntervals();j++) {
		if (j==8) {
                 out.printf("        %2d %7.2f %6.2f %6.2f %9.5f %9.5f \n",
                         j, 
                         node.depth[j], 
                         node.velocity[0][j],
                         node.velocity[1][j],
                         node.gradient[0],
                         node.gradient[1]);
		} else {
                 out.printf("        %2d %7.2f %6.2f %6.2f\n",
                         j, 
                         node.depth[j], 
                         node.velocity[0][j],
                         node.velocity[1][j]);
		}

	     }
       }


       public static void WriteANode(GridProfile node) {
	     System.out.printf("node %6d %7.3f %7.3f\n",node.nodeId, Math.toDegrees(node.lat),Math.toDegrees(node.lon));
             for (int j=0;j<node.getNIntervals();j++) {
		if (j==8) {
                 System.out.printf("        %2d %7.2f %6.2f %6.2f %9.5f %9.5f \n",
                         j, 
                         node.depth[j], 
                         node.velocity[0][j],
                         node.velocity[1][j],
                         node.gradient[0],
                         node.gradient[1]);
		} else {
                 System.out.printf("        %2d %7.2f %6.2f %6.2f\n",
                         j, 
                         node.depth[j], 
                         node.velocity[0][j],
                         node.velocity[1][j]);
		}

	     }
       }


         public void WriteNodeInfo (int node, PrintWriter out) throws FileNotFoundException, SLBMException {
         GridProfile nodeModel;
             nodeModel = slbm.getGridData(node);
             out.printf("node %6d %7.3f %7.3f\n",nodeModel.nodeId, Math.toDegrees(nodeModel.lat),Math.toDegrees(nodeModel.lon));
	   
             for (int j=0;j<nodeModel.getNIntervals();j++) {
		if (j==8) {
                 out.printf("        %2d %7.2f %6.2f %6.2f %9.5f %9.5f \n",
                         j, 
                         nodeModel.depth[j], 
                         nodeModel.velocity[0][j],
                         nodeModel.velocity[1][j],
                         nodeModel.gradient[0],
                         nodeModel.gradient[1]);
		} else {
                 out.printf("        %2d %7.2f %6.2f %6.2f\n",
                         j, 
                         nodeModel.depth[j], 
                         nodeModel.velocity[0][j],
                         nodeModel.velocity[1][j]);
		}
             }
     }

              public void WriteNodeInfo (int node) throws FileNotFoundException, SLBMException {
         GridProfile nodeModel;
             nodeModel = slbm.getGridData(node);
             System.out.printf("node %6d %7.3f %7.3f\n",nodeModel.nodeId, Math.toDegrees(nodeModel.lat),Math.toDegrees(nodeModel.lon));
             for (int j=0;j<nodeModel.getNIntervals();j++) {
		if (j==8) {
                 System.out.printf("        %2d %7.2f %6.2f %6.2f %9.5f %9.5f \n",
                         j, 
                         nodeModel.depth[j], 
                         nodeModel.velocity[0][j],
                         nodeModel.velocity[1][j],
                         nodeModel.gradient[0],
                         nodeModel.gradient[1]);
		} else {
                 System.out.printf("        %2d %7.2f %6.2f %6.2f\n",
                         j, 
                         nodeModel.depth[j], 
                         nodeModel.velocity[0][j],
                         nodeModel.velocity[1][j]);
		}
             }
     }
     
     public static void main(String[] args) {
	     if (args.length != 5 && args.length != 1 && args.length !=2 && args.length != 3) {
		     System.err.println("Usage: GetNodes <full path to RSTT model> latmin latmax lonmin lonmax");
		     System.err.println("         Writes information for nodes in specifed bounds to RSTTnodes.out");
		     System.err.println("         RSTTnodes.out has a node line 'node nodeID activeNodeID lat lon'.  note: nodeID applies to the global model and activeNodeID is a numbering system for the subset of selected nodes");
		     System.err.println("                             crustal layer lines 'layer# depth (km) Vp (km/s) Vs (km/s)'");
		     System.err.println("                             mantle layer lines 'layer# depth (km) Vp (km/s) Vs (km/s) Vp_gradient (km/s/km) Vs_gradient (km/s/km)'");
		     System.err.println("\n                   OR\n");
		     System.err.println("Usage: GetNodes <full path to RSTT model> nodeID    // prints the information for an individual node to the screen");
		     System.err.println("\n                   OR\n");
		     System.err.println("Usage: GetNodes <full path to RSTT model> <nodeIDfile>");
		     System.err.println("         nodeIDfile contains a list of nodeIDs.  The list of nodeIDs is taken from the first column of the file.");
		     System.err.println("         Output is to a file named <nodeIDfile>.nodeInfo.");
		     System.err.println("\n                   OR\n");
		     System.err.println("Usage: GetNodes <full path to RSTT model> <nodeIDfileExclude> <anyString>");
		     System.err.println("         Outputs all nodeIDs except the ones listed in nodeIDfileExclude (nodeIDs in first column). Output file is RSTT_nodesMinus<nodeIDfileExclude>.");
		     System.exit(0);
	     }
	if (args.length==5) {
		String modelPath = args[0];
             double latmin = Double.parseDouble(args[1]);
             double latmax = Double.parseDouble(args[2]);
             double lonmin = Double.parseDouble(args[3]);
             double lonmax = Double.parseDouble(args[4]);
             GetNodes nodes = new GetNodes();
	     if (modelPath.equals("default")) {
                 nodes.loadModel("/Users/Myers30/Documents/Location/SLBMWorkingGroup/Codes/SLBM_Root_2.8.2/models/na1010pn");
	     } else {
                 nodes.loadModel(modelPath);
	     }
             nodes.makeActive(latmin, lonmin, latmax, lonmax);
            try {
                nodes.WriteActiveNodeInfo("RSTTnodes.out");
            } catch (FileNotFoundException ex) {
                Logger.getLogger(GetNodes.class.getName()).log(Level.SEVERE, null, ex);
            } catch (SLBMException ex) {
                Logger.getLogger(GetNodes.class.getName()).log(Level.SEVERE, null, ex);
            }
	} else if (args.length == 1 || args.length == 2) {
             GetNodes nodes = new GetNodes();
	     boolean inputIsFile = false;
	     int node = 0;
	     String inModel = null;
	     if (args.length==1) {  // this is an undocumented way to use my default model
             nodes.loadModel("/Users/Myers30/Documents/Location/SLBMWorkingGroup/Codes/SLBM_Root_2.8.2/models/na1010pn");
		try {
                     node = Integer.parseInt(args[0]);
		} catch (NumberFormatException e) {inputIsFile = true;}
	     } else {
		     inModel = args[0];
                     nodes.loadModel(inModel);
		try {
                     node = Integer.parseInt(args[1]);
		} catch (NumberFormatException e) {inputIsFile = true;}

	     }
	       if(inputIsFile) {
				try {
					String inFile = args[0];
					String outFile = inFile.concat(".nodeInfo");
					PrintWriter out = new PrintWriter(outFile);
					BufferedReader in = IOUtilities.FileIO.openFile(inFile);
					String line;
					StringTokenizer t;
					while ((line=in.readLine()) != null) {
						t = new StringTokenizer(line);
						node = Integer.parseInt(t.nextToken());
					        nodes.WriteNodeInfo(node,out);
					}
					out.close();
				} catch (Exception ex) {
					Logger.getLogger(GetNodes.class.getName()).log(Level.SEVERE, null, ex);
				}
		} else {
				try {
					nodes.WriteNodeInfo(node);
				} catch (FileNotFoundException ex) {
					Logger.getLogger(GetNodes.class.getName()).log(Level.SEVERE, null, ex);
				} catch (SLBMException ex) {
					Logger.getLogger(GetNodes.class.getName()).log(Level.SEVERE, null, ex);
				}
		}

	} else {        // args.length must be 3. get all but the nodes in the node file 
	        String inModel = args[0];
                GetNodes nodes = new GetNodes();
		if (inModel.equals("default")) {
                   nodes.loadModel("/Users/Myers30/Documents/Location/SLBMWorkingGroup/Codes/SLBM_Root_2.8.2/models/na1010pn");
		} else {
		   nodes.loadModel(inModel);	
		}
		String nodeFileExclude = args[1];
		String excludeFile = args[2]; // if present then exclude nodes
	        ArrayList<Integer> excludedNodes = new ArrayList();	
		String temp = "RSTT_nodesMinus";
		String outputFile = temp.concat(nodeFileExclude);
                try {
		    PrintWriter out = new PrintWriter(outputFile);
                    BufferedReader    r = IOUtilities.FileIO.openFile(nodeFileExclude);
                    String line;
	            StringTokenizer t;
                    while ((line=r.readLine())!=null) {
		            t = new StringTokenizer(line);
                            excludedNodes.add(new Integer(t.nextToken()));
                    }
                    r.close();
		int Nnodes = nodes.slbm.getNGridNodes();
		GridProfile node;
		for (int i=0;i<Nnodes;i++) {
				try {
					node = nodes.slbm.getGridData(i);
					if (!excludedNodes.contains(new Integer(node.nodeId))) {
						nodes.WriteANode(node, out);

					}
				} catch (SLBMException ex) {
					Logger.getLogger(GetNodes.class.getName()).log(Level.SEVERE, null, ex);
				}
		}
		out.close();
               } catch (Exception ex) {
                   System.err.println("Error in GetNodes:"+ex);
               }
		
	}
     }

}

