// modified by Rob Burns <rburns@softhome.net>
/*
**  OGGEditor.m
**
**  Copyright (c) 2002
**
**  Author: Yen-Ju  <yjchenx@hotmail.com>
**
**  This program is free software; you can redistribute it and/or modify
**  it under the terms of the GNU Lesser 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 Lesser 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
*/

#include "OGGEditor.h"
#include <vorbis/vorbisfile.h>
#include "vcedit.h"

@implementation OGGEditor

- (void) dealloc
{
  ov_clear(&vf);
  //fclose(in);
  RELEASE(_info);
  RELEASE(_fname);
  RELEASE(_comments);
  [super dealloc];
}

- (BOOL) writeToFile: (NSString *) name
{
  int i;
  FILE *out;
  vcedit_state *state;
  vorbis_comment *vc;
  NSString *newfile;
  BOOL ret = NO;
  
  RETAIN(name);

  fseek(in, 0L, SEEK_SET);

  state = vcedit_new_state();

  if (vcedit_open(state, in) < 0) {
      vcedit_clear(state);
      return NO;
  }    

  vc = vcedit_comments(state);
  vorbis_comment_clear(vc);
  vorbis_comment_init(vc);

  for(i=0;i<[_comments count];i++)
    {
      if([[_comments objectAtIndex: i] objectForKey: @"value"] != nil &&
        ![[[_comments objectAtIndex: i] objectForKey: @"value"] isEqualToString: @""])
        {
          vorbis_comment_add_tag(vc, 
            (char *)[[[_comments objectAtIndex: i] objectForKey: @"tag"] cString], 
            (char *)[[[_comments objectAtIndex: i] objectForKey: @"value"] UTF8String]);
        }
    }


//  for(i = 0; i < state->vc->comments; i++)
//    {
//      NSLog(@"New: %s", state->vc->user_comments[i]);
//    }


  if ([name isEqualToString: _fname])
    {
      newfile = [name stringByAppendingString:@"_temp"];
    }
  else
    {
      newfile = name;
    }

  out = fopen([newfile cString], "w");

  if (out == NULL) {
      NSLog(@"fopen failed: %@", newfile);
      fclose(out);
      return NO;
  }
  
  if(vcedit_write(state, out) < 0)
    {
      NSLog(@"Failed to write comments to file %@", newfile);
      ret = NO;
    }

  vorbis_comment_clear(vc);
  vcedit_clear(state);
  fclose(out);

  if ([name isEqualToString: _fname])
    {
      NSFileManager *manager = [NSFileManager defaultManager];
      [manager removeFileAtPath: name handler: nil];
      [manager movePath: newfile toPath: name handler: nil];
      ret = YES;
    }
  RELEASE(name);
  return ret;
}

- (id) initWithFile: (NSString *) name
{
  NSMutableArray *rawComments;
  int i;
  vorbis_info *vi;
  vorbis_comment *vc;

  self = [super init];
  rawComments = [NSMutableArray new];
  _info = [NSMutableDictionary new];

  ASSIGN(_fname, name);

  in = fopen([_fname cString], "r");

  if(ov_open(in, &vf, NULL, 0) < 0)
    {
      NSLog(@"ov_open Can't open %@", name);
      return nil;
    }

  [_info setObject: [NSNumber numberWithInt: (int)ov_time_total(&vf, -1)] 
    forKey: @"Seconds"];

  vc = ov_comment(&vf, -1);

  for (i = 0; i < vc->comments; i++)
    {
      NSString *comment = [NSString stringWithUTF8String: vc->user_comments[i]];
      NSArray *array = [comment componentsSeparatedByString: @"="];
      if ([array count] != 2)
        continue;

      [rawComments addObject: [NSMutableDictionary dictionaryWithObjectsAndKeys:
        [[array objectAtIndex: 0] uppercaseString], @"tag", 
        [array objectAtIndex: 1], @"value", nil]];
    }

  _comments = [[NSMutableArray alloc] initWithArray: 
    [[Util singleInstance] formatComments: rawComments]];

  vi = ov_info(&vf, -1);
  [_info setObject: [NSNumber numberWithInt: vi->channels] forKey: @"Channels"];
  [_info setObject: [NSNumber numberWithFloat: vi->rate/1000.0] forKey: @"Rate"];

  if (vi->bitrate_nominal > 0)
    [_info setObject: [NSNumber numberWithDouble: vi->bitrate_nominal/1000.0]
             forKey: @"Bitrate Nominal"];

  if (vi->bitrate_upper > 0)
    [_info setObject: [NSNumber numberWithDouble: vi->bitrate_upper/1000.0]
             forKey: @"Bitrate Upper"];

  if (vi->bitrate_lower > 0)
    [_info setObject: [NSNumber numberWithDouble: vi->bitrate_lower/1000.0]
             forKey: @"Bitrate Lower"];

  [_info setObject: [NSNumber numberWithLong: (long)ov_pcm_total(&vf, -1)]
           forKey: @"Decoded Length"];

  vorbis_comment_clear(vc);
  vorbis_info_clear(vi);

  return self;
}

- (NSNumber *) decodedLength
{
  return [_info objectForKey: @"Decoded Length"];
}

- (NSNumber *) lowerOfBitrate
{
  return [_info objectForKey: @"Bitrate Lower"];
}

- (NSNumber *) upperOfBitrate
{
  return [_info objectForKey: @"Bitrate Upper"];
}

- (NSNumber *) nominalOfBitrate
{
  return [_info objectForKey: @"Bitrate Nominal"];
}

- (NSNumber *) rate
{
  return [_info objectForKey: @"Rate"];
}

- (NSNumber *) channels
{
  return [_info objectForKey: @"Channels"];
}

- (NSNumber *) seconds
{
  return [_info objectForKey: @"Seconds"];
}

- (NSString *) filename
{
  return _fname;
}

- (NSArray *) comments
{
  return [NSArray arrayWithArray: _comments];
}

- (void) addComment: (NSMutableDictionary *)comment
{
  NSMutableArray *temp;

  temp = [NSMutableArray arrayWithArray: _comments];
  RELEASE(_comments);
  [temp addObject: comment];

  _comments = [[NSMutableArray alloc] initWithArray: [[Util singleInstance] formatComments: temp]];
}

- (void) deleteCommentAtIndex: (int) index
{
  if(index <= [_comments count])
    {
      [_comments removeObjectAtIndex: index];
    }
}

// NSTableView data source protocol methods
//******************************************

- (int) numberOfRowsInTableView: (NSTableView *)aTableView
{
  return [_comments count];
}

- (id) tableView: (NSTableView *)aTableView
  objectValueForTableColumn: (NSTableColumn *)aTableColumn
                        row: (int)rowIndex
{
  NSString *theValue;

  NSParameterAssert(rowIndex >= 0);

  if( [[aTableColumn identifier] isEqualToString: @"title"] )
    {
      theValue = [[_comments objectAtIndex: rowIndex] objectForKey: @"title"];
      return theValue;
    }
  if( [[aTableColumn identifier] isEqualToString: @"value"] )
    {
      theValue = [[_comments objectAtIndex: rowIndex] objectForKey: @"value"];
      return theValue;
    }
  else
    {
      return nil;
    }
}

- (void) tableView: (NSTableView *)aTableView setObjectValue: (id)anObject
    forTableColumn: (NSTableColumn *)aTableColumn row: (int)rowIndex
{
  NSParameterAssert(rowIndex >= 0);

  [[_comments objectAtIndex: rowIndex] setObject: anObject forKey:
    [aTableColumn identifier]];
}

@end
