getHorizonString.cc [tools/Rusle2SoilsXMLCreator/pg/rusle2_from_ssurgo_build_newbackup] Revision:   Date:
#include <string>
#include <iostream>
#include <boost/lexical_cast.hpp>
#include "rusle2_from_ssurgo.h"

using namespace std;
using boost::lexical_cast;

/**
 *  Query the [CHORIZON] information for XML output
 *  chkey gets passed back to parent program to query this information directly
 *
 *  Yeah...it's a second query but I didn't really want to be passing data all over
 *  This just makes more sense to me...sorry if it doesn't to someone else later
 */
PGresult*
queryHorizonForXML( PGconn* conn, string chKEY )
{

	string Query = "SELECT "
					"om_l, om_r, om_h, "
					"ph1to1h2o_l, ph1to1h2o_r, ph1to1h2o_h, "
					"kffact, "
					"sandtotal_l, sandtotal_r, sandtotal_h, "
					"silttotal_l, silttotal_r, silttotal_h, "
					"claytotal_l, claytotal_r, claytotal_h, "
					"cec7_l, cec7_r, cec7_h, "
					"wthirdbar_l, wthirdbar_r, wthirdbar_h, "
					"wfifteenbar_l, wfifteenbar_r, wfifteenbar_h, "
					"dbthirdbar_l, dbthirdbar_r, dbthirdbar_h "
					"FROM ssurgo.chorizon WHERE chkey=$1::varchar";
		const char * paramValues[1];
		paramValues[0] = chKEY.c_str();
		int numParams = 1;
		PGresult *chHorizRes;

		chHorizRes = PQexecParams( conn,
			Query.c_str(),
			numParams,
			NULL,
			paramValues,
			NULL,
			NULL,
			0);
		if( PQresultStatus(chHorizRes) != PGRES_TUPLES_OK ){
			PQclear(chHorizRes);
			exit_nicely(conn);
		}

	return chHorizRes;

}

/**
 * Query out the [CHTEXTUREGRP] information
 */
PGresult*
queryHorizonTextureGroup( PGconn* conn, string chKEY )
{
	string chTexGrpQuery = "SELECT texture, texdesc, chtgkey FROM ssurgo.chtexturegrp WHERE chkey=$1::varchar";
	const char * paramValues[1];
	paramValues[0] = chKEY.c_str();
	int numParams = 1;
	PGresult *chtexgrpRes;

	chtexgrpRes = PQexecParams( conn,
		chTexGrpQuery.c_str(),
		numParams,
		NULL,
		paramValues,
		NULL,
		NULL,
		0);
	if( PQresultStatus(chtexgrpRes) != PGRES_TUPLES_OK ){
		PQclear(chtexgrpRes);
		exit_nicely(conn);
	}

	return chtexgrpRes;
}

/** 
 * Query out the [CHTEXTURE] information
 */
PGresult*
queryHorizonTextureLieutex( PGconn* conn, string chtgKEY)
{
	string chTexQuery = "SELECT lieutex FROM ssurgo.chtexture WHERE chtgkey=$1::varchar";
	const char * paramValues[1];
	paramValues[0] = chtgKEY.c_str();
	int numParams = 1;
	PGresult *chtexRes;

	chtexRes = PQexecParams( conn,
		chTexQuery.c_str(),
		numParams,
		NULL,
		paramValues,
		NULL,
		NULL,
		0);

	if( PQresultStatus(chtexRes) != PGRES_TUPLES_OK ){
		PQclear(chtexRes);
		exit_nicely(conn);
	}

	return chtexRes;
}

/** 
 * Query out the [HORIZON] information
 */
PGresult*
queryHorizons(PGconn* conn, string coKEY)
{
	
	string horizQuery = "SELECT cokey, chkey, hzdept_l, hzdept_r, hzdept_h "
						"FROM ssurgo.chorizon "
						"WHERE cokey=$1::varchar "
						"ORDER BY hzdept_r, hzdept_l";
    const char * paramValues[1]; 
    paramValues[0] = coKEY.c_str();
    int numParams = 1;
    PGresult *horizRes;


    horizRes = PQexecParams( conn,
        horizQuery.c_str(),
        numParams,
        NULL,
        paramValues,
        NULL,
        NULL,
        0);

    if( PQresultStatus(horizRes) != PGRES_TUPLES_OK ){
        PQclear(horizRes);
        exit_nicely(conn);
    }

	return horizRes;
}

/**
 * Get the Texture Group
 */
bool
getHorizonTextureGroup(string& hzGrp, PGresult* hzRes, int hzROW, PGconn* conn)
{
	if( hzROW >= PQntuples(hzRes) )
		return false;

	hzGrp = GetNasisString("chtgkey", hzRes, hzROW);
	return hzGrp.length() > 0 ? true : false;
}

/**
 * Get the Lieutex
 */
bool
getHorizonTextureLieutex(string& hzTex, PGresult* hzRes, int hzROW)
{
	if( hzROW >= PQntuples(hzRes) )
		return false;

	hzTex = GetNasisString("lieutex", hzRes, hzROW);
	/** Frustrating...
	 *	lieutex is often NULL...so can't test for length() > 0
	 */
	return true;

}

/**
 *	Query parent [COMPONENT] Taxonomic information...
 */
PGresult*
getParentComponentTaxInfo(string& coKEY, PGconn* conn )
{

	string Query = "SELECT taxorder, taxsubgrp "
					"FROM ssurgo.component "
					"WHERE cokey=$1::varchar";
	const char * paramValues[1];
	paramValues[0] = coKEY.c_str();
	int numParams = 1;
	PGresult *res;

	res = PQexecParams( conn,
			Query.c_str(),
			numParams,
			NULL,
			paramValues,
			NULL,
			NULL,
			0);

	if( PQresultStatus(res) != PGRES_TUPLES_OK ){
		PQclear(res);
		exit_nicely(conn);
	}

	
	return res;
}

/**
 *  Get the horizon string
 *  Or to be more specific, jump through all the hoops to get a texture
 *  Each horizon has mulitple textures...so we have to find a valid one
 *  But texture is not a property of a horizon, texture group is...
 *  So this is kind of a pain in the rear-end.
 *
 *  @note There are checks for lieutex which skip over Organic Soils
 *  Specifically, remember if the component IS a histosol (organic?), we just take
 *  the first result.
 *  If it is NOT a histosol, then we want to find a valid texture which then does not
 *  describe a histosol...
 */
bool 
getHorizonString(string& horizString, PGresult* chRes, int hROW, PGconn* conn)
{

#ifndef NDEBUG
	cout << "getHorizonString()" << endl;
#endif

	if( hROW >= PQntuples(chRes) || horizString.length() > 0 )
		return false;

	int i_horiz = 0;
	string hzTexGrp;
	string chKEY = GetNasisString("chkey", chRes, hROW);
	PGresult *chHorizonTexGrpRes = queryHorizonTextureGroup(conn, chKEY);
	int hzRow = 0;

	string coKEY = GetNasisString("cokey", chRes, hROW);
	PGresult *compTaxInfo = getParentComponentTaxInfo( coKEY, conn);

	while( getHorizonTextureGroup( hzTexGrp , chHorizonTexGrpRes, hzRow, conn ) == true ){

		string hzTexGrp = GetNasisString("chtgkey", chHorizonTexGrpRes, hzRow);
		PGresult *chHoizonTextureRes = queryHorizonTextureLieutex(conn, hzTexGrp);
		/* 
		 * Protect against not finding a lieutex
		 * Rare but have found it happen with MI003
		 */
		if( PQntuples(chHoizonTextureRes) <= 0 ){
			hzRow++;
			continue;
		}
		int hzTexRow = 0;
		string lieutex = GetNasisString("lieutex", chHoizonTextureRes, 0);


		bool foundGoodHorizon = false;
		while( getHorizonTextureLieutex(lieutex, chHoizonTextureRes, hzTexRow) == true ){

			if( GetNasisString("taxorder", compTaxInfo, 0) == "Histosols" || GetNasisString("taxsubgrp", compTaxInfo, 0).find("Histic") != string::npos ){
				/* This is the basic check for a good Horizon */
				if( GetNasisString("hzdept_r", chRes, hROW) == "0" || GetNasisString("hzdept_l", chRes, hROW) == "0" ){
					/* We have a the top Horizon */
					foundGoodHorizon = true;
				}else{
					/* We only want the top Horizon */
					hzTexRow++;
					lieutex.erase(0);
					continue;
				}

			}else if( lieutex == "Highly decomposed plant material" || lieutex == "Moderately decomposed plant material" ||
				lieutex == "Mucky peat" || lieutex == "Muck" ||
				lieutex == "Partially decomposed organic matter" || lieutex == "Peat" ||
				lieutex == "Slightly decomposed plant material" || lieutex == "Undecomposed organic matter"){
				/* the above lieutex checks are not acceptable for soils which are not histosols (organic?) 
				 * so if we are here...we are a regular soil annd want a better horizon texture 
				 * set as false and continue searching
				 */
					foundGoodHorizon = false;
			}

			/* A blank lieutex is acceptable... */
			if( lieutex.length() == 0 || lieutex == "" )
				foundGoodHorizon = true;
	
			/* Similar to components, erase the lieutex */
			hzTexRow++;
			lieutex.erase(0);
		}


		/* Did we find a horizon with a valid texture ? 
		 * If so...get the horizon description and return
		 * Otherwise...continue the iter
		 */
		if( foundGoodHorizon == true ){
			horizString = GetNasisString("texdesc", chHorizonTexGrpRes, hzRow);
			return true;
		}

		hzRow++;
	}

#ifndef NDEBUG
	cout << "\tleaving getHorizonString()" << endl;
#endif

	return true;
}