// ----------- node.cpp

// =======================================
// Parody file Node class member functions
// =======================================

#include <io.h>

#include "parody.h"

// -------- construct a file header
FileHeader::FileHeader(String filename)
{
	deletednode = highestnode = 0;
	newfile = (Bool) (access(filename, 0) != 0);
	// ----- open the file
	nfile.open(filename, ios::in | ios::out
#ifndef ZTC
				| ios::binary
#endif
				);
	if (!newfile)	{
		// ------- read the header
		nfile.read((char *)&highestnode, sizeof highestnode);
		nfile.read((char *)&deletednode, sizeof deletednode);
		nfile.seekp(nfile.tellg());
	}
	else	{
		// ------- write the header
		nfile.write((char *)&highestnode, sizeof highestnode);
		nfile.write((char *)&deletednode, sizeof deletednode);
		nfile.seekg(nfile.tellp());
	}
	origdeletednode = deletednode;
	orighighestnode = highestnode;
}

FileHeader::~FileHeader()
{
	if (deletednode != origdeletednode ||
			highestnode != orighighestnode)	{
		// ---- the file header has changed
		nfile.seekp(0);
		nfile.write((char *)&highestnode, sizeof highestnode);
		nfile.write((char *)&deletednode, sizeof deletednode);
	}
	nfile.close();
}

// ------- appropriate a new node
NodeNbr FileHeader::NewNode()
{
	NodeNbr newnode;
	if (deletednode)	{
		newnode = deletednode;
		Node node(this, newnode);
		deletednode = node.NextNode();
		node.SetNextNode(0);
	}
	else
		newnode = ++highestnode;
	return newnode;
}

// ----------- construct a new node
Node::Node(FileHeader *hd, NodeNbr node)
{
	nextnode = 0;
	nodechanged = deletenode = False;
	nodenbr = node;
	owner = hd;
	if (nodenbr)	{
		fstream& nf = owner->Nfile();

		long nad = NodeAddress();
		nf.seekg(nad);
		// ------- read the header
		nf.read((char *) &nextnode, sizeof nextnode);
		nf.seekp(nf.tellg());

		if (nf.eof() || nf.fail())	{
			nf.clear();
			// ----- appending a new node
			nf.seekp(nad);
			nf.write((char *) &nextnode, sizeof nextnode);
			nf.seekg(nf.tellp());
		}
	}
}

// ------- assignment operator
Node& Node::operator=(Node &node)
{
	nextnode = node.nextnode;
	owner = node.owner;
	nodenbr = node.nodenbr;
	nodechanged = node.nodechanged;
	deletenode = node.deletenode;
	return *this;
}	

// ------- destroy the node
Node::~Node()
{
	if (owner && nodenbr && (nodechanged || deletenode))	{
		fstream& nf = owner->Nfile();
		if (deletenode)	{
			nextnode = owner->DeletedNode();
			owner->SetDeletedNode(nodenbr);
		}
		nf.seekp(NodeAddress());
		// ------- write the header
		nf.write((char *) &nextnode, sizeof nextnode);
		if (deletenode)	{
			// ------ zero fill the deleted node
			char fill[nodedatalength];
			memset(fill, 0, nodedatalength);
			nf.write(fill, nodedatalength);
		}
	}
}

// ---------- compute the disk address of a node
long Node::NodeAddress()
{
	long adr = nodenbr-1;
	adr *= nodelength;
	adr += fileheadersize;
	return adr;
}
