/******************************************************************************
 SyGApplication.cc

	SyGApplication class

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

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

#include "SyGApplication.h"
#include "SyGPrefsMgr.h"
#include "SyGMDIServer.h"
#include "SyGTreeDir.h"
#include <SyGBindingsManager.h>
#include <BindingsDir.h>
#include "SyGGlobals.h"
#include <SyGAboutDialog.h>

#include <JXStringHistoryMenu.h>
#include <JXWindow.h>

#include <JPoint.h>
#include <JUserNotification.h>
#include <JUNIXPrefsFile.h>	
#include <JString.h>
#include <JStaticBuffer.h>
#include <JThisProcess.h>

#include <jFileUtil.h>
#include <jDirUtil.h>
#include <jGlobals.h>
#include <jStrStreamUtil.h>
#include <jProcessUtil.h>

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

extern const JCharacter* kSystemGVersionNumberStr;


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

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

SyGApplication::SyGApplication
	(
	int* 		argc, 
	char* 		argv[],
	JBoolean*	displayAbout,
	JString*	prevVersStr
	)
	:
	JXApplication(argc, argv)
{
	*displayAbout = SyGCreateGlobals(this);

	if (!*displayAbout)
		{
		*prevVersStr = (SyGGetPrefsMgr())->GetSystemGVersionStr();
		if (*prevVersStr == kSystemGVersionNumberStr)
			{
			prevVersStr->Clear();
			}
		else
			{
			*displayAbout = kTrue;
			}
		}
	else
		{
		prevVersStr->Clear();
		}
	
	SyGMDIServer* mdi = new SyGMDIServer(this);
	assert(mdi != NULL);
	
	itsChildWindows = new JPtrArray<SyGTreeDir>();
	assert( itsChildWindows != NULL );
	
	itsShortcuts = new JPtrArray<JString>();
	assert( itsShortcuts != NULL );

	SyGGetPrefsMgr()->GetShortcuts(itsShortcuts);

	if (*argc == 1)
		{
		LoadChildWindows();
		}
	else
		{
		mdi->HandleCmdLineOptions(*argc, argv);
		}

	ListenTo(JThisProcess::Instance());
}

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

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

SyGApplication::~SyGApplication()
{
	delete itsChildWindows;
	itsShortcuts->DeleteAll();
	delete itsShortcuts;
	SyGDeleteGlobals();
}

/******************************************************************************
 NewChildWindow

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

void
SyGApplication::NewChildWindow
	(
	const JString& pathName,
	const JCharacter* selectName
	)
{
	JIndex index = itsChildWindows->GetElementCount();
	
	JString newName(pathName);
	JAppendDirSeparator(&newName);	
	
	if (newName.BeginsWith("~/"))
		{
		JString homeDir;
		if (JGetHomeDirectory(&homeDir))
			{
			JAppendDirSeparator(&homeDir);
			newName.ReplaceSubstring(1, 2, homeDir);
			}
		}
	
	for (JIndex i = 1; i <= index; i++)
		{
		JString name((itsChildWindows->NthElement(i))->GetCurrentPath());
		JAppendDirSeparator(&name);
		
		if (name == newName)
			{
			(itsChildWindows->NthElement(i))->Activate();
			(itsChildWindows->NthElement(i))->SelectName(selectName);
			return;
			}
		}

	if (JDirectoryExists(pathName) && JDirectoryReadable(pathName))
		{
		JString cleanName = pathName;
		JCleanPath(&cleanName);
		SyGTreeDir* childDir = new SyGTreeDir(this, cleanName, kFalse);
		assert( childDir != NULL );

		childDir->Activate();
		childDir->SelectName(selectName);
		itsChildWindows->Append(childDir);
		}
}

/******************************************************************************
 Receive

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

void
SyGApplication::Receive
	(
	JBroadcaster*	sender,
	const Message&	message
	)
{
	cout << message.GetType() << endl;
	if (sender == JThisProcess::Instance())
		{
		cout << message.GetType() << endl;
		}
}

/******************************************************************************
 CloseAllChildWindows

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

void
SyGApplication::CloseAllChildWindows()
{
	JIndex index = itsChildWindows->GetElementCount();
	
	for (JIndex i = 1; i <= index; i++)
		{
		(itsChildWindows->NthElement(1))->Close();
		}
}

/******************************************************************************
 CloseOtherChildWindows

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

void
SyGApplication::CloseOtherChildWindows
	(
	JXWindowDirector* dir
	)
{
	JIndex index = itsChildWindows->GetElementCount();
	
	for (JIndex i = index; i >= 1; i--)
		{
		SyGTreeDir* treeDir = itsChildWindows->NthElement(i);
		if (treeDir != dir)
			{
			treeDir->Close();
			}
		}
}


/******************************************************************************
 BringWindowsToFront

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

void
SyGApplication::BringWindowsToFront()
{
	JIndex index = itsChildWindows->GetElementCount();
	
	for (JIndex i = 1; i <= index; i++)
		{
		(itsChildWindows->NthElement(i))->Activate();
		}
}


/******************************************************************************
 GetWindowNames

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

void
SyGApplication::GetWindowNames
	(
	JPtrArray<JString>& names
	)
{
	JIndex count = itsChildWindows->GetElementCount();	
	for (JIndex i = 1; i <= count; i++)
		{
		JString* name = 
			new JString((itsChildWindows->NthElement(i))->GetCurrentPath());
		assert( name != NULL );
		JString homeDir;
		if (JGetHomeDirectory(&homeDir))
			{
			JAppendDirSeparator(&homeDir);
			if (name->BeginsWith(homeDir))
				{
				name->ReplaceSubstring(1, homeDir.GetLength(), "~/");
				}
			}
		names.Append(name);
		}
}


/******************************************************************************
 DirectorClosed

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

void
SyGApplication::DirectorClosed
	(
	JXDirector* theDirector
	)
{
	if (IsClosing())
		{
		return;
		}
	JIndex index;

	const SyGTreeDir* dir = 
			dynamic_cast(SyGTreeDir*, theDirector);

	if (itsChildWindows->Find(dir, &index))
		{
		itsChildWindows->Remove(dir);		
		}
}

/******************************************************************************
 RaiseWindow

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

void  
SyGApplication::RaiseWindow
	(
	const JIndex index
	)
{
	assert (index <= itsChildWindows->GetElementCount());
		
	(itsChildWindows->NthElement(index))->Activate();
}

/******************************************************************************
 OpenShortcut

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

void
SyGApplication::OpenShortcut
	(
	const JIndex index
	)
{
	assert (index <= (JIndex)(itsShortcuts->GetElementCount()));
	JString newName(*(itsShortcuts->NthElement(index)));
	JAppendDirSeparator(&newName);	
	
	if (newName.BeginsWith("~/"))
		{
		JString homeDir;
		if (JGetHomeDirectory(&homeDir))
			{
			JAppendDirSeparator(&homeDir);
			newName.ReplaceSubstring(1, 2, homeDir);
			}
		else
			{
			newName.ReplaceSubstring(1, 2, "/");
			}
		}
	if (JDirectoryExists(newName))
		{
		NewChildWindow( newName);
		}
	else
		{
		JString askMsg = "This directory does not exist. Do you want to remove this shortcut?";
		
		if (JGetUserNotification()->AskUserYes(askMsg))
			{
			itsShortcuts->DeleteElement(index);
			}
		}
}

/******************************************************************************
 AddShortcut

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

void
SyGApplication::AddShortcut
	(
	const JString& shortcut
	)
{
	JIndex index = 0;

	for (JSize i = 1; i <= itsShortcuts->GetElementCount(); i++)
		{
		if ( *(itsShortcuts->NthElement(i)) == shortcut)
			{
			index = i;
			break;
			}
		}
		
	if (index == 0)
		{
		JString* newSC = new JString(shortcut);
		itsShortcuts->Append(newSC);
		}
}

/******************************************************************************
 RemoveShortcut

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

void
SyGApplication::RemoveShortcut
	(
	const JString& shortcut
	)
{
	JIndex index = 0;

	for (JSize i = 1; i <= itsShortcuts->GetElementCount(); i++)
		{
		if ( *(itsShortcuts->NthElement(i)) == shortcut)
			{
			index = i;
			break;
			}
		}
		
	if (index > 0)
		{
		itsShortcuts->DeleteElement(index);
		}
}

/******************************************************************************
 RemoveAllShortcuts

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

void
SyGApplication::RemoveAllShortcuts()
{
	itsShortcuts->DeleteAll();
}

/******************************************************************************
 GetShortcuts

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

JPtrArray<JString>&
SyGApplication::GetShortcuts()
{
	return *itsShortcuts;
}

/******************************************************************************
 Close

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

JBoolean 
SyGApplication::Close()
{
	SyGGetPrefsMgr()->SaveShortcuts(*itsShortcuts);
	SaveChildWindows();
	return JXApplication::Close();
}

/******************************************************************************
 SaveChildWindows

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

void
SyGApplication::SaveChildWindows()
{
	JPtrArray<JString> children;
	JSize count = itsChildWindows->GetElementCount();
	for (JSize i = 1; i<= count; i++)
		{
		JString* str = new JString((itsChildWindows->NthElement(i))->GetCurrentPath());
		assert(str != NULL);
		children.Append(str);
		}
	SyGGetPrefsMgr()->SaveChildWindows(children);
	children.DeleteAll();
}

/******************************************************************************
 LoadChildWindows

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

void
SyGApplication::LoadChildWindows()
{
	JPtrArray<JString> children;
	SyGGetPrefsMgr()->GetChildWindows(&children);

	JSize count = children.GetElementCount();
	
	for (JSize i = 1; i <= count; i++)
		{
		JString* str = children.NthElement(i);
		NewChildWindow(*str);
		}

	if (itsChildWindows->GetElementCount() == 0)
		{
		JString homeDir;
		if (!JGetHomeDirectory(&homeDir))
			{
			homeDir = "/";
			}
		NewChildWindow(homeDir);
		}
}

/******************************************************************************
 DisplayAbout (public)

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

void
SyGApplication::DisplayAbout
	(
	const JCharacter* prevVersStr
	)
{
	SyGAboutDialog* dlog = new SyGAboutDialog(this, prevVersStr);
	assert( dlog != NULL );
	dlog->BeginDialog();
}

/******************************************************************************
 ViewManPage (public)

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

void
SyGApplication::ViewManPage
	(
	const JCharacter* 	item, 
	const JCharacter	index, 
	const JBoolean 		apropos
	)
{
	JString cmd = SyGGetPrefsMgr()->GetManViewCmd();
	cmd += " ";
	if (apropos)
		{
		cmd += "-k ";
		}
	else if (index != ' ')
		{
		#ifdef _J_MAN_SECTION_VIA_DASH_S
		cmd += "-s ";
		#endif

		const JCharacter pageIndexStr[] = { index, ' ', '\0' };
		cmd += pageIndexStr;
		}
	cmd += JPrepArgForExec(item);
	pid_t pid;
	JError err = JExecute(cmd, &pid);
	if (!err.OK())
		{
		err.ReportError();
		}	
}

/******************************************************************************
 OpenTerminal (public)

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

void
SyGApplication::OpenTerminal
	(
	const JCharacter* dir
	)
{
	JString cwd	= JGetCurrentDirectory();
	JError err  = JChangeDirectory(dir);
	if (!err.OK())
		{
		err.ReportError();
		return;
		}
	JString termCmd = SyGGetPrefsMgr()->GetTerminalCmd();
	JString fullname = dir;
	JString path;
	JString name;
	JStripTrailingDirSeparator(&fullname);
	JSplitPathAndName(fullname, &path, &name);
	name.PrependCharacter('\"');
	name.AppendCharacter('\"');
	JIndex findex;
	while (termCmd.LocateSubstring("$n", &findex))
		{
		termCmd.ReplaceSubstring(findex, findex + 1, name);
		}

	pid_t pid;
	err = JExecute(termCmd, &pid);
	if (!err.OK())
		{
		err.ReportError();
		}
	JChangeDirectory(cwd);
}

/******************************************************************************
 CleanUpBeforeSuddenDeath (virtual protected)


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

void
SyGApplication::CleanUpBeforeSuddenDeath
	(
	const JXDocumentManager::SafetySaveReason reason
	)
{
	if (reason == JXDocumentManager::kServerDead)
		{
		Quit();
		}
}
