MSSQL_SOILS.java [src/soils/db] Revision: default  Date:
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package soils.db;

import csip.api.server.ServiceException;
import csip.SessionLogger;
import csip.utils.Validation;
import gisobjects.GISObject;
import gisobjects.GISObjectException;
import gisobjects.GISObjectFactory;
import gisobjects.db.GISEngine;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.logging.Level;
import soils.Cocropyld;
import soils.Coecoclass;
import soils.Comonth;
import soils.Component;
import soils.Horizon;
import soils.MapUnit;
import soils.Mucropyld;
import soils.TextureGroup;
import soils.db.tables.TableCocropyld;
import soils.db.tables.TableCoecoclass;
import soils.db.tables.TableComonth;
import soils.db.tables.TableComponent;
import soils.db.tables.TableComponentCalculations;
import soils.db.tables.TableFragments;
import soils.db.tables.TableHorizon;
import soils.db.tables.TableLegend;
import soils.db.tables.TableMapUnit;
import soils.db.tables.TableMapUnitCalculations;
import soils.db.tables.TableMuaggatt;
import soils.db.tables.TableMucropyld;
import soils.db.tables.TableSaCatalog;
import soils.db.tables.TableSaSpatialVer;
import soils.db.tables.TableSaTabularVer;
import soils.db.tables.TableTexture;
import soils.db.tables.TableTextureGroup;
import soils.exceptions.SDMException;
import soils.exceptions.WEPPException;
import soils.exceptions.WEPP_WEPSException;
import soils.exceptions.WEPSException;
import soils.utils.EvalResult;
import soils.utils.GenericIFCData;
import soils.utils.SoilUtils;
import static soils.utils.SoilUtils.metricConversion;
import static soils.utils.SoilUtils.pctToFraction;

/**
 *
 * This interface class is meant to be used only internally within soilsdb. All
 * software utilizing the soilsdb.jar file should access these internal
 * functions ONLY through a wrapped function call, preferably located in the AoA
 * class, or secondarily within some other wrapper class located in the soils
 * directory of soilsdb. Implementations of this class should never be
 * instantiated on their own outside of the soils package tree of the
 * soilsdb.jar library.
 * <p>
 * Internally, the implementations of this interface should always be created
 * through the SOILS_DB_FACTORY class, only.
 *
 *
 * @author <a href="mailto:shaun.case@colostate.edu">Shaun Case</a>
 */
public abstract class MSSQL_SOILS implements SOILS_DATA {

  /**
   * This value represents the SRID used in this database's geometry tables. Not
   * all implementations of the geometry tables are using the same SRID's
   * between databases. For instance SDM uses 4326 exclusively, while SSURGO
   * uses 0 exclusively. [By the way 0 is not a valid SRID]
   */
  protected String DB_GEOM_SRID;
  protected SessionLogger LOG;
  protected Connection connection;
  protected String logPrefix;

  protected final void Log(Level level, String msg, Throwable t) {
    if ((null != LOG) && (LOG.isLoggable(level))) {
      if (LOG.isLoggable(level)) {
        LOG.log(level, logPrefix + ":  " + msg, t);
      }
    }
  }

  protected final void Log(Level level, String msg) {
    if ((null != LOG) && (LOG.isLoggable(level))) {
      LOG.log(level, logPrefix + ":  " + msg);
    }
  }

  protected final void Log(Level level, String msg, Object... params) {
    if ((null != LOG) && (LOG.isLoggable(level))) {
      LOG.log(level, logPrefix + ":  " + msg, params);
    }
  }

  protected abstract String buildFindAllByShapeQuery(String WKT, boolean returnIntersectionShape) throws SDMException;

  protected abstract String buildPlainComponentQuery(String mukey);

  protected abstract String buildPlainCHFQuery(String mukey);

  protected abstract String buildPlainNoFilterCHFQuery(HashMap<String, MapUnit> mapUnits) throws ServiceException;

  protected abstract String buildBasicNoFilterCHFQuery(HashMap<String, MapUnit> mapUnits) throws ServiceException;

  protected abstract String buildPlainNoFilterCHFQuery(HashMap<String, MapUnit> mapUnits, boolean includeMajComp) throws ServiceException;

  protected abstract String buildBasicMukeyQuery(String mukey);

  protected abstract String buildBasicNoFilterMukeyByCokeyQuery(String cokey);

  protected abstract String buildBasicMukeyByCokeyQuery(String cokey);

  protected abstract String buildBasicMukeyQueryByArea(String areaSymbol);

  protected abstract String buildBasicMukeyQueryByAreaWithShape(String areaSymbol);

  protected abstract String buildCHFQuery(String mukey, String filter);

  protected abstract String buildCHQuery(String cokey, String filter);

  protected abstract String buildCSMQuery(MapUnit mapUnit);

  protected abstract String buildFindMapUnitsQuery(String WKTShape, boolean returnIntersectionShape);

  protected abstract String buildFindMapUnitsByPolyKeyQuery(String mupolygonkey, boolean returnIntersectionShape);

  protected abstract String buildMuCropYldQuery(HashMap<String, MapUnit> mapUnits, ArrayList<String> cropNames, ArrayList<String> yldUnits);

  protected abstract String buildCoCropYldQuery(HashMap<String, MapUnit> mapUnits, ArrayList<String> cropNames, ArrayList<String> yldUnits);

  protected abstract String buildCoEcoClassQuery(HashMap<String, MapUnit> mapUnits);

  protected abstract String buildCoCropYldQuery(LinkedHashMap<String, Component> component);

  protected abstract String buildCoEcoClassQuery(LinkedHashMap<String, Component> component);

  protected abstract String buildCoMonthQuery(HashMap<String, MapUnit> mapUnits);

  protected abstract String buildIsConusQuery(String lat, String lon);

  protected abstract String buildMinResdept_rQuery(String cokey);

  protected abstract String buildStateCountyByLocationQuery(String countyWKT);

  protected abstract String buildStateAreaSymbolQuery(String stateAbbrev);

  protected abstract String buildTextureDataQuery(HashMap<String, MapUnit> mapUnits);

  protected abstract String buildTextureGroupsQuery(String chkey);

  protected abstract String buildFragmentsQuery(String chkey);

  protected abstract boolean isValidDb();

  protected abstract String buildGenericMapUnitIntersectQuery();

  protected abstract String buildValidateCokeyQuery(int cokey);

  protected abstract String buildWeppWepsCHFQuery(String cokey, String filter);

  @Override
  public void close() throws SQLException {
    if (null != connection) {
      Log(Level.INFO, "Closing Database Connection.");
      connection.close();
    }
  }

  @Override
  /**
   *
   */
  public HashMap<String, MapUnit> findAllByShape(GISObject shape, boolean returnIntersectionShape) throws SDMException, GISObjectException {
    HashMap<String, MapUnit> ret_val = null;

    if ((null != shape) && (shape.isValid())) {
      String query = buildFindAllByShapeQuery(shape.toWKT(), returnIntersectionShape);

      if ((null != query) && !query.isEmpty()) {
        try (Statement statement = connection.createStatement();
            ResultSet resultSet = statement.executeQuery(query);) {

          TableMapUnit mapUnit = new TableMapUnit();
          TableMuaggatt muaggatt = new TableMuaggatt();
          TableComponent component = new TableComponent();
          TableFragments fragments = new TableFragments();
          TableTexture texture = new TableTexture();
          TableTextureGroup textureGroup = new TableTextureGroup();

          ArrayList<String> usedColumns = new ArrayList<>();
          usedColumns.addAll(mapUnit.getColumnList());
          usedColumns.addAll(muaggatt.getColumnList());
          usedColumns.addAll(component.getColumnList());
          usedColumns.addAll(fragments.getColumnList());
          usedColumns.addAll(texture.getColumnList());
          usedColumns.addAll(textureGroup.getColumnList());

          while (resultSet.next()) {
            String mukey = resultSet.getString(TableComponent.MUKEY);
            MapUnit tMapUnit = null;

            if (null != ret_val) {
              if (ret_val.containsKey(mukey)) {
                tMapUnit = ret_val.get(mukey);
              }
            }

            if (null == tMapUnit) {
              tMapUnit = new MapUnit();
              tMapUnit.setUsedColumns(usedColumns);
              ret_val.put(mukey, tMapUnit);
              tMapUnit.readFromSQL(resultSet);
            }

            String cokey = resultSet.getString(TableComponent.COKEY);

            Component tComponent = null;
            LinkedHashMap<String, Component> components = tMapUnit.components();

            if (components.containsKey(cokey)) {
              tComponent = components.get(cokey);
            } else {
              tComponent = new Component();
              tComponent.setUsedColumns(usedColumns);
              components.put(cokey, tComponent);
              tComponent.readFromSQL(resultSet);
            }

            String chkey = resultSet.getString(TableHorizon.CHKEY_NAME);

            Horizon tHorizon = null;
            LinkedHashMap<String, Horizon> horizons = tComponent.horizons;

            if (horizons.containsKey(chkey)) {
              tHorizon = horizons.get(chkey);
            } else {
              tHorizon = new Horizon();
              tHorizon.setUsedColumns(usedColumns);
              horizons.put(chkey, tHorizon);
              tHorizon.readFromSQL(resultSet);
            }

            String chtgkey = resultSet.getString(TableTextureGroup.CHTGKEY);
            TextureGroup tTextureGroup = null;

            LinkedHashMap<String, TextureGroup> textureGroups = tHorizon.textureGroups;

            if (textureGroups.containsKey(chtgkey)) {
              tTextureGroup = textureGroups.get(chtgkey);
            } else {
              tTextureGroup = new TextureGroup();
              tTextureGroup.setUsedColumns(usedColumns);
              textureGroups.put(chtgkey, tTextureGroup);
            }
            //  This needs to be called each time to read all the textures into the textureGroup object.  
            //  That is why this is outside of the the above "if" block.
            tTextureGroup.readFromSQL(resultSet);

          }
        } catch (SQLException ex) {
          throw new SDMException("SQLException: " + ex.getMessage(), ex);
        } catch (ServiceException ex) {
          throw new SDMException(ex);
        }

      }
    }
    return ret_val;
  }

  /**
   * This function finds all of the comonth table data for each component found
   * in this object's list of existing mapunits. It additionally computes the
   * maximum ratings for flood and pond frequencies, which are stored in the
   * TableComponentCalculations table of each Component object.
   *
   * @param map_units
   * @return
   * @throws ServiceException
   */
  @Override
  public synchronized boolean findAllComonthData(LinkedHashMap<String, MapUnit> map_units) throws ServiceException {
    boolean ret_val = false;

    if (null != map_units) {
      String query = buildCoMonthQuery(map_units);

      if (query.length() > 0) {
        try (Statement statement = connection.createStatement();
            ResultSet resultSet = statement.executeQuery(query);) {
          Comonth.setDefaultUsedColumns(new ArrayList<>(Arrays.asList(
              TableComonth.COKEY, TableComonth.COMONTH_KEY, TableComonth.FLOOD_FREQ_CL,
              TableComonth.MONTH, TableComonth.MONTH_SEQ, TableComonth.POND_FREQ_CL
          )));
          while (resultSet.next()) {
            synchronized (this) {
              MapUnit tMapUnit = map_units.get(resultSet.getString(TableComponent.MUKEY));
              if (null != tMapUnit) {
                Component tComponent = tMapUnit.components().get(resultSet.getString(TableComonth.COKEY));
                if (null != tComponent) {
                  Comonth tComonth = new Comonth();

                  tComonth.readFromSQL(resultSet);

                  tComponent.addComonth(tComonth);
                  ret_val = true;
                } else {
                  ret_val = false;
                  break;
                }
              } else {
                ret_val = false;
                break;
              }
            }
          }
        } catch (SQLException ex) {
          throw new ServiceException("SQL error in " + logPrefix + ".findAllTextureData: " + ex.getMessage(), ex);
        }
      }

    }

    if (ret_val) {
      if (null != map_units) {
        for (MapUnit tMapUnit : map_units.values()) {
          if (null != tMapUnit.components()) {
            for (Component tComponent : tMapUnit.components().values()) {
              tComponent.maxFloodFreq();
              tComponent.maxPoolFreq();
            }
          }
        }
      }
    }

    return ret_val;
  }

  @Override
  public synchronized boolean findAllTextureData(HashMap<String, MapUnit> mapUnits) throws ServiceException {
    boolean ret_val = false;

    if (null != mapUnits) {
      String query = buildTextureDataQuery(mapUnits);

      //  Using these static functions prevents us from having to set the used 
      //  columns each time we read a new row and create a new object.  
      //  Normally, we would avoid using these static functions if we were dealing with exisitng objects.
      ArrayList<String> textureGroupColumns = new ArrayList<>(Arrays.asList(
          TableTextureGroup.CHKEY, TableTextureGroup.CHTGKEY,
          TableTextureGroup.DESCRIPTION, TableTextureGroup.RVINDICATOR,
          TableTextureGroup.STRATEXTSFLAG, TableTextureGroup.TEXTURE
      ));
      ArrayList<String> textureColumns = new ArrayList<>(Arrays.asList(
          TableTexture.CHTGKEY, TableTexture.CHTKEY,
          TableTexture.LIEUTEX, TableTexture.TEXTURE_CL
      ));

      if (query.length() > 0) {
        try (Statement statement = connection.createStatement();
            ResultSet resultSet = statement.executeQuery(query);) {

          while (resultSet.next()) {
            //synchronized (this) {

            MapUnit tMapUnit = mapUnits.get(resultSet.getString(TableMapUnit.MUKEY));
            if (null != tMapUnit) {
              Component tComponent = tMapUnit.components().get(resultSet.getString(TableComponent.COKEY));
              if (null != tComponent) {
                Horizon tHorizon = tComponent.horizons().get(resultSet.getString(TableHorizon.CHKEY_NAME));

                if (null != tHorizon) {
                  //  First time through this data result, the returned texture group pointers will be null
                  //  Since there are duplicate texturegroup identifier potentials in the results this line of code
                  //  prevents us from forming a new texturegroup object, when not needed and allows us to populate that
                  //  texturegroup object's texture rows, which may be many.
                  TextureGroup tTextureGroup = tHorizon.textureGroups.get(resultSet.getString(TableTextureGroup.CHTGKEY));

                  //  TextureGroup.readFromSQL() also reads any associated Texture data that is in the result set, 
                  //     and creates new Texture objects under this texture group as needed.
                  if (null != tTextureGroup) {
                    tTextureGroup.setUsedColumns(textureGroupColumns);
                    tTextureGroup.readFromSQL(resultSet, textureColumns);
                    ret_val = true;
                  } else {
                    //Creates a new texture group and reads its values from the result set.
                    tHorizon.setTextureGroups(resultSet, textureGroupColumns, textureColumns);
                    ret_val = true;
                  }

                } else {
                  ret_val = false;
                  break;
                }
              } else {
                ret_val = false;
                break;
              }
            } else {
              ret_val = false;
              break;
            }
            //}
          }

        } catch (SQLException ex) {
          throw new ServiceException("SQL error in " + logPrefix + ".findAllTextureData: " + ex.getMessage(), ex);
        }
      }
    }

    return ret_val;
  }

  @Override
  public ArrayList<String> findAreaSymbolsByState(String stateAbbrev) throws ServiceException {
    ArrayList<String> ret_val = new ArrayList<>();

    if (null != stateAbbrev) {
      if (stateAbbrev.length() == 2) {
        String query = buildStateAreaSymbolQuery(stateAbbrev);
        if (query.length() > 0) {
          try (Statement statement = connection.createStatement();
              ResultSet resultSet = statement.executeQuery(query);) {

            while (resultSet.next()) {
              ret_val.add(resultSet.getString("areasymbol"));
            }
          } catch (SQLException ex) {
            throw new ServiceException("Could not find any soil surveys, (areasymbol), for that state, " + stateAbbrev + ": " + ex.getMessage(), ex);
          }
        }
      } else {
        throw new ServiceException("State abbreviation value passed to findAreaSymbolsByState() had more than 2 characters. Cannot proceed; function requires a valid state abbreviation.");

      }
    } else {
      throw new ServiceException("State abbreviation value was empty passed to findAreaSymbolsByState(). Cannot proceed; function requires a valid state abbreviation.");
    }

    if (ret_val.size() <= 0) {
      throw new ServiceException("Could not find any soil surveys, (areasymbol), for this state: " + stateAbbrev + ".");
    }
    return ret_val;
  }

  @Override
  public ArrayList<String> findAreaSymbolsByCounty(String countyWKT) throws ServiceException {
    ArrayList<String> ret_val = new ArrayList<>();

    if (null != countyWKT) {
      String query = buildStateCountyByLocationQuery(countyWKT);
      if (query.length() > 0) {
        try (Statement statement = connection.createStatement();
            ResultSet resultSet = statement.executeQuery(query);) {

          while (resultSet.next()) {
            ret_val.add(resultSet.getString("areasymbol"));
          }
        } catch (SQLException ex) {
          throw new ServiceException("Could not find any soil surveys, (areasymbol), for that county shape: " + ex.getMessage(), ex);
        }
      }
    } else {
      throw new ServiceException("County shape value was empty passed to findAreaSymbolsByCounty(). Cannot proceed; function requires a valid WKT county shape.");
    }

    if (ret_val.size() <= 0) {
      throw new ServiceException("Could not find any soil surveys, (areasymbol), for this county shape.");
    }
    return ret_val;
  }

  @Override
  public synchronized boolean findEcoClassForMukeyList(HashMap<String, MapUnit> mapUnits) throws ServiceException {
    return findEcoClassForMukeyList(mapUnits, null);
  }

  @Override
  public synchronized boolean findEcoClassForMukeyList(HashMap<String, MapUnit> mapUnits, String addWhere) throws ServiceException {
    boolean ret_val = false;

    if (null != mapUnits) {
      String query = buildCoEcoClassQuery(mapUnits);
      if ((null != addWhere) && (!addWhere.isEmpty())) {
        String preQuery = query.substring(0, query.lastIndexOf("ORDER BY"));
        String postQuery = query.substring(query.lastIndexOf("ORDER BY"));

        query = preQuery + " AND " + addWhere + " " + postQuery;
      }

      if (query.length() > 0) {
        try (Statement statement = connection.createStatement();
            ResultSet resultSet = statement.executeQuery(query);) {

          while (resultSet.next()) {
            synchronized (this) {
              MapUnit tMapUnit = mapUnits.get(resultSet.getString(TableMapUnit.MUKEY));
              if (null != tMapUnit) {
                Component tComponent = tMapUnit.components().get(resultSet.getString(TableComponent.COKEY));
                if (null != tComponent) {

                  ArrayList<String> tList = Coecoclass.getDefaultUsedColumns();

                  //  Using the static function here works because the component will create a new object of type Coecoclass
                  //  as it reads each line of the returned data.  If the object instance already existed, we would not use this funciton.
                  Coecoclass.setDefaultUsedColumns(new ArrayList<>(Arrays.asList(
                      TableCoecoclass.ECOCLASSTYPENAME, TableCoecoclass.ECOCLASSREF, TableCoecoclass.ECOCLASSID,
                      TableCoecoclass.ECOCLASSNAME, TableCoecoclass.COKEY, TableCoecoclass.COECOCLASSKEY,
                      TableCoecoclass.SOURCESDWPRIMARYKEY, TableCoecoclass.SOURCESDWTABLEPHYSICALNAME
                  )));
                  tComponent.readEcoClassFromSQL(resultSet);

                  //  Restore previous used-list.
                  Coecoclass.setDefaultUsedColumns(tList);
                  //TableCoecoclass ecoClass = tComponent.getTableCoecoclass();
                  //ecoClass.readValuesFromSQL(resultSet);
                  ret_val = true;
                }
              }
            }
          }
        } catch (SQLException ex) {
          throw new ServiceException("SQL error in " + logPrefix + ".findEcoClassForMukeyList: " + ex.getMessage(), ex);
        }
      }

    }
    return ret_val;
  }

  @Override
  public synchronized boolean findCoCropYieldsByCropNameOrUnit(HashMap<String, MapUnit> mapUnits, ArrayList<String> cropNames,
      ArrayList<String> yldUnits) throws ServiceException {
    boolean ret_val = false;

    if (null != mapUnits) {
      String query = buildCoCropYldQuery(mapUnits, cropNames, yldUnits);
      if (query.length() > 0) {
        try (Statement statement = connection.createStatement();
            ResultSet resultSet = statement.executeQuery(query);) {

          Cocropyld.setDefaultUsedColumns(new ArrayList<>(Arrays.asList(
              TableCocropyld.CROPNAME,
              TableCocropyld.YLDUNITS,
              TableCocropyld.NONIRRYIELD_L,
              TableCocropyld.NONIRRYIELD_R,
              TableCocropyld.NONIRRYIELD_H,
              TableCocropyld.IRRYIELD_L,
              TableCocropyld.IRRYIELD_R,
              TableCocropyld.IRRYIELD_H,
              TableCocropyld.CROPPRODINDEX,
              TableCocropyld.VASOIPRDGRP,
              TableCocropyld.COKEY,
              TableCocropyld.COCROPYLDKEY
          )));

          while (resultSet.next()) {
            synchronized (this) {
              MapUnit tMapUnit = mapUnits.get(resultSet.getString(TableMapUnit.MUKEY));
              if (null != tMapUnit) {
                Component tComponent = tMapUnit.components().get(resultSet.getString(TableComponent.COKEY));
                if (null != tComponent) {

                  tComponent.readCropYldFromSQL(resultSet);
                  ret_val = true;
                }
              }
            }
          }
        } catch (SQLException ex) {
          throw new ServiceException("SQL error in " + logPrefix + ".findCoCropYldForMukeyList: " + ex.getMessage(), ex);
        }
      }
    }
    return ret_val;
  }

  @Override
  public synchronized boolean findMuCropYieldsByCropNameOrUnit(HashMap<String, MapUnit> mapUnits, ArrayList<String> cropNames,
      ArrayList<String> yldUnits) throws ServiceException {
    boolean ret_val = false;

    if (null != mapUnits) {
      String query = buildMuCropYldQuery(mapUnits, cropNames, yldUnits);
      if (query.length() > 0) {
        try (Statement statement = connection.createStatement();
            ResultSet resultSet = statement.executeQuery(query);) {
          Mucropyld.setDefaultUsedColumns(new ArrayList<>(Arrays.asList(
              TableMucropyld.CROPNAME,
              TableMucropyld.YLDUNITS,
              TableMucropyld.NONIRRYIELD_L,
              TableMucropyld.NONIRRYIELD_R,
              TableMucropyld.NONIRRYIELD_H,
              TableMucropyld.IRRYIELD_L,
              TableMucropyld.IRRYIELD_R,
              TableMucropyld.IRRYIELD_H,
              TableMucropyld.MUKEY,
              TableMucropyld.MUCRPYLDKEY
          )));
          while (resultSet.next()) {
            synchronized (this) {
              MapUnit tMapUnit = mapUnits.get(resultSet.getString(TableMapUnit.MUKEY));
              if (null != tMapUnit) {
                tMapUnit.readCropYldFromSQL(resultSet);
                ret_val = true;
              }
            }
          }
        } catch (SQLException ex) {
          throw new ServiceException("SQL error in " + logPrefix + ".findMuCropYldForMukeyList: " + ex.getMessage(), ex);
        }
      }
    }

    return ret_val;
  }

  @Override
  public boolean findCoCropYldForMukeyList(HashMap<String, MapUnit> mapUnits) throws ServiceException {
    return findCoCropYieldsByCropNameOrUnit(mapUnits, null, null);
  }

  @Override
  public boolean findMuCropYldForMukeyList(HashMap<String, MapUnit> mapUnits) throws ServiceException {
    return findMuCropYieldsByCropNameOrUnit(mapUnits, null, null);
  }

  /**
   * Looks up the mukey parameter in the database and finds the data associated
   * with it. Specifically fills in the MapUnit object with the mukey, musym,
   * muname, muacres, areasymbol, and areaname. This additionally has the
   * side-effect in MapUnit of identifying if the MapUnit isPalouse. This
   * function has a synchronized section because it temporarily rewrites the
   * default used columns for MapUnit, which are static. It is synchronized to
   * avoid causing difficulties elsewhere, where the used columns may also be in
   * use in another thread.
   *
   * @param mukey
   * @return Returns an instance of MapUnit.
   * @throws ServiceException An exception is thrown if the lookup of the data
   * associated with the mukey parameter is unsuccessful.
   * @see MapUnit
   */
  @Override
  public synchronized MapUnit findMukeyData(String mukey) throws ServiceException {
    MapUnit ret_val = null;
    if ((null != mukey) && (!mukey.isEmpty())) {
      Validation.checkMukey(mukey);
      String query = buildBasicMukeyQuery(mukey);
      if (query.length() > 0) {
        try (Statement statement = connection.createStatement();
            ResultSet resultSet = statement.executeQuery(query);) {

          if (resultSet.next()) {

            synchronized (this) {
              //Temp storage for current used-list.
              ArrayList<String> tList = MapUnit.getDefaultUsedColumns();

              MapUnit.setDefaultUsedColumns(new ArrayList<>(Arrays.asList(TableMapUnit.MUKEY, TableMapUnit.MUNAME, TableMapUnit.MUSYM, TableMapUnit.MUACRES, TableMapUnit.AREASYMBOL_NAME, TableMapUnit.AREA_NAME)));
              ret_val = new MapUnit(mukey, resultSet, null);

              //  Restore previous used-list.
              MapUnit.setDefaultUsedColumns(tList);
            }

          } else {
            throw new ServiceException("Mukey not found in" + logPrefix + ".findMukeyData, for mukey: '" + mukey + "'");
          }

        } catch (SQLException ex) {
          throw new ServiceException("SQL error in " + logPrefix + ".findMukeyData: " + ex.getMessage(), ex);
        }
      }
    }

    return ret_val;
  }

  /**
   * Looks up the cokey parameter in the database and finds the mapunit data
   * associated with it. Specifically fills in the MapUnit object with the
   * mukey, musym, muname, muacres, areasymbol, and areaname. This additionally
   * has the side-effect in MapUnit of identifying if the MapUnit isPalouse.
   * This function has a synchronized section because it temporarily rewrites
   * the default used columns for MapUnit, which are static. It is synchronized
   * to avoid causing difficulties elsewhere, where the used columns may also be
   * in use in another thread.
   *
   * @param component
   * @return Returns an instance of MapUnit.
   * @throws ServiceException An exception is thrown if the lookup of the data
   * associated with the component parameter is unsuccessful.
   * @see MapUnit
   */
  @Override
  public MapUnit findMukeyDataByCokey(Component component) throws ServiceException {
    MapUnit ret_val = null;
    String cokey;

    if (null != component) {
      cokey = component.cokey();

      if (!cokey.isEmpty()) {
        String query = buildBasicMukeyByCokeyQuery(cokey);
        if (query.length() > 0) {
          try (Statement statement = connection.createStatement();
              ResultSet resultSet = statement.executeQuery(query);) {

            if (resultSet.next()) {
              synchronized (this) {
                ret_val = new MapUnit();
                ret_val.setUsedColumns(new ArrayList<>(Arrays.asList(TableMapUnit.MUKEY, TableMapUnit.MUNAME, TableMapUnit.MUSYM, TableMapUnit.MUACRES, TableMapUnit.AREASYMBOL_NAME, TableMapUnit.AREA_NAME)));
                ret_val.readFromSQL(resultSet);
              }

            } else {
              throw new ServiceException("Mukey not found in " + logPrefix + ".findMukeyDataByCokey, for cokey: '" + cokey + "' .  This cokey may not be located in a non-MLRA area type.");
            }

          } catch (SQLException ex) {
            throw new ServiceException("SQL error in " + logPrefix + ".findMukeyDataByCokey: " + ex.getMessage(), ex);
          }
        }
      }
    }

    return ret_val;
  }

  @Override
  public MapUnit findBasicNoFilterMukeyDataByCokey(Component component) throws ServiceException {
    MapUnit ret_val = null;
    String cokey;

    if (null != component) {
      cokey = component.cokey();

      if (!cokey.isEmpty()) {
        String query = buildBasicNoFilterMukeyByCokeyQuery(cokey);
        if (query.length() > 0) {
          try (Statement statement = connection.createStatement();
              ResultSet resultSet = statement.executeQuery(query);) {

            if (resultSet.next()) {
              synchronized (this) {
                TableMapUnit tmapUnit = new TableMapUnit();
                ret_val = new MapUnit();
                ArrayList<String> usedColumns = new ArrayList<>();
                usedColumns.addAll(tmapUnit.getColumnList());
                usedColumns.add(TableLegend.AREASYMBOL_NAME);
                usedColumns.add(TableLegend.AREA_NAME);
                usedColumns.add(TableSaCatalog.SA_VERSION);
                usedColumns.add(TableSaCatalog.SA_VER_EST);
                usedColumns.add(TableSaSpatialVer.SPATIAL_VERSION_EST);
                usedColumns.add(TableSaSpatialVer.SPATIAL_VERSION);
                usedColumns.add(TableSaSpatialVer.SPATIAL_VERSION_EST);
                usedColumns.add(TableSaTabularVer.TABULAR_VERSION);
                usedColumns.add(TableSaTabularVer.TABULAR_VERSION_EST);
                
                ret_val.setUsedColumns(usedColumns);
                ret_val.readFromSQL(resultSet);
              }

            } else {
              throw new ServiceException("Mukey not found in " + logPrefix + ".findBasicNoFilterMukeyDataByCokey, for cokey: '" + cokey + "' .  This cokey may not be located in a non-MLRA area type.");
            }

          } catch (SQLException ex) {
            throw new ServiceException("SQL error in " + logPrefix + ".findBasicNoFilterMukeyDataByCokey: " + ex.getMessage(), ex);
          }
        }
      }
    }

    return ret_val;
  }

  /**
   * Looks up the mukey parameter in the database and finds the data associated
   * with it. Specifically fills in the MapUnit object with the mukey, musym,
   * muname, muacres, areasymbol, and areaname. This additionally has the
   * side-effect in MapUnit of identifying if the MapUnit isPalouse. This
   * function has a synchronized section because it temporarily rewrites the
   * default used columns for MapUnit, which are static. It is synchronized to
   * avoid causing difficulties elsewhere, where the used columns may also be in
   * use in another thread.
   *
   * @param mapUnit
   * @return Returns an instance of MapUnit.
   * @throws ServiceException An exception is thrown if the lookup of the data
   * associated with the mukey parameter is unsuccessful.
   * @see MapUnit
   */
  @Override
  public boolean findMukeyData(MapUnit mapUnit) throws ServiceException {
    boolean ret_val = false;
    String mukey;

    if (null != mapUnit) {
      mukey = mapUnit.mukey();

      if (!mukey.isEmpty()) {
        String query = buildBasicMukeyQuery(mukey);
        if (query.length() > 0) {
          try (Statement statement = connection.createStatement();
              ResultSet resultSet = statement.executeQuery(query);) {

            if (resultSet.next()) {
              synchronized (this) {
                mapUnit.setUsedColumns(new ArrayList<>(Arrays.asList(TableMapUnit.MUKEY, TableMapUnit.MUNAME, TableMapUnit.MUSYM, TableMapUnit.MUACRES, TableMapUnit.AREASYMBOL_NAME, TableMapUnit.AREA_NAME)));
                mapUnit.readFromSQL(resultSet);
                ret_val = true;
              }

            } else {
              throw new ServiceException("Mukey not found in" + logPrefix + ".findMukeyData, for mukey: '" + mukey + "'");
            }

          } catch (SQLException ex) {
            throw new ServiceException("SQL error in " + logPrefix + ".findMukeyData: " + ex.getMessage(), ex);
          }
        }
      }
    }

    return ret_val;
  }

  /**
   * Looks up the mukey parameter in the database and finds the data associated
   * with it. Specifically fills in the MapUnit object with the mukey, musym,
   * muname, muacres, areasymbol, and areaname. This additionally has the
   * side-effect in MapUnit of identifying if the MapUnit isPalouse. This
   * function has a synchronized section because it temporarily rewrites the
   * default used columns for MapUnit, which are static. It is synchronized to
   * avoid causing difficulties elsewhere, where the used columns may also be in
   * use in another thread.
   *
   * @param areaSymbol
   * @return Returns an instance of MapUnit.
   * @throws ServiceException An exception is thrown if the lookup of the data
   * associated with the mukey parameter is unsuccessful.
   * @see MapUnit
   */
  @Override
  public synchronized HashMap<String, MapUnit> findMukeyDataByAreasymbol(String areaSymbol) throws ServiceException {
    HashMap<String, MapUnit> ret_val = null;
    if ((null != areaSymbol) && (!areaSymbol.isEmpty())) {
      String query = buildBasicMukeyQueryByArea(areaSymbol);
      if (query.length() > 0) {
        try (Statement statement = connection.createStatement();
            ResultSet resultSet = statement.executeQuery(query);) {
          ret_val = new HashMap<>();
          while (resultSet.next()) {

            synchronized (this) {
              MapUnit tMapUnit;
              String mukey = resultSet.getString(TableMapUnit.MUKEY);
              //Temp storage for current used-list.
              ArrayList<String> tList = MapUnit.getDefaultUsedColumns();

              MapUnit.setDefaultUsedColumns(new ArrayList<>(Arrays.asList(TableMapUnit.MUKEY, TableMapUnit.MUNAME, TableMapUnit.MUSYM, TableMapUnit.MUACRES, TableMapUnit.AREASYMBOL_NAME, TableMapUnit.AREA_NAME)));
              ret_val.put(mukey, new MapUnit(mukey, resultSet, null));

              //  Restore previous used-list.
              MapUnit.setDefaultUsedColumns(tList);
            }

          }

          if (ret_val.size() <= 0) {
            throw new ServiceException("Data not found in" + logPrefix + ".findMukeyDataByAreasymbol, for areasymbol: '" + areaSymbol + "'");
          }

        } catch (SQLException ex) {
          throw new ServiceException("SQL error in " + logPrefix + ".findMukeyDataByAreasymbol: " + ex.getMessage(), ex);
        }
      }
    }

    return ret_val;
  }

  @Override
  public synchronized void findMukeyDataAndShapeByAreasymbol(ArrayList<String> areaSymbols, GISEngine gisEngine,
      HashMap<String, MapUnit> mapUnits) throws ServiceException {
    if (null != areaSymbols) {
      for (String areaSymbol : areaSymbols) {
        if (!areaSymbol.isEmpty()) {
          String query = buildBasicMukeyQueryByAreaWithShape(areaSymbol);
          if (query.length() > 0) {
            try (Statement statement = connection.createStatement();
                ResultSet resultSet = statement.executeQuery(query);) {
              ArrayList<String> mapUnitColumns = new ArrayList<>(Arrays.asList(TableMapUnit.MUKEY, TableMapUnit.MUNAME, TableMapUnit.MUSYM, TableMapUnit.MUACRES, TableMapUnit.AREASYMBOL_NAME, TableMapUnit.AREA_NAME));

              while (resultSet.next()) {
                MapUnit tMapUnit = new MapUnit();
                String mukey = resultSet.getString(TableMapUnit.MUKEY);
                String WKT = resultSet.getString("muPoly");
                GISObject muPoly = GISObjectFactory.createGISObject(WKT, gisEngine);
                tMapUnit.mukey(mukey);

                tMapUnit.setDefaultUsedColumns(mapUnitColumns);
                tMapUnit.readFromSQL(resultSet);
                tMapUnit.addShape(muPoly);
                mapUnits.put(mukey, tMapUnit);
              }

              if (mapUnits.size() <= 0) {
                throw new ServiceException("Data not found in" + logPrefix + ".findMukeyDataAndShapeByAreasymbol, for areasymbol: '" + areaSymbol + "'");
              }

            } catch (SQLException ex) {
              throw new ServiceException("SQL error in " + logPrefix + ".findMukeyDataAndShapeByAreasymbol: " + ex.getMessage(), ex);
            } catch (GISObjectException ex) {
              throw new ServiceException("GIS Object creation error in " + logPrefix + ".findMukeyDataAndShapeByAreasymbol: " + ex.getMessage(), ex);
            }
          }
        }
      }
    }
  }

  @Override
  public boolean findComponentSoilMoisture(HashMap<String, MapUnit> mapUnits) throws ServiceException {
    boolean ret_val = false;

    if (null != mapUnits) {
      for (String mukey : mapUnits.keySet()) {
        MapUnit mapUnit = mapUnits.get(mukey);
        Component component;

        String query = buildCSMQuery(mapUnit);

        if (query.length() > 0) {
          try (Statement statement = connection.createStatement();
              ResultSet resultSet = statement.executeQuery(query);) {

            while (resultSet.next()) {
              String tCokey = resultSet.getString(TableComponent.COKEY);
              component = mapUnit.components().get(tCokey);
              if (null != component) {
                component.calculated_wtkind(EvalResult.getString(resultSet, "wtkind"));

                if (component.calculated_wtkind().equals(EvalResult.getDefaultString())) {
                  component.calculated_wtkind("None");
                  component.calculated_wtbl_top_min(Double.NaN);
                } else {
                  component.calculated_wtbl_top_min(EvalResult.getDouble(resultSet, "wtbl_top_min"));
                }
                component.calculated_hwt_lt_24((component.calculated_wtbl_top_min() <= 61));
              } else {
                throw new ServiceException("Database returned a cokey that was not requested.");
              }
            }
          } catch (SQLException ex) {
            throw new ServiceException("SQL error in " + logPrefix + ".findComponentSoilMoisture: " + ex.getMessage(), ex);
          }
        }
      }
    } else {
      throw new ServiceException("NULL value passed to " + logPrefix + ".findComponentSoilMoisture for MapUnit list.");

    }
    return ret_val;
  }

  @Override
  public Boolean findComponentsByMukey(MapUnit mapUnit) throws ServiceException {
    Boolean ret_val = false;

    if ((null != mapUnit) && (null != mapUnit.mukey()) && !mapUnit.mukey().isEmpty()) {
      try (Statement statement = connection.createStatement();) {

        String query = buildPlainComponentQuery(mapUnit.mukey());

        Log(Level.INFO, " soils db query=" + query);
        ResultSet results = statement.executeQuery(query);
        Log(Level.INFO, " past the query execute");

        ret_val = noFilterComponentData(results, mapUnit);

      } catch (SQLException ex) {
        throw new ServiceException("Could not continue processing the component lookups for this mapunit:  " + ex.getMessage(), ex);
      }
    } else {
      throw new ServiceException("No map unit key passed to the " + logPrefix + ".findComponentsByMukey() function.");
    }

    return ret_val;
  }

  @Override
  @Deprecated
  public Boolean findComponentsHorizonsFragsByMukey(MapUnit mapUnit, boolean computeLightleWeesieSlope, String filter) throws ServiceException {
    Boolean ret_val = true;

    if (filter.equalsIgnoreCase("WIND") || filter.equalsIgnoreCase("WATER")) {
      if ((null != mapUnit) && (null != mapUnit.mukey()) && !mapUnit.mukey().isEmpty()) {
        try (Statement statement = connection.createStatement();) {

          String query = buildCHFQuery(mapUnit.mukey(), filter);

          Log(Level.INFO, " soils db query=" + query);
          ResultSet results = statement.executeQuery(query);
          Log(Level.INFO, " past the query execute");

          FilterResults filterResults = new FilterResults();

          ret_val = filterComponentHorizonFragData(results, filterResults, mapUnit, filter, computeLightleWeesieSlope);

          if (filter.equalsIgnoreCase("WATER") && !filterResults.foundKffact) {
            ret_val = false;
            Log(Level.WARNING, "No kffact found for this soil component in its horizon data.");
          }

          if ((mapUnit.components().size() <= 0)) {
            ret_val = false;
            Log(Level.WARNING, "No suitable soil components and/or horizon data found for this mapunit: " + mapUnit.mukey() + " .");
          }
        } catch (SQLException ex) {
          throw new ServiceException("Could not continue processing the component lookups for this mapunit:  " + ex.getMessage(), ex);
        }
      } else {
        throw new ServiceException("No map unit key passed to the " + logPrefix + ".findComponentsHorizonsFragsByMukey() function.");
      }
    } else {
      if (filter.equalsIgnoreCase("NONE")) {
        if ((null != mapUnit) && (null != mapUnit.mukey()) && !mapUnit.mukey().isEmpty()) {
          try (Statement statement = connection.createStatement();) {

            String query = buildPlainCHFQuery(mapUnit.mukey());

            Log(Level.INFO, " soils db query=" + query);
            ResultSet results = statement.executeQuery(query);
            Log(Level.INFO, " past the query execute");

            ret_val = noFilterComponentHorizonFragData(results, mapUnit, computeLightleWeesieSlope);

          } catch (SQLException ex) {
            throw new ServiceException("Could not continue processing the component lookups for this mapunit:  " + ex.getMessage(), ex);
          }
        } else {
          throw new ServiceException("No map unit key passed to the " + logPrefix + ".findComponentsHorizonsFragsByMukey() function.");
        }

      } else {
        throw new ServiceException("Invalid filter value, " + filter + ", passed to the " + logPrefix + ".findComponentsHorizonsFragsByMukey() function.");
      }
    }

    return ret_val;
  }

  
      
  @Override
  public boolean findAllBasicNoFilterComponentHorizonFragTextureData(HashMap<String, MapUnit> mapUnits) throws ServiceException {
    boolean ret_val = false;
    if (null != mapUnits) {
      try (Statement statement = connection.createStatement();) {

        String query = buildBasicNoFilterCHFQuery(mapUnits);

        Log(Level.INFO, " soils db query=" + query);
        ResultSet results = statement.executeQuery(query);
        Log(Level.INFO, " past the query execute");

        if (noFilterComponentHorizonFragData(results, mapUnits, true)) {
          if (findAllTextureData(mapUnits)) {
            ret_val = true;
          } else {
            throw new ServiceException("Could not get texture data those mapunits");
          }

        } else {
          throw new ServiceException("Could not get component, horizon, fragments data for those mapunits");
        }

      } catch (SQLException ex) {
        throw new ServiceException("Could not continue processing the basic component, horizon, frag, and textures lookups for these mapunits:  " + ex.getMessage(), ex);
      }
    }

    return ret_val;
  }
  
  @Override
  public boolean findAllBasicComponentHorizonFragTextureData(HashMap<String, MapUnit> mapUnits, boolean includeNonMajComp) throws ServiceException {
    boolean ret_val = false;
    if (null != mapUnits) {
      try (Statement statement = connection.createStatement();) {

        String query = buildPlainNoFilterCHFQuery(mapUnits, includeNonMajComp);

        Log(Level.INFO, " soils db query=" + query);
        ResultSet results = statement.executeQuery(query);
        Log(Level.INFO, " past the query execute");

        if (noFilterComponentHorizonFragData(results, mapUnits, true)) {
          if (findAllTextureData(mapUnits)) {
            ret_val = true;
          } else {
            throw new ServiceException("Could not get texture data those mapunits");
          }

        } else {
          throw new ServiceException("Could not get component, horizon, fragments data for those mapunits");
        }

      } catch (SQLException ex) {
        throw new ServiceException("Could not continue processing the basic component, horizon, frag, and textures lookups for these mapunits:  " + ex.getMessage(), ex);
      }
    }

    return ret_val;
  }

  @Override
  public boolean findAllBasicComponentHorizonFragTextureData(HashMap<String, MapUnit> mapUnits) throws ServiceException {
    return findAllBasicComponentHorizonFragTextureData(mapUnits, false);
  }

  @Override
  public boolean findComponentsHorizonsFragsForMukeyList(HashMap<String, MapUnit> mapUnits, boolean computeLightleWeesieSlope, String filter) throws ServiceException {
    boolean ret_val = true;

    for (String mukey : mapUnits.keySet()) {
      ret_val = findComponentsHorizonsFragsByMukey(mapUnits.get(mukey), computeLightleWeesieSlope, filter);
      if (!ret_val) {
        mapUnits.get(mukey).setExclude(true, "No soil components for this mapunit were found having a sufficient set of parameters required for NRCS quality assessment (" + filter + ").");
      }
    }

    return ret_val;
  }

  @Override
  public ArrayList<ComponentsHorizonsFrags> findComponentsHorizonsFragsForMukeyList(ArrayList<String> mukeys, boolean computeLightleWeesieSlope, String filter) throws ServiceException {
    ArrayList<ComponentsHorizonsFrags> ret_val = new ArrayList<>();
    throw new UnsupportedOperationException("Not supported yet.");
  }

  @Override
  public boolean findComponentsForMukeyList(HashMap<String, MapUnit> mapUnits, boolean computeLightleWeesieSlope) throws ServiceException {
    boolean ret_val = true;

    for (String mukey : mapUnits.keySet()) {
      ret_val = findComponentsHorizonsFragsByMukey(mapUnits.get(mukey), computeLightleWeesieSlope, "NONE");
      if (!ret_val) {
        mapUnits.get(mukey).setExclude(true, "No soil components for this mapunit were found having a sufficient set of parameters required for NRCS quality assessment (No Filter).");
      }
    }

    return ret_val;
  }

  @Override
  public MapUnit findBasicNoFilterDataByCokey(Component component) throws ServiceException {
    MapUnit mapUnit = null;
    HashMap<String, MapUnit> mapUnits;
    if ((null != component) && (null != component.cokey()) && !component.cokey().isEmpty()) {
      //  Get mapUnit data
      if (null == (mapUnit = findBasicNoFilterMukeyDataByCokey(component))) {
        throw new ServiceException("Could not find any Mapunit information for the cokey, " + component.cokey() + ", provided.");
      }

      mapUnits = new HashMap<>();
      mapUnits.put(mapUnit.mukey(), mapUnit);
      mapUnit.putComponent(component);

      findAllBasicNoFilterComponentHorizonFragTextureData(mapUnits);

    } else {
      throw new ServiceException("No component key passed to the " + logPrefix + ".findWEPPDataByCokey() function.");
    }

    return mapUnit;
  }

  @Override
  public MapUnit findWEPPDataByCokey(Component component) throws ServiceException, WEPPException {
    MapUnit mapUnit = null;
    HashMap<String, MapUnit> mapUnits;
    if ((null != component) && (null != component.cokey()) && !component.cokey().isEmpty()) {
      //  Get mapUnit data
      if (null == (mapUnit = findMukeyDataByCokey(component))) {
        throw new ServiceException("Could not find any Mapunit information for the cokey, " + component.cokey() + ", provided.");
      }

      mapUnits = new HashMap<>();
      mapUnits.put(mapUnit.mukey(), mapUnit);
      mapUnit.putComponent(component);

      findAllBasicComponentHorizonFragTextureData(mapUnits);
      component.updateCalculations();

      try {
        component.adjustForWEPP_WEPS("wepp");
      } catch (SDMException | WEPP_WEPSException | WEPSException ex) {
        throw new ServiceException(ex);
      }

    } else {
      throw new ServiceException("No component key passed to the " + logPrefix + ".findWEPPDataByCokey() function.");
    }

    return mapUnit;
  }

  @Override
  public MapUnit findWEPSDataByCokey(Component component, boolean adjustStratified, boolean organicChecks, boolean estimateNulls) throws ServiceException, WEPSException {

    MapUnit mapUnit = null;
    HashMap<String, MapUnit> mapUnits;
    if ((null != component) && (null != component.cokey()) && !component.cokey().isEmpty()) {
      //  Get mapUnit data
      if (null == (mapUnit = findMukeyDataByCokey(component))) {
        throw new ServiceException("Could not find any Mapunit information for the cokey, " + component.cokey() + ", provided.");
      }

      mapUnits = new HashMap<>();
      mapUnits.put(mapUnit.mukey(), mapUnit);
      mapUnit.putComponent(component);

      findAllBasicComponentHorizonFragTextureData(mapUnits);
      try (Statement statement = connection.createStatement()) {
        ResultSet results;
        String query = buildMinResdept_rQuery(component.cokey());

        results = statement.executeQuery(query);

        if (results.next()) {
          component.calculated_resdeptmin_r(EvalResult.getDouble(results, TableComponentCalculations.RESDEPTMIN_R));
        } else {
          component.calculated_resdeptmin_r(EvalResult.getDefaultDouble());
        }
        results.close();
      } catch (SQLException ex) {
        throw new ServiceException("Cannot execute the resdept_r query for this component: " + ex.getMessage(), ex);
      }
      component.updateCalculations();

      try {
        component.adjustForWEPP_WEPS("weps");
      } catch (SDMException | WEPP_WEPSException | WEPPException ex) {
        throw new ServiceException(ex);
      }

      //Clean up some values and set some final defaults if missing.
      if (EvalResult.testDefaultInteger(mapUnit.brockdepmin())) {
        mapUnit.brockdepmin(GenericIFCData.depthToBedrock);
      } else {
        mapUnit.brockdepmin(mapUnit.brockdepmin() * 10);
      }
      if (EvalResult.testDefaultDouble(component.calculated_resdeptmin_r())) {

      } else {
        component.calculated_resdeptmin_r(component.calculated_resdeptmin_r() * 10);
      }

      if (EvalResult.testDefaultDouble(component.slope_r())) {
        component.slope_r(0.01);
      } else {
        component.slope_r(component.slope_r() / 100);
      }

      for (Horizon h : component.horizons.values()) {
        if (!EvalResult.testDefaultDouble(h.hzdepb_r())) {
          h.hzdepb_r(metricConversion(h.hzdepb_r(), SoilUtils.Metric.CM, SoilUtils.Metric.MM));
        }
        if (!EvalResult.testDefaultDouble(h.hzdept_r())) {
          h.hzdept_r(metricConversion(h.hzdept_r(), SoilUtils.Metric.CM, SoilUtils.Metric.MM));
        }
        if (!EvalResult.testDefaultDouble(h.sandtotal_r())) {
          h.sandtotal_r(pctToFraction(h.sandtotal_r()));
        }
        if (!EvalResult.testDefaultDouble(h.claytotal_r())) {
          h.claytotal_r(pctToFraction(h.claytotal_r()));
        }
        if (!EvalResult.testDefaultDouble(h.silttotal_r())) {
          h.silttotal_r(pctToFraction(h.silttotal_r()));
        }
        if (!EvalResult.testDefaultDouble(h.sandvc_r())) {
          h.sandvc_r(pctToFraction(h.sandvc_r()));
        }
        if (!EvalResult.testDefaultDouble(h.sandco_r())) {
          h.sandco_r(pctToFraction(h.sandco_r()));
        }
        if (!EvalResult.testDefaultDouble(h.sandmed_r())) {
          h.sandmed_r(pctToFraction(h.sandmed_r()));
        }
        if (!EvalResult.testDefaultDouble(h.hzdepb_r())) {
          h.sandfine_r(pctToFraction(h.sandfine_r()));
        }
        if (!EvalResult.testDefaultDouble(h.sandvf_r())) {
          h.sandvf_r(pctToFraction(h.sandvf_r()));
        }
        if (!EvalResult.testDefaultDouble(h.om_r())) {
          h.om_r(pctToFraction(h.om_r()));
        }
        if (!EvalResult.testDefaultDouble(h.caco3_r())) {
          h.caco3_r(pctToFraction(h.caco3_r()));
        }
      }
    } else {
      throw new ServiceException("No component key passed to the " + logPrefix + ".findWEPPDataByCokey() function.");
    }

    return mapUnit;
  }

  //TODO:  Add logging for ret_val's that get set to false during this function, after calling other functions that return a boolean assigned to it.
  @Override
  @Deprecated
  public synchronized boolean findWEPSHorizonsForCokey(MapUnit mapUnit, Component component) throws ServiceException {
    boolean ret_val = false;
//        TextureGroup.setDefaultUsedColumns(new ArrayList<>(Arrays.asList(TableTextureGroup.CHTGKEY, TableTextureGroup.TEXTURE,
//                TableTextureGroup.STRATEXTSFLAG, TableTextureGroup.RVINDICATOR)));
//        Fragments.setDefaultUsedColumns(new ArrayList<>(Arrays.asList(TableFragments.CHFRAGSKEY, TableFragments.FRAGVOL_R, TableFragments.FRAGVOL_L,
//                TableFragments.FRAGVOL_H, TableFragments.FRAGSIZE_R, TableFragments.FRAGSIZE_L, TableFragments.FRAGSIZE_H,
//                TableFragments.FRAGHARD, TableFragments.FRAGSHP, TableFragments.FRAGROUND, TableFragments.FRAGKIND)));

    if ((null != component) && (null != component.cokey()) && !component.cokey().isEmpty()) {
      Validation.checkCokey(component.cokey());
      try (Statement statement = connection.createStatement();) {

        String query = buildCHQuery(component.cokey(), "WIND");

        Log(Level.INFO, " soils db query=" + query);
        ResultSet results = statement.executeQuery(query);
        Log(Level.INFO, " past the query execute");

        FilterResults filterResults = new FilterResults();

        ret_val = filterWEPSComponentHorizonFragData(results, filterResults, mapUnit, component, true);
        results.close();

        //  Fill-in the MapUnit object too
        if ((!component.mukey().isEmpty()) && ret_val) {
          mapUnit.mukey(component.mukey());
          ret_val = findMukeyData(mapUnit);
        }

        if (!filterResults.foundSandLayer) {
          ret_val = false;
          Log(Level.WARNING, "No sand layer found for this soil component in its horizon data.");
        }

        //TODO:  Verify this test still works in this case...
        if ((mapUnit.components().size() <= 0)) {
          ret_val = false;
          Log(Level.WARNING, "No suitable soil horizon data found for this component: " + component.cokey() + " .");
        } else {
          query = buildMinResdept_rQuery(component.cokey());
          Log(Level.INFO, " soils db query=" + query);
          results = statement.executeQuery(query);
          Log(Level.INFO, " past the query execute");
          if (results.next()) {
            component.calculated_resdeptmin_r(EvalResult.getDouble(results, TableComponentCalculations.RESDEPTMIN_R));
          } else {
            component.calculated_resdeptmin_r(EvalResult.getDefaultDouble());
          }
          results.close();

          ArrayList<String> textureGroupColumns = new ArrayList<>(Arrays.asList(TableTextureGroup.CHTGKEY, TableTextureGroup.TEXTURE,
              TableTextureGroup.STRATEXTSFLAG, TableTextureGroup.RVINDICATOR));
          ArrayList<String> fragmentsColumns = new ArrayList<>(Arrays.asList(TableFragments.CHFRAGSKEY, TableFragments.FRAGVOL_R, TableFragments.FRAGVOL_L,
              TableFragments.FRAGVOL_H, TableFragments.FRAGSIZE_R, TableFragments.FRAGSIZE_L, TableFragments.FRAGSIZE_H,
              TableFragments.FRAGHARD, TableFragments.FRAGSHP, TableFragments.FRAGROUND, TableFragments.FRAGKIND));

          for (Horizon tHorizon : component.horizons.values()) {
            query = buildTextureGroupsQuery(tHorizon.chkey());
            Log(Level.INFO, " soils db query=" + query);
            results = statement.executeQuery(query);
            Log(Level.INFO, " past the query execute");

//                        TextureGroup.setDefaultUsedColumns(new ArrayList<>(Arrays.asList(TableTextureGroup.CHTGKEY, TableTextureGroup.TEXTURE,
//                                TableTextureGroup.STRATEXTSFLAG, TableTextureGroup.RVINDICATOR)));
            while (results.next()) {
              tHorizon.setTextureGroups(results, textureGroupColumns, new ArrayList<>());
            }

            query = buildFragmentsQuery(tHorizon.chkey());
            Log(Level.INFO, " soils db query=" + query);
            results = statement.executeQuery(query);
            Log(Level.INFO, " past the query execute");

//                        Fragments.setDefaultUsedColumns(new ArrayList<>(Arrays.asList(TableFragments.CHFRAGSKEY, TableFragments.FRAGVOL_R, TableFragments.FRAGVOL_L,
//                                TableFragments.FRAGVOL_H, TableFragments.FRAGSIZE_R, TableFragments.FRAGSIZE_L, TableFragments.FRAGSIZE_H,
//                                TableFragments.FRAGHARD, TableFragments.FRAGSHP, TableFragments.FRAGROUND, TableFragments.FRAGKIND)));
            tHorizon.setFragments(results, fragmentsColumns);

          }

        }
      } catch (SQLException ex) {
        throw new ServiceException("Could not continue processing the horizon lookups for this component:  " + ex.getMessage(), ex);
      }
    } else {
      throw new ServiceException("No component key passed to the " + logPrefix + ".findHorizonsFragsByCokey() function.");
    }

    return ret_val;
  }

  @Override
  public boolean findHorizonsForCokey(MapUnit mapUnit, Component component) throws ServiceException {
    boolean ret_val = false;

    if ((null != component) && (null != component.cokey()) && !component.cokey().isEmpty()) {
      Validation.checkCokey(component.cokey());
      try (Statement statement = connection.createStatement();) {
        String query = buildCHQuery(component.cokey(), "WATER");

        Log(Level.INFO, " soils db query=" + query);
        ResultSet results = statement.executeQuery(query);
        Log(Level.INFO, " past the query execute");

        FilterResults filterResults = new FilterResults();

        ret_val = filterRusle2ComponentHorizonData(results, filterResults, mapUnit, component);
        results.close();

        //  Fill-in the MapUnit object too
        if (!component.mukey().isEmpty() && ret_val) {
          ret_val = findMukeyData(mapUnit);
        }

        if (!filterResults.foundKffact) {
          ret_val = false;
          Log(Level.WARNING, "No kffact found for this soil component in its horizon data.");
        }

        //TODO:  Verify this test still works in this case...
        if ((mapUnit.components().size() <= 0)) {
          ret_val = false;
          Log(Level.WARNING, "No suitable soil horizon data found for this component: " + component.cokey() + " .");
        }
      } catch (SQLException ex) {
        throw new ServiceException("Could not continue processing the horizon lookups for this component:  " + ex.getMessage(), ex);
      }
    } else {
      throw new ServiceException("No component key passed to the " + logPrefix + ".findHorizonsFragsByCokey() function.");
    }

    return ret_val;
  }

  @Override
  public HashMap<String, MapUnit> findMapUnitsForGISObject(GISObject gisObject) throws ServiceException, GISObjectException {
    return findMapUnitsForGISObject(gisObject, false, false);
  }

  @Override
  public synchronized MapUnit findMapUnitsByMupolygonKey(String mupolygonkey, GISEngine gisEngine, boolean computeIntersectionArea, boolean returnIntersectionShape) throws ServiceException, GISObjectException {
    MapUnit map_unit = null;

    MapUnit.setDefaultUsedColumns(new ArrayList<>(Arrays.asList(
        TableMapUnit.AREASYMBOL_NAME, TableMapUnit.MUKEY, TableMapUnit.MUSYM,
        TableMapUnit.MUNAME, TableMapUnitCalculations.AREA_NAME, TableMuaggatt.BROCKDEPMIN, TableMapUnit.MUACRES,
        TableSaCatalog.SA_VERSION, TableSaCatalog.SA_VER_EST,
        TableSaSpatialVer.SPATIAL_VERSION, TableSaSpatialVer.SPATIAL_VERSION_EST,
        TableSaTabularVer.TABULAR_VERSION, TableSaTabularVer.TABULAR_VERSION_EST
    )));

    if ((null != mupolygonkey) && (!mupolygonkey.isEmpty())) {

      String query = buildFindMapUnitsByPolyKeyQuery(mupolygonkey, returnIntersectionShape);

      try (Statement statement = connection.createStatement()) {
        ResultSet results = statement.executeQuery(query);
        while (results.next()) {
          String mukey = results.getString(TableMapUnit.MUKEY);

          map_unit = new MapUnit(mukey, results,
              (returnIntersectionShape ? GISObjectFactory.createGISObject(results.getString("intersectionShape"), gisEngine) : null)
          );

          map_unit.aoaArea(map_unit.muacres());
        }
      } catch (SQLException ex) {
        throw new ServiceException(logPrefix + ".findMapUnitsByMupolygonKey: SQL Exception encountered while finding map units for this shape.", ex);
      } catch (GISObjectException ex) {
        throw new ServiceException(logPrefix + ".findMapUnitsByMupolygonKey: GISObject Exception encountered while examining intersected shapes of map units for this shape.", ex);
      }
    }

    return map_unit;
  }

  @Override
  public synchronized HashMap<String, MapUnit> findMapUnitsForGISObject(GISObject gisObject, boolean computeIntersectionArea, boolean returnIntersectionShape) throws ServiceException, GISObjectException {
    LinkedHashMap<String, MapUnit> map_units = new LinkedHashMap<>();
    MapUnit.setDefaultUsedColumns(new ArrayList<>(Arrays.asList(
        TableMapUnit.AREASYMBOL_NAME, TableMapUnit.MUKEY, TableMapUnit.MUSYM, TableMapUnit.AREA_NAME,
        TableMapUnit.MUNAME, TableMapUnitCalculations.AREA_NAME, TableMuaggatt.BROCKDEPMIN, TableMapUnit.MUACRES,
        TableSaCatalog.SA_VERSION, TableSaCatalog.SA_VER_EST,
        TableSaSpatialVer.SPATIAL_VERSION, TableSaSpatialVer.SPATIAL_VERSION_EST,
        TableSaTabularVer.TABULAR_VERSION, TableSaTabularVer.TABULAR_VERSION_EST
    )));

    if ((null != gisObject) && (gisObject.isValid())) {
      String WKTShape = gisObject.toWKT();
      double aoaArea = gisObject.areaInAcres();

      String query = buildFindMapUnitsQuery(WKTShape, returnIntersectionShape);

      try (Statement statement = connection.createStatement()) {
        ResultSet results = statement.executeQuery(query);
        while (results.next()) {
          String mukey = results.getString(TableMapUnit.MUKEY);
          MapUnit tMapUnit;
          if (map_units.containsKey(mukey)) {
            double addArea = results.getDouble("area");
            tMapUnit = map_units.get(mukey);

            tMapUnit.areaAdd(addArea);

            if (returnIntersectionShape) {
              tMapUnit.addShape(GISObjectFactory.createGISObject(results.getString("intersectionShape"), gisObject.getEngine()));
            }
          } else {
            tMapUnit = new MapUnit(mukey, results,
                (returnIntersectionShape ? GISObjectFactory.createGISObject(results.getString("intersectionShape"), gisObject.getEngine()) : null)
            );
            tMapUnit.aoaArea(aoaArea);
            map_units.put(tMapUnit.mukey(), tMapUnit);
          }
        }
      } catch (SQLException ex) {
        throw new ServiceException(logPrefix + ".findMapUnitsForGISObject: SQL Exception encountered while finding map units for this shape.", ex);
      } catch (GISObjectException ex) {
        throw new ServiceException(logPrefix + ".findMapUnitsForGISObject: GISObject Exception encountered while examining intersected shapes of map units for this shape.", ex);
      }
    } else if (null == gisObject) {
      throw new ServiceException("NULL gisObject value passed to " + logPrefix + ".findMapUnitsForGISObject.");
    } else {
      throw new ServiceException("Invalid gisObject value passed to " + logPrefix + ".findMapUnitsForGISObject.");
    }

    return map_units;
  }

  @Override
  public HashMap<String, MapUnit> findMapUnitsForWKT(String wkt) throws ServiceException {
    return findMapUnitsForWKT(wkt, false, false);
  }

  @Override
  public HashMap<String, MapUnit> findMapUnitsForWKT(String wkt, boolean computeIntersectinArea, boolean returnIntersectionShape) throws ServiceException {
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
  }

  @Override
  public Connection getConnection() {
    return connection;
  }

  @Override
  public boolean isCONUS(double lat, double lon) throws SQLException, ServiceException {
    boolean ret_val = false;

    String query = buildIsConusQuery(String.valueOf(lat), String.valueOf(lon));

    try (Statement statement = connection.createStatement();) {

      ResultSet results = statement.executeQuery(query);

      if (results.next()) {
        ret_val = results.getBoolean("CONUS");
      } else {
        throw new ServiceException("Cannot determine if the location provided is within CONUS.  " + logPrefix + ".isCONUS query returned no results.");
      }
    }

    return ret_val;
  }

  @Override
  public boolean validateComponent(int cokey) throws SQLException {
    boolean ret_val = false;
    String query = buildValidateCokeyQuery(cokey);

    try (Statement statement = connection.createStatement();) {

      ResultSet results = statement.executeQuery(query);

      if (results.next()) {
        int tCokey = results.getInt("cokey");
        ret_val = (tCokey == cokey);
      }
    }

    return ret_val;
  }
}