V1_0.java [src/java/m/interp_wdb] Revision: default  Date:
package m.interp_wdb;

import csip.Config;
import csip.Executable;
import csip.ModelDataService;
import csip.ServiceException;
import csip.annotations.*;
import static csip.annotations.ResourceType.*;
import java.io.BufferedReader;
import java.io.EOFException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.logging.*;
import oms3.annotations.*;

import javax.ws.rs.*;
import static m.windgen.V1_0.PARMITEMDATAFILE;
import static m.windgen.V1_0.PARMITEMOUTPUTFILE;
import static m.windgen.V1_0.PARMITEMUSEINTERNAL;

/**
 * This implements the CSIP INTERP_WDB service : WINDGEN Generate interpolated data support service.
 *
 * @author od, mh
 */
@Name("StationGenData")
@Description("Station interpolation data generation utility")
@VersionInfo("1.0")
@Path("m/interp_wdb/1.0")
@Polling(first = 100, next = 100)

@Resource(file = "/bin/win-x86/interp_wdb.exe", wine = true, id = "interp_wdb", type = EXECUTABLE)
@Resource(file = "/d/windgenData/windgenData.zip", id = "windgenDataID", type = ARCHIVE)
@Resource(file = "*stdout.txt *stderr.txt", type = OUTPUT)

/*
    windgenData.zip includes:
        wind_gen_his_upper_US.idx
        wind_gen_his_upper_US.wdb
        wind_gen_his_upper_US_NRCS.idx
    which are automatically unzipped by CSIP and can be found at (ex.):
        Config.getString("csip.dir") + "/d/windgen/wind_gen_his_upper_US.idx"
  
*/

public class V1_0 extends ModelDataService {

        
        String parmWdbFile;
        String parmDataInFile;
        String parmWeightsInFile;
        String parmDBFileName;

        String parmIn1File;
        String parmIn2File;
        String parmIn3File;
        String getStaDataIdx1;
        String getStaDataIdx2;
        String getStaDataIdx3;
        String parmIn1Weight;
        String parmIn2Weight;
        String parmIn3Weight;
        boolean getStaDataFlag = false;
        
    Logger modelLog;
    String version = "CSIP weps: v 0.0.3";
        
    @Override
    public void doProcess() throws Exception {
        
        Executable interp_wdb = getResourceExe("interp_wdb");
        // Ex. call syntax
        // bin/Windows/interp_wdb.exe test.wdb 724517 0.7576871450528201 724518 0.1762846085406619 724510 6.602824640651805E-02
        
        parmWdbFile = getStringParam(PARMITEMOUTPUTFILE, "test.wdb");

        
        // The weights and indices to be combined can optionally specified in this input file
        // which the output file from the interpolate endpoint
        parmWeightsInFile = getStringParam("weightsInfile", "");
        if (parmWeightsInFile.length() > 0) {
            parmWeightsInFile = getWorkspaceDir() + "/" + parmWeightsInFile;
            
            File weightsFile = new File(parmWeightsInFile);
            //checkFileExists(weightsFile);
            if (!weightsFile.exists()) {
                throw new ServiceException ("File does not exist, filename=" + weightsFile.getName());
            }
            ArrayList weightsParms = parseWeightFile(weightsFile);
            
            getStaDataIdx1 = (String) weightsParms.get(0);
            parmIn1Weight = (String) weightsParms.get(1);
            getStaDataIdx2 = (String) weightsParms.get(2);
            parmIn2Weight = (String) weightsParms.get(3);
            getStaDataIdx3 = (String) weightsParms.get(4);
            parmIn3Weight = (String) weightsParms.get(5);
            getStaDataFlag = true;
            
        } else {
            // If no weights file, then weights must be specified
            // If no weights file, indices have 2 choices:
            // 1. specified as parms : stationIdx1
            // 2. implied by the inputFile1 parm, which is the supplied data record for the index
            
            getStaDataIdx1 = getStringParam("stationIdx1", "");
            //checkParmExists("weight1");
            if (!hasParam("weight1")) {
                throw new ServiceException ("File does not exist, filename=" + "weight1");
            }
            parmIn1Weight = Double.toString(getDoubleParam("weight1"));

            getStaDataIdx2 = getStringParam("stationIdx2", "");
            //checkParmExists("weight2");
            if (!hasParam("weight2")) {
                throw new ServiceException ("File does not exist, filename=" + "weight2");
            }
            parmIn2Weight = Double.toString(getDoubleParam("weight2"));

            getStaDataIdx3 = getStringParam("stationIdx3", "");
            //checkParmExists("weight3");
            if (!hasParam("weight3")) {
                throw new ServiceException ("File does not exist, filename=" + "weight3");
            }
            parmIn3Weight = Double.toString(getDoubleParam("weight3"));
        }
        
       
        // If an index is specified, either directly or from the weights file, use it.
        // If an index is specified, then that record must be extracted from the datafile.
        // At this point, if there is no index, then there MUST be an inputFile parm.
        if (getStaDataIdx1.length() > 0) {
            parmIn1File = getStaDataIdx1;
            getStaDataFlag = true;
        } else {
            //checkParmExists("inputFile1", "Must specify either inputFile1 or stationIdx1");
            if (!hasParam("inputFile1")) {
                throw new ServiceException ( "Must specify either inputFile1 or stationIdx1");
            }
            parmIn1File = getStringParam("inputFile1", "");
        }
        
        if (getStaDataIdx2.length() > 0) {
            parmIn2File = getStaDataIdx2;
            getStaDataFlag = true;
        } else {
            //checkParmExists("inputFile2", "Must specify either inputFile2 or stationIdx2");
            if (!hasParam("inputFile2")) {
                throw new ServiceException ( "Must specify either inputFile2 or stationIdx2");
            }
            parmIn2File = getStringParam("inputFile2", "");
        }

        if (getStaDataIdx3.length() > 0) {
            parmIn3File = getStaDataIdx3;
            getStaDataFlag = true;
        } else {
            //checkParmExists("inputFile3", "Must specify either inputFile3 or stationIdx3");
            if (!hasParam("inputFile3")) {
                throw new ServiceException ( "Must specify either inputFile3 or stationIdx3");
            }
            parmIn3File = getStringParam("inputFile3", "");
        }

        //
        // Enter here if we need to get station data.
        // I.e. all 3 station data records (inputFile1,2,3) have not been specified.
        //
        if (getStaDataFlag) {
        
            // The data can come from one of 3 sources:
            // 1. The internal database include with this endpoint
            // 2. A supplied data file included with this request
            // 3. Specified as individual file records with the inputFile1.2.3 parms
            //if ( hasParam(PARMITEMDATAFILE) ) {
            boolean b;
            try {
                b = getParamMap().get(PARMITEMDATAFILE).getString(PARMITEMUSEINTERNAL).contentEquals("true");
            } catch (Exception ex) {
                b = false;
            }
            if (b) {
                parmDataInFile = getStringParam(PARMITEMDATAFILE, "");
                //if (getParamInternalVal(PARMITEMDATAFILE).contentEquals("true")) {
                try {
                    b = getParamMap().get(PARMITEMDATAFILE).getString(PARMITEMUSEINTERNAL).contentEquals("true");
                } catch (Exception ex) {
                    b = false;
                }
                if (b) {
                        // if useInternal, then get internal file
                    if (parmDataInFile.length() == 0) {
                        parmDataInFile = "wind_gen_his_upper_US.wdb";
                    }
                    parmDBFileName = Config.getString("csip.dir") + "/d/windgenData/" + parmDataInFile;
                } else {
                    if (parmDataInFile.length() > 0) {
                        // if name is given, use that file
                        parmDBFileName = getWorkspaceDir() + "/" + parmDataInFile;
                    } else {
                        throw new ServiceException ("CSIP windgen interp_wdb:need to specify all 3 inputFile parms OR a datafile");
                    }
                }
            } else {
                throw new ServiceException ("CSIP windgen interp_wdb:need to specify all 3 inputFile parms OR a datafile");
            }
            
             getStationData (getStaDataIdx1,getStaDataIdx2,getStaDataIdx3);
        }
        
        //checkFileExists(getWorkspaceDir() + "/" + parmIn1File);
        if (!(new File (getWorkspaceDir() + "/" + parmIn1File).exists())) {
            throw new ServiceException ("File does not exist, filename=" + parmIn1File);
        }
        //checkFileExists(getWorkspaceDir() + "/" + parmIn2File);
        if (!(new File (getWorkspaceDir() + "/" + parmIn2File).exists())) {
            throw new ServiceException ("File does not exist, filename=" + parmIn2File);
        }
        //checkFileExists(getWorkspaceDir() + "/" + parmIn3File);
        if (!(new File (getWorkspaceDir() + "/" + parmIn3File).exists())) {
            throw new ServiceException ("File does not exist, filename=" + parmIn3File);
        }
        
        interp_wdb.setArguments(parmWdbFile,
                                parmIn1File, parmIn1Weight,
                                parmIn2File, parmIn2Weight,
                                parmIn3File, parmIn3Weight
        );
        
      
        interp_wdb.exec();
    }
    
    protected void getStationData (String stationName1,String stationName2,String stationName3) throws Exception {
            //String parmDBFileName = csipDirName + "/d/windgenData/" + "wind_gen_his_upper_US.wdb";
        
        if (parmDBFileName.length() > 0) {
            File parmDBFile = new File(parmDBFileName);
            //checkFileExists (parmDBFile);
            if (!parmDBFile.exists()) {
                throw new ServiceException ("File does not exist, filename=" + parmDBFile.getName());
            }
            String outDir = getWorkspaceDir().toString();
            
            try {
                ExtractStationFromWDB (parmDBFile, outDir, stationName1, stationName2, stationName3);
            } catch (IOException ex) {
                modelLog.log(Level.SEVERE, null, ex);
            }
        } else {
            if (modelLog.isLoggable(Level.INFO)) {
                modelLog.info("getStationData : " + "Need to get Station data and no file specified");
            }
            throw new ServiceException ("Station database name is null in \"CSIP windgen interp_wdb");
        }
        
    }
    
    //
    // copied verbatum from usda.weru.uti.windgen.ExtractStationFromWdb.java
    // (one change: TFile to File).
    // (next change: copied the 
    //                 if (stat.equals(inpArr[1])) { 
    //                 block 3 times so that we can search for all 3 records with one pass through the data file)
    // (next change: added the
    //                 if (stat2.length() == 0 && stat3.length() == 0) {
    //                 check so that we only break after all 3 stations are found.
    //
    /*
     * one less than actual since 1st is already in inpLin
     */
    static int linesToCopy = 212;
    //protected void ExtractStationFromWDB(File wdb, String outDir, String stat) throws FileNotFoundException, IOException {
    protected void ExtractStationFromWDB(File wdb, String outDir, String stat1, String stat2, String stat3) throws FileNotFoundException, IOException {

        BufferedReader bfr = new BufferedReader(new FileReader(wdb), 32000);  // each record is aprox. 20k
        while (true) {
            String inpLin = bfr.readLine();
            if (inpLin == null) {
                bfr.close();
                throw new EOFException("station not found");
            }
            if (inpLin.length() > 10) {
                String[] inpArr = inpLin.substring(0, 10).split(" ");
                if ("#".equals(inpArr[0])) {
//                    System.out.println("inplin " + inpLin);
                    if (stat1.equals(inpArr[1])) {
                        try (PrintWriter pw = new PrintWriter(new File(outDir, stat1))) {
                            pw.println(inpLin);
                            for (int idx = 0; idx < linesToCopy; idx++) {
                                inpLin = bfr.readLine();
                                pw.println(inpLin);
                            }
                        }
                        stat1 = "";
                        if (stat2.length() == 0 && stat3.length() == 0) {
                            bfr.close();
                            break;
                        }
                    }
                    else if (stat2.equals(inpArr[1])) {
                        try (PrintWriter pw = new PrintWriter(new File(outDir, stat2))) {
                            pw.println(inpLin);
                            for (int idx = 0; idx < linesToCopy; idx++) {
                                inpLin = bfr.readLine();
                                pw.println(inpLin);
                            }
                        }
                        stat2 = "";
                        if (stat1.length() == 0 && stat3.length() == 0) {
                            bfr.close();
                            break;
                        }
                    }
                    else if (stat3.equals(inpArr[1])) {
                        try (PrintWriter pw = new PrintWriter(new File(outDir, stat3))) {
                            pw.println(inpLin);
                            for (int idx = 0; idx < linesToCopy; idx++) {
                                inpLin = bfr.readLine();
                                pw.println(inpLin);
                            }
                        }
                        stat3 = "";
                        if (stat1.length() == 0 && stat2.length() == 0) {
                            bfr.close();
                            break;
                        }
                    }
                }
            }
        }
    }

    
    //
    // Source for this routine is : usda.weru.util.windgen.MakeInterpolatedStation.run() (line:288)
    // note: possiblie Linux / Windows issues?
    //
    protected ArrayList parseWeightFile (File weightsInputFile) {
        
        BufferedReader br = null;
        String inpLin = null;
        ArrayList stationsList;
        
        stationsList = new ArrayList();

        try {
            br = new BufferedReader(new FileReader(weightsInputFile));
        } catch (FileNotFoundException ex) {
            if (modelLog.isLoggable(Level.INFO)) {
                modelLog.info("parseWeightFile : " + "IO Error (on new Reader): " + weightsInputFile.getAbsolutePath());
            }
        }
        
        try {
            do {
                try {
                    inpLin = br.readLine();
                    if (inpLin != null) {
                        inpLin = inpLin.trim();
                        if(!inpLin.startsWith("#")) {
                            
                            String[] inpArr = inpLin.split(" +");

                            if(inpArr.length == 2) {
                                stationsList.add(inpArr[0]);
                                stationsList.add(String.valueOf(inpArr[1]));
                            }
                        }
                    }
                } catch (IOException ex) {
                    if (modelLog.isLoggable(Level.INFO)) {
                        modelLog.info("parseWeightFile : " + "IO Error (on readLine): " + weightsInputFile.getAbsolutePath());
                    }
                    inpLin = null;
                }
            } while (inpLin != null);
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    if (modelLog.isLoggable(Level.INFO)) {
                        modelLog.info("parseWeightFile : " + "Unable to close stream: " + weightsInputFile.getAbsolutePath());
                    }
                }
            }
            
            if (stationsList.size() != 6) {
                if (modelLog.isLoggable(Level.INFO)) {
                    modelLog.info("parseWeightFile : " + "Incorrect result size, should be 6: " + stationsList.size());
                }
            }

            return stationsList;
        }
   }

    
    @Override
    protected void postProcess () throws Exception {
        putResult(new File(getWorkspaceDir() + "/" + parmWdbFile));
    }
}