/******************************************************************************
 SyGTreeSet.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 "SyGTreeSet.h"

#include "SyGHeaderWidget.h"
#include "SyGFileTreeTable.h"
#include "JTreeList.h"
#include "SyGFileTreeList.h"
#include "JTreeNode.h"
#include "SyGFileTree.h"
#include "SyGFileTreeNode.h"
#include <JUNIXDirEntry.h>
#include "SyGSet.h"
#include "SyGFilterInput.h"
#include "SyGPathInput.h"
#include "SyGApplication.h"
#include "SyGGlobals.h"
#include "SyGPrefsMgr.h"

#include <JXStaticText.h>
#include <JXWindow.h>
#include <JXTextButton.h>
#include <JXTextMenu.h>
#include <JXXFontMenu.h>
#include <JXFontSizeMenu.h>
#include <JXMenuBar.h>
#include <JXScrollbarSet.h>
#include <JXStringHistoryMenu.h>

#include <JFontManager.h>
#include <JFontStyle.h>
#include <JString.h>

#include <jDirUtil.h>
#include <jGlobals.h>

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

const JCoordinate kHeaderHeight 		= 20;

const JFileVersion kCurrentFileVersion	= 1;

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

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

SyGTreeSet::SyGTreeSet
	(
	istream& 			is,
	const int 			type,
	JXMenuBar* 			menuBar,
	const JCharacter*	pathName,
	SyGSet* 			set,
	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)
{
	JBoolean showHidden = kFalse;
	JFileVersion version = 0;
	if (!(is.fail()) )
		{
		is >> version;
		is >> showHidden;
		}		

	SyGTreeSetX(menuBar, pathName, set, enclosure, 
					hSizing, vSizing, x, y, w, h);

	if (showHidden)
		{
		itsFileTree->ShowHiddenEntries(showHidden);
		}

	if (!(is.fail()) )
		{
		JString str;
		is >> str;
		itsFilterInput->SetText(str);
		itsFilter = str;
		itsFileTree->TurnOnFilter(str);
		itsFilterHistory->ReadSetup(is);
		itsTable->InitializeColumns(is);
		JBoolean sF;
		is >> sF;
		if (!sF)
			{
			itsFilterInput->Hide();
			itsFilterLabel->Hide();
			itsFilterHistory->Hide();
			itsScrollbarSet->Place(0,0);
			itsScrollbarSet->AdjustSize(0,kHeaderHeight);
			SetDirectoryFilter("");
			}
		itsTable->InitDirs(is);
		}
}

SyGTreeSet::SyGTreeSet
	(
	JXMenuBar* 			menuBar,
	const JCharacter*	pathName,
	SyGSet* 			set,
	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)
{
	SyGTreeSetX(menuBar, pathName, set, enclosure, 
					hSizing, vSizing, x, y, w, h);
	itsTable->InitializeColumns();
	JBoolean show = SyGGetPrefsMgr()->GetFilterStatePref();
	if (!show)
		{
		itsFilterInput->Hide();
		itsFilterLabel->Hide();
		itsFilterHistory->Hide();
		itsScrollbarSet->Place(0,0);
		itsScrollbarSet->AdjustSize(0,kHeaderHeight);
		}
}

void SyGTreeSet::SyGTreeSetX
	(
	JXMenuBar* 			menuBar,
	const JCharacter*	pathName,
	SyGSet* 			set,
	JXContainer*		enclosure,
	const HSizingOption	hSizing,
	const VSizingOption	vSizing,
	const JCoordinate	x,
	const JCoordinate	y,
	const JCoordinate	w,
	const JCoordinate	h
	)
{
	itsScrollbarSet =
		new JXScrollbarSet(this, kHElastic,kVElastic,
						   0, kHeaderHeight,
						   w, h - 2 * kHeaderHeight);
	assert( itsScrollbarSet != NULL );
	
	JUNIXDirEntry* entry = new JUNIXDirEntry(pathName);
	assert(entry != NULL);
	SyGFileTreeNode* base = 
		new SyGFileTreeNode(NULL, entry, NULL,pathName, kTrue);
	assert (base != NULL);
	itsFileTree = new SyGFileTree(base);
	assert(itsFileTree != NULL);
	
	SyGFileTreeList* obj1 = new SyGFileTreeList(itsFileTree);
	assert(obj1 != NULL);
	itsFileTree->SetTreeList(obj1);
	
	JXContainer* encl = itsScrollbarSet->GetScrollEnclosure();
	JRect enclApG     = encl->GetApertureGlobal();

	itsTable = SyGFileTreeTable::Create(menuBar, itsFileTree, obj1, set,
						itsScrollbarSet, encl,
					   JXWidget::kHElastic, JXWidget::kVElastic,
					   0,kHeaderHeight, enclApG.width(),
					   enclApG.height()-kHeaderHeight);				   				   
	assert( itsTable != NULL );
	base->BuildChildList();
	ListenTo(itsFileTree);

	itsFilterInput =
		new SyGFilterInput(itsTable, this, JXWidget::kHElastic, JXWidget::kFixedTop,
			45, 0, w - 45 - 30, kHeaderHeight);
	assert( itsFilterInput != NULL );
	ListenTo(itsFilterInput);
	
	itsFilterHistory = 
		new JXStringHistoryMenu(10, "", this,
                    JXWidget::kFixedRight, JXWidget::kFixedTop, w - 30 - 2,0, 30,20);
    assert(itsFilterHistory != NULL);
	ListenTo(itsFilterHistory); 

	itsFilterLabel =
        new JXStaticText("Filter:", this,
                    JXWidget::kFixedLeft, JXWidget::kFixedTop, 5,3, 40,13);
    assert( itsFilterLabel != NULL );
    	
	enclApG     = encl->GetApertureGlobal();
	
	SyGHeaderWidget* colHeader = 
		SyGHeaderWidget::Create(itsTable, itsScrollbarSet, encl,
							  JXWidget::kHElastic, JXWidget::kFixedTop,
							  0,0, enclApG.width(),
							  kHeaderHeight);
	assert(colHeader != NULL);	

	itsHomeButton = 
		new JXTextButton("Home", this, JXWidget::kFixedLeft, 
			JXWidget::kFixedBottom, 30, h - kHeaderHeight, 50, kHeaderHeight);
	assert( itsHomeButton != NULL);
	
	ListenTo( itsHomeButton );
	itsHomeButton->SetShortcuts("#H");
	
	itsUpButton = 
		new JXTextButton("Up", this, JXWidget::kFixedLeft, 
			JXWidget::kFixedBottom, 0, h - kHeaderHeight, 30, kHeaderHeight);
	assert( itsUpButton != NULL);
	
	ListenTo( itsUpButton );
	itsUpButton->SetShortcuts("#U");

	itsPathInput = 
		new SyGPathInput(itsTable, this, JXWidget::kHElastic, JXWidget::kFixedBottom,
			80, h - kHeaderHeight, w - 80, kHeaderHeight);
	assert( itsPathInput != NULL );
	
	ListenTo( itsPathInput );
	itsPathInput->SetText(pathName);

	JXTEBase* te = itsTable->GetEditMenuHandler();
	JXTextMenu* menu;
	if (te->GetEditMenu(&menu))
		{
		itsPathInput->ShareEditMenu(te, kFalse, kFalse);
		itsFilterInput->ShareEditMenu(te, kFalse, kFalse);
		}
}

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

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

SyGTreeSet::~SyGTreeSet()
{
}

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

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

void
SyGTreeSet::Receive
	(
	JBroadcaster*	sender,
	const Message&	message
	)
{	

	if (sender == itsPathInput && message.Is(JXWidget::kLostFocus))
		{
		GoToItsPath();
		}
		
	else if (sender == itsFilterInput && message.Is(JXWidget::kLostFocus))
		{
		JString inputstr = itsFilterInput->GetText();
		if (inputstr != itsFilter)
			{
			SetDirectoryFilter(inputstr);
			itsFilterHistory->AddString(inputstr);
			}
		}
		
	else if (sender == itsFilterHistory && message.Is(JXMenu::kItemSelected))
		{
		const JXMenu::ItemSelected* selection =
			dynamic_cast(const JXMenu::ItemSelected*, &message);
		assert( selection != NULL );
		const JString str = itsFilterHistory->GetItemText(selection->GetIndex());
		itsFilterInput->SetText(str);
		if (str != itsFilter)
			{
			SetDirectoryFilter(str);
			}
		}
		
	else if (sender == itsHomeButton && message.Is(JXButton::kPushed))
		{
		JString homeDir;
		const JBoolean found = JGetHomeDirectory(&homeDir);
		JTreeNode* jnode = itsFileTree->GetRoot();
		SyGFileTreeNode* node = dynamic_cast(SyGFileTreeNode*, jnode);
		assert(node != NULL);
		if (found && (homeDir != node->GetName()))
			{
			node->GoTo(homeDir);
			}
		else if (!found)
			{
			JGetUserNotification()->ReportError("Unable to find your home directory.");
			}
		}

	else if (sender == itsUpButton && message.Is(JXButton::kPushed))
		{
		JTreeNode* jnode = itsFileTree->GetRoot();
		SyGFileTreeNode* node = dynamic_cast(SyGFileTreeNode*, jnode);
		assert(node != NULL);
		JString cwd = node->GetName();
		if (cwd != "/")
			{
			if (cwd.GetLastCharacter() == '/')
				{
				cwd.RemoveSubstring(cwd.GetLength(), cwd.GetLength());
				}
			JString path;
			JString name;
			JSplitPathAndName(cwd, &path, &name);
			if (path != "/")
				{
				if (path.GetLastCharacter() == '/')
					{
					path.RemoveSubstring(path.GetLength(), path.GetLength());
					}
				}
			node->GoTo(path);
			}
		}
		
	else if (sender == itsFileTree && message.Is(SyGFileTree::kPathChanged))
		{
		JTreeNode* jnode = itsFileTree->GetRoot();
		SyGFileTreeNode* node = dynamic_cast(SyGFileTreeNode*, jnode);
		assert(node != NULL);
		JString file = node->GetFullPathAndName();
		JCleanPath(&file);
		itsPathInput->SetText(file);
		JString path;
		JString name = file;
		if ((file.GetLastCharacter() == '/') && (file != "/"))
			{
			file.RemoveSubstring(file.GetLength(), file.GetLength());
			}
		if (file != "/")
			{
			JSplitPathAndName(file, &path, &name);
			}
//		name.Prepend("G: ");
		GetWindow()->SetTitle(name);
		}
}

/******************************************************************************
 GoToItsPath

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

void  
SyGTreeSet::GoToItsPath()
{
	if (itsPathInput->InputValid())
		{
		JString path = itsPathInput->GetText();
		JCleanPath(&path);
		itsPathInput->SetText(path);
		JTreeNode* jnode = itsFileTree->GetRoot();
		SyGFileTreeNode* node = dynamic_cast(SyGFileTreeNode*, jnode);
		assert(node != NULL);
		
		if (path != node->GetName())
			{
			JError err = node->GoTo(path);
			assert( err.OK() );
			}
		}
}

/******************************************************************************
 SetDirectoryFilter 

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

void
SyGTreeSet::SetDirectoryFilter
	(
	const JString& filter
	)
{
	itsFilter = filter;
	itsFileTree->TurnOnFilter(filter);
}

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

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

void
SyGTreeSet::SavePreferences
	(
	ostream& os
	)
{
	os << kCurrentFileVersion << ' ';
	os << itsFileTree->HiddenEntriesVisible() << " ";
	os << itsFilterInput->GetText() << " ";
	itsFilterHistory->WriteSetup(os);
	itsTable->SavePreferences(os);
	os << itsFilterInput->IsVisible() << " ";
	itsTable->SaveDirState(os);
}

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

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

JBoolean
SyGTreeSet::FilterVisible()
{
	return itsFilterInput->IsVisible();
}

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

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

void
SyGTreeSet::ToggleFilter()
{
	if (itsFilterInput->IsVisible())
		{
		itsFilterInput->Hide();
		itsFilterLabel->Hide();
		itsFilterHistory->Hide();
		itsScrollbarSet->Place(0,0);
		itsScrollbarSet->AdjustSize(0,kHeaderHeight);
		SetDirectoryFilter("");
		}
	else
		{
		itsFilterInput->Show();
		itsFilterLabel->Show();
		itsFilterHistory->Show();
		itsScrollbarSet->Place(0,kHeaderHeight);
		itsScrollbarSet->AdjustSize(0,-kHeaderHeight);
		SetDirectoryFilter(itsFilterInput->GetText());
		}
}

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

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

void
SyGTreeSet::SaveFilterPref()
{
	SyGGetPrefsMgr()->SaveFilterStatePref(itsFilterInput->IsVisible());
}
