//- ****************************************************************************
//- 
//- Copyright 2009 Sandia Corporation. Under the terms of Contract 
//- DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains 
//- certain rights in this software.
//-
//- BSD Open Source License.
//- All rights reserved.
//- 
//- 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 following disclaimer.
//-    * Redistributions in binary form must reproduce the above copyright 
//-      notice, this list of conditions and the following disclaimer in the 
//-      documentation and/or other materials provided with the distribution.
//-    * Neither the name of Sandia National Laboratories 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 THE COPYRIGHT HOLDER 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.
//-


//- Unauthorized reproduction or distribution of this program, or any
//- portion of it, may result in civil and criminal penalties, and will be
//- prosecuted to the maximum extent possible under the law.
//- 

/*
*
* Copyright (c) 1990-1999 Science Applications International Corporation.
*
* NAME
*
* FILE slbmshell.cc
*
* DESCRIPTION
* SLBM- Thin "C" Shell Interface
*
*
* Functions:
*
*
*/

#include "SlbmInterface.h"
#include "slbm_F_shell.h"
#include "SLBMException.h"
#include <stdio.h>
//#include <string>

using namespace slbm;

static SlbmInterface* slbm_handle = NULL;

string errortext;

//==============================================================================
void slbm_get_version(char* str, int* size, int* err)
{
  	try
	{
		*err = 1;		errortext = "";
		string temp = slbm_handle->getVersion();
		for( int i = 0; i < *size; i++ )
		{
			if (i < (int)temp.length())
				*str++ = temp[i];
			else
				*str++ = '\0';
		}
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_error_message( char* str, int* size)
{
	if (errortext.length() == 0)
		errortext = "An unrecognized error has occurred in slbmFortshell.cc";

	for( int i = 0; i < *size; i++ )
		*str++ = i < (int)errortext.length() ? errortext[i] : '\0';
}

//==============================================================================
void slbm_create (int * err)
{
	// If the handle already exists, then return w/ error
	if (slbm_handle != (SlbmInterface*) NULL) 
	{
		*err = 1;
		return;
	}
  
  	try
	{
		*err = 1;		errortext = "";
		slbm_handle = new SlbmInterface ();                                
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
} /* END slbm_create */

//==============================================================================
void slbm_create_fixed_earth_radius (double* radius, int* err)
{
	// If the handle already exists, then return w/error
	if (slbm_handle != (SlbmInterface*) NULL) 
	{
		*err = 1;		errortext = "Already instantiated.";
	}
  
  	try
	{
		*err = 1;		errortext = "";
		slbm_handle = new SlbmInterface (*radius); 
		*err = 0;		
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
		*err = 1;
	}
}
//==============================================================================
void slbm_load_velocity_model(const char* modelFileName, int* nameLength, int* err)
{
  	try
	{
		*err = 1;		errortext = "";
		string modelFileName_cc(modelFileName);
		if( *nameLength <= (int)modelFileName_cc.length() )
		{
			modelFileName_cc = modelFileName_cc.substr(0, *nameLength );
		}
		slbm_handle->loadVelocityModel(modelFileName_cc);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
 
//==============================================================================
void slbm_save_velocity_model(const char* modelFileName, int* nameLength, int* err)
{
  	try
	{
		*err = 1;		errortext = "";
		string modelFileName_cc(modelFileName);
		if( *nameLength <= (int)modelFileName_cc.length() )
		{
			modelFileName_cc = modelFileName_cc.substr(0, *nameLength );
		}
		slbm_handle->saveVelocityModel(modelFileName_cc);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
 
//==============================================================================
void slbm_save_velocity_model_f(const char* modelFileName, int* nameLength, int* format, int* err)
{
  	try
	{
		*err = 1;		errortext = "";
		string modelFileName_cc(modelFileName);
		if( *nameLength <= (int)modelFileName_cc.length() )
		{
			modelFileName_cc = modelFileName_cc.substr(0, *nameLength );
		}
		slbm_handle->saveVelocityModel(modelFileName_cc, *format);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}

//==============================================================================
void slbm_delete (int* err)
{
	try
	{
		*err = 1;		errortext = "";
		if (slbm_handle != (SlbmInterface*) NULL)
		{
			delete slbm_handle;
			slbm_handle = (SlbmInterface *) NULL;
		}
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
} // END slbm_delete


//==============================================================================
void slbm_create_great_circle (int* phase, 
								  double* sourceLat, 
								  double* sourceLon, 
								  double* sourceDepth, 
								  double* receiverLat, 
								  double* receiverLon, 
								  double* receiverDepth, 
								  int* err) 
{	

try
	{
		*err = 1;		errortext = "";

		slbm_handle->createGreatCircle( *phase	,
									  *sourceLat,
									  *sourceLon,
									  *sourceDepth,
									  *receiverLat,
									  *receiverLon,
									  *receiverDepth);	
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; 
				*err = ex.ecode;
	}
}
//==============================================================================
void slbm_is_valid (int* err)
{
	try
	{
		*err = 1;		errortext = "";
		if (slbm_handle->isValid()) 
			*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}

//==============================================================================
void  slbm_clear (int* err)
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->clear();
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_distance (double* distance, int* err) 
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getDistance(*distance);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_source_distance(double* dist, int* err)
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getSourceDistance(*dist);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
 void slbm_get_receiver_distance(double* dist, int* err)
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getReceiverDistance(*dist);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
 void slbm_get_head_wave_distance(double* dist, int* err)
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getHeadwaveDistance(*dist);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
 void slbm_get_head_wave_distance_km(double* dist, int* err)
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getHeadwaveDistanceKm(*dist);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_travel_time (double* travelTime, int* err) 
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getTravelTime(*travelTime);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
 void slbm_get_travel_time_components (double* tTotal, double* tSource, double* tReceiver, double* tHeadwave, double* tGradient, int* err) 
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getTravelTimeComponents(*tTotal, *tSource, *tReceiver, *tHeadwave, *tGradient);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_weights (int nodeId[], double weight[], int* nweights, int* err) 
  {
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getWeights( nodeId, weight, *nweights);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_weights_source(int nodeids[], double weights[], int* nWeights, int* err)
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getWeightsSource( nodeids, weights, *nWeights);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_weights_receiver(int nodeids[], double weights[], int* nWeights, int* err)
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getWeightsReceiver(nodeids, weights, *nWeights);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_n_grid_nodes(int* numGridNodes, int* err)
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getNGridNodes(*numGridNodes);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}

//==============================================================================
void slbm_get_n_head_wave_points(int* nHeadWavePoints, int* err)
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getNHeadWavePoints(*nHeadWavePoints);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_grid_data(int* nodeId, double* latitude, double* longitude, double* depth, double* pvelocity,
							double* svelocity, double* gradient, int* err)
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getGridData( *nodeId, 
								  *latitude,
								  *longitude,
								  depth,
								  pvelocity,
								  svelocity,
								  gradient);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_set_grid_data(int* nodeId, double* depths, double* pvelocity, double* svelocity, double* gradient, int* err)
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->setGridData(*nodeId, depths, pvelocity, svelocity, gradient);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_great_circle_data (
		int* phase, double* path_increment, 
		double sourceDepth[MAX_POINTS], 
		double sourceVelocity[MAX_POINTS],
		double receiverDepth[MAX_POINTS],	
		double receiverVelocity[MAX_POINTS], 
		double headWaveVelocity[MAX_POINTS],
		double gradient[MAX_POINTS], 
		int* npoints, int* err)
{
	int i;
	vector<double> sourceDepth_cc;
	vector<double> sourceVelocity_cc;
	vector<double> receiverDepth_cc;
	vector<double> receiverVelocity_cc;
	vector<double> headWaveVelocity_cc;
	vector<double> gradient_cc;

	try
	{
		*err = 1;		errortext = "";
		*npoints = -1;
		slbm_handle->getGreatCircleObject()->getData(
			*phase, *path_increment,
			sourceDepth_cc, sourceVelocity_cc, receiverDepth_cc,
			receiverVelocity_cc, headWaveVelocity_cc, gradient_cc);

		if ((int)sourceDepth_cc.size() > MAX_POINTS)
		{
			ostringstream os;
			os << endl << "ERROR in slbm_getGreatCircleData" << endl
				<< "Call to slbm_handle->getGreatCircleObject()->getData()"	<< endl
				<< "returned arrays of size " << sourceDepth_cc.size() << endl
				<< "which exceeds global constant MAX_POINTS = " << MAX_POINTS << endl
				<< "Version " << SlbmVersion << "  File " << __FILE__ << " line " << __LINE__ << endl << endl;

			errortext = os.str();
			return;
		}

		for (i=0; i<(int)sourceDepth_cc.size(); i++)
		{
			sourceDepth[i] = sourceDepth_cc[i];
			sourceVelocity[i] = sourceVelocity_cc[i];
			receiverDepth[i] = receiverDepth_cc[i];
			receiverVelocity[i] = receiverVelocity_cc[i];
		}

		*npoints = (int)headWaveVelocity_cc.size();

		for (i=0; i<*npoints; i++)
		{
			headWaveVelocity[i] = headWaveVelocity_cc[i];
			gradient[i] = gradient_cc[i];
		}
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_great_circle_node_info (
		int nodes[MAX_POINTS][MAX_NODES],
		double coefficients[MAX_POINTS][MAX_NODES],
		int* npoints, int nnodes[MAX_POINTS], int* err)
{
	int i;

	int** nodes_cc = CPPUtils::new2DArray<int>(MAX_POINTS, MAX_NODES);
	double** coefficients_cc = CPPUtils::new2DArray<double>(MAX_POINTS, MAX_NODES);

	try
	{
		*err = 1;		errortext = "";
		*npoints = -1;
		slbm_handle->getGreatCircleNodeInfo(
				nodes_cc, coefficients_cc, MAX_POINTS, MAX_NODES, *npoints, nnodes);

		if (*npoints > MAX_POINTS)
		{
			ostringstream os;
			os << endl << "ERROR in slbm_get_great_circle_node_info" << endl
				<< "Call to slbm_handle->getGreatCircleObject()->getGreatCircleNodeInfo()"	<< endl
				<< "returned arrays of size " << *npoints << endl
				<< "which exceeds global constant MAX_POINTS = " << MAX_POINTS << endl
				<< "Version " << SlbmVersion << "  File " << __FILE__ << " line " << __LINE__ << endl << endl;

			errortext = os.str();
			return;
		}

		int* n = (int*)nodes;
		double* c = (double*)coefficients;

		for (i=0; i<*npoints; i++)
		{
			//translate array elements from row order to column order for fortran
			for(int j = 0; j < nnodes[i]; j++ )
			{
				n[j*MAX_POINTS+i] = nodes_cc[i][j];
				c[j*MAX_POINTS+i] = coefficients_cc[i][j];
			}
		}
		*err = 0;
	}
	catch(SLBMException ex)
	{
		errortext = ex.emessage; *err = ex.ecode;
	}

	CPPUtils::delete2DArray(nodes_cc);
	CPPUtils::delete2DArray(coefficients_cc);
}
//==============================================================================
void slbm_get_interpolated_point (double* lat, double* lon, int* nodeId, double* coefficients, 
									 int* nnodes, double* depth, double* pvelocity,
									 double* svelocity, double* pgradient, double* sgradient, int* err) 
{ 
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getInterpolatedPoint(	*lat, 
											*lon,
											nodeId,
											coefficients,
											*nnodes,
											depth,
											pvelocity,
											svelocity,
											*pgradient,
											*sgradient);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
} 
//==============================================================================
void slbm_initialize_active_nodes(double* latmin, double* lonmin, double* latmax, double* lonmax, int* err)
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->initializeActiveNodes(*latmin, *lonmin, *latmax, *lonmax);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_n_active_nodes(int* nNodes, int* err)
{
	try
	{
		*err = 1;		errortext = "";
		*nNodes = slbm_handle->getNActiveNodes();
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_grid_node_id(int* activeNodeId, int* gridNodeId, int* err)
{
	try
	{
		*err = 1;		errortext = "";
		*gridNodeId = slbm_handle->getGridNodeId(*activeNodeId);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_active_node_id(int* gridNodeId, int* activeNodeId, int* err)
{
	try
	{
		*err = 1;		errortext = "";
		*activeNodeId = slbm_handle->getActiveNodeId(*gridNodeId);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_node_hit_count(int* nodeId, int* hitCount, int* err)
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getNodeHitCount(*nodeId, *hitCount);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_node_neighbors(int* nid, int neighbors[], int* nNeighbors, int* err)
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getNodeNeighbors(*nid, neighbors, *nNeighbors);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_node_neighbor_info(int* nid, int neighbors[], double distance[], double azimuth[],
									int* nNeighbors, int* err)
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getNodeNeighborInfo(*nid, neighbors, distance, azimuth,
									*nNeighbors);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_node_separation(int* node1, int* node2, double* distance, int* err)
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getNodeSeparation(*node1, *node2, *distance);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_node_azimuth(int* node1, int* node2, double* azimuth, int* err)
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getNodeAzimuth(*node1, *node2, *azimuth);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_traveltime_uncertainty( int* phase, double* distance, double* uncertainty, int* err )
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getTravelTimeUncertainty( *phase, *distance, *uncertainty );
		*err = 0;
	}
	catch(SLBMException ex)
	{
		errortext = ex.emessage; *err = ex.ecode;
		*uncertainty = NA_VALUE;
	}
}
//==============================================================================
void slbm_get_tt_uncertainty(double* tt_uncertainty, int* err )
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getTravelTimeUncertainty( *tt_uncertainty );
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_zhao_parameters(double* Vm, double* Gm, double* H, double* C, double* Cm, int* udSign, int* err )
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getZhaoParameters( *Vm, *Gm, *H, *C, *Cm, *udSign );
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_active_node_weights(int nodeId[], double weight[], int* nWeights, int* err )
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getActiveNodeWeights(nodeId, weight, *nWeights );
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_active_node_weights_src(int nodeids[], double weights[], int* nweights, int* err )
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getActiveNodeWeightsSource( nodeids, weights, *nweights );
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_active_node_weights_rcvr(int nodeids[], double weights[], int* nweights, int* err )
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getActiveNodeWeightsReceiver( nodeids, weights, *nweights );
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_active_node_neighbors( int* nid, int neighbors[], int* nNeighbors, int* err )
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getActiveNodeNeighbors( *nid, neighbors, *nNeighbors );
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_active_node_neighbor_info(	int* nid, int neighbors[], double distance[],
											double azimuth[], int* nNeighbors, int* err )
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getActiveNodeNeighborInfo( *nid, neighbors, distance, azimuth, *nNeighbors );
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_active_node_data(	int* nodeId,
									double* latitude,
									double* longitude,
									double depth[NLAYERS],
									double pvelocity[NLAYERS],
									double svelocity[NLAYERS],
									double gradient[2], int* err )

{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getActiveNodeData(	*nodeId, *latitude, *longitude,	depth,
										pvelocity, svelocity, gradient );
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_set_active_node_data(	int* nodeId,
									double depths[NLAYERS],
									double pvelocity[NLAYERS], 
									double svelocity[NLAYERS],
									double gradient[2], int* err )
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->setActiveNodeData(	*nodeId, depths,
									pvelocity, 
									svelocity,
									gradient );
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_set_ch_max( double* chMax, int* err )
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->setCHMax( *chMax );
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_ch_max( double* chMax, int* err )
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getCHMax( *chMax );
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_average_mantle_velocity( int* type, double* velocity, int* err )
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getAverageMantleVelocity( *type, *velocity );
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_set_average_mantle_velocity( int* type, double* velocity, int* err )
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->setAverageMantleVelocity( *type, *velocity );
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_load_velocity_model_binary(const char* modelDirectory, int* nameLength, int* err )
{
	try
	{
		*err = 1;		errortext = "";
		string modelDirectory_cc(modelDirectory);
		if( *nameLength <= (int)modelDirectory_cc.length() )
		{
			modelDirectory_cc = modelDirectory_cc.substr(0, *nameLength );
		}
		slbm_handle->loadVelocityModelBinary( modelDirectory_cc );
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_specify_output_directory(const char* directoryName, int* dirNameLength, int* err )
{
	try
	{
		*err = 1;		errortext = "";
		string directoryName_cc(directoryName);
		if( *dirNameLength <= (int)directoryName_cc.length() )
		{
			directoryName_cc = directoryName_cc.substr(0, *dirNameLength );
		}
		slbm_handle->specifyOutputDirectory( directoryName_cc );
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_save_velocity_model_binary( int* err)
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->saveVelocityModelBinary();
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_tess_id( char* tessId, int* size, int* err )
{
	try
	{
		*err = 1;		errortext = "";
		string tessId_cc;
		slbm_handle->getTessId( tessId_cc );
		
		for (int i=0; i<*size; ++i)
		   *tessId++ = i < (int)tessId_cc.length() ? tessId_cc[i] : '\0';
		   	
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_fraction_active ( double* fractionActive, int* err )
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getFractionActive ( *fractionActive );
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_set_max_distance ( const double* maxDistance, int* err ) 
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->setMaxDistance ( *maxDistance );
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_max_distance ( double* maxDistance, int* err ) 
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getMaxDistance ( *maxDistance );
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_set_max_depth ( const double* maxDepth, int* err ) 
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->setMaxDepth ( *maxDepth );
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_max_depth ( double* maxDepth, int* err ) 
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getMaxDepth ( *maxDepth );
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_pg_lg_components ( double* tTotal, double* tTaup, 
			double* tHeadwave, double* pTaup, double* pHeadwave, double* trTaup, 
			double* trHeadwave, int* err )
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getPgLgComponents (*tTotal, *tTaup, 
										*tHeadwave, *pTaup, *pHeadwave, *trTaup, *trHeadwave );
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================


// new gtb 16Jan2009
//==============================================================================
void slbm_get_dtt_dlat(double* dtt_dlat, int* err )
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->get_dtt_dlat ( *dtt_dlat );
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_dtt_dlon(double* dtt_dlon, int* err )
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->get_dtt_dlon ( *dtt_dlon );
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_dtt_ddepth(double* dtt_ddepth, int* err )
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->get_dtt_ddepth ( *dtt_ddepth );
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}

////==============================================================================
//void slbm_get_dsh_ddist(double* dsh_dldist, int* err )
//{
//	try
//	{
//		*err = 1;		errortext = "";
//		slbm_handle->get_dsh_ddist ( *dsh_ddist );
//		*err = 0;
//	}
//	catch(SLBMException ex)
//	{
//				errortext = ex.emessage; *err = ex.ecode;
//	}
//}
////==============================================================================
//void slbm_get_dsh_dlat(double* dsh_dlat, int* err )
//{
//	try
//	{
//		*err = 1;		errortext = "";
//		slbm_handle->get_dsh_dlat ( *dsh_dlat );
//		*err = 0;
//	}
//	catch(SLBMException ex)
//	{
//				errortext = ex.emessage; *err = ex.ecode;
//	}
//}
////==============================================================================
//void slbm_get_dsh_dlon(double* dsh_dlon, int* err )
//{
//	try
//	{
//		*err = 1;		errortext = "";
//		slbm_handle->get_dsh_dlon ( *dsh_dlon );
//		*err = 0;
//	}
//	catch(SLBMException ex)
//	{
//				errortext = ex.emessage; *err = ex.ecode;
//	}
//}
////==============================================================================
//void slbm_get_dsh_ddepth(double* dsh_ddepth, int* err )
//{
//	try
//	{
//		*err = 1;		errortext = "";
//		slbm_handle->get_dsh_ddepth ( *dsh_ddepth );
//		*err = 0;
//	}
//	catch(SLBMException ex)
//	{
//				errortext = ex.emessage; *err = ex.ecode;
//	}
//}

//==============================================================================
void slbm_get_slowness(double* slowness, int* err )
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getSlowness ( *slowness );
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_slowness_uncertainty( int* phase, double* distance, double* slowness_uncertainty, int* err )
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getSlownessUncertainty ( *phase, *distance, *slowness_uncertainty );
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_sh_uncertainty(double* slowness_uncertainty, int* err )
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getSlownessUncertainty ( *slowness_uncertainty );
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================

// new sb 8/2011  version 2.7.0
//==============================================================================
void slbm_get_great_circle_locations (double lat[MAX_POINTS],
									  double lon[MAX_POINTS],
									  double depth[MAX_POINTS],
									  int* npoints, int* err) 
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getGreatCircleLocations(lat, lon, depth, *npoints);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================

void slbm_get_great_circle_points (double* aLat, double* aLon, 
		double* bLat, double* bLon, int* npoints, 
		double latitude[MAX_POINTS], double longitude[MAX_POINTS], int* err)
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getGreatCirclePoints(*aLat, *aLon, *bLat, *bLon, *npoints, latitude, longitude);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================

void slbm_get_great_circle_points_on_centers (double* aLat, double* aLon, 
		double* bLat, double* bLon, int* npoints, 
		double latitude[MAX_POINTS], double longitude[MAX_POINTS], int* err)
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getGreatCirclePointsOnCenters(*aLat, *aLon, *bLat, *bLon, *npoints, latitude, longitude);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================

void slbm_get_pierce_point_source(double* lat, double* lon, double* depth, int* err)
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getPiercePointSource ( *lat, *lon, *depth );
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}
//==============================================================================
void slbm_get_pierce_point_receiver(double* lat, double* lon, double* depth, int* err)
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getPiercePointReceiver ( *lat, *lon, *depth );
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}

//==============================================================================
void slbm_get_dist_az(double* aLat, double* aLon, 
					  double* bLat, double* bLon, 
					  double* distance, double* azimuth, 
					  double* naValue, int* err )
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getDistAz (*aLat, *aLon, *bLat, *bLon, 
					  *distance, *azimuth, *naValue);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}

//==============================================================================
void slbm_move_point(double* aLat, double* aLon, 
	double* distance, double* azimuth, double* bLat, double* bLon, int* err )
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->movePoint (*aLat, *aLon, *distance, *azimuth, *bLat, *bLon);
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}

//==============================================================================
void slbm_get_del_distance(double* delDistance, int* err ){
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getDelDistance( *delDistance );
		*err = 0;
	}
	catch(SLBMException ex)
	{
						errortext = ex.emessage; *err = ex.ecode; 
	}
}
//==============================================================================
void slbm_get_del_depth(double* delDepth, int* err )
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getDelDepth( *delDepth );
		*err = 0;
	}
	catch(SLBMException ex)
	{
						errortext = ex.emessage; *err = ex.ecode; 
	}
}
//==============================================================================
void slbm_set_del_distance( double* delDistance, int* err )
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->setDelDistance( *delDistance );
		*err = 0;
	}
	catch(SLBMException ex)
	{
						errortext = ex.emessage; *err = ex.ecode; 
	}
}
//==============================================================================
void slbm_set_del_depth( double* delDepth, int* err )
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->setDelDepth( *delDepth );
		*err = 0;
	}
	catch(SLBMException ex)
	{
				errortext = ex.emessage; *err = ex.ecode;
	}
}

//==============================================================================
void slbm_set_path_increment(double* pathIncrement, int* err)
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->setPathIncrement( *pathIncrement );
		*err = 0;
	}
	catch(SLBMException ex)
	{
		errortext = ex.emessage; *err = ex.ecode; 
	}
}

//==============================================================================
void slbm_get_path_increment(double* pathIncrement, int* err)
{
	try
	{
		*err = 1;		errortext = "";
		slbm_handle->getPathIncrement( *pathIncrement );
		*err = 0;
	}
	catch(SLBMException ex)
	{
						errortext = ex.emessage; *err = ex.ecode; 
	}
}

//==============================================================================
void slbm_set_interpolator_type(const char* interpolatorType, int* size, int* err)
{
	try
	{
		*err = 1;		errortext = "";
		string s(interpolatorType);
		if( *size <= (int)s.length() )
		{
			s = s.substr(0, *size );
		}
		slbm_handle->setInterpolatorType(s);
		*err = 0;
	}
	catch(SLBMException ex)
	{
		errortext = ex.emessage; *err = ex.ecode; 
	}
}

//==============================================================================
void slbm_get_interpolator_type(char* interpolatorType, int* size, int* err)
{
  	try
	{
		*err = 1;		errortext = "";
		string temp = slbm_handle->getInterpolatorType();
		for( int i = 0; i < *size; i++ )
		{
			if (i < (int)temp.length())
				*interpolatorType++ = temp[i];
			else
				*interpolatorType++ = '\0';
		}
		*err = 0;
	}
	catch(SLBMException ex)
	{
		errortext = ex.emessage; *err = ex.ecode;
	}
}
