/******************************************************************************
 JUNIXEnvironmentInfo.cc

	Copyright © 1997 by Glenn Bach. All rights reserved.

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

#include "JUNIXEnvironmentInfo.h"
#include "JUNIXEnvironmentEntry.h"

#include <JUserNotification.h>

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

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

#include <jAssert.h>

const JCharacter* 	kBindingsFileName = ".gxfm.filebindings";
const JCharacter* 	kSysBindingsFileName = "filebindings";
const JCharacter* 	kSysBindingsPath = "/usr/local/lib/gfm/";
const JIndex		kCurrentVersion = 1;
const JIndex		kCurrentRevision = 0;

/******************************************************************************
 Static Create function and Constructor

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

JBoolean
JUNIXEnvironmentInfo::Create
	(
	JUNIXEnvironmentInfo** list
	)
{
	if (JDirectoryWritable("/usr/local/lib"))
		{
		if (!JDirectoryExists(kSysBindingsPath))
			{
			JError err = JCreateDirectory(kSysBindingsPath);
			if (!err.OK())
				{
				JString notice = "Unable to create directory \"" + JString(kSysBindingsPath) + "\"";
				JGetUserNotification()->ReportError(notice);
				return kFalse;
				}
			}
		JString bindingsfile = JString(kSysBindingsPath) + kSysBindingsFileName;
		if (!JFileExists(bindingsfile))
			{
			ofstream os(bindingsfile);
			os.close();
			}
		*list = new JUNIXEnvironmentInfo(bindingsfile);
		return kTrue;
		}
	JString home;
	if (JGetHomeDirectory(&home))
		{
		if (!JDirectoryWritable(home))
			{
			return kFalse;
			}
		JAppendDirSeparator(&home);
		JString bindingsfile = home + kBindingsFileName;
		if (!JFileExists(bindingsfile))
			{
			ofstream os(bindingsfile);
			os.close();
			}
		if (!JFileExists(bindingsfile))
			{
			return kFalse;
			}
		*list = new JUNIXEnvironmentInfo(bindingsfile);
		return kTrue;
		}
	return kFalse;
}

/******************************************************************************
 Constructor (private)

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

JUNIXEnvironmentInfo::JUNIXEnvironmentInfo
	(
	const JCharacter* bindingsfile
	)
	:
	JPtrArray<JUNIXEnvironmentEntry>(),
	itsBindingsFile(bindingsfile)
{
	itsDeletedEntries = new JPtrArray<JUNIXEnvironmentEntry>;
	itsDeletedEntries->SetCompareFunction(JUNIXEnvironmentEntry::CompareVariables);
	SetCompareFunction(JUNIXEnvironmentEntry::CompareVariables);
	Revert();
}

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

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

JUNIXEnvironmentInfo::~JUNIXEnvironmentInfo()
{
	itsDeletedEntries->DeleteAll();
	delete itsDeletedEntries;
	DeleteAll();
}

/******************************************************************************
 Apply

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

void
JUNIXEnvironmentInfo::Apply()
{
	ofstream os(itsBindingsFile);
	os << kCurrentVersion << " " << kCurrentRevision << endl;
	for (JSize i = 1; i <= GetElementCount(); i++)
		{
		JUNIXEnvironmentEntry* pb = NthElement(i);
//		if (!(pb->IsSystemBinding()) && !(pb->GetPattern().IsEmpty()))
//			{
//			os << *pb;
//			}
		}
	
	os.close();
}

/******************************************************************************
 AddEntry

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

void
JUNIXEnvironmentInfo::AddEntry
	(
	const JCharacter* pattern, 
	const JCharacter* action, 
	const JCharacter* alternate, 
	const JBoolean system
	)
{
	JUNIXEnvironmentEntry* pb = 
		new JUNIXEnvironmentEntry(pattern, action);
	assert(pb != NULL);
	JBoolean found = kFalse;
	JIndex index = 
		SearchSorted1(	pb, 
						JOrderedSetT::kLastMatch,
						&found);
	if (found)
		{
		JUNIXEnvironmentEntry* duplicate = NthElement(index);
		if (!system && duplicate->IsSystemBinding())
			{
			itsDeletedEntries->InsertSorted(duplicate, kFalse);
			RemoveElement(index);
			}
		else
			{
			DeleteElement(index);
			}
		}
	InsertSorted(pb, kFalse);
}

/******************************************************************************
 LoadBindings

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

void
JUNIXEnvironmentInfo::LoadBindings
	(
	const JCharacter* 	bindingsfile, 
	const JBoolean 		system
	)
{
	assert(JFileExists(bindingsfile));

	ifstream is(bindingsfile);
	assert(is.good());
	JBoolean firstversion = kFalse;
	int version;
	int revision;
	is >> version;
	if (is.fail())
		{
		firstversion = kTrue;
		is.clear();
		}
	else
		{
		is >> revision;
		}
	while (!is.eof())
		{
		JString pattern;
		JString action;
		JString alternate;
		is >> pattern;
		is >> action;
		is >> alternate;
		if (version == 1)
			{
			if (revision == 0)
				{
				
				}
			}
		if (is.good())
			{
			AddBinding(pattern, action, alternate, system);
			}
		else
			{
			return;
			}
		}
}


/******************************************************************************
 Revert

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

void
JUNIXEnvironmentInfo::Revert()
{
	DeleteAll();
	itsDeletedEntries->DeleteAll();
	JString systemfile(kSysBindingsPath);
	systemfile += kSysBindingsFileName;
	if (itsBindingsFile != systemfile)
		{
		if (JFileExists(systemfile))
			{
			LoadBindings(systemfile, kTrue);
			}
		}
	LoadBindings(itsBindingsFile, kFalse);
}

/******************************************************************************
 DeleteBinding

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

void
JUNIXEnvironmentInfo::MarkEntryAsDeleted
	(
	const JIndex index
	)
{
	JUNIXEnvironmentEntry* pb = NthElement(index);
	JString pattern = pb->GetPattern();
	JBoolean found = kFalse;
	JIndex findex = 
		itsDeletedEntries->SearchSorted1(	pb, 
										JOrderedSetT::kLastMatch,
										&found);
	DeleteElement(index);
	if (found)
		{
		pb = itsDeletedEntries->NthElement(findex);
		InsertSorted(pb, kFalse);
		itsDeletedEntries->RemoveElement(findex);
		JString notice = "Entry \"" + pattern + "\" has been replaced by the system entry.";
		JGetUserNotification()->ReportError(notice);
		}
}

/******************************************************************************
 ChangeVariable

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

JBoolean
JUNIXEnvironmentInfo::ChangeVariable
	(
	const JIndex 		index,
	const JCharacter* 	variable,
	JIndex*				newindex
	)
{
	JUNIXEnvironmentEntry* pb = NthElement(index);
	if (pattern != pb->GetPattern())
		{
		JUNIXEnvironmentEntry temp(pattern, "", "", kFalse);
		JIndex findex;
		if (SearchSorted(&temp, JOrderedSetT::kAnyMatch, &findex))
			{
			JString notice = "Pattern \"" + JString(pattern) + "\" is already in use.";
			JGetUserNotification()->ReportError(notice);
			return kFalse;
			}
		if (pb->IsSystemBinding())
			{
			AddBinding(pattern, pb->GetAction(), pb->GetAlternate(), kFalse);
			JUNIXEnvironmentEntry temp(pattern, "", "", kFalse);
			JIndex findex;
			if (SearchSorted(&temp, JOrderedSetT::kAnyMatch, &findex))
				{
				*newindex = findex;
				}
			}
		else
			{
			JString action(pb->GetAction());
			JString alternate(pb->GetAlternate());
			JString newpattern(pattern);
			DeleteBinding(index);
			AddBinding(newpattern, action, alternate, kFalse);
			JUNIXEnvironmentEntry temp(newpattern, "", "", kFalse);
			JIndex findex;
			if (SearchSorted(&temp, JOrderedSetT::kAnyMatch, &findex))
				{
				*newindex = findex;
				}

			}
		return kTrue;
		}
	return kFalse;
}

/******************************************************************************
 ChangeAction

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

JBoolean
JUNIXEnvironmentInfo::ChangeAction
	(
	const JIndex 		index,
	const JCharacter* 	action
	)
{
	JUNIXEnvironmentEntry* pb = NthElement(index);
	JString oldaction = pb->GetAction();
	if (action != oldaction)
		{
		if (pb->IsSystemBinding())
			{
			AddBinding(pb->GetPattern(), action, pb->GetAlternate(), kFalse);
			}
		else
			{
			pb->SetAction(action);
			}
		return kTrue;
		}
	return kFalse;
}

/******************************************************************************
 ChangeAlternate

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

JBoolean
JUNIXEnvironmentInfo::ChangeAlternate
	(
	const JIndex 		index,
	const JCharacter* 	alternate
	)
{
	JUNIXEnvironmentEntry* pb = NthElement(index);
	JString oldalternate = pb->GetAlternate();
	if (alternate != oldalternate)
		{
		if (pb->IsSystemBinding())
			{
			AddBinding(pb->GetPattern(), pb->GetAction(), alternate, kFalse);
			}
		else
			{
			pb->SetAlternate(alternate);
			}
		return kTrue;
		}
	return kFalse;
}