/******************************************************************************
 SyGSet.cc

	Maintains an enclosure for all the objects required by a CBCodeEditor.

	BASE CLASS = JXWidgetSet

	Copyright © 1997 by Glenn W. Bach. All rights reserved.

 ******************************************************************************/

#include "SyGSet.h"
#include "SyGTreeSet.h"
#include "SyGFileTreeTable.h"
#include "SyGApplication.h"
#include "SyGBindingsManager.h"
#include "SyGGlobals.h"
#include "SyGHelpText.h"
#include "SyGPrefsMgr.h"

#include <jx_file_open.xpm>
#include "jx_help_specific.xpm"
#include "jx_help_toc.xpm"

#include <cross_out.xpm>
#include <mini_term.xpm>
#include "man.xpm"
#include "home.xpm"
#include "trash.xpm"
#include "movetotrash.xpm"
#include "opentrash.xpm"
#include "emptytrash.xpm"

#include "SyGDirUtil.h"

#include <JXTextMenu.h>
#include <JXHorizPartition.h>
#include <JXWindow.h>
#include <JXWindowDirector.h>
#include <JXApplication.h>
#include <JXMenuBar.h>
#include <JXScrollbarSet.h>
#include <JXHelpManager.h>
#include <JXToolBar.h>
#include <JXEngravedRect.h>

#include <JTableSelection.h>
#include <JUNIXDirEntry.h>
#include <JUNIXDirInfo.h>
#include <JUNIXDirInfo.h>
#include <JUserNotification.h>
#include <JString.h>

#include <jXGlobals.h>
#include <jXCSFIcons.h>

#include <jDirUtil.h>

#include <fstream.h>
#include <strstream.h>
#include <iostream.h>
#include <jAssert.h>

const JSize kHeaderHeight = 20;

static const JCharacter* kWindowsMenuTitleStr = "Windows";
static const JCharacter* kWindowsMenuStr = 
	"Bring windows to front %i \"BringFront::SyG\""
	"| Close all other windows %k Meta-Shift-W %i \"CloseOther::SyG\"%l";
	
enum
{
	kBringWindowsToFront = 1,
	kCloseOtherChildWindows
};

static const JCharacter* kFileMenuTitleStr = "File";
static const JCharacter* kFileMenuStr = 
	"New folder %k Meta-N %i \"NewDirectory::SyG\""
	"| Open %k Meta-O %i \"Open::SyG\""
	"| Duplicate %k Meta-D %i \"Duplicate::SyG\""
	"%l| Home window %k Meta-Shift-H %i \"Home::SyG\"" 
	"%l| Open trash %i \"OpenTrash::SyG\""
	"| Empty trash %k Meta-E %i \"EmptyTrash::SyG\""
	"| Move to trash %k Backspace. %i \"MoveToTrash::SyG\""
	"| Delete %i \"Delete::SyG\""
	"%l|View man page %k Meta-I %i \"ViewMan::SyG\"" 
	"| Open terminal %k Meta-T %i \"OpenTerm::SyG\""
	"| Run command... %k Meta-R %i \"RunCmd::SyG\""
	"%l|Close %k Meta-W %i \"Close::SyG\""
	"|Quit %k Meta-Q %i \"Quit::SyG\"";
	
enum
{
	kNewDirCmd = 1,
	kOpenCmd,
	kDuplicateCmd,
	kHomeWindowCmd,
	kOpenTrashCmd,
	kEmptyTrashCmd,
	kMoveToTrashCmd,
	kDeleteCmd,
	kViewManCmd,
	kOpenTermCmd,
	kRunCmdCmd,
	kCloseCmd,
	kQuitCmd
};

static const JCharacter* kPrefsMenuTitleStr = "Preferences";
static const JCharacter* kPrefsMenuStr = 
	"Preferences... %i \"EditPrefs::SyG\""
	"| File bindings... %i \"EditBindings::SyG\""
	"|Toolbar buttons... %i \"EditToolBar::SyG\""
	"%l|Save preferences as default %i \"SavePrefs::SyG\"";

enum
{	
	kEditPrefsCmd = 1,
	kEditBindings,
	kEditToolBarCmd,
	kSavePrefsCmd
};

static const JCharacter* kHelpMenuTitleStr = "Help";
static const JCharacter* kHelpMenuStr = 
	"About %i \"About::SyG\""
	"%l|Table of Contents %i \"TOC::SyG\""
	"|Getting started %i \"GettingStarted::SyG\""
//	"|This window %i \"ThisWindowHelp::SyG\""
	"%l|Changes %i \"Changes::SyG\""
	"|Credits %i \"Credits::SyG\"";

enum
{	
	kAboutCmd = 1,
	kTOCCmd,
	kOverviewCmd,
	kChangesCmd,
	kCreditsCmd
};

const JFileVersion kCurrentFileVersion	= 1;

/******************************************************************************
 Constructor

 ******************************************************************************/

SyGSet::SyGSet
	(
	ifstream& 			ifs,
	const JCharacter*	pathName,
	JBoolean 			isMain,
	JCoordinate 		part1Width,
	JXContainer*		enclosure,
	const HSizingOption	hSizing,
	const VSizingOption	vSizing,
	const JCoordinate	x,
	const JCoordinate	y,
	const JCoordinate	w,
	const JCoordinate	h
	)
	:
	JXWidgetSet(enclosure, hSizing, vSizing, x,y, w,h)
{	
	int version;

	JBoolean ok = kFalse;	
	if ( !(ifs.fail()) )
		{
		ifs >> version;
		ok = kTrue;
		}
	
	itsMenuBar =
		new JXMenuBar(this, kHElastic, kFixedTop, 0,0, w,kJXStdMenuBarHeight);
	assert( itsMenuBar != NULL );

	itsFileMenu = itsMenuBar->PrependTextMenu(kFileMenuTitleStr);
	itsFileMenu->SetMenuItems(kFileMenuStr);
	itsFileMenu->SetUpdateAction(JXMenu::kDisableNone);
	ListenTo(itsFileMenu);

	itsFileMenu->SetItemImage(kNewDirCmd, JXGetFolderIcon());
	itsFileMenu->SetItemImage(kOpenCmd, jx_file_open);
	itsFileMenu->SetItemImage(kHomeWindowCmd, home);
	itsFileMenu->SetItemImage(kOpenTrashCmd, trash);
	itsFileMenu->SetItemImage(kEmptyTrashCmd, emptytrash);
	itsFileMenu->SetItemImage(kMoveToTrashCmd, movetotrash);
	itsFileMenu->SetItemImage(kDeleteCmd, cross_out);
	itsFileMenu->SetItemImage(kViewManCmd, man);
	itsFileMenu->SetItemImage(kOpenTermCmd, mini_term);

	itsToolBar = 
		new JXToolBar(SyGGetPrefsMgr(), kSMainToolBarID,
			itsMenuBar, 100, 200, this,
			JXWidget::kHElastic, JXWidget::kVElastic, 
			0, kJXStdMenuBarHeight, w, h - kJXStdMenuBarHeight);
	assert(itsToolBar != NULL);

	const JCoordinate newheight = itsToolBar->GetWidgetEnclosure()->GetBoundsHeight();

	JXEngravedRect* rect = 
		new JXEngravedRect(itsToolBar->GetWidgetEnclosure(), 
			JXWidget::kHElastic, JXWidget::kVElastic,
			0,0,w+2,newheight);
	assert(rect != NULL);
			

	if (ok)
		{
		itsTreeSet = 
			new SyGTreeSet(ifs, version, itsMenuBar, 
				pathName, this, itsToolBar->GetWidgetEnclosure(),
				JXWidget::kHElastic, JXWidget::kVElastic,
				0,1,w,newheight-1);
		}
	else
		{
		itsTreeSet = 
			new SyGTreeSet(itsMenuBar, 
				pathName, this, itsToolBar->GetWidgetEnclosure(),
				JXWidget::kHElastic, JXWidget::kVElastic,
				0,1,w,newheight-1);
		}
	assert(itsTreeSet != NULL);
	ListenTo(itsTreeSet->GetTable());

	itsWindowsMenu = itsMenuBar->AppendTextMenu(kWindowsMenuTitleStr);
	itsWindowsMenu->SetMenuItems(kWindowsMenuStr);
	itsWindowsMenu->SetUpdateAction(JXMenu::kDisableNone);
	ListenTo(itsWindowsMenu);
	
	itsPrefsMenu = itsMenuBar->AppendTextMenu(kPrefsMenuTitleStr);
	itsPrefsMenu->SetMenuItems(kPrefsMenuStr);
	itsPrefsMenu->SetUpdateAction(JXMenu::kDisableNone);
	ListenTo(itsPrefsMenu);

	itsHelpMenu = itsMenuBar->AppendTextMenu(kHelpMenuTitleStr);
	itsHelpMenu->SetMenuItems(kHelpMenuStr);
	itsHelpMenu->SetUpdateAction(JXMenu::kDisableNone);
	ListenTo(itsHelpMenu);

	itsHelpMenu->SetItemImage(kTOCCmd, jx_help_toc);
//	itsHelpMenu->SetItemImage(kThisWindowCmd, JXPM(jx_help_specific));

	itsToolBar->LoadPrefs();

	if (itsToolBar->IsEmpty())
		{
		itsToolBar->AppendButton(itsFileMenu, kNewDirCmd);
		itsToolBar->AppendButton(itsFileMenu, kOpenCmd);
		itsToolBar->NewGroup();
		itsToolBar->AppendButton(itsFileMenu, kHomeWindowCmd);
		itsToolBar->NewGroup();
		itsToolBar->AppendButton(itsFileMenu, kOpenTrashCmd);
		itsToolBar->NewGroup();
		itsToolBar->AppendButton(itsFileMenu, kViewManCmd);
		itsToolBar->AppendButton(itsFileMenu, kOpenTermCmd);
		
		itsTreeSet->GetTable()->LoadToolBarDefaults(itsToolBar);
		}

	ListenTo(SyGGetPrefsMgr());
	if (!SyGGetPrefsMgr()->BSIsTrashing())
		{
		itsFileMenu->SetItemNMShortcut(kMoveToTrashCmd, "");
		itsFileMenu->SetItemNMShortcut(kDeleteCmd, "Backspace.");
		}
}

/******************************************************************************
 Destructor

 ******************************************************************************/

SyGSet::~SyGSet()
{
}

/******************************************************************************
 Receive (virtual protected)

	Listen for adjustments in vertical scrollbar.

 ******************************************************************************/

void
SyGSet::Receive
	(
	JBroadcaster*	sender,
	const Message&	message
	)
{
	if (sender == itsFileMenu && message.Is(JXMenu::kItemSelected))
		{
		 const JXMenu::ItemSelected* selection =
			dynamic_cast(const JXMenu::ItemSelected*, &message);
		assert( selection != NULL );
		HandleFileMenu(selection->GetIndex());
		}

	else if (sender == itsFileMenu && message.Is(JXMenu::kNeedsUpdate))
		{
		UpdateFileMenu();
		}
	else if (sender == itsWindowsMenu && message.Is(JXMenu::kItemSelected))
		{
		const JXMenu::ItemSelected* selection =
			dynamic_cast(const JXMenu::ItemSelected*, &message);
		assert( selection != NULL );
		HandleWindowsMenu(selection->GetIndex());
		}
		
	else if (sender == itsWindowsMenu && message.Is(JXMenu::kNeedsUpdate))
		{
		UpdateWindowsMenu();
		}
		
	else if (sender == itsPrefsMenu && message.Is(JXMenu::kItemSelected))
		{
		const JXMenu::ItemSelected* selection =
			dynamic_cast(const JXMenu::ItemSelected*, &message);
		assert( selection != NULL );
		HandlePrefsMenu(selection->GetIndex());
		}

	else if (sender == itsHelpMenu && message.Is(JXMenu::kItemSelected))
		{
		const JXMenu::ItemSelected* selection =
			dynamic_cast(const JXMenu::ItemSelected*, &message);
		assert( selection != NULL );
		HandleHelpMenu(selection->GetIndex());
		}
	else if (sender == SyGGetPrefsMgr() && message.Is(SyGPrefsMgr::kSyGPrefsChanged))
		{
		if (SyGGetPrefsMgr()->BSIsTrashing())
			{
			itsFileMenu->SetItemNMShortcut(kMoveToTrashCmd, "Backspace.");
			itsFileMenu->SetItemNMShortcut(kDeleteCmd, "");
			}
		else
			{
			itsFileMenu->SetItemNMShortcut(kMoveToTrashCmd, "");
			itsFileMenu->SetItemNMShortcut(kDeleteCmd, "Backspace.");
			}
		}
}

/******************************************************************************
 UpdateFileMenu (private)

 ******************************************************************************/

void
SyGSet::UpdateFileMenu()
{
	JBoolean selected = itsTreeSet->GetTable()->HasSelectionAndFocus();
	if (selected)
		{
		itsFileMenu->EnableItem(kDuplicateCmd);
		itsFileMenu->EnableItem(kMoveToTrashCmd);
		itsFileMenu->EnableItem(kDeleteCmd);
		}
	else
		{
		itsFileMenu->DisableItem(kDuplicateCmd);
		itsFileMenu->DisableItem(kMoveToTrashCmd);
		itsFileMenu->DisableItem(kDeleteCmd);
		}
}


/******************************************************************************
 HandleFileMenu

 ******************************************************************************/

void  
SyGSet::HandleFileMenu
	(
	const JIndex index
	)
{

	if (index == kNewDirCmd)
		{
		itsTreeSet->GetTable()->CreateNewDirectory();
		}
	else if (index == kOpenCmd)
		{
		itsTreeSet->GetTable()->PerformOpen();
		}
	else if (index == kDuplicateCmd)
		{
		itsTreeSet->GetTable()->DuplicateSelected();
		}
	else if (index == kMoveToTrashCmd)
		{
		itsTreeSet->GetTable()->MoveSelectedToTrash();
		}
	else if (index == kDeleteCmd)
		{
		itsTreeSet->GetTable()->DeleteSelected();
		}
	else if (index == kViewManCmd)
		{
		itsTreeSet->GetTable()->ViewManPage();
		}
	else if (index == kOpenTermCmd)
		{
		SyGGetApplication()->OpenTerminal(itsTreeSet->GetTable()->GetCurrentPath());
		}
	else if (index == kRunCmdCmd)
		{
		itsTreeSet->GetTable()->RunCommand();
		}
	else if (index == kHomeWindowCmd)
		{
		JString homeDir;
		if (JGetHomeDirectory(&homeDir))
			{
			SyGGetApplication()->NewChildWindow(homeDir);
			}
		}
	else if (index == kOpenTrashCmd)
		{
		JString trashDir;
		if (JGetHomeDirectory(&trashDir))
			{
			JAppendDirSeparator(&trashDir);
			trashDir = trashDir + ".trashcan/";
			if (JDirectoryExists(trashDir))
				{
				SyGGetApplication()->NewChildWindow(trashDir);
				}
			else
				{
				JGetUserNotification()->ReportError("Can't find trashcan directory.");
				}
			}
		else
			{
			JGetUserNotification()->ReportError("Can't find trashcan directory.");
			}
		}
	else if (index == kEmptyTrashCmd)
		{
		JString trashDir;
		if (JGetHomeDirectory(&trashDir))
			{
			if (JGetUserNotification()->AskUserYes("Are you sure you want to empty the trashcan?"))
				{
				JAppendDirSeparator(&trashDir);
				trashDir = trashDir + ".trashcan/";
				JUNIXDirInfo *info;
				if (JUNIXDirInfo::Create(trashDir, &info))
					{
					info->ShowHidden(kTrue);
					JSize count = info->GetEntryCount();
					for (JSize i = 1; i <= count; i++)
						{
						const JUNIXDirEntry& entry = info->GetEntry(i);
						if ((entry.GetName() != ".") && (entry.GetName() != ".."))
							{
							JString sysCmd = "rm -rf " + entry.GetFullName();
							SystemCall(sysCmd);
							}
						}
					}
				}
			}
		
		}
			
	else if (index == kCloseCmd)
		{
		(GetWindow())->Close();
		}
		
	else if (index == kQuitCmd)
		{
		JXGetApplication()->Quit();
		}
	
	
}

/******************************************************************************
 GetCurrentPath

 ******************************************************************************/

const JString& 
SyGSet::GetCurrentPath()
{
	return itsTreeSet->GetTable()->GetCurrentPath();
}

/******************************************************************************
 UpdateWindowsMenu

 ******************************************************************************/

void  
SyGSet::UpdateWindowsMenu()
{
	JSize count = itsWindowsMenu->GetItemCount();
	
	for (JSize j = 3; j <= count; j++)
		{
		itsWindowsMenu->DeleteItem(3);
		}

	JPtrArray<JString> names;
	
	SyGGetApplication()->GetWindowNames(names);
	
	JIndex index = names.GetElementCount();
	
	for (JIndex i = 1; i <= index; i++)
		{
		JString num(i-1);
		JString shorts = "Meta-" + num;
		itsWindowsMenu->AppendItem(*(names.NthElement(i)),kFalse,kFalse,NULL,shorts);
		}
	names.DeleteAll();
}

/******************************************************************************
 HandleWindowsMenu

 ******************************************************************************/

void  
SyGSet::HandleWindowsMenu
	(
	const JIndex index
	)
{
	if (index == kBringWindowsToFront)
		{
		SyGGetApplication()->BringWindowsToFront();
		}
		
	else if (index == kCloseOtherChildWindows)
		{
		SyGGetApplication()->CloseOtherChildWindows(GetWindow()->GetDirector());
		}
	
	else
		{
		SyGGetApplication()->RaiseWindow(index - 2);
		}
}

/******************************************************************************
 SavePreferences

 ******************************************************************************/

void  
SyGSet::SavePreferences
	(
	ofstream& os
	)
{
	os << kCurrentFileVersion << ' ';
	itsTreeSet->SavePreferences(os);
}

/******************************************************************************
 SavePreferences

 ******************************************************************************/

void  
SyGSet::SavePartitionSize
	(
	ostrstream& os
	)
{
}

/******************************************************************************
 SelectName

 ******************************************************************************/

void  
SyGSet::SelectName
	(
	const JString& selectName
	)
{
	itsTreeSet->GetTable()->SelectName(selectName);
}

/******************************************************************************
 SelectAll

 ******************************************************************************/

void  
SyGSet::SelectAll()
{

}

/******************************************************************************
 SaveMainPrefs 

 ******************************************************************************/

void
SyGSet::SaveMainPrefs()
{

}

/******************************************************************************
 FilterVisible 

 ******************************************************************************/

JBoolean
SyGSet::FilterVisible()
{
	return itsTreeSet->FilterVisible();
}

/******************************************************************************
 ToggleFilter 

 ******************************************************************************/

void
SyGSet::ToggleFilter()
{
	itsTreeSet->ToggleFilter();
}

/******************************************************************************
 SaveFilterPref 

 ******************************************************************************/

void
SyGSet::SaveFilterPref()
{
	itsTreeSet->SaveFilterPref();
}

/******************************************************************************
 HandleHelpMenu

 ******************************************************************************/

void  
SyGSet::HandlePrefsMenu
	(
	const JIndex index
	)
{
	if (index == kEditPrefsCmd)
		{
		SyGGetPrefsMgr()->EditPrefs();
		}
	else if (index == kEditBindings)
		{
		SyGGetBindingsMgr()->EditBindings();;
		}
	else if (index == kEditToolBarCmd)
		{
		itsToolBar->Edit();
		}
	else if (index == kSavePrefsCmd)
		{
		itsTreeSet->GetTable()->SaveAsDefault();
		}
}
/******************************************************************************
 HandleHelpMenu

 ******************************************************************************/

void  
SyGSet::HandleHelpMenu
	(
	const JIndex index
	)
{
	if (index == kAboutCmd)
		{
		SyGGetApplication()->DisplayAbout();
		}
	else if (index == kTOCCmd)
		{
		(JXGetHelpManager())->ShowSection(kTOCHelpName);
		}
	else if (index == kOverviewCmd)
		{
		(JXGetHelpManager())->ShowSection(kGettingStartedHelpName);
		}
//	else if (index == kThisWindowCmd)
//		{
//		(JXGetHelpManager())->ShowSection(kMainHelpName);
//		}
	else if (index == kChangesCmd)
		{
		(JXGetHelpManager())->ShowSection(kChangeLogName);
		}
	else if (index == kCreditsCmd)
		{
		(JXGetHelpManager())->ShowSection(kCreditsName);
		}
}

/******************************************************************************
 WindowIconified (public)

 ******************************************************************************/

void
SyGSet::WindowIconified()
{
	itsTreeSet->GetTable()->WindowIconified();
}

/******************************************************************************
 WindowDeiconified (public)

 ******************************************************************************/

void
SyGSet::WindowDeiconified()
{
	itsTreeSet->GetTable()->WindowDeiconified();
}
