/*
 * "p" - A very simple Project Manager using the GIMP Toolkit
 * Copyright (c) 1998  Elmar Ludwig - Universitaet Osnabrueck
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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 Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <string.h>
#ifdef HAVE_UNISTD_H
#include <sys/types.h>
#include <unistd.h>
#else
extern char *getcwd ();
#endif

#include <GToolKit/GToolKit.h>
#include <Foundation/NSArray.h>
#include <Foundation/NSDictionary.h>
#include "Manager.h"

@implementation Manager

- init
{
    GTKWindow *window = [GTKWindow windowWithType:GTK_WINDOW_TOPLEVEL];
    GTKVBox *vbox = [GTKVBox vBoxWithHomogeneous:NO spacing:0];
    GTKHBox *hbox1 = [GTKHBox hBoxWithHomogeneous:NO spacing:0];
    GTKButton *launch = [GTKButton buttonWithLabel:@"Launch"];
    GTKButton *debug = [GTKButton buttonWithLabel:@"Debug"];
    GTKButton *attrib = [GTKButton buttonWithLabel:@"Attributes"];
    GTKButton *build = [GTKButton buttonWithLabel:@"Build"];
    GTKHSeparator *hsep = [GTKHSeparator hSeparator];
    GTKVSeparator *vsep = [GTKVSeparator vSeparator];
    GTKHBox *hbox2 = [GTKHBox hBoxWithHomogeneous:NO spacing:0];
    GTKMenu *popup = [GTKMenu menu];
    GTKMenuFactory *menu_factory =
	[GTKMenuFactory menuFactoryWithType:GTK_MENU_FACTORY_MENU_BAR];
    GTKScrolledWindow *scroll1 =
	[GTKScrolledWindow scrolledWindowWithHadjustment:nil vadjustment:nil];
    GTKScrolledWindow *scroll2 =
	[GTKScrolledWindow scrolledWindowWithHadjustment:nil vadjustment:nil];
    GTKAction *select =
	[GTKAction actionWithTarget:self selector:@selector(select:)];
    GTKTooltips *tips = [GTKTooltips tooltips];

    static GdkColor yellow, black;
    static GtkMenuEntry menus[] =
    {
	{ "Project/Info Panel...",  "<control>I", 0, @selector(info:) },
	{ "Project/Preferences..." },
	{ "Project/<separator>" },
	{ "File/Open",		    "<control>O", 0, @selector(open:) },
	{ "File/<separator>" },
	{ "File/Add...",	    "<control>A", 0, @selector(add:) },
	{ "File/Remove",	    "<control>R", 0, @selector(remove:) },
	{ }
    };
    static GtkMenuEntry menus2[] =
    {
	{ "Project/Quit",	    "<control>Q", 0, @selector(destroy) },
	{ }
    };
    int index;
    char buffer[1024];

    [super init];
#ifdef HAVE_GETCWD
    if (getcwd(buffer, sizeof buffer))
	path = [[NSString alloc] initWithCString:buffer];
    else
#endif
	path = [@"." retain];
    program = [[path lastPathComponent] retain];

    list1 = [GTKList list];
    list2 = [GTKList list];
    groups = [NSArray arrayWithObjects:
		      [GTKListItem listItemWithLabel:@"Classes"],
		      [GTKListItem listItemWithLabel:@"Headers"],
		      [GTKListItem listItemWithLabel:@"Other Sources"],
		      [GTKListItem listItemWithLabel:@"Images"],
		      [GTKListItem listItemWithLabel:@"Other Resources"],
		      [GTKListItem listItemWithLabel:@"Supporting Files"],
		      [GTKListItem listItemWithLabel:@"Libraries"], nil];
    [list1 appendItems:groups];

    [menu_factory addEntries:menus forTarget:self];
    [menu_factory addEntries:menus2 forTarget:window];
    [GTK_GET_OBJECT(menus[1].widget) setSensitive:NO];

    target = [GTKOptionMenu optionMenu];
    [popup append:[GTKMenuItem menuItemWithLabel:@"(default)"]];
    [popup append:[GTKMenuItem menuItemWithLabel:@"install"]];
    [popup append:[GTKMenuItem menuItemWithLabel:@"clean"]];
    [target setMenu:popup];

    [scroll1 setPolicy:GTK_POLICY_AUTOMATIC vscrollbarPolicy:GTK_POLICY_ALWAYS];
    [scroll2 setPolicy:GTK_POLICY_AUTOMATIC vscrollbarPolicy:GTK_POLICY_ALWAYS];
    [scroll1 add:list1];
    [scroll2 add:list2];

    [launch connectSignal:@"clicked" withTarget:self sel:@selector(launch:)];
    [debug  connectSignal:@"clicked" withTarget:self sel:@selector(debug:)];
    [attrib connectSignal:@"clicked" withTarget:self sel:@selector(attrib:)];
    [build  connectSignal:@"clicked" withTarget:self sel:@selector(build:)];

    gdk_color_parse("light yellow", &yellow);
    gdk_color_alloc([window getColormap], &yellow);
    gdk_color_parse("black", &black);
    gdk_color_alloc([window getColormap], &black);

    [tips setColors:&yellow foreground:&black];
    [tips setTip:launch tipText:@"Start the Program" tipPrivate:nil];
    [tips setTip:debug tipText:@"Start the Debugger" tipPrivate:nil];
    [tips setTip:attrib tipText:@"Modify Project Options" tipPrivate:nil];
    [tips setTip:build tipText:@"Build the Project" tipPrivate:nil];
    [tips setTip:target tipText:@"Select Build Target" tipPrivate:nil];

    [hbox1 packStart:launch expand:NO fill:YES padding:4];
    [hbox1 packStart:debug expand:NO fill:YES padding:4];
    [hbox1 packStart:attrib expand:NO fill:YES padding:4];
    [hbox1 packStart:build expand:NO fill:YES padding:4];
    [hbox1 packStart:vsep expand:NO fill:YES padding:4];
    [hbox1 packStart:target expand:NO fill:YES padding:4];
    [hbox2 packStart:scroll1 expand:YES fill:YES padding:4];
    [hbox2 packStart:scroll2 expand:YES fill:YES padding:4];
    [vbox packStart:[menu_factory widget] expand:NO fill:YES padding:0];
    [vbox packStart:hbox1 expand:NO fill:NO padding:8];
    [vbox packStart:hsep expand:NO fill:YES padding:0];
    [vbox packStart:hbox2 expand:YES fill:YES padding:8];

    [window add:vbox];
    [window addAcceleratorTable:[menu_factory acceleratorTable]];
    [window connectSignal:@"destroy" withTarget:GTKApp
	    sel:@selector(terminate:)];
    [window setUsize:320 height:220];
    [window setTitle:[NSString stringWithFormat:@" %@ - %@ ", program,
				[path stringByAbbreviatingWithTildeInPath]]];
    [window show];

    files = [[NSMutableDictionary alloc] initWithCapacity:8];
    for (index = [groups count]; index;)
    {
	GTKListItem *item = [groups objectAtIndex:--index];

	[files setObject:[NSMutableArray array] forKey:(id) item];
	[item connectSignal:@"select" withAction:select];
    }

    [list2 connectSignal:@"selection_changed" withTarget:self
	   sel:@selector(selectFile:)];
    return self;
}

- (void) dealloc
{
    [files release];
    [program release];
    [path release];
    [filename release];
    [super dealloc];
}

- (void) info:sender
{
    GTKRunMessageBox(@"Info Panel", @"This is an example of a very simple\n"
		     @"Project Manager using the GIMP Toolkit.",
		     @"Continue", nil, nil);
}

- (void) select:sender
{
    [list2 removeItems:[list2 children]];
    [list2 appendItems:[files objectForKey:sender]];
    if ([GTKApp getCurrentEvent]->type == GDK_2BUTTON_PRESS)
	[self addFile:sender];
}

- (void) selectFile:sender
{
    if ([GTKApp getCurrentEvent]->type == GDK_2BUTTON_PRESS)
	[self open:sender];
}

- (void) add:sender
{
    NSArray *sel = [list1 selection];

    if ([sel count]) [self addFile:[sel objectAtIndex:0]];
}

- (void) addFile:(GTKListItem *) group
{
    NSMutableArray *items = [files objectForKey:(id) group];
    GTKFileSelection *filesel =
	[[GTKFileSelection alloc] initWithTitle:@"Add File..."];

    [[filesel okButton] connectSignal:@"clicked" withTarget:self
	sel:@selector(ok:)];
    [[filesel cancelButton] connectSignal:@"clicked" withTarget:self
	sel:@selector(cancel:)];
    [filesel connectSignal:@"delete_event" withTarget:GTKApp
	sel:@selector(true)];
    [filesel hideFileopButtons];
    [filesel show];

    if ([GTKApp runModalForWindow:filesel])
    {
	NSString *name = [[filesel getFilename] lastPathComponent];
	GTKListItem *item = [GTKListItem listItemWithLabel:name];

	[items addObject:item];
	[list2 add:item];
	[self save:self];
    }

    [filesel destroy];
    [filesel release];
}

- (void) ok:sender
{
    [GTKApp stopModalWithCode:YES];
}

- (void) cancel:sender
{
    [GTKApp stopModalWithCode:NO];
}

- (void) remove:sender
{
    NSArray *sel1 = [list1 selection];
    NSArray *sel2 = [list2 selection];
    NSMutableArray *items;
    GTKListItem *item;

    if ([sel1 count] == 0 || [sel2 count] == 0) return;
    items = [files objectForKey:[sel1 objectAtIndex:0]];
    item = [sel2 objectAtIndex:0];

    [list2 remove:item];
    [items removeObject:item];
    [self save:self];
}

- (void) open:sender
{
    NSArray *sel2 = [list2 selection];
    NSString *command;

    if ([sel2 count] == 0) return;
    command = [NSString stringWithFormat:@"%@ '%@' &", TEXT_EDITOR,
			[[[sel2 objectAtIndex:0] child] stringValue]];
    system([command cString]);
}

- (void) launch:sender
{
    NSString *command = [NSString stringWithFormat:@"%@ '%@' &",
				  LAUNCH_CMD, program];

    system([command cString]);
}

- (void) debug:sender
{
    NSString *command = [NSString stringWithFormat:@"%@ '%@' &",
				  DEBUG_CMD, program];

    system([command cString]);
}

- (void) attrib:sender
{
    NSString *command = [NSString stringWithFormat:@"%@ '%@' &",
				  TEXT_EDITOR, @"Makefile"];

    system([command cString]);
}

- (void) build:sender
{
    GTKWindow *output = [GTKWindow windowWithType:GTK_WINDOW_TOPLEVEL];
    GTKHBox *box = [GTKHBox hBoxWithHomogeneous:NO spacing:4];
    GTKVScrollbar *bar = [GTKVScrollbar vScrollbarWithAdjustment:nil];
    GTKText *text = [GTKText textWithHadj:nil vadj:[bar getAdjustment]];
    NSString *command;
    FILE *pipe;
    char buffer[1024];

    [text setEditable:NO];
    [box packStart:text expand:YES fill:YES padding:0];
    [box packStart:bar expand:NO fill:YES padding:0];
    [output setTitle:@"Build Output Window"];
    [output borderWidth:2];
    [output add:box];
    [output setUsize:480 height:240];
    [output show];
    [text grabFocus];

    command = [[target child] stringValue];
    if ([command isEqualToString:@"(default)"]) command = @"";
    command = [MAKE_CMD stringByAppendingFormat:@" %@", command];

    if ((pipe = popen([command cString], "r")))
    {
	while (fgets(buffer, sizeof buffer, pipe))
	    [text insert:NULL fore:NULL back:NULL
		  chars:[NSString stringWithCString:buffer] length:-1];
	pclose(pipe);
    }

    [text insert:NULL fore:NULL back:NULL chars:@"--- finished ---" length:-1];
}

- (void) loadFromFile:(NSString *) _filename
{
    const char *name;
    FILE *file;
    NSEnumerator *keys;
    GTKListItem *item;

    [filename autorelease];
    filename = [_filename copy];
    name = [_filename cString];
    file = fopen(name, "r");

    if (!file)
    {
	perror(name);
	return;
    }

    keys = [groups objectEnumerator];
    while ((item = [keys nextObject]))
    {
	NSMutableArray *array = [files objectForKey:(id) item];
	char buffer[4096];
	char *ptr, *string;

	[array removeAllObjects];

	if (!fgets(buffer, sizeof buffer, file) || !(ptr = strchr(buffer, '=')))
	    break;
	++ptr;
	while ((string = strtok(ptr, " \t\r\n")))
	{
	    ptr = NULL;
	    item = [GTKListItem listItemWithLabel:
			[NSString stringWithCString:string]];
	    [array addObject:item];
	}
    }

    if (ferror(file)) perror(name);
    fclose(file);
}

- (void) save:sender
{
    if (!filename)
	filename = [[program stringByAppendingString:@".project"] retain];
    [self saveToFile:filename];
}

- (void) saveToFile:(NSString *) _filename
{
    const char *name = [_filename cString];
    FILE *file = fopen(name, "w");
    NSEnumerator *keys, *values;
    GTKListItem *item;
    NSMutableString *command = [[MAKEFILE_GEN mutableCopy] autorelease];
    NSString *string;

    if (!file)
    {
	perror(name);
	return;
    }

    [command appendFormat:@" %@", program];
    keys = [groups objectEnumerator];
    while ((item = [keys nextObject]))
    {
	fprintf(file, "%s =", [[[item child] stringValue] cString]);
	values = [[files objectForKey:(id) item] objectEnumerator];
	while ((item = [values nextObject]))
	{
	    string = [[item child] stringValue];
	    [command appendFormat:@" %@", string];
	    fprintf(file, " %s", [string cString]);
	}
	fputc('\n', file);
    }

    fflush(file);
    if (ferror(file)) perror(name);
    fclose(file);
    system([command cString]);
}
@end
