/**
 ** PrefsPanel is a subclass of Panel which
 ** defines the logic for managing user preferences.
 **/

#import "PrefsPanel.h"
#import "Eval.h"
#import "EvalText.h"
#import "CodeBrowser.h"

#import <defaults/defaults.h>
#import "EvalString.h"
#include <stdio.h>

#define TEXTDEFAULTKNT 7 /* number of text categories */
static NXDefaultsVector evalDefaults = 
{ {"Frame","100.0 100.0 300.0 300.0"},
  {"TextScrollViewSize","300.0 150.0"},
  {"GraphicsScrollViewSize","300.0 150.0"},
  {"GraphicsViewSize","400.0 400.0"},
  {"EmacsBindings","1"},
  {"TextBackgroundColor","0.666 0.666 0.666"},
  {"CompilerSwitches",""},
  {"CompilerOutput","0"},
  {"Libraries",""},
  {"LastFileOpened",""},
  // preproc,directive,methoddef,comment,string,keyword,normal
  {"text0",  "Courier \\fs28  \\red0\\green0\\blue0 \\ul0"},
  {"text1",  "Courier \\fs28 \\red0\\green0\\blue0 \\ul0"},
  {"text2",  "Ohlfs \\fs22 \\red0\\green0\\blue0 \\ul"},
  {"text3",  "Courier \\fs22 \\red0\\green0\\blue0 \\ul0"},
  {"text4",  "Courier \\fs22 \\red0\\green0\\blue0 \\ul0 "},
  {"text5",  "Courier \\fs22 \\red0\\green0\\blue0 \\ul0 "},
  {"text6",  "Courier \\fs22 \\red0\\green0\\blue0 \\ul0 "},
  {NULL} 
} ;
 
// archive (library) extension 
const char *libTypes[] = 
{ "a",
  "o",
  NULL 
} ;


@implementation PrefsPanel
{ id prefsView ;
  id graphicsViewSizeForm ;
  id compilerSwitchesForm ;
  id compilerOutput ;
  id emacsBindings ;
  id fontNameAndSize ;
  id fontColor ;
  id fontUnderline ;
  id textBackgroundColorWell ;
  id libBrowser ;
  id libList ;
  id libSelection ;
}

- (int)browser:sender fillMatrix:matrix inColumn:(int)column ;
{ // This is a delegate method for libBrowser, the browser object
  // displaying a list of libraries.
  return [libList count] ;
}

- browser:sender loadCell:cell atRow:(int)row inColumn:(int)column ;
{ // Load a cell in the libBrowser.
  [cell setStringValue: [[libList objectAt: row] cString]] ;
  [cell setLeaf: YES] ;
  return self ;
}

- changeFont: sender ;
{ // This message is automagically sent down the responder chain
  // from the FontManager whenever a new font is selected.  This
  // implementation writes the font and size currently selected
  // in the FontPanel to the Button instance currently selected in the
  // fontNameAndSize Matrix.
  char buf[80] ;
  id aFont  = [sender convertFont: [sender selFont]] ;
  sprintf(buf,"%s %.3f",[aFont name],[aFont pointSize]) ;
  [[fontNameAndSize selectedCell] setTitle: buf] ;
  [self doFont: sender] ;
  return self ;
}

- changePrefsView: sender ;
{ // Force the prefs panel to display a different part of its
  // prefsView subView. 
  NXRect aRect ;
  [prefsView getFrame: &aRect] ;
  [prefsView moveTo: -370 *[[sender selectedCell] tag] :aRect.origin.y] ;
  return [self display] ;
}

- doCompilerOutput: sender
{ // Process the Compiler Output switch
  char *defaultName = "CompilerOutput" ;  
  if(sender) // set default from widget
    NXWriteDefault([NXApp appName],defaultName,
      [compilerOutput selectedCol] ? "1" : "0") ;
  else // set widget from default
    [compilerOutput selectCellAt:
       *NXGetDefaultValue([NXApp appName],defaultName) == '0' ?  0 : 1
      :0 ]  ;
  return self ;
}


- doCompilerSwitches: sender
{ // Process the compiler switches.
  char *defaultName = "CompilerSwitches" ;
  if(sender) // set defaults from widget
    NXWriteDefault([NXApp appName],defaultName,
      [compilerSwitchesForm stringValue]) ;
  else // set widget from defaults
    [compilerSwitchesForm setStringValue:
       NXGetDefaultValue([NXApp appName],"CompilerSwitches")] ;
  return self ;
}

- doEmacsBindings: sender
{ // Process the Emacs Bindings preference.
  char *defaultName = "EmacsBindings" ;  
  if(sender) // set default from widget
    NXWriteDefault([NXApp appName],defaultName,
      [emacsBindings selectedRow] ? "1" : "0") ;
  else // set widget from default
    [emacsBindings selectCellAt:
       *NXGetDefaultValue([NXApp appName],defaultName) == '0' ?  0 : 1
      :0 ]  ;
  // set transcript text's state
  [[NXApp transcriptText] useEmacsBindings: [emacsBindings selectedRow]] ;
  return self ;
}

- doFont: sender
{ // Process a font attribute.
  char prefsValue[512], fontName[256], defaultName[6] ;
  float fontSize, red, green, blue ;
  if(sender) // set default from widgets
  { int tag ; // sender might be a Matrix, FontManager, or NXColorWell instance
    if([sender isMemberOf: [NXColorWell class]])
       tag = [sender tag] ;
    else if([sender isMemberOf: [FontManager class]])
      tag = [[fontNameAndSize selectedCell] tag] ;
    else     
      tag = [[sender selectedCell] tag] ; 
    sprintf(defaultName,"text%1d",tag) ;
    sscanf([[fontNameAndSize cellAt: tag :0] title],"%s %f",fontName,&fontSize) ;
    NXConvertColorToRGB([[fontColor findViewWithTag: tag] color], &red, &green, &blue) ;
    sprintf(prefsValue,"%s \\fs%d \\red%d\\green%d\\blue%d \\ul%s", 
      fontName,(int) fontSize * 2,(int) (red * 256), (int) (green * 256), (int) (blue * 256),
      ([[fontUnderline cellAt: tag :0] state] == 1) ? "" : "0") ;
     NXWriteDefault([NXApp appName],defaultName,prefsValue) ;
  } 
  return self ;
}


- doGraphicsViewSize: sender ;
{ // Process the graphics size preference.
  char *defaultName = "GraphicsViewSize" ;
  if(sender) // set defaults from widget
    NXWriteDefault([NXApp appName], defaultName,[graphicsViewSizeForm stringValue]) ;
  else // set widget from defaults
    [graphicsViewSizeForm setStringValue: 
      NXGetDefaultValue([NXApp appName],defaultName)] ;
  return self ;
}

- doLibraries: sender ;
{ // Process the libraries preference.
  const char *s, *defaultName = "Libraries" ;
  int i = 0 ;
  if(sender) // set default from widget
  { int knt = [libList count] ;
    NXStream *libStream = NXOpenMemory(NULL, 0, NX_WRITEONLY) ;
    for( ; i < knt ; i++)
      NXPrintf(libStream,"%s ",[[libList objectAt: i] cString]) ;
    NXGetMemoryBuffer(libStream,&s,&i,&knt) ;   
    NXWriteDefault([NXApp appName],defaultName,s) ;
    NXCloseMemory(libStream,NX_FREEBUFFER) ;
  }
  else // set widget from default
  { const char *delims = " \n\t" ;
    const char *aString ;
    s = NXGetDefaultValue([NXApp appName],defaultName) ;
    if(aString = strtok((char *) s,delims))
    { do
        [libList addObject: [EvalString new: aString]] ;
      while(aString = strtok(NULL,delims)) ;
    }
    [libBrowser loadColumnZero] ;
  }
  return self ;
}

- doTextBackgroundColor: sender ;
{ // Process the text background color preference.
  char *defaultName = "TextBackgroundColor" ; 
  float red, green, blue ;
  id aWin = [NXApp mainWindow] ;
  if(![aWin isKindOf: [CodeBrowser class]])
    aWin = nil ;
  if(sender) // set defaults from widget
  { char buf[80] ;
    NXConvertColorToRGB([textBackgroundColorWell color], &red, &green, &blue) ;
    sprintf(buf,"%f %f %f",red,green,blue) ;
    NXWriteDefault([NXApp appName],defaultName,buf) ;
  }
  else // set widget from default
  { sscanf(NXGetDefaultValue([NXApp appName],defaultName),
      "%f %f %f",&red,&green,&blue) ;
    [textBackgroundColorWell setColor: NXConvertRGBToColor(red,green,blue)] ;
  }
  if([[NXApp transcriptText] shouldDrawColor])
  { if(aWin)
      [[aWin codeBrowserText] setBackgroundColor: [textBackgroundColorWell color]] ;
  }
  else
  { float g ;
    NXConvertColorToGray([textBackgroundColorWell color], &g) ;
    if(aWin) 
    [[aWin codeBrowserText] setBackgroundGray:g] ;
  }
  if(aWin)
    [aWin display] ;
  return self ; 
}



- libAdd: sender ;
{ // Add a library file's name to the list
  // of libraries to be searched.
  id openPanel ;
  char **theList, buf[256] ;
  openPanel = [OpenPanel new] ;
  if([openPanel runModalForTypes: libTypes])
  { theList = (char **) [openPanel filenames] ;
    { sprintf(buf,"%s/%s",[openPanel directory],
        *theList++) ;
      [libList addObject: [EvalString new:buf]] ;
    }
    [libBrowser loadColumnZero] ;
    [self doLibraries: self] ;
  }  
  return self ;   
}

- libBrowserHit: sender ;
{ // whenever a library is selected in the browser, we 
  // copy the entry into the libSelection, because long path names
  // may be truncated in the browser.
  [libSelection setStringValue:
   [[[libBrowser matrixInColumn: 0] selectedCell] stringValue]] ;
  return self ;
}

- libList ;
{ // Return the libList, a List instance containing
  // EvalString instances each of which is the name of
  // a library to be searched during linking.
  return libList ;
}

- libRemove: sender ;
{ // Remove a library file's name from the list
  // of libraries to be searched.
  int theRow ;
  theRow = [[libBrowser matrixInColumn: 0] selectedRow] ;
  if(theRow >= 0)
  { [[libList removeObjectAt: theRow] free] ;
    [libBrowser loadColumnZero] ;
    [self doLibraries: self] ;
  }
  return self ;
}

- setup ;
{ // Read in the app's defaults, then populate the preferences
  // panel widgets and initialize user interface objects as required.
  const char * theAppName = [NXApp appName] ;
  int i ;
  int red, green, blue ;
  // setup the defaults
  NXRegisterDefaults(theAppName, evalDefaults) ;
  // Populate prefs panel widgets and set state of UI objects
  // as required by calling the "do" methods with a NULL argument
  [self doGraphicsViewSize: NULL] ;
  [self doEmacsBindings: NULL] ; 
  [self doTextBackgroundColor: NULL] ;
  [self doCompilerSwitches: NULL] ;
  [self doCompilerOutput: NULL] ;	
  // init the libList, display in browser 
  libList = [[List alloc] init] ;
  [self doLibraries: NULL] ;
  [libBrowser loadColumnZero] ;
  // Populate the font options
  for(i = 0 ; i < TEXTDEFAULTKNT ; i++)
  { char defaultName[6] ;
    char fontName[256],fontUnderlineString[10],tmp[256] ;
    float fontSize ;
    sprintf(defaultName,"text%1d",i) ;  
    sscanf(NXGetDefaultValue(theAppName,defaultName),
       "%s \\fs%f \\red%d\\green%d\\blue%d %s ",
       fontName, &fontSize, &red, &green, &blue, fontUnderlineString) ;
    sprintf(tmp,"%s %.3f", fontName, fontSize / 2.0) ;
    [[fontNameAndSize cellAt: i:0] setTitle: tmp] ;
    [[fontColor findViewWithTag:i] setColor:
      NXConvertRGBAToColor(red/255.0, green/255.0 , blue/255.0, NX_NOALPHA)];
    [[fontUnderline cellAt: i :0]     
       setState: !strcmp(fontUnderlineString,"\\ul") ? 1 : 0] ;
  }
  return self ;
}

- textBackgroundColorWell ;
{ return textBackgroundColorWell ;
}

@end
