/*
 * Copyright (c) 2002, Peter Bentley
 * 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.
 * 
 *   The name Peter Bentley may not 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
 * OWNER 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.
 *
 *
 *
 * ** omd_time.c - Time stuff
 */
#include <stdio.h>
#include <string.h>
#include "omd.h"

CVSID( "$Id: omd_time.c,v 1.8 2002/11/07 09:09:12 pete Exp $" );

#define DECIMAL( x )	( ( 10 * ( (x) >> 4) ) + ( (x) & 0x0f ))
#define BCD( x )	( (((x) / 10) << 4) | ((x) % 10 ))
#define FRAMES_PER_SEC	86	/* Not sure this is right yet */

int omd_time_from_bytes( omd_time_t *t, uint8 *data )
{
    int hours;

    if( t == NULL )
    {
	return -1;
    }

    hours = DECIMAL( data[0] );
    t->minutes = (60 * hours) + DECIMAL( data[1] );
    t->seconds = DECIMAL( data[2] );
    t->frames = DECIMAL( data[3] );

    return 0;
}

/*****************************************************************************
 * Convert time to BCD where highest byte is hundred of minutes, not hours
 */
uint32 omd_time_to_bcd( omd_time_t *t )
{
    uint32 bcd = 0;

    bcd |= BCD( t->minutes / 100 ) << 24;
    bcd |= BCD( t->minutes % 100 ) << 16;
    bcd |= BCD( t->seconds ) << 8;
    bcd |= BCD( t->frames );

    slog( LOG_DEBUG, "BCD Value: %08x", bcd );
    return bcd;
}


void omd_time_from_double( omd_time_t *t, double val )
{
    t->minutes = (int) ( val / 60.0 );

    val -= 60.0 * (double) t->minutes;
    t->seconds = (int) val;

    val -= (double) t->seconds;

    /* Remainder left in value should just be the fractional part */
    t->frames = (int) ( val * FRAMES_PER_SEC );
}

double omd_time_to_double( omd_time_t *t )
{
    return 60.0 * t->minutes
            + (double) t->seconds
            + (double) t->frames / (double) FRAMES_PER_SEC;
}



char *omd_time_to_string( omd_time_t *t, char *buffer )
{	
    static char statbuf[12];

    /* If they pass a NULL buffer in, use the static one for convenience */
    if( buffer == NULL )
	buffer = statbuf;

    if( t->minutes > 60 )
    {
	int hours = t->minutes / 60;
	int minutes = t->minutes - (60 * hours );
	
	sprintf( buffer, "%d:%02d:%02d.%02d", hours, minutes,
		 t->seconds, t->frames );
    }
    else
    {
	sprintf( buffer, "%d:%02d.%02d", t->minutes, t->seconds, t->frames );
    }
    return buffer;
}

void omd_time_add( omd_time_t *to, omd_time_t *amt )
{
    to->frames += amt->frames;
    while( to->frames >= FRAMES_PER_SEC )
    {
	to->seconds++;
	to->frames -= FRAMES_PER_SEC;
    }

    to->seconds += amt->seconds;
    while( to->seconds >= 60 )
    {
	to->minutes++;
	to->seconds -= 60;
    }

    to->minutes += amt->minutes;
}

int omd_time_from_string( omd_time_t *t, const char *string )
{
    char buffer[16];
    char *ptr[3], *dot, *str;
    char **this;
    int num;

    if( strlen( string ) > 15 )
    {
	slog( LOG_ERROR, "Invalid time string '%s' (too long)", string );
	return -1;
    }
    strcpy( buffer, string );

    /* Zero out the time struct */
    memset( t, 0, sizeof( *t ));

    /* Strip off any frame part first */
    dot = strchr( buffer, '.' );
    if( dot )
    {
	*dot = '\0';
	dot++;
	t->frames = atoi( dot );
	if( t->frames >= FRAMES_PER_SEC )
	{
	    slog( LOG_ERROR, "Invalid time string: frames too big" );
	    return -1;
	}
    }

    /* Tokenise the rest on the colons */
    num = 0;
    for( str = strtok( buffer, ":" ); str != NULL; str = strtok( NULL, ":" ) )
    {
	if( num >= 3 )
	{
	    slog( LOG_ERROR, "Invalid time string: too many colons" );
	    return -1;
	}
	ptr[num++] = str;
    }

    this = ptr;
    if( num == 3 )
    {
	t->minutes = 60 * atoi( *this++ );
	num--;
    }
    if( num == 2 )
    {
	t->minutes += atoi( *this++ );
	num--;
    }
    if( num == 1 )
    {
	t->seconds = atoi( *this );
    }
    return 0;
}

