/*
   GNUstep ProjectCenter - http://www.gnustep.org

   Copyright (C) 2000-2004 Free Software Foundation

   Authors: Philippe C.D. Robert
            Serg Stoyan

   This file is part of GNUstep.

   This application 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 application 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
   Library General Public License for more details.

   You should have received a copy of the GNU General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
*/

#include "PCDefines.h"
#include "PCProjectManager.h"
#include "PCProject.h"
#include "PCProjectBrowser.h"
#include "PCProjectWindow.h"
#include "PCProjectInspector.h"

#include "PCLogController.h"

@implementation PCFileNameField

- (void)setEditableField:(BOOL)yn
{
  NSRect frame = [self frame];

  if ([self textShouldSetEditable] == NO)
    {
      return;
    }

  if (yn == YES)
    {
      frame.size.width += 4;
      frame.origin.x -= 4;
      [self setFrame:frame];
      
      [self setBordered:YES];
      [self setBackgroundColor:[NSColor whiteColor]];
      [self setEditable:YES];
      [self setNeedsDisplay:YES];
      [[self superview] setNeedsDisplay:YES];
    }
  else
    {
      frame.size.width -= 4;
      frame.origin.x += 4;
      [self setFrame:frame];

      [self setBackgroundColor:[NSColor lightGrayColor]];
      [self setBordered:NO];
      [self setEditable:NO];
      [self setNeedsDisplay:YES];
      [[self superview] setNeedsDisplay:YES];
    }
}

- (void)mouseDown:(NSEvent *)theEvent
{
  [self setEditableField:YES];
  [super mouseDown:theEvent];
}

- (BOOL)textShouldSetEditable
{
  NSString *text = [self stringValue];

  if ([text isEqualToString:@"No files selected"]
      || [text isEqualToString:@"Multiple files selected"])
    {
      return NO;
    }

  return YES;
}

- (void)textDidEndEditing:(NSNotification *)aNotification
{
  [self setEditableField:NO];
  [super textDidEndEditing:aNotification];
}

@end

@implementation PCProjectInspector

// ============================================================================
// ==== Intialization & deallocation
// ============================================================================

- (id)initWithProjectManager:(PCProjectManager *)manager
{
  projectManager = manager;

  [self loadPanel];

  // Track project switching
  [[NSNotificationCenter defaultCenter] 
    addObserver:self
       selector:@selector(activeProjectDidChange:)
           name:PCActiveProjectDidChangeNotification
         object:nil];

  // Track project dictionary changing
  [[NSNotificationCenter defaultCenter] 
    addObserver:self
       selector:@selector(updateValues:)
           name:PCProjectDictDidChangeNotification
         object:nil];

  [self inspectorPopupDidChange:inspectorPopup];

  return self;
}

- (void)close
{
  [inspectorPanel performClose:self];
}

- (void)dealloc
{
#ifdef DEVELOPMENT
  NSLog (@"PCProjectInspector: dealloc");
#endif
  [[NSNotificationCenter defaultCenter] removeObserver:self];

  RELEASE(buildAttributesView);
  RELEASE(projectAttributesView);
  RELEASE(projectDescriptionView);
  RELEASE(fileAttributesView);

  RELEASE(inspectorPanel);
  RELEASE(fileName);

  [super dealloc];
}

// ============================================================================
// ==== Panel & contents
// ============================================================================

- (BOOL)loadPanel
{
  if ([NSBundle loadNibNamed:@"ProjectInspector" owner:self] == NO)
    {
      PCLogError(self, @"error loading NIB file!");
      return NO;
    }

  // Panel
  [inspectorPanel setFrameAutosaveName:@"ProjectInspector"];
  [inspectorPanel setFrameUsingName:@"ProjectInspector"];
  
  // PopUp
  [inspectorPopup selectItemAtIndex:0];
  
  // Build Attributes
  [self createBuildAttributes];

  // Project Description
  [self createProjectDescription];

  // File Attributes
  [self createFileAttributes];

  [self activeProjectDidChange:nil];

  return YES;
}

- (NSPanel *)panel
{
  if (!inspectorPanel && ([self loadPanel] == NO))
    {
      return nil;
    }

  return inspectorPanel;
}

- (NSView *)contentView
{
  if (!contentView && ([self loadPanel] == NO))
    {
      return nil;
    }
    
  return contentView;
}

// ============================================================================
// ==== Actions
// ============================================================================

- (void)inspectorPopupDidChange:(id)sender
{
  switch([sender indexOfSelectedItem]) 
    {
    case 0:
      [inspectorView setContentView:buildAttributesView];
      break;
    case 1:
      [inspectorView setContentView: projectAttributesView];
      break;
    case 2:
      [inspectorView setContentView: projectDescriptionView];
      break;
    case 3:
      [inspectorView setContentView:fileAttributesView];
      break;
    }

  [inspectorView display];
}

- (void)changeCommonProjectEntry:(id)sender
{
  NSString *newEntry = [sender stringValue];

  // Build Atributes
  if (sender == installPathField)
    {
      [project setProjectDictObject:newEntry forKey:PCInstallDir notify:YES];
    }
  else if (sender == cppOptField)
    {
      [project setProjectDictObject:newEntry
	                     forKey:PCPreprocessorOptions
			     notify:YES];
    }
  else if (sender == objcOptField)
    {
      [project setProjectDictObject:newEntry
                             forKey:PCObjCCompilerOptions
			     notify:YES];
    }
  else if (sender == cOptField)
    {
      [project setProjectDictObject:newEntry
                             forKey:PCCompilerOptions
			     notify:YES];
    }
  else if (sender == ldOptField)
    {
      [project setProjectDictObject:newEntry
                             forKey:PCLinkerOptions
			     notify:YES];
    }
  // Project Description
  else if (sender == descriptionField)
    {
      [project setProjectDictObject:newEntry forKey:PCDescription notify:YES];
    }
  else if (sender == releaseField)
    {
      [project setProjectDictObject:newEntry forKey:PCRelease notify:YES];
    }
  else if (sender == licenseField)
    {
      [project setProjectDictObject:newEntry forKey:PCCopyright notify:YES];
    }
  else if (sender == licDescriptionField)
    {
      [project setProjectDictObject:newEntry
	                     forKey:PCCopyrightDescription
			     notify:YES];
    }
  else if (sender == urlField)
    {
      [project setProjectDictObject:newEntry forKey:PCURL notify:YES];
    }
}

- (void)selectSectionWithTitle:(NSString *)sectionTitle
{
  [inspectorPopup selectItemWithTitle:sectionTitle];
  [self inspectorPopupDidChange:inspectorPopup];
}

- (void)controlTextDidEndEditing:(NSNotification *)aNotif
{
  NSControl  *anObject = [aNotif object];
  id         target = [anObject target];
  SEL        action = [anObject action];

  if ([target respondsToSelector:action])
    {
      [target performSelector:action withObject:anObject];
    }
}

// ============================================================================
// ==== Notifications
// ============================================================================

- (void)activeProjectDidChange:(NSNotification *)aNotif
{
  PCProject *rootProject = [projectManager rootActiveProject];
  
  if (rootProject != project)
    {
      [inspectorPanel setTitle: [NSString stringWithFormat: 
	@"%@ - Project Inspector", [rootProject projectName]]];
    }

  project = [projectManager activeProject];
  projectDict = [project projectDict];

  PCLogStatus(self, @"Active projectChanged to %@", 
	      [[project projectDict] objectForKey:PCProjectName]);

  // 1. Get custom project attributes view
  projectAttributesView = [project projectAttributesView];

  // 2. Update values in UI elements
  [self updateValues:nil];

  // 3. Display current view
  [self inspectorPopupDidChange:inspectorPopup];
}

- (void)updateValues:(NSNotification *)aNotif
{
  // Build Attributes view
  searchHeaders = [projectDict objectForKey:PCSearchHeaders];
  searchLibs = [projectDict objectForKey:PCSearchLibs];
  [self searchOrderPopupDidChange:searchOrderPopup];

  [projectNameLabel setStringValue:[project projectName]];

  [cppOptField setStringValue:
    [projectDict objectForKey:PCPreprocessorOptions]];
  [objcOptField setStringValue:
    [projectDict objectForKey:PCObjCCompilerOptions]];
  [cOptField setStringValue:
    [projectDict objectForKey:PCCompilerOptions]];
  [ldOptField setStringValue:
    [projectDict objectForKey:PCLinkerOptions]];
  [installPathField setStringValue:
    [projectDict objectForKey:PCInstallDir]];
    
  // Project Description view
  [descriptionField setStringValue:
    [projectDict objectForKey:PCDescription]];
  [releaseField setStringValue:
    [projectDict objectForKey:PCRelease]];
  [licenseField setStringValue:
    [projectDict objectForKey:PCCopyright]];
  [licDescriptionField setStringValue:
    [projectDict objectForKey:PCCopyrightDescription]];
  [urlField setStringValue:
    [projectDict objectForKey:PCURL]];

  authorsItems = [projectDict objectForKey:PCAuthors];
  [authorsList reloadData];

  // File Attributes view
//  [self setFileNameAndIcon:[project projectBrowser]];
}

// ============================================================================
// ==== Build Attributes
// ============================================================================

- (void)createBuildAttributes
{
  if (buildAttributesView)
    {
      return;
    }

  if ([NSBundle loadNibNamed:@"BuildAttributes" owner:self] == NO)
    {
      PCLogError(self, @"error loading BuildAttributes NIB file!");
      return;
    }

  // Search Order
  // Popup
  [searchOrderPopup selectItemAtIndex:0];

  // Table
  [searchOrderList setCornerView:nil];
  [searchOrderList setHeaderView:nil];

  // Buttons
  [self setSearchOrderButtonsState];

  // Retain view
  [buildAttributesView retain];
}

// --- Search Order
- (void)searchOrderPopupDidChange:(id)sender
{
  NSString *selectedTitle = [sender titleOfSelectedItem];
  
  if ([selectedTitle isEqualToString: @"Header Directories Search Order"])
    {
      ASSIGN(searchItems, searchHeaders);
    }
  else if ([selectedTitle isEqualToString: @"Library Directories Search Order"])
    {
      ASSIGN(searchItems, searchLibs);
    }
  else
    {
      ASSIGN(searchItems,nil);
    }

  // Enable/disable buttons according to selected/not selected item
  [self setSearchOrderButtonsState];

  [searchOrderList reloadData];
}

- (void)searchOrderDoubleClick:(id)sender
{
}

- (void)searchOrderClick:(id)sender
{
  // Warning! NSTableView doesn't call action method
  // TODO: Fix NSTableView (NSCell/NSActionCell?)
  [self setSearchOrderButtonsState];
}

- (void)setSearchOrderButtonsState
{
  // Disable until implemented
  [searchOrderSet setEnabled:NO];

  return; // See searchOrderClick
  
  if ([searchOrderList selectedRow] == -1)
    {
      [searchOrderRemove setEnabled:NO];
    }
  else
    {
      [searchOrderRemove setEnabled:YES];
    }
}

- (void)setSearchOrder:(id)sender
{
}

- (void)removeSearchOrder:(id)sender
{
  int row = [searchOrderList selectedRow];

  if (row != -1)
    {
      [searchItems removeObjectAtIndex:row];
      [self syncSearchOrder];

      [searchOrderList reloadData];
    }
}

- (void)addSearchOrder:(id)sender
{
  NSString *value = [searchOrderTF stringValue];

  [searchItems addObject:value];
  [searchOrderTF setStringValue:@""];
  [self syncSearchOrder];
  
  [searchOrderList reloadData];
}

- (void)syncSearchOrder
{
  int pIndex;

  pIndex = [searchOrderPopup indexOfSelectedItem];
  switch (pIndex)
    {
    case 0:
      [project setProjectDictObject:searchItems
                             forKey:PCSearchHeaders
			     notify:YES];
      break;
    case 1:
      [project setProjectDictObject:searchItems
                             forKey:PCSearchLibs
			     notify:YES];
      break;
    case 2:
      return;
    }
}

// ============================================================================
// ==== Project Description
// ============================================================================

- (void)createProjectDescription
{
  if (projectDescriptionView)
    {
      return;
    }
    
  if ([NSBundle loadNibNamed:@"ProjectDescription" owner:self] == NO)
    {
      PCLogError(self, @"error loading ProjectDescription NIB file!");
      return;
    }

  // Authors table
  authorsColumn = [(NSTableColumn *)[NSTableColumn alloc] 
    initWithIdentifier: @"Authors List"];
  [authorsColumn setEditable:YES];

  authorsList = [[NSTableView alloc]
    initWithFrame:NSMakeRect(6,6,209,111)];
  [authorsList setAllowsMultipleSelection:NO];
  [authorsList setAllowsColumnReordering:NO];
  [authorsList setAllowsColumnResizing:NO];
  [authorsList setAllowsEmptySelection:YES];
  [authorsList setAllowsColumnSelection:NO];
  [authorsList setRowHeight:17.0];
  [authorsList setCornerView:nil];
  [authorsList setHeaderView:nil];
  [authorsList addTableColumn:authorsColumn];
  [authorsList setDataSource:self];

  //
  [authorsScroll setDocumentView:authorsList];
  [authorsScroll setHasHorizontalScroller:NO];
  [authorsScroll setHasVerticalScroller:YES];
  [authorsScroll setBorderType:NSBezelBorder];

  // Authors' buttons
  [authorAdd setRefusesFirstResponder:YES];
  [authorRemove setRefusesFirstResponder:YES];
  
  [authorUp setRefusesFirstResponder:YES];
  [authorUp setImage: [NSImage imageNamed:@"common_ArrowUp"]];
  
  [authorDown setRefusesFirstResponder:YES];
  [authorDown setImage: [NSImage imageNamed:@"common_ArrowDown"]];

  // Link textfields
  [descriptionField setNextText:releaseField];
  [releaseField setNextText:licenseField];
  [licenseField setNextText:licDescriptionField];
  [licDescriptionField setNextText:urlField];
  [urlField setNextText:descriptionField];

  [projectDescriptionView retain];
}

// --- Actions
- (void)addAuthor:(id)sender
{
  int row;

  [authorsItems addObject:[NSMutableString stringWithString:@""]];
  [authorsList reloadData];
  
  row = [authorsItems count] - 1;
  [authorsList selectRow:row byExtendingSelection:NO];
  [authorsList editColumn:0 row:row withEvent:nil select:YES];

  [project setProjectDictObject:authorsItems forKey:PCAuthors notify:YES];
}

- (void)removeAuthor:(id)sender
{
  int selectedRow = [authorsList selectedRow];
  
  if (selectedRow >= 0)
  {
    [authorsItems removeObjectAtIndex:selectedRow];
    [authorsList reloadData];
  }
  
  if ([authorsList selectedRow] < 0 && [authorsItems count] > 0)
  {
    [authorsList selectRow:[authorsItems count]-1 byExtendingSelection:NO];
  }

  [project setProjectDictObject:authorsItems forKey:PCAuthors notify:YES];
}

- (void)upAuthor:(id)sender
{
  int selectedRow = [authorsList selectedRow];
  id  previousRow;
  id  currentRow;

  if (selectedRow > 0)
  {
    previousRow = [[authorsItems objectAtIndex: selectedRow-1] copy];
    currentRow = [authorsItems objectAtIndex: selectedRow];
      
    [authorsItems replaceObjectAtIndex: selectedRow-1 withObject: currentRow];
    [authorsItems replaceObjectAtIndex: selectedRow withObject: previousRow];
  
    [authorsList selectRow: selectedRow-1 byExtendingSelection: NO];

    [authorsList reloadData];
    [project setProjectDictObject:authorsItems forKey:PCAuthors notify:YES];
  }
}

- (void)downAuthor:(id)sender
{
  int selectedRow = [authorsList selectedRow];
  id  nextRow;
  id  currentRow;

  if (selectedRow < [authorsItems count]-1)
  {
    nextRow = [[authorsItems objectAtIndex: selectedRow+1] copy];
    currentRow = [authorsItems objectAtIndex: selectedRow];

    [authorsItems replaceObjectAtIndex: selectedRow+1 withObject: currentRow];
    [authorsItems replaceObjectAtIndex: selectedRow withObject: nextRow];

    [authorsList selectRow: selectedRow+1 byExtendingSelection: NO];

    [authorsList reloadData];
    [project setProjectDictObject:authorsItems forKey:PCAuthors notify:YES];
  }
}

// ============================================================================
// ==== File Attributes
// ============================================================================

- (void)createFileAttributes
{
  if (fileAttributesView)
    {
      return;
    }

  if ([NSBundle loadNibNamed:@"FileAttributes" owner:self] == NO)
    {
      PCLogError(self, @"error loading ProjectDescription NIB file!");
      return;
    }

  [fileAttributesView retain];
  [localizableButton setRefusesFirstResponder:YES];
  [publicHeaderButton setRefusesFirstResponder:YES];

/*  [[NSNotificationCenter defaultCenter] 
    addObserver:self
       selector:@selector(browserDidSetPath:)
           name:PCBrowserDidSetPathNotification
         object:[project projectBrowser]];*/
  [[NSNotificationCenter defaultCenter] 
    addObserver:self
       selector:@selector(panelDidResignKey:)
           name: NSWindowDidResignKeyNotification
         object:inspectorPanel];
}

- (void)beginFileRename
{
  [fileNameField setEditableField:YES];
  [inspectorPanel makeFirstResponder:fileNameField];
}

//- (void)setFileNameAndIcon:(PCProjectBrowser *)browser
- (void)setFileName:(NSString *)name andIcon:(NSImage *)icon
{
  NSArray   *publicHeaders = nil;

//  NSLog(@"PCPI: setFANameAndIcon");

  // Initial default buttons state
  [localizableButton setEnabled:NO];
  [localizableButton setState:NSOffState];
  [publicHeaderButton setEnabled:NO];
  [publicHeaderButton setState:NSOffState];

  if (fileName != nil)
    {
      [fileName release];
    }

//  fileName = [[browser nameOfSelectedFile] retain];
  fileName = [name copy];

  if (fileName && icon)
    {
      [fileNameField setStringValue:fileName];
      [fileIconView setImage:[[project projectWindow] fileIconImage]];

      if ([project canHavePublicHeaders] 
	  && [[fileName pathExtension] isEqualToString:@"h"])
	{
	  [publicHeaderButton setEnabled:YES];
	  publicHeaders = [project publicHeaders];
	  if (publicHeaders && [publicHeaders containsObject:fileName])
	    {
	      [publicHeaderButton setState:NSOnState];
	    }
	}
    }
/*  else if ([[browser selectedFiles] count] > 1)
    {
      [fileNameField setStringValue:@"Multiple files selected"];
      [fileIconView setImage:[[project projectWindow] fileIconImage]];
    }*/
  else
    {
      [fileNameField setStringValue:@"No files selected"];
      [fileIconView setImage:[NSImage imageNamed:@"common_Unknown"]];
    }
}

- (void)fileNameDidChange:(id)sender
{
  if ([fileName isEqualToString:[fileNameField stringValue]])
    {
      return;
    }

/*  PCLogInfo(self, @"{%@} file name changed from: %@ to: %@",
	    [project projectName], fileName, [fileNameField stringValue]);*/

  if ([project renameFile:fileName toFile:[fileNameField stringValue]] == NO)
    {
      [fileNameField setStringValue:fileName];
    }
}

- (void)setPublicHeader:(id)sender
{
  if ([sender state] == NSOffState)
    {
      [project setHeaderFile:fileName public:NO];
    }
  else
    {
      [project setHeaderFile:fileName public:YES];
    }
}

- (void)setLocalizableResource:(id)sender
{
  if ([sender state] == NSOffState)
    {
      [project setLocalizableFile:fileName public:NO];
    }
  else
    {
      [project setLocalizableFile:fileName public:YES];
    }
}

// --- Notifications
- (void)browserDidSetPath:(NSNotification *)aNotif
{
//  [self setFANameAndIcon:[aNotif object]];
}

- (void)panelDidResignKey:(NSNotification *)aNotif
{
  if ([fileNameField isEditable] == YES)
    {
      [inspectorPanel makeFirstResponder:fileIconView];
      [fileNameField setStringValue:fileName];
    }
}

// ============================================================================
// ==== NSTableViews
// ============================================================================

- (int)numberOfRowsInTableView: (NSTableView *)aTableView
{
  if (searchOrderList != nil && aTableView == searchOrderList)
    {
      return [searchItems count];
    }
  else if (authorsList != nil && aTableView == authorsList)
    {
      return [authorsItems count];
    }

  return 0;
}
    
- (id)            tableView: (NSTableView *)aTableView
  objectValueForTableColumn: (NSTableColumn *)aTableColumn
                        row: (int)rowIndex
{
  if (searchOrderList != nil && aTableView == searchOrderList)
    {
      return [searchItems objectAtIndex:rowIndex];
    }
  else if (authorsList != nil && aTableView == authorsList)
    {
      return [authorsItems objectAtIndex:rowIndex];
    }

  return nil;
}
  
- (void) tableView:(NSTableView *)aTableView
    setObjectValue:anObject
    forTableColumn:(NSTableColumn *)aTableColumn
               row:(int)rowIndex
{
  if (authorsList != nil && aTableView == authorsList)
    {
      if([authorsItems count] <= 0)
	{
	  return;
	}
	
      [authorsItems removeObjectAtIndex:rowIndex];
      [authorsItems insertObject:anObject atIndex:rowIndex];

      [project setProjectDictObject:authorsItems forKey:PCAuthors notify:YES];
    }
}

@end
