/*
 *
 * Copyright 2002 Alexander Malmberg <alexander@malmberg.org>
 *           2012 The Free Software Foundation
 *
 * Authors: Alexander Malmberg <alexander@malmberg.org>
 *          Riccardo Mottola <rm@gnu.org>
 *
 */

#import <Foundation/NSObject.h>
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSUserDefaults.h>
#import <Foundation/NSPathUtilities.h>
#import <Foundation/NSBundle.h>
#import <Foundation/NSDictionary.h>
#import <AppKit/NSApplication.h>
#import <AppKit/NSGraphics.h>
#import <AppKit/NSMenu.h>
#import <AppKit/NSWindow.h>

#import <Pantomime/CWCharset.h>

#import "MsgDB.h"

#import "LogWindowController.h"
#import "FolderWindowController.h"
#import "FolderListController.h"
#import "ComposeWindowController.h"


#import "main.h"

#include "VERSION"


AppDelegate *app_delegate;


#define LOG_MESSAGES_ONLY


#define LogWindowVisibleKey @"LogWindowVisible"
#define FolderListVisibleKey @"FolderListVisible"
#define FoldersVisibleKey @"FoldersVisible"

#define LocationKey @"MessageDatabaseLocation"

NSString *DefaultEncodingChangedNotification = @"DefaultEncodingChangedNotification";

@interface NSMenu (im_lazy)
-(id <NSMenuItem>) addItemWithTitle: (NSString *)s;
-(id <NSMenuItem>) addItemWithTitle: (NSString *)s  action: (SEL)sel;
@end

@implementation NSMenu (im_lazy)
-(id <NSMenuItem>) addItemWithTitle: (NSString *)s
{
	return [self addItemWithTitle: s  action: NULL  keyEquivalent: nil];
}

-(id <NSMenuItem>) addItemWithTitle: (NSString *)s  action: (SEL)sel
{
	return [self addItemWithTitle: s  action: sel  keyEquivalent: nil];
}
@end


#include <AppKit/NSSavePanel.h>

@implementation AppDelegate


-(void) composeArticle: (NSDictionary *)headers;
{
	[[[ComposeWindowController alloc] initWithHeaders: headers] showWindow: self];
}

-(void) composeFollowupToMessage: (CWMessage *)msg
{
	[[[ComposeWindowController alloc] initWithFollowupToMessage: msg] showWindow: self];
}


-(void) composeNewArticle: (id)sender
{
	[self composeArticle: nil];
}


-(void) postArticleFrom: (id)sender : (const unsigned char *)data : (int)length
{ /* TODO */
	NSObject<Msg_Source> *src;

//	fprintf(stderr,"post article %@\n",sender);
	src=[[mdb sources] objectAtIndex: 0];
	if (!src || ![src respondsToSelector: @selector(postArticle:length:sender:)])
	{
		fprintf(stderr,"no source!\n");
		NSBeep();
		return;
	}

	[src postArticle: data  length: length  sender: sender];
}


- initWithApp: (NSApplication *)a
{
	CREATE_AUTORELEASE_POOL(arp);
	NSString *dir;

	if (!(self=[super init])) return nil;
	app=a;
	folder_windows=[[NSMutableDictionary alloc] init];

	dir=[[NSUserDefaults standardUserDefaults] objectForKey: LocationKey];
	if (!dir)
	{
		dir=[NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,NSUserDomainMask,YES) objectAtIndex: 0];
		dir=[[dir stringByAppendingPathComponent: @"LuserNET"]
			stringByStandardizingPath];

		[[NSUserDefaults standardUserDefaults] setObject: dir  forKey: LocationKey];
	}

	mdb=[[MsgDB alloc] initWithDirectory: dir];

	DESTROY(arp);
	return self;
}

-(void) applicationWillTerminate: (NSNotification *)n
{
	[mdb syncToDisk];

	[[NSNotificationCenter defaultCenter]
		removeObserver: self];

	{
		NSUserDefaults *ud=[NSUserDefaults standardUserDefaults];
		NSMutableArray *a;
		NSEnumerator *e;
		NSString *fn;

		[ud setBool: [[log_window window] isVisible] forKey: LogWindowVisibleKey];
		if (folder_list)
			[ud setBool: [[folder_list window] isVisible] forKey: FolderListVisibleKey];
		else
			[ud setBool: NO forKey: FolderListVisibleKey];

		a=[[NSMutableArray alloc] init];
		for (e=[folder_windows keyEnumerator];(fn=[e nextObject]);)
		{
			if ([[[folder_windows objectForKey: fn] window] isVisible])
				[a addObject: fn];
		}
		[ud setObject: a forKey: FoldersVisibleKey];
		[a release];
	}

	DESTROY(preferences_window);
	DESTROY(log_window);
	DESTROY(folder_list);
	DESTROY(folder_windows);
	DESTROY(mdb);
}


-(void) openFolderWindow: (NSString *)folder_name
{
	FolderWindowController *fw;

	fw=[folder_windows objectForKey: folder_name];
	if (!fw)
	{
		fw=[[FolderWindowController alloc] initWithMsgDB: mdb  folder: folder_name];
		if (!fw) return; /* TODO: bring up error panel? */
		[folder_windows setObject: fw forKey: folder_name];
		[fw release];
	}
	[fw showWindow: self];
}

-(void) openMessageWindow: (msg_id_t)mid
{
	NSLog(@"TODO: openMessageWindow: %i\n",mid);
}


-(void) quit: (id)sender
{
	[app terminate: sender];
}

-(void) update: (id)sender
{
	[mdb updateAll];
}

-(void) listFolders: (id)sender
{
	if (!folder_list)
		folder_list=[[FolderListController alloc] initWithMsgDB: mdb];
	[folder_list showWindow: self];
}

-(void) logWindow: (id)sender
{
	[log_window showWindow: self];
}


-(void) logMessage: (NSNotification *)n
{
#ifdef LOG_MESSAGES_ONLY
	[log_window addLogString: [[n userInfo] objectForKey: @"Message"]];
#else
	[log_window addLogString: [NSString stringWithFormat: @"%@: %@ %@ %@",n,[n name],[n object],[n userInfo]]];
#endif
}

-(void) changeEncoding:(id)sender
{
  NSDictionary *charsets = [CWCharset allCharsets];

  //  [sender selectItemWithTitle:[sender title]];
  //  [sender synchronizeTitleAndSelectedItem];
  
  [[NSUserDefaults standardUserDefaults] setObject:
	[[charsets allKeysForObject:[sender title]] objectAtIndex:0] 
      forKey:@"DefaultEncoding"];

  [[NSNotificationCenter defaultCenter]
    postNotificationName: DefaultEncodingChangedNotification
    object: nil];
}

-(void) applicationWillFinishLaunching: (NSNotification *)n
{
	NSMenu *menu,*m,*m2;

	menu=[[NSMenu alloc] init];

	/* 'Info' menu */
	m=[[NSMenu alloc] init];
	[m addItemWithTitle: _(@"Preferences...")
		action: @selector(openPreferences:)];
	[m addItemWithTitle: _(@"Info...")
		action: @selector(orderFrontStandardInfoPanel:)];
	[menu setSubmenu: m forItem: [menu addItemWithTitle: _(@"Info")]];
	[m release];

	/* 'Folder list' menu */
	m=[[NSMenu alloc] init];
	[m addItemWithTitle: _(@"Open list")
		action: @selector(listFolders:)
		keyEquivalent: @"f"];
	[m addItemWithTitle: _(@"Open folder")
		action: @selector(openFolder:)];
	[menu setSubmenu: m forItem: [menu addItemWithTitle: _(@"Folder list")]];
	[m release];


	/* 'Folder' menu */
	m=[[NSMenu alloc] init];

	/* Folder->Move to */
	m2=[[NSMenu alloc] init];
	[m2 addItemWithTitle: _(@"Parent")
		action: @selector(moveToParent:)
		keyEquivalent: @"P"];
	[m2 addItemWithTitle: _(@"Next unread")
		action: @selector(moveToNextUnread:)
		keyEquivalent: @"n"];
	[m2 addItemWithTitle: _(@"Scroll/next")
		action: @selector(scrollNextUnread:)
		keyEquivalent: @" "];
	[m2 addItemWithTitle: _(@"Next branch")
		action: @selector(skipBranch:)
		keyEquivalent: @"b"];
	[m2 addItemWithTitle: _(@"Next thread")
		action: @selector(skipBranch:)
		keyEquivalent: @"t"];
	[m setSubmenu: m2 forItem: [m addItemWithTitle: _(@"Move to")]];
	[m2 release];

	/* Folder->Mark read */
	m2=[[NSMenu alloc] init];
	[m2 addItemWithTitle: _(@"Branch")
		action: @selector(skipBranchMark:)
		keyEquivalent: @"B"];
	[m2 addItemWithTitle: _(@"Thread")
		action: @selector(skipBranchMark:)
		keyEquivalent: @"T"];
	[m2 addItemWithTitle: _(@"All")
		action: @selector(markAll:)
		keyEquivalent: @"A"];
	[m setSubmenu: m2 forItem: [m addItemWithTitle: _(@"Mark read")]];
	[m2 release];

	/* Folder->Sort by */
	m2=[[NSMenu alloc] init];
	[m2 addItemWithTitle: _(@"Thread")
		action: @selector(folderSortThread)];
	[m2 addItemWithTitle: _(@"Reverse thread")
		action: @selector(folderSortReverseThread)];
/* TODO: these are currently unusably slow
	[m2 addItemWithTitle: _(@"Subject")
		action: @selector(folderSortSubject)];
	[m2 addItemWithTitle: _(@"Reverse subject")
		action: @selector(folderSortReverseSubject)];
	[m2 addItemWithTitle: _(@"From")
		action: @selector(folderSortFrom)];
	[m2 addItemWithTitle: _(@"Reverse from")
		action: @selector(folderSortReverseFrom)];
	[m2 addItemWithTitle: _(@"Date")
		action: @selector(folderSortDate)];
	[m2 addItemWithTitle: _(@"Reverse date")
		action: @selector(folderSortReverseDate)];*/
	[m2 addItemWithTitle: _(@"Arrival")
		action: @selector(folderSortOrder)];
	[m2 addItemWithTitle: _(@"Reverse arrival")
		action: @selector(folderSortReverseOrder)];
	[m setSubmenu: m2 forItem: [m addItemWithTitle: _(@"Sort by")]];
	[m2 release];

	[menu setSubmenu: m forItem: [menu addItemWithTitle: _(@"Folder")]];
	[m release];


	/* 'Message' menu */
	m=[[NSMenu alloc] init];
/*	[m addItemWithTitle: _(@"Open")
		action: @selector(openMessage:)];*/
	m2=[[NSMenu alloc] init];
	
	NSDictionary *charsets = [CWCharset allCharsets];
	NSEnumerator *en = [[charsets allValues] objectEnumerator];
	NSString *encoding;
	while((encoding = [en nextObject]))
	  {
	    [m2 addItemWithTitle: encoding
		action: @selector(changeEncoding:)];
	  }

	[m setSubmenu: m2 forItem: [m addItemWithTitle: _(@"Change encoding...")]];
	[m addItemWithTitle: _(@"Toggle read/unread")
		action: @selector(messageToggleRead:)
		keyEquivalent: @"m"];
	[m addItemWithTitle: _(@"Switch font")
		action: @selector(switchFont)
		keyEquivalent: @"F"];
	[m addItemWithTitle: _(@"Show source")
		action: @selector(showSource)];
	[m addItemWithTitle: _(@"Download")
		action: @selector(messageDownload)];
	[m addItemWithTitle: _(@"Save...")
		action: @selector(messageSave)
		keyEquivalent: @"s"];
	[menu setSubmenu: m forItem: [menu addItemWithTitle: _(@"Message")]];
	[m release];


	/* 'Compose' menu */
	m=[[NSMenu alloc] init];
	[m addItemWithTitle: _(@"New article")
		action: @selector(composeNewArticle:)];
	[m addItemWithTitle: _(@"Followup to group")
		action: @selector(composeFollowup:)
		keyEquivalent: @"r"];
	[menu setSubmenu: m forItem: [menu addItemWithTitle: _(@"Compose")]];
	[m release];


	/* 'Edit' menu */
	m=[[NSMenu alloc] init];
	[m addItemWithTitle: _(@"Copy")
		action: @selector(copy:)
		keyEquivalent: @"c"];
	[m addItemWithTitle: _(@"Cut")
		action: @selector(cut:)
		keyEquivalent: @"x"];
	[m addItemWithTitle: _(@"Paste")
		action: @selector(paste:)
		keyEquivalent: @"v"];
	[menu setSubmenu: m forItem: [menu addItemWithTitle: _(@"Edit")]];
	[m release];


	/* Main menu entries */
	[menu addItemWithTitle: _(@"Update")
		action: @selector(update:)
		keyEquivalent: @"u"];

	[menu addItemWithTitle: _(@"Log window")
		action: @selector(logWindow:)
		keyEquivalent: @"l"];

	m=[[NSMenu alloc] init];
	[m addItemWithTitle: _(@"Close")
		action: @selector(performClose:)
		keyEquivalent: @"w"];
	[menu setSubmenu: m forItem: [menu addItemWithTitle: _(@"Windows")]];
	[app setWindowsMenu: m];
	[m release];

	m=[[NSMenu alloc] init];
	[menu setSubmenu: m forItem: [menu addItemWithTitle: _(@"Services")]];
	[app setServicesMenu: m];
	[m release];

	[menu addItemWithTitle: _(@"Hide")
		action: @selector(hide:)
		keyEquivalent: @"h"];

	[menu addItemWithTitle: _(@"Quit")
		action: @selector(quit:)
		keyEquivalent: @"q"];

	[app setMainMenu: menu];
	[menu setTitle: @"LuserNET.app"];
	[menu release];


	log_window=[[LogWindowController alloc] init];
	[log_window addLogString: [NSString stringWithFormat: _(@"Welcome to LuserNET.app v%s"),VERSION]];
	[log_window addLogString: _(@"alt-f brings up the folder lists; alt-u checks for new messages")];


	[[NSNotificationCenter defaultCenter]
		addObserver: self
		selector: @selector(logMessage:)
#ifdef LOG_MESSAGES_ONLY
		name: MsgDB_LogMessageNotification
#else
		name: nil
#endif
		object: mdb];
}

-(void) applicationDidFinishLaunching: (NSNotification *)n
{
	NSUserDefaults *ud=[NSUserDefaults standardUserDefaults];
	NSArray *a;

	if ([ud boolForKey: LogWindowVisibleKey])
		[log_window showWindow: self];
	if ([ud boolForKey: FolderListVisibleKey])
		[self listFolders: self];

	a=[ud arrayForKey: FoldersVisibleKey];
	if (a)
	{
		int i,c=[a count];
		for (i=0;i<c;i++)
			[self openFolderWindow: [a objectAtIndex: i]];
	}
}

@end


int main(int argc, char **argv)
{
	AppDelegate *ad;
	NSApplication *a;

	CREATE_AUTORELEASE_POOL(arp);

//	[NSObject enableDoubleReleaseCheck: YES];

	a=[NSApplication sharedApplication];
	app_delegate=ad=[[AppDelegate alloc] initWithApp: a];
	[a setDelegate: ad];
	[a run];

	DESTROY(ad);
	DESTROY(a);

	DESTROY(arp);
	return 0;
}

