// 
//  Lynkeos
//  $Id: MyUserPrefsController.m,v 1.5 2005/02/01 22:55:52 j-etienne Exp $
//
//  Created by Jean-Etienne LAMIAUD on Sun Feb 8 2004.
//  Copyright (c) 2003-2005. Jean-Etienne LAMIAUD
//
// 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.
//

#import "MyUserPrefsController.h"

static MyUserPrefsController *instancePointer = nil;

@interface MyUserPrefsController(Private)

- (void) getNumericPref :(double*)pref 
                  forKey:(NSString*)key
                minValue:(double)minv 
                maxValue:(double)maxv ;
- (void)initPrefsValue;
- (void) readPrefs ;
- (void) savePrefs ;
- (void) updatePanel ;
@end

@implementation MyUserPrefsController(Private)

- (void) getNumericPref :(double*)pref 
                  forKey:(NSString*)key
                minValue:(double)minv 
                maxValue:(double)maxv
{
#ifdef GNUSTEP
   double v = [_user floatForKey:key];

   if ( v < minv )
     v = minv;
   else if ( v > maxv )
     v = maxv;
   *pref = v;
#else
   NSString* stringValue = [_user stringForKey:key];
   double v;

   if ( stringValue != nil )
   {
      v = [stringValue doubleValue];
      if ( v < minv )
         v = minv;
      else if ( v > maxv )
         v = maxv;
      *pref = v;
   }
#endif
}

- (void)initPrefsValue
{
   // Set the factory defaults value
   _adjustFFTSizes = YES;
   _alignFrequencyCutoff = 0.41;
   _alignThreshold = 0.125;
   _alignImageUpdating = YES;
   _alignMultiProc = ListThreadsOptimizations;
   _analysisLowerCutoff = 0.125;
   _analysisUpperCutoff = 0.7;
   _analysisImageUpdating = NO;
   _analysisMultiProc = ListThreadsOptimizations;
   _stackImageUpdating = NO;
   _stackMultiProc = YES;
   _processMultiProc = YES;
}

- (void) readPrefs 
{
   u_short opt;

   // Set all values to their factory defaults
   [self initPrefsValue];

   // Update with database value, if any
   if ( [_user objectForKey:K_PREF_ADJUST_FFT_SIZES] != nil ){
      _adjustFFTSizes = [_user boolForKey:K_PREF_ADJUST_FFT_SIZES];
   }
   [self getNumericPref:&_alignFrequencyCutoff 
                 forKey:K_PREF_ALIGN_FREQUENCY_CUTOFF
               minValue:0.0 maxValue:0.71];
   [self getNumericPref:&_alignThreshold 
                 forKey:K_PREF_ALIGN_PRECISION_THRESHOLD
               minValue:0.0 maxValue:1.0];
   if ( [_user objectForKey:K_PREF_ALIGN_IMAGE_UPDATING] != nil ){
      _alignImageUpdating = [_user boolForKey:K_PREF_ALIGN_IMAGE_UPDATING];
   }
   if ( [_user objectForKey:K_PREF_ALIGN_MULTIPROC] != nil &&
        (opt = [_user integerForKey:K_PREF_ALIGN_MULTIPROC]) 
        <= ListThreadsOptimizations ){
     _alignMultiProc = opt;
   }
   [self getNumericPref:&_analysisLowerCutoff 
                 forKey:K_PREF_ANALYSIS_LOWER_CUTOFF
               minValue:0.0 maxValue:0.71];
   [self getNumericPref:&_analysisUpperCutoff 
                 forKey:K_PREF_ANALYSIS_UPPER_CUTOFF
               minValue:0.0 maxValue:0.71];
   if ( [_user objectForKey:K_PREF_ANALYSIS_IMAGE_UPDATING] != nil ){
      _analysisImageUpdating = [_user boolForKey:K_PREF_ANALYSIS_IMAGE_UPDATING];
   }
   if ( [_user objectForKey:K_PREF_ANALYSIS_MULTIPROC] != nil &&
        (opt = [_user integerForKey:K_PREF_ANALYSIS_MULTIPROC]) 
        <= ListThreadsOptimizations ){
      _analysisMultiProc = opt;
   }
   if ( [_user objectForKey:K_PREF_STACK_IMAGE_UPDATING] != nil ){
      _stackImageUpdating = [_user boolForKey:K_PREF_STACK_IMAGE_UPDATING];
   }
   if ( [_user objectForKey:K_PREF_STACK_MULTIPROC] != nil ){
     _stackMultiProc = [_user boolForKey:K_PREF_STACK_MULTIPROC];
   }
   if ( [_user objectForKey:K_PREF_PROCESS_MULTIPROC] != nil ){
     _processMultiProc = [_user boolForKey:K_PREF_PROCESS_MULTIPROC];
   }
}

- (void) savePrefs 
{
   [_user setBool:_adjustFFTSizes forKey:K_PREF_ADJUST_FFT_SIZES];
   [_user setFloat:_alignFrequencyCutoff forKey:K_PREF_ALIGN_FREQUENCY_CUTOFF];
   [_user setFloat:_alignThreshold forKey:K_PREF_ALIGN_PRECISION_THRESHOLD];
   [_user setBool:_alignImageUpdating forKey:K_PREF_ALIGN_IMAGE_UPDATING];
   [_user setInteger:_alignMultiProc forKey:K_PREF_ALIGN_MULTIPROC];
   [_user setFloat:_analysisLowerCutoff forKey:K_PREF_ANALYSIS_LOWER_CUTOFF];
   [_user setFloat:_analysisUpperCutoff forKey:K_PREF_ANALYSIS_UPPER_CUTOFF];
   [_user setBool:_analysisImageUpdating forKey:K_PREF_ANALYSIS_IMAGE_UPDATING];
   [_user setInteger:_analysisMultiProc forKey:K_PREF_ANALYSIS_MULTIPROC];
   [_user setBool:_stackImageUpdating forKey:K_PREF_STACK_IMAGE_UPDATING];
   [_user setBool:_stackMultiProc forKey:K_PREF_STACK_MULTIPROC];
   [_user setBool:_processMultiProc forKey:K_PREF_PROCESS_MULTIPROC];
}

- (void) updatePanel
{
   [_adjustFFTSizesButton setState: (_adjustFFTSizes ? NSOnState : NSOffState)];
   [_alignFrequencyCutoffSlider setDoubleValue: _alignFrequencyCutoff*10.0];
   [_alignFrequencyCutoffText setDoubleValue: _alignFrequencyCutoff];
   [_alignThresholdSlider setDoubleValue: _alignThreshold*100.0];
   [_alignThresholdText setDoubleValue: _alignThreshold*100.0];
   [_alignImageUpdatingButton setState: 
      (_alignImageUpdating ? NSOnState : NSOffState)];
   [_alignMultiProcPopup selectItemAtIndex: _alignMultiProc];
   [_analysisLowerCutoffSlider setDoubleValue: _analysisLowerCutoff*10.0];
   [_analysisLowerCutoffText setDoubleValue: _analysisLowerCutoff];
   [_analysisUpperCutoffSlider setDoubleValue: _analysisUpperCutoff*10.0];
   [_analysisUpperCutoffText setDoubleValue: _analysisUpperCutoff];
   [_analysisImageUpdatingButton setState: 
      (_analysisImageUpdating ? NSOnState : NSOffState)];
   [_analysisMultiProcPopup selectItemAtIndex: _analysisMultiProc];
   [_stackImageUpdatingButton setState: 
      (_stackImageUpdating ? NSOnState : NSOffState)];
   [_stackMultiProcPopup selectItemAtIndex: (_stackMultiProc ? 1 : 0)];
   [_processMultiProcPopup selectItemAtIndex: (_processMultiProc ? 1 : 0)];
}

@end

@implementation MyUserPrefsController

- (id) init
{
   NSAssert( instancePointer == nil, 
             @"Creation of more than 1 MyUserPrefsController object" );

   self = [super init];

   _user = [NSUserDefaults standardUserDefaults];

   // Force preferences to have a consistent value
   [self readPrefs];
   [self savePrefs];
   instancePointer = self;

   return( self );
}

+ (MyUserPrefsController*) getUserPref { return instancePointer; }

// The accessors read the value in NSUserDefaults, because our attributes could
// be transient values while the user is interacting with the window
+ (bool) adjustFFTSizes { return [instancePointer->_user boolForKey:
                                                     K_PREF_ADJUST_FFT_SIZES]; }
+ (double) alignFrequencyCutoff { return [instancePointer->_user floatForKey:
                                               K_PREF_ALIGN_FREQUENCY_CUTOFF]; }
+ (double) alignThreshold { return [instancePointer->_user floatForKey:
                                            K_PREF_ALIGN_PRECISION_THRESHOLD]; }
+ (bool) alignImageUpdating { return [instancePointer->_user boolForKey:
                                                  K_PREF_ALIGN_IMAGE_UPDATING]; }
+ (ParalelOptimization_t) alignMultiProc { return [instancePointer->_user 
                                       integerForKey: K_PREF_ALIGN_MULTIPROC]; }
+ (double) analysisLowerCutoff { return [instancePointer->_user floatForKey:
                                                K_PREF_ANALYSIS_LOWER_CUTOFF]; }
+ (double) analysisUpperCutoff { return [instancePointer->_user floatForKey:
                                                K_PREF_ANALYSIS_UPPER_CUTOFF]; }
+ (bool) analysisImageUpdating { return [instancePointer->_user boolForKey:
                                              K_PREF_ANALYSIS_IMAGE_UPDATING]; }
+ (ParalelOptimization_t) analysisMultiProc {  return [instancePointer->_user 
                                     integerForKey:K_PREF_ANALYSIS_MULTIPROC]; }
+ (bool) stackImageUpdating { return [instancePointer->_user boolForKey:
                                                 K_PREF_STACK_IMAGE_UPDATING]; }
+ (bool) stackMultiProc { return [instancePointer->_user boolForKey:
                                                      K_PREF_STACK_MULTIPROC]; }
+ (bool) processMultiProc { return [instancePointer->_user boolForKey:
                                                    K_PREF_PROCESS_MULTIPROC]; }

- (IBAction)changeAdjustFFTSizes:(id)sender
{
   _adjustFFTSizes = ([sender state] == NSOnState);
}

- (IBAction)changeEndProcessingSound:(id)sender
{
}

- (IBAction)changeAlignFrequencyCutoff:(id)sender
{
   _alignFrequencyCutoff = [sender doubleValue];
   
   if ( sender == _alignFrequencyCutoffSlider )
   {
      _alignFrequencyCutoff /= 10.0;
      [_alignFrequencyCutoffText setDoubleValue: _alignFrequencyCutoff];
   }
   
   else
      [_alignFrequencyCutoffSlider setDoubleValue: _alignFrequencyCutoff*10.0];
}

- (IBAction)changeAlignThreshold:(id)sender
{
   _alignThreshold = [sender doubleValue]/100.0;
   
   if ( sender != _alignThresholdSlider )
      [_alignThresholdSlider setDoubleValue: _alignThreshold*100.0];
   
   if ( sender != _alignThresholdText )
      [_alignThresholdText setDoubleValue: _alignThreshold*100.0];
}

- (IBAction)changeAlignImageUpdating:(id)sender
{
   _alignImageUpdating = ([sender state] == NSOnState);
}

- (IBAction)changeAlignMultiProc:(id)sender
{
   _alignMultiProc = [sender indexOfSelectedItem];
}

- (IBAction)changeAnalysisLowerCutoff:(id)sender
{
   _analysisLowerCutoff = [sender doubleValue];
   
   if ( sender == _analysisLowerCutoffSlider )
      _analysisLowerCutoff /= 10.0;
   
   // Enforce consistency
   if ( _analysisLowerCutoff > _analysisUpperCutoff )
      _analysisLowerCutoff = _analysisUpperCutoff;
   
   [_analysisLowerCutoffSlider setDoubleValue: _analysisLowerCutoff*10.0];
   [_analysisLowerCutoffText setDoubleValue: _analysisLowerCutoff];
}

- (IBAction)changeAnalysisUpperCutoff:(id)sender
{
   _analysisUpperCutoff = [sender doubleValue];
   
   if ( sender == _analysisUpperCutoffSlider )
      _analysisUpperCutoff /= 10.0;
   
   // Enforce consistency
   if ( _analysisUpperCutoff < _analysisLowerCutoff )
      _analysisUpperCutoff = _analysisLowerCutoff;
   
   [_analysisUpperCutoffSlider setDoubleValue: _analysisUpperCutoff*10.0];
   [_analysisUpperCutoffText setDoubleValue: _analysisUpperCutoff];
}

- (IBAction)changeAnalysisImageUpdating:(id)sender
{
   _analysisImageUpdating = ([sender state] == NSOnState);
}

- (IBAction)changeAnalysisMultiProc:(id)sender
{
   _analysisMultiProc = [sender indexOfSelectedItem];
}

- (IBAction)changeStackImageUpdating:(id)sender
{
   _stackImageUpdating = ([sender state] == NSOnState);
}

- (IBAction)changeStackMultiProc:(id)sender
{
   _stackMultiProc = ([sender indexOfSelectedItem] == 1);
}

- (IBAction)changeProcessMultiProc:(id)sender
{
   _processMultiProc = ([sender indexOfSelectedItem] == 1);
}

- (IBAction)resetPrefs:(id)sender
{
   [self initPrefsValue];
   [self savePrefs];
   [self updatePanel];
}

- (IBAction)applyChanges:(id)sender
{
   [self savePrefs];
}

- (IBAction)cancelChanges:(id)sender
{
   [_panel orderOut:sender];
}

- (IBAction)confirmChanges:(id)sender
{
   [self savePrefs];
   [_panel orderOut:sender];
}

- (IBAction) showPrefs :(id)sender
{
   [self readPrefs];
   [self updatePanel];
   
   [_panel makeKeyAndOrderFront:self];
}

@end
