//- ****************************************************************************
//-
//- Copyright 2009 National Technology & Engineering Solutions of Sandia, LLC
//- (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, 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:
//-
//-   1. Redistributions of source code must retain the above copyright notice,
//-      this list of conditions and the following disclaimer.
//-
//-   2. 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.
//-
//-   3. Neither the name of the copyright holder 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_tt_uncertainty_randerr(double* tt_uncertainty, int* err )
{
    try
    {
        *err = 1;       errortext = "";
        slbm_handle->getTravelTimeUncertainty( *tt_uncertainty, true );
        *err = 0;
    }
    catch(SLBMException ex)
    {
                errortext = ex.emessage; *err = ex.ecode;
    }
}
//==============================================================================
void slbm_get_tt_uncertainty1d(double* tt_uncertainty, int* err )
{
    try
    {
        *err = 1;       errortext = "";
        slbm_handle->getTravelTimeUncertainty1D( *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_get_rayparameter( double* rayParameter, int* err )
{
    try
    {
        *err = 1;       errortext = "";
        slbm_handle->getRayParameter( *rayParameter );
        *err = 0;
    }
    catch(SLBMException ex)
    {
                        errortext = ex.emessage; *err = ex.ecode;
    }
}
//==============================================================================
void slbm_get_turningradius( double* turningRadius, int* err )
{
    try
    {
        *err = 1;       errortext = "";
        slbm_handle->getTurningRadius( *turningRadius );
        *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;
    }
}

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

//==============================================================================
void slbm_models_equal(const char *modelPath1, const int *size1, const char *modelPath2, const int *size2, int *err)
{
    try
    {
        *err = 1;
        errortext = "";

        // get model path #1
        string modelPath1_str = modelPath1;
        if(*size1 <= (int)modelPath1_str.length())
            modelPath1_str = modelPath1_str.substr(0, *size1);

        // get model path #2
        string modelPath2_str = modelPath2;
        if(*size2 <= (int)modelPath2_str.length())
            modelPath2_str = modelPath2_str.substr(0, *size2);

        // get the result
        bool result = SlbmInterface::modelsEqual(modelPath1_str, modelPath2_str);

        // return the result
        if (result == true)
            *err = 0;
        else
            *err = 1;
    }
    catch(SLBMException ex)
    {
                errortext = ex.emessage; *err = ex.ecode;
    }
}

