/*
*+
*  Name:
*     palDafin

*  Purpose:
*     Sexagesimal character string to angle

*  Language:
*     Starlink ANSI C

*  Type of Module:
*     Library routine

*  Invocation:
*     void palDafin ( const char *string, int *ipos, double *a, int *j );

*  Arguments:
*     string = const char * (Given)
*        String containing deg, arcmin, arcsec fields
*     ipos = int * (Given & Returned)
*        Position to start decoding "string". First character
*        is position 1 for compatibility with SLA. After
*        calling this routine "iptr" will be positioned after
*        the sexagesimal string.
*     a = double * (Returned)
*        Angle in radians.
*     j = int * (Returned)
*        status:  0 = OK
*                +1 = default, A unchanged
*                -1 = bad degrees      )
*                -2 = bad arcminutes   )  (note 3)
*                -3 = bad arcseconds   )

*  Description:
*     Extracts an angle from a sexagesimal string with degrees, arcmin,
*     arcsec fields using space or comma delimiters.

*  Authors:
*     TIMJ: Tim Jenness (JAC, Hawaii)
*     PTW: Patrick T. Wallace
*     {enter_new_authors_here}

*  Example:
*     argument    before                           after
*
*     STRING      '-57 17 44.806  12 34 56.7'      unchanged
*     IPTR        1                                16 (points to 12...)
*     A           ?                                -1.00000D0
*     J           ?                                0

*  Notes:
*     - The first three "fields" in STRING are degrees, arcminutes,
*       arcseconds, separated by spaces or commas.  The degrees field
*       may be signed, but not the others.  The decoding is carried
*       out by the palDfltin routine and is free-format.
*     - Successive fields may be absent, defaulting to zero.  For
*       zero status, the only combinations allowed are degrees alone,
*       degrees and arcminutes, and all three fields present.  If all
*       three fields are omitted, a status of +1 is returned and A is
*       unchanged.  In all other cases A is changed.
*     - Range checking:
*
*           The degrees field is not range checked.  However, it is
*           expected to be integral unless the other two fields are absent.
*
*           The arcminutes field is expected to be 0-59, and integral if
*           the arcseconds field is present.  If the arcseconds field
*           is absent, the arcminutes is expected to be 0-59.9999...
*
*           The arcseconds field is expected to be 0-59.9999...
*
*     - Decoding continues even when a check has failed.  Under these
*       circumstances the field takes the supplied value, defaulting
*       to zero, and the result A is computed and returned.
*     - Further fields after the three expected ones are not treated
*       as an error.  The pointer IPOS is left in the correct state
*       for further decoding with the present routine or with palDfltin
*       etc. See the example, above.
*     - If STRING contains hours, minutes, seconds instead of degrees
*       etc, or if the required units are turns (or days) instead of
*       radians, the result A should be multiplied as follows:
*
*           for        to obtain    multiply
*           STRING     A in         A by
*
*           d ' "      radians      1       =  1.0
*           d ' "      turns        1/2pi   =  0.1591549430918953358
*           h m s      radians      15      =  15.0
*           h m s      days         15/2pi  =  2.3873241463784300365

*  History:
*     2012-03-08 (TIMJ):
*        Initial version from SLA/F using Fortran documentation
*        Adapted with permission from the Fortran SLALIB library.
*     2012-10-17 (TIMJ):
*        Fix range check on arcminute value.
*     {enter_further_changes_here}

*  Copyright:
*     Copyright (C) 1996 Rutherford Appleton Laboratory
*     Copyright (C) 2012 Science and Technology Facilities Council.
*     All Rights Reserved.

*  Licence:
*     This program is free software; you can redistribute it and/or
*     modify it under the terms of the GNU General Public License as
*     published by the Free Software Foundation; either version 3 of
*     the License, or (at your option) any later version.
*
*     This program is distributed in the hope that it will be
*     useful, but WITHOUT ANY WARRANTY; without even the implied
*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
*     PURPOSE. See the GNU General Public License for more details.
*
*     You should have received a copy of the GNU General Public License
*     along with this program; if not, write to the Free Software
*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
*     MA 02110-1301, USA.

*  Bugs:
*     {note_any_bugs_here}
*-
*/

#include "pal.h"
#include "palmac.h"
#include "pal1sofa.h"

#include <math.h>

void palDafin ( const char *string, int *ipos, double *a, int *j ) {

  int jd = 0;    /* Status for degree parsing */
  int jm = 0;    /* Status for arcmin parsing */
  int js = 0;    /* Status for arcsec parsing */
  int jf = 0;    /* Internal copy of status */
  double deg = 0.0;
  double arcmin = 0.0;
  double arcsec = 0.0;

  /* Decode degrees, arcminutes, arcseconds */
  palDfltin( string, ipos, &deg, &jd );
  if (jd > 1) {
    jf = -1;
  } else {

    palDfltin( string, ipos, &arcmin, &jm );
    if ( jm < 0 || jm > 1 ) {
      jf = -2;
    } else {

      palDfltin( string, ipos, &arcsec, &js );
      if (js < 0 || js > 1) {
        jf = -3;

      } else if (jd > 0) { /* See if combination of fields is credible */
        /* No degrees: arcmin, arcsec ought also to be absent */
        if (jm == 0) {
          /* Suspect arcmin */
          jf = -2;
        } else if (js == 0) {
          /* Suspect arcsec */
          jf = -3;
        } else {
          /* All three fields absent */
          jf = 1;
        }

      } else if (jm != 0 && js == 0) { /* Deg present: if arcsec present should have arcmin */
        jf = -3;

      /* Tests for range and integrality */
      } else if (jm == 0 && DINT(deg) != deg) { /* Degrees */
        jf = -1;

      } else if ( (js == 0 && DINT(arcmin) != arcmin) || arcmin >= 60.0 ) { /* Arcmin */
        jf = -2;

      } else if (arcsec >= 60.0) { /* Arcsec */
        jf = -3;
      }
    }
  }

  /* Unless all three fields absent, compute angle value */
  if (jf <= 0) {
    *a = PAL__DAS2R * ( 60.0 * ( 60.0 * fabs(deg) + arcmin) + arcsec );
    if ( jd < 0 ) *a *= -1.;
  }

  *j = jf;

}
