//
//  MainController_rec.m
//  VH7PC_Controller
//
//  Created by nya on 04/12/03.
//  Copyright 2004 __MyCompanyName__. All rights reserved.
//

//#import <CHSequenceGrabber/CHSequenceGrabber.h>
#import <WhackedSequenceGrabber/WhackedSG.h>
#import "Recoder.h"


#define VH7PC_DEVICE_NAME		@"Kenwood  Audio Device"
#define DEFAULT_REC_FILENAME	@"vh7pc"
#define DEFAULT_REC_EXTENSION	[self extension]


    #define BAILSETERR(x)               do { err = (x); if (err) { goto bail; } } while (0)


@implementation Recoder

- (NSString *) currentFilename {
	NSString *time = [[NSDate date] descriptionWithCalendarFormat:@"%Y%m%d_%H%M%S" timeZone:nil locale:nil];
	return [recordDir_ stringByAppendingPathComponent:time];
}

//- (void) recordWithName:(NSNotification *)not {
//	[self recordTo:[recordDir_ stringByAppendingPathComponent:[not object]]];
//}

/**
	filename.ext → filename_1.ext → filename_2.ext → ... → filename_10.ext → ....
*/
- (NSString *)incrementFilename:(NSString *)path {
	NSString *dir = [path stringByDeletingLastPathComponent];
	NSString *name = [[path lastPathComponent] stringByDeletingPathExtension];
	NSString *extension = [path pathExtension];
	int num = 0;
	
	NSArray *ary = [name componentsSeparatedByString:@"_"];
	if ([ary count] == 1) {
		//'_'がない
		num = 1;
	} else {
		num = [(NSString *)[ary lastObject] intValue] + 1;
		if (num != 1) {
			int idx = [name length] - [(NSString *)[ary lastObject] length] - 1;
			if (idx >= 0) {
				name = [name substringToIndex:idx];
			}
		}
		//num == 1の時はnameはそのまま
	}
	
	return [[dir stringByAppendingPathComponent:[name stringByAppendingString:[NSString stringWithFormat:@"_%d", num]]] stringByAppendingPathExtension:extension];
}

- (void)addAudioTrack
{
#pragma unused(sender)
	SeqGrab *mGrabber = grabber_;

	[mGrabber stop];
	SGAudio * audi = [[SGAudio alloc] initWithSeqGrab:mGrabber];
        // set the default preview volume very low to prevent 
        // feedback loop from microphone near speakers
    Float32 masterVolume = 1.0;
    NSString * prevDevice = nil;
    int i;
    
    if (audi != nil)
    {
			// Want to perform custom set-up on the audi channel?  Do it here.
		[audi setUsage:seqGrabPreview + seqGrabRecord + seqGrabPlayDuringRecord];

            // instead of just setting the master gain of the preview device very low,
            // first find out if there are any other audi channels using this
            // preview device.  If there are, retain their current volume
        [audi getPropertyWithClass: kQTPropertyClass_SGAudioPreviewDevice 
                    id:kQTSGAudioPropertyID_DeviceUID 
                    size:sizeof(prevDevice) 
                    address:&prevDevice 
                    sizeUsed:NULL];
            
            
        for (i = 0; i < [[mGrabber channels] count]; i++)
        {
            SGChan * chan = [[mGrabber channels] objectAtIndex:i];
            if (chan != audi && [chan isAudioChannel])
            {
                NSString * tempDev = nil;
                [(SGAudio*)chan getPropertyWithClass: kQTPropertyClass_SGAudioPreviewDevice 
                    id:kQTSGAudioPropertyID_DeviceUID 
                    size:sizeof(tempDev) 
                    address:&tempDev 
                    sizeUsed:NULL];
                    
                if ([prevDevice isEqualToString:tempDev])
                {
                    [(SGAudio*)chan getPropertyWithClass: kQTPropertyClass_SGAudioPreviewDevice 
                        id:kQTSGAudioPropertyID_MasterGain
                        size:sizeof(masterVolume) 
                        address:&masterVolume 
                        sizeUsed:NULL];
                        
                    [tempDev release];
                    break;
                }
                [tempDev release];
            }
        }
        
		[audi setPropertyWithClass: kQTPropertyClass_SGAudioPreviewDevice
								id: kQTSGAudioPropertyID_MasterGain
							  size: sizeof(Float32)
						   address: &masterVolume];
        
		
		[audi release]; // it was retained by its mGrabber

	}
	else {
        NSRunAlertPanel(@"WhackedTV", 
            @"Couldn't create an audio channel.  Check your audio device connections and try again.",
            nil, nil, nil);
    }
    
    if ( [[mGrabber channels] count] > 0)
	{
        //[mGrabber preview];
		chan_ = audi;
	}
    [prevDevice release];
}

// for the duration of the SGAudioSettings dialog, we want to preview.  But several
// properties can only be set when the channel is not in recording or previewing mode,
// so we'll call this method to stop/start the preview if we receive a -2200 error
// on the first try
- (OSStatus)setSGAudioPropertyWithClass:(ComponentPropertyClass)theClass
                                id:(ComponentPropertyID)theID
                                size:(ByteCount)sz
                                address:(ConstComponentValuePtr)addr
{
	SGAudio *mChan = chan_;

    OSStatus err = noErr;
    err = [mChan setPropertyWithClass: theClass 
								 id: theID 
							   size: sz 
						    address: addr];
                            
    if (err == kQTPropertyAskLaterErr)
    {
        //[self stopChannelPreview];
        
        err = [mChan setPropertyWithClass: theClass 
								 id: theID 
							   size: sz 
						    address: addr];
        
        //[self startChannelPreview];
    }
    
    return err;
}

- (void)selectRecordDevice:(NSString *)uid
{
	SGAudio *mChan = chan_;

    //NSArray *       deviceList = [mChan deviceList];
    //NSDictionary *  devDict = nil;
    OSStatus        err = noErr;
    
    //devDict = [deviceList objectAtIndex:[(NSMenuItem*)[sender selectedItem] tag]];
    
    if (uid)
    {
        //NSString * uid = [devDict objectForKey:(id)kQTAudioDeviceAttribute_DeviceUIDKey];
		NSString *		curDevUID = nil;
		
		BAILSETERR( [mChan getPropertyWithClass: kQTPropertyClass_SGAudioRecordDevice 
											 id: kQTSGAudioPropertyID_DeviceUID 
										   size: sizeof(curDevUID) 
										address: &curDevUID 
									   sizeUsed: NULL] );
		
		if ( NO == [curDevUID isEqualToString: uid] )
		{
			//[self stopChannelPreview];
			
			BAILSETERR( [self setSGAudioPropertyWithClass: kQTPropertyClass_SGAudioRecordDevice
												 id: kQTSGAudioPropertyID_DeviceUID
											   size: sizeof(uid)
											address: &uid] );
											
			// make sure we start off totally fresh, namely
			// 1. nuke record device layout
			// 2. nuke output layout
			// 3. nuke output magic cookie
			BAILSETERR( [mChan setPropertyWithClass: kQTPropertyClass_SGAudioRecordDevice 
									id: kQTSGAudioPropertyID_ChannelLayout 
								  size: 0  address:NULL] );
			BAILSETERR( [mChan setPropertyWithClass: kQTPropertyClass_SGAudio 
									id: kQTSGAudioPropertyID_ChannelLayout
								  size: 0  address:NULL] );
			BAILSETERR( [mChan setPropertyWithClass: kQTPropertyClass_SGAudio 
									id: kQTSGAudioPropertyID_MagicCookie
								  size: 0  address:NULL] );
			
			
			//[self startChannelPreview];
			//[self updateRecordDeviceControls:self];
		}
		
		[curDevUID release];
    }
bail:
    return;
}


#pragma mark-


- (id) init {
	self = [super init];
	if (!self) return nil;
	
	grabber_ = nil;
	recordDir_ = nil;
	status_ = REC_IDLE;
	playWhileRecording_ = YES;			//最大
	
	//[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(recordWithName:) name:@"RecordStartTo" object:nil];
	//[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(stop) name:@"RecordStop" object:nil];
	
	return self;
}

- (void) dealloc {
	[[NSNotificationCenter defaultCenter] removeObserver:self];

	if (status_ != REC_IDLE) {
		[self stop];
	}
	[recordDir_ release];
	
	[super dealloc];
}

- (int) status {
	return status_;
}

- (NSString *) throughMenuString {
	switch (status_) {
	case REC_IDLE:
	case REC_RECORD:
		return [[NSBundle mainBundle] localizedStringForKey:@"Play through" value:nil table:nil];
	case REC_THROUGH:
		return [[NSBundle mainBundle] localizedStringForKey:@"Stop through" value:nil table:nil];
	default:
		return nil;
	}
}

- (NSString *) recordMenuString {
	switch (status_) {
	case REC_IDLE:
	case REC_THROUGH:
		return [[NSBundle mainBundle] localizedStringForKey:@"Record" value:nil table:nil];
	case REC_RECORD:
		return [[NSBundle mainBundle] localizedStringForKey:@"Stop Record" value:nil table:nil];
	default:
		return nil;
	}
}

- (void) recordWithName:(NSString *)name {
	[self recordTo:[recordDir_ stringByAppendingPathComponent:name]];
}

- (long) recordTo:(NSString *)pathname {
	long err = 0;
	NSString *path = pathname ? [pathname stringByAppendingPathExtension:DEFAULT_REC_EXTENSION] : nil;
    //Float32 masterVolume = 0.5;
	
	NSLog(@"recordTo %@", path ? path : @"nil");
	
	if (status_ == REC_THROUGH) {
		if (path) {
			err = [self stop];
			if (err) {
				return err;
			}
		} else {
			return [self stop];
		}
	} else if (status_ == REC_RECORD) {
		if (path) {
			return [self stop];
		} else {
			err = [self stop];
			if (err) {
				return err;
			}
		}
	}

	grabber_ = [[SeqGrab alloc] init];
	[grabber_ setIdleFrequency:[[[[NSBundle mainBundle] infoDictionary] objectForKey:@"IdleFrequency"] intValue]];
	/*
	{
		NSEnumerator	*enu = [[grabber_ channels] objectEnumerator];
		id				obj;
		
		while (obj = [enu nextObject]) {
			if ([obj isAudioChannel]) {
				NSEnumerator	*aenu = [[obj deviceList] objectEnumerator];
				id				aobj;
				NSString		*aname, *uid;
				
				while (aobj = [aenu nextObject]) {
					aname = [aobj objectForKey:(id)kQTAudioDeviceAttribute_DeviceNameKey];		//デバイス名
					uid = [aobj objectForKey:(id)kQTAudioDeviceAttribute_DeviceNameKey];		//uid
					if ([aname compare:VH7PC_DEVICE_NAME] == NSOrderedSame) {
						chan_ = [obj retain];
					
						[chan_ setPropertyWithClass: kQTPropertyClass_SGAudioRecordDevice
												 id: kQTSGAudioPropertyID_DeviceUID
											   size: sizeof(uid)
											address: &uid];
					}
				}
			}
		}
	}
	*/
	
	[self addAudioTrack];

	//chan_ = [[SGAudio alloc] initWithSeqGrab:grabber_];
			{
				NSEnumerator	*aenu = [[chan_ recordCapableDeviceList] objectEnumerator];
				id				aobj;
				NSString		*aname, *uid;
				
				while (aobj = [aenu nextObject]) {
					aname = [aobj objectForKey:(id)kQTAudioDeviceAttribute_DeviceNameKey];		//デバイス名
					uid = [aobj objectForKey:(id)kQTAudioDeviceAttribute_DeviceUIDKey];		//uid
					if ([aname compare:VH7PC_DEVICE_NAME] == NSOrderedSame) {
						[self selectRecordDevice:uid];
						break;
					}
				}
			}
	/*		
	[chan_ setUsage:seqGrabPreview + seqGrabRecord + seqGrabPlayDuringRecord];
	[chan_ setPropertyWithClass: kQTPropertyClass_SGAudioPreviewDevice
								id: kQTSGAudioPropertyID_MasterGain
							  size: sizeof(Float32)
						   address: &masterVolume];

	[grabber_ addChannel:chan_];
	*/
	
	/*
	grabber_ = [[CHAudioGrabber alloc] init];
	
	err = [grabber_ enterAudio];
	if (err) {
		goto bail;
	}

	err = [grabber_ setSoundDeviceWithName:VH7PC_DEVICE_NAME];
	if (err) {
		goto bail;
	}
	
	err = [grabber_ setAudioVolume:(!path || (path && playWhileRecording_) ? 0x0100 : 0x8100)];
	if (err) {
		goto bail;
	}
	*/
	
	[chan_ setConfigureWithDictionary:channelsetting_];
	
	if (path) {
		if (!playWhileRecording_) [chan_ setUsage:seqGrabRecord];
		err = [grabber_ setCapturePath:path flags:seqGrabToDisk | seqGrabDontPreAllocateFileSize];
		err = [grabber_ record];
	} else {
		err = [grabber_ preview];
	}
	
	//開始
	//err = [grabber_ startRecordTo:path];
	if (err) {
		goto bail;
	}

bail:
	if (err) {
		NSLog(@"recordTo err = %d", err);
		[grabber_ release];
		grabber_ = nil;
		[chan_ release];
		chan_ = nil;
	} else {
		status_ = path ? REC_RECORD : REC_THROUGH;
		[[NSNotificationCenter defaultCenter] postNotificationName:@"MenuImageUpdateNotification" object:nil];
	}
	return err;
}


- (long) playThrough {
	return [self recordTo:nil];
}

- (long) record {
	return [self recordTo:[self currentFilename]];
}

- (long) stop {
	NSLog(@"stop");

	if (status_ == REC_IDLE) {
		return -1;
	}

	long err = 0;
	
	//err = [grabber_ stopRecord];
	err = [(SeqGrab *)grabber_ stop];
	if (err) {
		goto bail;
	}
	/*
	err = [grabber_ exit];
	if (err) {
		goto bail;
	}
	*/
	
bail:
	[grabber_ release];
	grabber_ = nil;
	//[chan_ release];
	chan_ = nil;
	
	if (!err) {
		status_ = REC_IDLE;
		[[NSNotificationCenter defaultCenter] postNotificationName:@"MenuImageUpdateNotification" object:nil];
	}
	return err;
}

- (long) setting {
	long err = 0;
	int stat = [self status];

	if (stat == REC_RECORD) {
		NSBeep();
		return 1;
	}

	if (stat != REC_THROUGH) {
		[self playThrough];
	}
	
	[(SeqGrab *)grabber_ stop];
	err = [chan_ runConfigureDialog];
	//NSLog([[chan_ setting] description]);
	
	[channelsetting_ release];
	channelsetting_ = [[chan_ configureDictionary] retain];
	
	if (stat == REC_THROUGH) {
		[self playThrough];
	} else {
		[self stop];
	}
	return err;
}

- (void) settingWithDictionary:(NSDictionary *)dic {
	[channelsetting_ release];
	channelsetting_ = [dic retain];
}

- (NSDictionary *) settingDictionary {
	return channelsetting_;
}

- (NSString *) format {
	NSString		*res;
	
	res = [channelsetting_ objectForKey:@"Format"];
	if (res) return res;
	return @"PCM";
}

- (NSString *) extension {
	NSString		*res;
	
	res = [channelsetting_ objectForKey:@"Extension"];
	if (res) return res;
	return @"aiff";
}

- (void) setRecordDir:(NSString *)path {
	[recordDir_ release];
	recordDir_ = [path retain];
	[recordDestField_ setStringValue:recordDir_];
}

- (NSString *) recordDir {
	return recordDir_;
}

- (void) setPlayWhileRecording:(BOOL)b {
	playWhileRecording_ = b;
	[playWhileRecCheck_ setState:b ? NSOnState : NSOffState];
}

- (BOOL ) playWhileRecording {
	return playWhileRecording_;
}

- (IBAction) changeRecordDest:(id) sender {
    NSOpenPanel *opFile=[NSOpenPanel openPanel];
    int tmp;

	[opFile setCanChooseFiles:NO];
	[opFile setCanChooseDirectories:YES];
    tmp=[opFile runModalForTypes:[NSArray arrayWithObject:@""]];
    if(tmp==NSOKButton){
        [self setRecordDir:[opFile filename]];
    }
}

@end
