// 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.


#import "OmdUnit.h"
#import "OmdDisc.h"
#import "OmdToc.h"
#import "OmdPosition.h"
#import "OmdTime.h"
#import "OmdTrackInfo.h"
#import "OmdGroupInfo.h"

CVSID( "$Id: OmdUnit.m,v 1.22 2002/11/24 12:44:33 pete Exp $");

@implementation OmdUnit

- (id) init
{
    if( (self = [super init]) != nil )
    {
        hasDisc = NO;
        triedDisc = NO;
        toc = nil;
    }
    return self;
}



- (void) dealloc
{
    if( unit )
    {
        omd_close_unit( unit );
    }
    if( toc )
    {
        [toc release];
    }
    [super dealloc];
}

- (void) setUnit: (omd_unit_t *) theUnit
{
    if( unit )
    {
        omd_close_unit( unit );
    }
    unit = theUnit;
    slog( LOG_DEBUG, "Opening unit..." );
    if( omd_open_unit( unit ) < 0 )
    {
        slog( LOG_WARNING, "omd_open_unit failed" );
    }
    [omdDisc refresh];
}


- (omd_unit_t *) unit
{
    return unit;
}



- (NSString *) description
{
    NSString *result;

    if( unit )
    {
        result = [[NSString alloc] initWithFormat: @"OmdUnit at %p", unit];
    }
    else
    {
            result = [[NSString alloc] initWithFormat: @"OmdUnit"];
    }
    [result autorelease];
    return result;
}

- (NSString *) unitTypeString
{
    if( unit )
    {
        return [[NSString alloc] initWithCString: unit->info->description];
    }
    else
    {
        return @"Unknown";
    }
}

- (int) unitStatus
{
    omd_playback_status_b_t	status_b;

    if( !unit )
    {
        return -1;
    }

    if( omd_get_playback_status_b( unit, &status_b ) < 0 )
    {
        return -1;
    }
    // slog_hex( LOG_DEBUG, "B::   ", status_b.raw, 6 );

    return status_b.playback_mode;

}

- (NSString *) unitStatusString 
{
    return [self stringForStatus: [self unitStatus]];
}

- (NSString *) stringForStatus: (int) status
{
    NSString *ret = @"Unknown!";

    switch( status )
    {
        case OMD_PLAY:
            ret = @"Playing";
            break;

        case OMD_STOPPED:
            ret = @"Stopped";
            break;

        case OMD_PAUSED:
            ret = @"Paused";
            break;

        case OMD_REWIND:
            ret = @"Rewinding";
            break;

        case OMD_FFORWARD:
            ret = @"Fast forwarding";
            break;
    }

    return ret;
}

- (NSString *) playbackPositionString
{
    NSString *ret = @"Unknown";
    omd_playback_position_t	position;

    if( !unit )
    {
        return [[NSString alloc] initWithFormat: @"Unknown"];
    }

    if( unit )
    {
	if( omd_get_playback_position( unit, &position ) == NULL )
	{
	    slog( LOG_ERROR, "Get playback position failed" );
	}
	else
	{
	    slog_hex( LOG_DEBUG, "Pos   ", position.raw, 11 );
	    ret = [[NSString alloc] initWithFormat: @"Track %d, %s\n", 
				    position.track + 1,
				    omd_time_to_string( &position.position, NULL )];
	}
    }
    return ret;
}



// XXX - Cache return value for a short period (half a second?)
- (BOOL) discInserted: (BOOL) useCached
{
    omd_unit_status_t	status;
    if( !useCached  || !triedDisc )
    {
        if( omd_get_unit_status( unit, &status ) == NULL )
        {
            slog( LOG_WARNING, "discInserted: get_unit_status failed" );
            hasDisc = NO;
        }
        else
        {
            hasDisc = status.disc_inserted;
        }
        triedDisc = YES;
    }
    return hasDisc;
}

- (OmdDisc *) getDisc
{
    return omdDisc;
}

- (OmdToc *) toc
{
    if( ! toc )
    {
        omd_toc_t *t = omd_toc_read( unit, NULL, TRUE, FALSE );
        if( t )
        {
            toc = [[OmdToc alloc] initWithCToc: t unit: self];
        }
    }
    return toc;
}

- (int) tocRefresh: (OmdToc *) theToc
{
    return omd_toc_refresh_tracks( unit, [theToc ctoc], NULL );
}

- (omd_track_t *) rawTrackInfo: (int) trk
{
    omd_toc_t	*ctoc = [toc ctoc];
    omd_track_t *cinfo = omd_toc_track_info( unit, ctoc, trk);

    return cinfo;
}

- (omd_group_t *) rawGroupInfo: (int) grp
{
    omd_toc_t	*ctoc = [toc ctoc];
    omd_group_t *cinfo = omd_toc_get_group( ctoc, grp );
    return cinfo;
}


- (OmdPosition *) getPlaybackPosition
{
    omd_playback_position_t	pos;
    OmdTime			*time;
    OmdPosition			*omdpos;
    
    if( omd_get_playback_position( unit, &pos ) == NULL )
    {
        return nil;
    }
    time = [[OmdTime alloc] initWithTime: &pos.position];
    [time autorelease];
    omdpos = [[OmdPosition alloc] initWithTrack: pos.track andTime: time];
    [omdpos autorelease];
    return omdpos;
}


- (int) setPlaybackPosition: (OmdPosition *) newpos
{
    omd_playback_position_t	pos;
    
    pos.track = [newpos track];
    omd_time_from_double( &pos.position, [[newpos time] doubleValue] );    
    return omd_set_playback_position( unit, &pos );
}

- (int) setTrack: (int) t title: (NSString *) str
{
    const char *cstr = [str lossyCString];
    
    // XXX Find the old disc info struct to pass in
    return omd_rename_track( unit, t, NULL, cstr );
}

- (int) setGroup: (int) g title: (NSString *) str
{
    const char *cstr = [str lossyCString];
    
    if( omd_toc_rename_group( [toc ctoc], g, cstr ) < 0 )
    {
        slog( LOG_ERROR, "setGroup: %d title: %s failed", g, str );
        return -1;
    }
        
    if( omd_toc_write_title( unit, [toc ctoc] ) < 0 )
    {
        slog( LOG_ERROR, "setGroup: %d title: %s write failed", g, str );
        return -1;
    }
    
    if( omd_toc_read_groups( unit, [toc ctoc] ) < 0 )
    {
        slog( LOG_ERROR, "setGroup: %d title: %s reread failed", g, str );
        return -1;
    }
    return 0;
}



- (int) play
{
    return netmd_start_playback( unit );
}

- (int) stop
{
    return netmd_stop_playback( unit );
}

- (int) pause
{
    return netmd_pause_playback( unit );
}
- (int) fforward
{
    return netmd_start_fforward( unit );
}

- (int) rewind
{
    return netmd_start_rewind( unit );
}

- (int) nextTrack
{
    omd_playback_position_t	pos;
    if( omd_get_playback_position( unit, &pos ) == NULL )
    {
        return -1;
    }

    if( pos.track >= [omdDisc numTracks] - 1 )
    {
        return -1;
    }
    return omd_set_playback_track( unit, pos.track + 1 );
}

- (int) previousTrack
{
    omd_playback_position_t	pos;
    if( omd_get_playback_position( unit, &pos ) == NULL )
    {
        return -1;
    }
    if( pos.track <= 0 )
    {
        return -1;
    }
    return omd_set_playback_track( unit, pos.track - 1 );
}


@end
