//-----------------------------------------------------------------------------
// Copyright © 2004 - Philip Howard - All rights reserved
//
// 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 2
// 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//-----------------------------------------------------------------------------
// package	libh/time
// homepage	http://libh.slashusr.org/
//-----------------------------------------------------------------------------
// author	Philip Howard
// email	libh at ipal dot org
// homepage	http://phil.ipal.org/
//-----------------------------------------------------------------------------
// This file is best viewed using a fixed spaced font such as Courier
// and in a display at least 120 columns wide.
//-----------------------------------------------------------------------------

#include "time_lib.h"

__PROTO_BEGIN__
//-----------------------------------------------------------------------------
// function	str_cal_to_etime
//
// purpose	Convert date and time in a string to type etime.
//
// arguments	1 (const char *) date and time string
//		2 (eday_t (*)(long,int,int)) function to do conversion
//
// returns	(etime_t) == ETIME_MIN: error
//		(etime_t) == ETIME_MAX: error
//		(etime_t) date and time converted
//
// format	yyyy/mm/dd_hh:mm:ss.nnnnnn[nnnnnnnnnnnn]
//
// note		Any non-numeric character may be used as separators, but
//		such use should be limited to reasonable punctuation only
//		for future compatibility.
//-----------------------------------------------------------------------------
etime_t
str_cal_to_etime (
    const char *	arg_str
    ,
    eday_t ( *		arg_fun		)( long, int, int )
    )
__PROTO_END__
{
    etime_t	etime	;


    if ( ! arg_str ) return ETIME_ERROR;

    {
	long	year	;
	int	month	;
	int	mday	;
	int	neg	;
	int	ch	;


	//--------------
	// Convert year.
	//--------------
	neg = 0;
	if ( ( ch = * arg_str ) == '-' ) {
	    neg = 1;
	    ++ arg_str;
	}
	else if ( ( ch = * arg_str ) == '+' ) {
	    ++ arg_str;
	}
	for ( year = 0; ( ch = * arg_str ) >= '0' && ch <= '9'; ++ arg_str ) {
	    year *= 10;
	    year += ch - '0';
	}
	if ( ( ( ch == 'a' || ch == 'A' ) && ( arg_str[1] == 'd' || arg_str[1] == 'D' ) ) ||
	     ( ( ch == 'c' || ch == 'C' ) && ( arg_str[1] == 'e' || arg_str[1] == 'E' ) ) ) {
	    arg_str += 2;
	}
	else if ( ( ch == 'b' || ch == 'B' ) && ( arg_str[1] == 'c' || arg_str[1] == 'C' ) ) {
	    year = 1 - year;
	    arg_str += 2;
	    if ( ( ch = * arg_str ) == 'e' || ch == 'E' ) ++ arg_str;
	}
	else if ( neg ) {
	    year = 0 - year;
	}
	if ( * arg_str ) ++ arg_str;

	//---------------
	// Convert month.
	//---------------
	for ( month = 0; ( ch = * arg_str ) >= '0' && ch <= '9'; ++ arg_str ) {
	    month *= 10;
	    month += ch - '0';
	}
	if ( * arg_str ) ++ arg_str;

	//----------------------
	// Convert day of month.
	//----------------------
	for ( mday = 0; ( ch = * arg_str ) >= '0' && ch <= '9'; ++ arg_str ) {
	    mday *= 10;
	    mday += ch - '0';
	}
	if ( * arg_str ) ++ arg_str;

	//----------------------------------------------
	// Convert to eday format and check etime range.
	//----------------------------------------------
	etime = (* arg_fun)( year, month, mday );
	if ( etime > EDAY_ETIME_MAX ) return ETIME_MAX;
	if ( etime < EDAY_ETIME_MIN ) return ETIME_MIN;

	//----------------------------------------
	// If we are still here, convert to etime.
	//----------------------------------------
	etime *= ETIME_C( 86400000000 );
    }

    //--------------
    // Convert hour.
    //--------------
    if ( * arg_str ) {
	etime_t		ehour	;
	int		hour	;
	int		ch	;

	for ( hour = 0; ( ch = * arg_str ) >= '0' && ch <= '9'; ++ arg_str ) {
	    hour *= 10;
	    hour += ch - '0';
	}
	ehour = (etime_t) hour;
	ehour *= ETIME_C(3600000000);
	if ( etime > ETIME_MAX - ehour ) return ETIME_MAX;
	if ( etime < ETIME_MIN + ehour ) return ETIME_MIN;
	etime += ehour;
	if ( * arg_str ) ++ arg_str;
    }

    //----------------
    // Convert minute.
    //----------------
    if ( * arg_str ) {
	etime_t		eminute	;
	int		minute	;
	int		ch	;

	for ( minute = 0; ( ch = * arg_str ) >= '0' && ch <= '9'; ++ arg_str ) {
	    minute *= 10;
	    minute += ch - '0';
	}
	eminute = (etime_t) minute;
	eminute *= ETIME_C(60000000);
	if ( etime > ETIME_MAX - eminute ) return ETIME_MAX;
	if ( etime < ETIME_MIN + eminute ) return ETIME_MIN;
	etime += eminute;
	if ( * arg_str ) ++ arg_str;
    }

    //----------------
    // Convert second.
    //----------------
    if ( * arg_str ) {
	etime_t		esecond	;
	int		second	;
	int		ch	;

	for ( second = 0; ( ch = * arg_str ) >= '0' && ch <= '9'; ++ arg_str ) {
	    second *= 10;
	    second += ch - '0';
	}
	esecond = (etime_t) second;
	esecond *= ETIME_C(1000000);
	if ( etime > ETIME_MAX - esecond ) return ETIME_MAX;
	if ( etime < ETIME_MIN + esecond ) return ETIME_MIN;
	etime += esecond;
	if ( * arg_str ) ++ arg_str;
    }

    //----------------------------
    // Convert fraction of second.
    //----------------------------
    if ( * arg_str ) {
	long		fract	;
	long		scale	;
	int		ch	;

	scale = 1000000;
	for ( fract = 0; ( ch = * arg_str ) >= '0' && ch <= '9'; ++ arg_str ) {
	    if ( scale > 1 ) {
		fract *= 10;
		fract += ch - '0';
		scale /= 10;
	    }
	}
	fract *= scale;
	if ( etime > ETIME_MAX - fract ) return ETIME_MAX;
	if ( etime < ETIME_MIN + fract ) return ETIME_MIN;
	etime += fract;
	if ( * arg_str ) ++ arg_str;
    }

    return etime;
}

