/*______________________________________________________________________________
                                                   


    	Schema.cpp
   	  10 Nov 1997

		Implementation of NDS SCHEMA Class and its definitions.

      Developed by:		David Wagstaff
      					Jeff Sabin

      Disclaimer:

			This program is an unpublished copyrighted work which is proprietary
			to Novell, Inc. and contains confidential information that is not
			to be reproduced or disclosed to any other person or entity without
			prior written consent from Novell, Inc. in each and every instance.

			WARNING:  Unauthorized reproduction of this program as well as
			unauthorized preparation of derivative works based upon the
			program or distribution of copies by sale, rental, lease or
			lending are violations of federal copyright laws and state trade
			secret laws, punishable by civil and criminal penalties.



______________________________________________________________________________*/



#include "schema.h"


//------------------------------------------------------------------------------
//	ClassDef class Methods
//------------------------------------------------------------------------------
ClassDef::ClassDef(string &newname,nuint32 newflag){
	name.set_case_sensitive(FALSE);
	name = newname;
	flags = newflag;
}

ClassDef::ClassDef(char *newname, nuint32 newflag)  {
	string temp(newname);
	name.set_case_sensitive(FALSE);
	name = temp;
	flags = newflag;
}


int ClassDef::operator == (const ClassDef& B)  {             //must be defined in order to use Borland's Set container class
	if ( name == B.name )
    	return(TRUE);
	return(FALSE);
}

int ClassDef::operator < (ClassDef& B) const {             //must be defined in order to use Borland's Set container class
	if ( name < B.name )
    	return(TRUE);
	return(FALSE);
}

int ClassDef::operator !=(const ClassDef& B)  {             //must be defined in order to use Borland's Set container class
	return (!(name == B.name));
}


void ClassDef::print(void) {
	int num;

	// Print NAME
	cout << "[\"" << name << "\"]"<<  endl;

	// Print FLAGS
	if ( flags )  {
		cout << "\tFlags" << endl;
		cout << ((flags & DS_AMBIGUOUS_CONTAINMENT) 	? "\t\t\"DS_AMBIGUOUS_CONTAINMENT\"\n" : "");
		cout << ((flags & DS_AMBIGUOUS_NAMING) 			? "\t\t\"DS_AMBIGUOUS_NAMING\"\n" : "");
		cout << ((flags & DS_CONTAINER_CLASS) 			? "\t\t\"DS_CONTAINER_CLASS\"\n" : "");
		cout << ((flags & DS_EFFECTIVE_CLASS) 			? "\t\t\"DS_EFFECTIVE_CLASS\"\n" : "");
		cout << ((flags & DS_NONREMOVABLE_CLASS) 		? "\t\t\"DS_NONREMOVABLE_CLASS\"\n" : "");
	}

	// Print SUPER CLASS
	num = superClasses.GetItemsInContainer();
	if ( num > 0 )
		cout << "\tSuper Class" << endl;
	for( int i=0; i < num; i++ ) {
		cout << "\t\t" << "\"" << superClasses[i] << "\"" << endl;
	}
	// Print CONTAINMENT
	num = containment.GetItemsInContainer();
	if ( num > 0 )
		cout << "\tContainment" << endl;
	for( int i=0; i < num; i++ ) {
		cout << "\t\t" << "\"" << containment[i] << "\"" << endl;
	}
	// Print NAMEDBY
	num = namedBy.GetItemsInContainer();
	if ( num > 0 )
		cout << "\tNamed By" << endl;
	for( int i=0; i < num; i++ ) {
		cout << "\t\t" << "\"" << namedBy[i] << "\"" << endl;
	}
	// Print MANDATORY
	num = mandatory.GetItemsInContainer();
	if ( num > 0 )
		cout << "\tMandatory Attributes" << endl;
	for( int i=0; i < num; i++ ) {
		cout << "\t\t" << "\"" << mandatory[i] << "\"" << endl;
	}
	// Print OPTIONAL
	num = optional.GetItemsInContainer();
	if ( num > 0 )
		cout << "\tOptional Attributes" << endl;
	for( int i=0; i < num; i++ ) {
 		cout << "\t\t" << "\"" << optional[i] << "\"" << endl;
	}
}


void ClassDef::add(nuint32 newflags)  {
	flags = newflags;
}

void ClassDef::add(ClassType type, char *value) {
	string temp(value);
	add(type, temp);
}

void ClassDef::add(ClassType type, string &value) {
	value.set_case_sensitive(FALSE);
	switch(type) {
		case SUPERCLASSES:
			superClasses.Add(value);
			break;
		case CONTAINMENT:
			containment.Add(value);
			break;
		case NAMEDBY:
			namedBy.Add(value);
			break;
		case MANDATORY:
			mandatory.Add(value);
			break;
		case OPT:
			optional.Add(value);
			break;
     default:
		cout << "Error occurred adding a class definition!" << endl;
	}
}

bool ClassDef::isDifferent(ClassDef& b, ClassDef& newclass) {
	bool 	dflag = FALSE;
	int 	num, i;

	if (name != b.name )  {
		cout << "Cannot compare class definitions of different names." << endl;
		return FALSE;
	}

	// Are flags Different?
	if ( (flags^b.flags)&flags )  {
		newclass.add((flags^b.flags)&flags);
		dflag = TRUE;
	}

	num = superClasses.GetItemsInContainer();
	for (i=0; i<num; i++) {
		if (!b.superClasses.HasMember(superClasses[i]))  {
			newclass.add(SUPERCLASSES, superClasses[i]);
			dflag = TRUE;
		}
	}

	num = containment.GetItemsInContainer();
	for (i=0; i<num; i++) {
		if (!b.containment.HasMember(containment[i]))  {
			newclass.add(CONTAINMENT, containment[i]);
			dflag = TRUE;
		}
	}

	num = namedBy.GetItemsInContainer();
	for (i=0; i<num; i++) {
		if (!b.namedBy.HasMember(namedBy[i]))  {
			newclass.add(NAMEDBY, namedBy[i]);
			dflag = TRUE;
		}
	}

	num = mandatory.GetItemsInContainer();
	for (i=0; i<num; i++) {
		if (!b.mandatory.HasMember(mandatory[i]))  {
			newclass.add(MANDATORY, mandatory[i]);
			dflag = TRUE;
		}
	}

	num = optional.GetItemsInContainer();
	for (i=0; i<num; i++) {
		if (!b.optional.HasMember(optional[i]))  {
			newclass.add(OPT, optional[i]);
			dflag = TRUE;
		}
	}
	return dflag;
}

ostream& operator << (ostream& os, ClassDef &classdef) {
    	return os << classdef.name;
}
  

//------------------------------------------------------------------------------
//	AttrDef CLASS Methods
//------------------------------------------------------------------------------
AttrDef::AttrDef(string newname)  {
	name.set_case_sensitive(FALSE);
	name = newname;
	flags  = 0;
	syntax = -1;		// UNKNOWN is 0 so use -1 here
}

AttrDef::AttrDef(nuint32 newsyntax, nuint32 newflag, string newname) {
		name.set_case_sensitive(FALSE);
		name = newname;
		flags = newflag;
		syntax = newsyntax;
}

void AttrDef::addFlags(nuint32 newFlags)  {
	flags = newFlags;
}

void AttrDef::addSyntax(nuint32 newSyntax)  {
	syntax = newSyntax;
}

void AttrDef::print(void) {
	// Print NAME
	cout << "[\"" << name << "\"]" << endl;

	// Print FLAGS
	if ( flags )  {
		cout << "\tFlags" << endl;
		cout << ((flags & DS_SINGLE_VALUED_ATTR) 	? "\t\t\"DS_SINGLE_VALUED_ATTR\"\n" : "");
		cout << ((flags & DS_SIZED_ATTR) 			? "\t\t\"DS_SIZED_ATTR\"\n" : "");
		cout << ((flags & DS_NONREMOVABLE_ATTR)    	? "\t\t\"DS_NONREMOVABLE_ATTR\"\n" : "");
		cout << ((flags & DS_READ_ONLY_ATTR) 	   	? "\t\t\"DS_READ_ONLY_ATTR\"\n" : "");
		cout << ((flags & DS_STRING_ATTR) 			? "\t\t\"DS_STRING_ATTR\"\n" : "");
		cout << ((flags & DS_HIDDEN_ATTR) 			? "\t\t\"DS_HIDDEN_ATTR\"\n" : "");
		cout << ((flags & DS_SYNC_IMMEDIATE) 		? "\t\t\"DS_SYNC_IMMEDIATE\"\n" : "");
		cout << ((flags & DS_PUBLIC_READ)	 		? "\t\t\"DS_PUBLIC_READ\"\n" : "");
		cout << ((flags & DS_SERVER_READ)	 		? "\t\t\"DS_SERVER_READ\"\n" : "");
		cout << ((flags & DS_PER_REPLICA)  			? "\t\t\"DS_PER_REPLICA\"\n" : "");
		cout << ((flags & DS_WRITE_MANAGED)  		? "\t\t\"DS_WRITE_MANAGED\"\n" : "");
	}

	if ( syntax != (nuint32)-1 )  {
		// Print Syntax ID
		cout << "\tSyntax" << endl;
		switch(syntax) {
			case SYN_UNKNOWN :
				cout << "\t\t\"SYN_UNKNOWN\"" << endl;
				break;
			case SYN_DIST_NAME :
				cout << "\t\t\"SYN_DIST_NAME\"" << endl;
				break;
			case SYN_CE_STRING :
				cout << "\t\t\"SYN_CE_STRING\"" << endl;
				break;
			case SYN_CI_STRING :
				cout << "\t\t\"SYN_CI_STRING\"" << endl;
				break;
			case SYN_PR_STRING :
				cout << "\t\t\"SYN_PR_STRING\"" << endl;
				break;
			case SYN_NU_STRING :
				cout << "\t\t\"SYN_NU_STRING\"" << endl;
				break;
			case SYN_CI_LIST :
				cout << "\t\t\"SYN_CI_LIST\"" << endl;
				break;
			case SYN_BOOLEAN :
				cout << "\t\t\"SYN_BOOLEAN\"" << endl;
				break;
			case SYN_INTEGER :
				cout << "\t\t\"SYN_INTEGER\"" << endl;
				break;
			case SYN_OCTET_STRING :
				cout << "\t\t\"SYN_OCTET_STRING\"" << endl;
				break;
			case SYN_TEL_NUMBER :
				cout << "\t\t\"SYN_TEL_NUMBER\"" << endl;
				break;
			case SYN_FAX_NUMBER :
				cout << "\t\t\"SYN_FAX_NUMBER\"" << endl;
				break;
			case SYN_NET_ADDRESS :
				cout << "\t\t\"SYN_NET_ADDRESS\"" << endl;
				break;
			case SYN_OCTET_LIST :
				cout << "\t\t\"SYN_OCTET_LIST\"" << endl;
				break;
			case SYN_EMAIL_ADDRESS :
				cout << "\t\t\"SYN_EMAIL_ADDRESS\"" << endl;
				break;
			case SYN_PATH :
				cout << "\t\t\"SYN_PATH\"" << endl;
				break;
			case SYN_REPLICA_POINTER :
				cout << "\t\t\"SYN_REPLICA_POINTER\"" << endl;
				break;
			case SYN_OBJECT_ACL :
				cout << "\t\t\"SYN_OBJECT_ACL\"" << endl;
				break;
			case SYN_PO_ADDRESS :
				cout << "\t\t\"SYN_PO_ADDRESS\"" << endl;
				break;
			case SYN_TIMESTAMP :
				cout << "\t\t\"SYN_TIMESTAMP\"" << endl;
				break;
			case SYN_CLASS_NAME :
				cout << "\t\t\"SYN_CLASS_NAME\"" << endl;
				break;
			case SYN_STREAM :
				cout << "\t\t\"SYN_STREAM\"" << endl;
				break;
			case SYN_COUNTER :
				cout << "\t\t\"SYN_COUNTER\"" << endl;
				break;
			case SYN_BACK_LINK :
				cout << "\t\t\"SYN_BACK_LINK\"" << endl;
				break;
			case SYN_TIME :
				cout << "\t\t\"SYN_TIME\"" << endl;
				break;
			case SYN_TYPED_NAME :
				cout << "\t\t\"SYN_TYPED_NAME\"" << endl;
				break;
			case SYN_HOLD :
				cout << "\t\t\"SYN_HOLD\"" << endl;
				break;
			case SYN_INTERVAL :
				cout << "\t\t\"SYN_INTERVAL\"" << endl;
				break;
			case SYNTAX_COUNT :
				cout << "\t\t\"SYNTAX_COUNT\"" << endl;
				break;
			default:
				cout << "An error occurred reading the Syntax ID." << endl;
		}
	}
}


int AttrDef::operator == (const AttrDef& B) {
	if (this->name==B.name)
   	return 1;
   return 0;
}

int AttrDef::operator < (AttrDef& B) const {
	if (this->name < B.name)
		return 1;
	return 0;
}

int AttrDef::operator !=(const AttrDef& B)  {             //must be defined in order to use Borland's Set container class
	return (!(name == B.name));
}


bool AttrDef::isDifferent(AttrDef& b, AttrDef& newattr) {
	bool 	dflag = FALSE;

	if (name != b.name )  {
		cout << "Cannot compare attribute definitions of different names." << endl;
		return FALSE;
	}

	// Are flags Different?
	if ( (flags^b.flags)&flags )  {
		newattr.addFlags((flags^b.flags)&flags);
		dflag = TRUE;
	}

	// Is the syntax different?
	if ( syntax != b.syntax)   {
		newattr.addSyntax(syntax);
		dflag = TRUE;
	}
	return dflag;
}


ostream& operator << (ostream& os, AttrDef &attrdef) {
    	return os << attrdef.name;
}



//------------------------------------------------------------------------------
//	SyntaxDef CLASS Methods
//------------------------------------------------------------------------------
SyntaxDef::SyntaxDef(string &newname, nflag16 newflags) {
	name.set_case_sensitive(FALSE);
	flags=newflags;
	name=newname;
}

void SyntaxDef::add(nflag16 newflags)  {
	flags = newflags;
}


void SyntaxDef::print(void) {
	// Print NAME
	cout << "[\"" << name << "\"]" <<  endl;

	if ( flags )  {
		// Print FLAGS
		cout << "\tFlags" << endl;
		cout << ((flags & DS_STRING) 	        ? "\t\t\"DS_STRING\"\n" : "");
		cout << ((flags & DS_SINGLE_VALUED) 	? "\t\t\"DS_SINGLE_VALUED\"\n" : "");
		cout << ((flags & DS_SUPPORTS_ORDER) 	? "\t\t\"DS_SUPPORTS_ORDER\"\n" : "");
		cout << ((flags & DS_SUPPORTS_EQUAL) 	? "\t\t\"DS_SUPPORTS_EQUAL\"\n" : "");
		cout << ((flags & DS_IGNORE_CASE) 		? "\t\t\"DS_IGNORE_CASE\"\n" : "");
		cout << ((flags & DS_IGNORE_SPACE) 	    ? "\t\t\"DS_IGNORE_SPACE\"\n" : "");
		cout << ((flags & DS_IGNORE_DASH) 		? "\t\t\"DS_IGNORE_DASH\"\n" : "");
		cout << ((flags & DS_ONLY_DIGITS) 		? "\t\t\"DS_ONLY_DIGITS\"\n" : "");
		cout << ((flags & DS_ONLY_PRINTABLE) 	? "\t\t\"DS_ONLY_PRINTABLE\"\n" : "");
		cout << ((flags & DS_SIZEABLE) 		    ? "\t\t\"DS_SIZEABLE\"\n" : "");
	}
}

int SyntaxDef::operator == (const SyntaxDef& B) {
	if (this->name == B.name)
   		return 1;
   	return 0;
}

int SyntaxDef::operator <  (SyntaxDef& B) const {
	if (this->name < B.name)
	   	return 1;
	return 0;
}

int SyntaxDef::operator !=(const SyntaxDef& B)  {             //must be defined in order to use Borland's Set container class
	return (!(name == B.name));
}

bool SyntaxDef::isDifferent(SyntaxDef& b, SyntaxDef& newsyntax) {
	bool 	dflag = FALSE;

	if (name != b.name )  {
		cout << "Cannot compare syntax definitions of different names." << endl;
		return FALSE;
	}

	// Are flags Different?
	if ( (flags^b.flags)&flags )  {
		newsyntax.add((flags^b.flags)&flags);
		dflag = TRUE;
	}
	return dflag;
}

ostream& operator << (ostream& os, SyntaxDef &syntaxdef) {
    	return os << syntaxdef.name;
}




//------------------------------------------------------------------------------
//	Schema CLASS Methods
//------------------------------------------------------------------------------
void Schema::write(ostream_withassign &stream) {
	int 	num;
	bool	differences = FALSE;

	// Print ClassDefs
	num = classDef.GetItemsInContainer();
	if ( num )  {
		differences = TRUE;
		stream << "\nClass Definitions" << endl;
		for( int i = 0; i < num; i++ )  {
			classDef[i].print();
		}
	}

	// Print AttrDefs
	num = attrDef.GetItemsInContainer();
	if ( num )  {
		differences = TRUE;
		stream << "\nAttribute Definitions" << endl;
		for( int i = 0; i < num; i++ )  {
			attrDef[i].print();
		}
	}


	// Print Syntax
	num = syntaxDef.GetItemsInContainer();
	if ( num )  {
		differences = TRUE;
		stream << "\nSyntax Definitions" << endl;
		for( int i = 0; i < num; i++ )  {
			syntaxDef[i].print();
		}
	}

	if (!differences)
		cout << "\tNONE" << endl;

}



int Schema::operator == (const Schema& B)  {             //must be defined in order to use Borland's Set container class
	if ( name == B.name )
    	return(TRUE);
	return(FALSE);
}

int Schema::operator < (const Schema& B)  {             //must be defined in order to use Borland's Set container class
	if ( name < B.name )
    	return(TRUE);
	return(FALSE);
}

int Schema::operator !=(const Schema& B)  {             //must be defined in order to use Borland's Set container class
	return (!(name == B.name));
}



int Schema::readClassDefs(NWCONN_HANDLE connHandle, DSContext &dsContext) {
	NWDSCCODE         	cCode;
	NWDS_ITERATION    	iterationHandle = NO_MORE_ITERATIONS;
	unsigned int      	i,j,k;
	NWCOUNT				classDefCount, classItemCount;;
    char				classDefName[MAX_SCHEMA_NAME_BYTES];
    char                classItemName[MAX_SCHEMA_NAME_BYTES];
    Class_Info_T	    classInfo;
	NWCONN_HANDLE	  	tempConnHandle;
	pBuf_T  			outBuf;
	NWDSContextHandle	contextHandle = dsContext.getContextHandle();

	/* Allocate Output Buffer */
	cCode = NWDSAllocBuf(MAX_MESSAGE_LEN, &outBuf);
	if (cCode)	{
		cout << "NWDSAllocBuf returned " << cCode  << ":" << hex << cCode << endl;
		return FALSE;
	}


	/* Display a list of  classes */
	iterationHandle=NO_MORE_ITERATIONS;


	do {
		// Read buffer of classes
		cCode = NWDSReadClassDef( contextHandle, DS_CLASS_DEFS, TRUE, NULL, 
						&iterationHandle, outBuf );
		if (cCode)  {
			cout << "NWDSReadClassDef returned " << cCode  << ":" << hex << cCode << endl;
			return FALSE;
		}

		cCode = NWDSGetContext(contextHandle,DCK_LAST_CONNECTION,&tempConnHandle);
		if (cCode)  {
			cout << "NWDSGetContext returned " << cCode  << ":" << hex << cCode << endl;
			return FALSE;
		}

		if ( connHandle != tempConnHandle ) {
			char serverName[48], tempServerName[48];
			NWGetFileServerName(connHandle, serverName);
			NWGetFileServerName(tempConnHandle, tempServerName);
			cout << "The schema information requested from " << serverName ;
			cout << " was acutally returned by " << tempServerName << endl;
			return FALSE;
			
		}

		cCode = NWDSGetClassDefCount( contextHandle,outBuf, &classDefCount );
		if (cCode)  {
			cout << "NWDSGetClassDefCount returned " << cCode  << ":" << hex << cCode << endl;
			return FALSE;
		}

		// Read a class
        for (i = 0; i < (int)classDefCount; ++i) {
			if (whirly)
				whirlyGig();
            cCode = NWDSGetClassDef(contextHandle,outBuf,classDefName,&classInfo);
			if (cCode)  {
				cout << "NWDSGetClassDef returned " << cCode  << ":" << hex << cCode << endl;
				return FALSE;
			}

			ClassDef classdef(classDefName, classInfo.classFlags);

			// Read Superclasses, containment, namedby, mandatory, optional
	        for (j = 0; j < 5; ++j)	{

	            cCode = NWDSGetClassItemCount(contextHandle,outBuf,&classItemCount);
				if (cCode)  {
					cout << "NWDSGetClassItemCount returned " << cCode  << ":" << hex << cCode << endl;
					return FALSE;
				}

				// Read each time in the definition
	           	for (k = 0; k < classItemCount; ++k){
		            cCode = NWDSGetClassItem(contextHandle,outBuf,classItemName);
					if (cCode)  {
						cout << "NWDSGetClassItem returned " << cCode  << ":" << hex << cCode << endl;
						return FALSE;
					}
					classdef.add((ClassType)j, classItemName);
				}
			}
		   	add(classdef);
		}
	}while ( iterationHandle != NO_MORE_ITERATIONS );

	NWDSFreeBuf(outBuf);
	return TRUE;
}

bool Schema::readClassDefs(TextStreamParser *tsp) {
	ClassType classtype;

	tsp->reset();	// Set stream pointer back to top of file

   if (!tsp->getLine("Class Definitions")) return FALSE;
   if (!tsp->getLine()) return FALSE;
   while ( (tsp->line != "Attribute Definitions") && (tsp->line != "Syntax Definitions") && (!tsp->wasWhite)) {
		if (whirly)
			whirlyGig();


      ClassDef classdef(tsp->line);
      if (!tsp->getLine()) return FALSE;
      while (tsp->wasWhite) {
         if ( tsp->line == "super class"             ) classtype = SUPERCLASSES;
	     else if ( tsp->line == "containment"          ) classtype = CONTAINMENT;
         else if ( tsp->line == "named by"             ) classtype = NAMEDBY;
         else if ( tsp->line == "mandatory attributes" ) classtype = MANDATORY;
         else if ( tsp->line == "optional attributes"  ) classtype = OPT;
         else if ( tsp->line == "flags"                ) classtype = FLAGS;
         else if ( classtype == FLAGS ) {
            if ( tsp->line == "DS_AMBIGUOUS_CONTAINMENT"   ) classdef.flags |= DS_AMBIGUOUS_CONTAINMENT;
            else if ( tsp->line == "DS_AMBIGUOUS_NAMING"   ) classdef.flags |= DS_AMBIGUOUS_NAMING;
            else if ( tsp->line == "DS_CONTAINER_CLASS"    ) classdef.flags |= DS_CONTAINER_CLASS;
            else if ( tsp->line == "DS_EFFECTIVE_CLASS"    ) classdef.flags |= DS_EFFECTIVE_CLASS;
            else if ( tsp->line == "DS_NONREMOVABLE_CLASS" ) classdef.flags |= DS_NONREMOVABLE_CLASS;
            else ;// ERROR!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
         }
         else classdef.add(classtype, tsp->line);
         if (!tsp->getLine())  {
			add(classdef);
			return TRUE;
		}
      }
      add(classdef);
   }
   return TRUE;
}



int Schema::readAttrDefs(NWCONN_HANDLE connHandle, DSContext &dsContext) {
	NWDSCCODE         	cCode;
	NWDS_ITERATION    	iterationHandle = NO_MORE_ITERATIONS;
	unsigned int      	i;
	char              	aname[MAX_SCHEMA_NAME_CHARS+1];
	NWCOUNT           	count;
	Attr_Info_T			attrInfo;
	NWDSContextHandle	contextHandle = dsContext.getContextHandle();
	pBuf_T  			outBuf;
	NWCONN_HANDLE	  	tempConnHandle;


	/* Allocate Output Buffer */
	cCode = NWDSAllocBuf(MAX_MESSAGE_LEN, &outBuf);
	if (cCode)	{
		cout << "NWDSAllocBuf returned " << cCode  << ":" << hex << cCode << endl;
		return FALSE;
	}


	/* List all attributes */
	iterationHandle=NO_MORE_ITERATIONS;

	do {
		cCode = NWDSReadAttrDef( contextHandle, DS_ATTR_DEFS , TRUE, NULL, &iterationHandle, outBuf );
		if (cCode)	{
			cout << "NWDSReadAttrDef returned " << cCode  << ":" << hex << cCode << endl;
			return FALSE;
		}

		cCode = NWDSGetContext(contextHandle,DCK_LAST_CONNECTION,&tempConnHandle);
		if (cCode)  {
			cout << "NWDSGetContext returned " << cCode  << ":" << hex << cCode << endl;
			return FALSE;
		}

		if ( connHandle != tempConnHandle ) {
			char serverName[48], tempServerName[48];
			NWGetFileServerName(connHandle, serverName);
			NWGetFileServerName(tempConnHandle, tempServerName);
			cout << "The schema information requested from " << serverName ;
			cout << " was acutally returned by " << tempServerName << endl;
			return(FALSE);
		}


		cCode = NWDSGetAttrCount( contextHandle, outBuf, &count );
		if (cCode)	{
			cout << "NWDSGetAttrCount returned " << cCode  << ":" << hex << cCode << endl;
			return FALSE;
		}

		for (i=0; i<count; i++)	{
			if (whirly)
				whirlyGig();

			cCode = NWDSGetAttrDef(contextHandle, outBuf, aname, &attrInfo);
			if (cCode)	{
				cout << "NWDSGetAttrDef returned " << cCode  << ":" << hex << cCode << endl;
				return FALSE;
			}

			AttrDef  attrdef(attrInfo.attrSyntaxID, attrInfo.attrFlags,aname);
			add(attrdef);
		}
	} while ( iterationHandle != NO_MORE_ITERATIONS );

	NWDSFreeBuf(outBuf);
	return TRUE;
}

bool Schema::readAttrDefs(TextStreamParser *tsp) {
	string attrtype;

	tsp->reset();	// Set stream pointer back to top of file


   if (!tsp->getLine("Attribute Definitions")) return FALSE;
   if (!tsp->getLine()) return FALSE;
   while ( (tsp->line != "Class Definitions") && (tsp->line != "Syntax Definitions") && (!tsp->wasWhite)) {
   	  if (whirly)
	  	whirlyGig();

      AttrDef attrdef(tsp->line);
      if (!tsp->getLine()) return FALSE;
      while (tsp->wasWhite) {
         if ( tsp->line == "flags" )    attrtype = "FLAGS";
         else if ( tsp->line == "syntax" )   attrtype = "SYNTAX";
         else if ( attrtype == "FLAGS" ) {
            if ( tsp->line == "DS_SINGLE_VALUED_ATTR"       ) attrdef.flags |= DS_SINGLE_VALUED_ATTR;
            else if ( tsp->line == "DS_SIZED_ATTR"          ) attrdef.flags |= DS_SIZED_ATTR;
            else if ( tsp->line == "DS_NONREMOVABLE_ATTR"   ) attrdef.flags |= DS_NONREMOVABLE_ATTR;
            else if ( tsp->line == "DS_READ_ONLY_ATTR"      ) attrdef.flags |= DS_READ_ONLY_ATTR;
            else if ( tsp->line == "DS_STRING_ATTR"         ) attrdef.flags |= DS_STRING_ATTR;
            else if ( tsp->line == "DS_HIDDEN_ATTR"         ) attrdef.flags |= DS_HIDDEN_ATTR;
            else if ( tsp->line == "DS_SYNC_IMMEDIATE" 		) attrdef.flags |= DS_SYNC_IMMEDIATE;
            else if ( tsp->line == "DS_PUBLIC_READ"		    ) attrdef.flags |= DS_PUBLIC_READ;
            else if ( tsp->line == "DS_SERVER_READ"         ) attrdef.flags |= DS_SERVER_READ;
            else if ( tsp->line == "DS_PER_REPLICA"         ) attrdef.flags |= DS_PER_REPLICA;
            else if ( tsp->line == "DS_WRITE_MANAGED"       ) attrdef.flags |= DS_WRITE_MANAGED;
            else ;// ERROR!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
         }
         else if (attrtype == "SYNTAX") {
			if      ( tsp->line == "SYN_UNKNOWN"         ) attrdef.syntax = SYN_UNKNOWN;
            else if ( tsp->line == "SYN_DIST_NAME"       ) attrdef.syntax = SYN_DIST_NAME;
            else if ( tsp->line == "SYN_CE_STRING"       ) attrdef.syntax = SYN_CE_STRING;
            else if ( tsp->line == "SYN_CI_STRING"       ) attrdef.syntax = SYN_CI_STRING;
            else if ( tsp->line == "SYN_PR_STRING"       ) attrdef.syntax = SYN_PR_STRING;
            else if ( tsp->line == "SYN_NU_STRING"       ) attrdef.syntax = SYN_NU_STRING;
            else if ( tsp->line == "SYN_CI_LIST"         ) attrdef.syntax = SYN_CI_LIST;
            else if ( tsp->line == "SYN_BOOLEAN"         ) attrdef.syntax = SYN_BOOLEAN;
            else if ( tsp->line == "SYN_INTEGER"         ) attrdef.syntax = SYN_INTEGER;
            else if ( tsp->line == "SYN_OCTET_STRING"    ) attrdef.syntax = SYN_OCTET_STRING;
            else if ( tsp->line == "SYN_TEL_NUMBER"      ) attrdef.syntax = SYN_TEL_NUMBER;
            else if ( tsp->line == "SYN_FAX_NUMBER"      ) attrdef.syntax = SYN_FAX_NUMBER;
            else if ( tsp->line == "SYN_NET_ADDRESS"     ) attrdef.syntax = SYN_NET_ADDRESS;
            else if ( tsp->line == "SYN_OCTET_LIST"      ) attrdef.syntax = SYN_OCTET_LIST;
            else if ( tsp->line == "SYN_EMAIL_ADDRESS"   ) attrdef.syntax = SYN_EMAIL_ADDRESS;
            else if ( tsp->line == "SYN_PATH"            ) attrdef.syntax = SYN_PATH;
            else if ( tsp->line == "SYN_REPLICA_POINTER" ) attrdef.syntax = SYN_REPLICA_POINTER;
            else if ( tsp->line == "SYN_OBJECT_ACL"      ) attrdef.syntax = SYN_OBJECT_ACL;
            else if ( tsp->line == "SYN_PO_ADDRESS"      ) attrdef.syntax = SYN_PO_ADDRESS;
            else if ( tsp->line == "SYN_TIMESTAMP"	     ) attrdef.syntax = SYN_TIMESTAMP;
            else if ( tsp->line == "SYN_CLASS_NAME"      ) attrdef.syntax = SYN_CLASS_NAME;
            else if ( tsp->line == "SYN_STREAM"          ) attrdef.syntax = SYN_STREAM;
            else if ( tsp->line == "SYN_COUNTER"         ) attrdef.syntax = SYN_COUNTER;
            else if ( tsp->line == "SYN_BACK_LINK"	     ) attrdef.syntax = SYN_BACK_LINK;
            else if ( tsp->line == "SYN_TIME"            ) attrdef.syntax = SYN_TIME;
            else if ( tsp->line == "SYN_TYPED_NAME"      ) attrdef.syntax = SYN_TYPED_NAME;
            else if ( tsp->line == "SYN_HOLD"            ) attrdef.syntax = SYN_HOLD;
            else if ( tsp->line == "SYN_INTERVAL"        ) attrdef.syntax = SYN_INTERVAL;
            else if ( tsp->line == "SYNTAX_COUNT"        ) attrdef.syntax = SYNTAX_COUNT;
            else ; // ERROR !!!!!!!!!!!!!!!!!!!!!!!!!!!
		}
        if (!tsp->getLine())  {
			add(attrdef);
			return TRUE;
		}
      }
      add(attrdef);
   }
   return TRUE;
}



int Schema::readSyntaxDefs(NWCONN_HANDLE connHandle, DSContext &dsContext) {
	// List all syntaxes
  	NWDSCCODE         	cCode;
	NWDS_ITERATION    	iterationHandle;
	unsigned int      	i;
	char              	sname[MAX_SCHEMA_NAME_CHARS+1];
	NWCOUNT           	count;
	Syntax_Info_T		syntaxInfo;
	NWDSContextHandle	contextHandle = dsContext.getContextHandle();
	pBuf_T  			outBuf;
	NWCONN_HANDLE	  	tempConnHandle;


	/* Allocate Output Buffer */
	cCode = NWDSAllocBuf(MAX_MESSAGE_LEN, &outBuf);
	if (cCode)	{
		cout << "NWDSAllocBuf returned " << cCode  << ":" << hex << cCode << endl;
		return FALSE;
	}


	iterationHandle=NO_MORE_ITERATIONS;
	do {
		cCode = NWDSReadSyntaxes(contextHandle, DS_SYNTAX_DEFS, TRUE,
									 NULL, &iterationHandle, outBuf);
		if (cCode)  {
			cout << "NWDSReadSyntaxes returned " << cCode  << ":" << hex << cCode << endl;
			return FALSE;
		}
		cCode = NWDSGetContext(contextHandle,DCK_LAST_CONNECTION,&tempConnHandle);
		if (cCode)  {
			cout << "NWDSGetContext returned " << cCode  << ":" << hex << cCode << endl;
			return FALSE;
		}

		if ( connHandle != tempConnHandle ) {
			char serverName[48], tempServerName[48];
			NWGetFileServerName(connHandle, serverName);
			NWGetFileServerName(tempConnHandle, tempServerName);
			cout << "The schema information requested from " << serverName ;
			cout << " was acutally returned by " << tempServerName << endl;
			return(FALSE);
		}

		cCode = NWDSGetSyntaxCount(contextHandle, outBuf, &count);
		if (cCode)  {
			cout << "NWDSGetSyntaxCount returned " << cCode  << ":" << hex << cCode << endl;
			return FALSE;
		}

		for (i = 0; i < count; i++) 	{
			if (whirly)
				whirlyGig();

	        cCode = NWDSGetSyntaxDef(contextHandle, outBuf, sname, &syntaxInfo);
			if (cCode)  {
				cout << "NWDSGetSyntaxDef returned " << cCode  << ":" << hex << cCode << endl;
				return FALSE;
			}
			string temp(sname);
  			SyntaxDef  syntaxdef(temp, syntaxInfo.flags);
			add(syntaxdef);
		}
	} while ( iterationHandle != NO_MORE_ITERATIONS );

	NWDSFreeBuf(outBuf);
	return TRUE;
}

bool Schema::readSyntaxDefs(TextStreamParser *tsp) {
	string syntaxtype;

	tsp->reset();	// Set stream pointer back to top of file


   if (!tsp->getLine("Syntax Definitions")) return FALSE;
   if (!tsp->getLine()) return FALSE;
   while ( (tsp->line != "Attribute Definitions") && (tsp->line != "Class Definitions") && (!tsp->wasWhite)) {
      if (whirly)
	  	whirlyGig();

      SyntaxDef syntaxdef(tsp->line);
      if (!tsp->getLine()) return FALSE;
      while (tsp->wasWhite) {
         if ( tsp->line == "flags" )               syntaxtype = "FLAGS";
	     else if ( syntaxtype == "FLAGS" ) {
            if      ( tsp->line == "DS_STRING"         ) syntaxdef.flags |= DS_STRING;
            else if ( tsp->line == "DS_SINGLE_VALUED"  ) syntaxdef.flags |= DS_SINGLE_VALUED;
            else if ( tsp->line == "DS_SUPPORTS_ORDER" ) syntaxdef.flags |= DS_SUPPORTS_ORDER;
            else if ( tsp->line == "DS_SUPPORTS_EQUAL" ) syntaxdef.flags |= DS_SUPPORTS_EQUAL;
            else if ( tsp->line == "DS_IGNORE_CASE"    ) syntaxdef.flags |= DS_IGNORE_CASE;
            else if ( tsp->line == "DS_IGNORE_SPACE"   ) syntaxdef.flags |= DS_IGNORE_SPACE;
            else if ( tsp->line == "DS_IGNORE_DASH"    ) syntaxdef.flags |= DS_IGNORE_DASH;
            else if ( tsp->line == "DS_ONLY_DIGITS"    ) syntaxdef.flags |= DS_ONLY_DIGITS;
            else if ( tsp->line == "DS_ONLY_PRINTABLE" ) syntaxdef.flags |= DS_ONLY_PRINTABLE;
            else if ( tsp->line == "DS_SIZEABLE"       ) syntaxdef.flags |= DS_SIZEABLE;
         else ;// ERROR!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
         }
         if (!tsp->getLine())  {
			 add(syntaxdef);
			 return TRUE;
		}
      }
      add(syntaxdef);
   }
   return TRUE;
}


// Compares the Schema and returns 0 if Schemas are the same or 1 if different
int Schema::compare(Schema& b)  {
	int 		i,num;
	bool		same;
	Schema 		schemaAB("AB");			// A - B
	Schema 		schemaBA("BA");			// B - a
	bool			error = FALSE;

	// Compare Class definitions
	num = classDef.GetItemsInContainer();
	if ( num != 0 )  {
		same = TRUE;
		cout << endl << "Classes unique to " << name << endl;
		for( i = 0; i < num; i++ )  {
			// ClassDef is unique
			if ( !b.classDef.HasMember(classDef[i]) )   {
				cout << "\t" << classDef[i].name << endl;
//				schemaAB.add(classDef[i]);
				same = FALSE;
				error = TRUE;
			}
			else  {
				ClassDef tempClassDef(classDef[i].name);
				// If there are differences then add to schemaAB
				int index = b.classDef.Find(classDef[i]);
				if (classDef[i].isDifferent(b.classDef[index], tempClassDef))  {
					schemaAB.add(tempClassDef);
					error = TRUE;
				}
			}
		}
		if ( same )  {
			cout << "\tNONE" << endl;
		}
	}

  	num = b.classDef.GetItemsInContainer();
  	if ( num != 0 )  {
		same = TRUE;
		cout << endl << "Classes unique to " << b.name << endl;
		for( i = 0; i < num; i++ )  {
			if ( !classDef.HasMember(b.classDef[i]) )  {
				cout << "\t" << b.classDef[i].name << endl;
//				schemaBA.add(b.classDef[i]);
				same = FALSE;
				error = TRUE;
			}
			else  {
				ClassDef tempClassDef(b.classDef[i].name);
				// If there are differences then add to schemaBA
				int index = classDef.Find(b.classDef[i]);
				if (b.classDef[i].isDifferent(classDef[index], tempClassDef))  {
					schemaBA.add(tempClassDef);
					error = TRUE;
				}
			}
		}
		if ( same )  {
			cout << "\tNONE" << endl;
		}
	}


	// Compare attribute definitions
	num = attrDef.GetItemsInContainer();
  	if ( num != 0 )  {
		same = TRUE;
		cout << endl << "Attributes unique to " << name << endl;
		
		for( i = 0; i < num; i++ )  {
			if ( !b.attrDef.HasMember(attrDef[i]) )	 {
				cout << "\t" << attrDef[i].name << endl;
//				schemaAB.add(attrDef[i]);
				same = FALSE;
				error = TRUE;
			}
			else  {
				AttrDef tempAttrDef(attrDef[i].name);
				// If there are differences then add to schemaAB
				int index = b.attrDef.Find(attrDef[i]);
				if (attrDef[i].isDifferent(b.attrDef[index], tempAttrDef))  {
					schemaAB.add(tempAttrDef);
					error = TRUE;
				}
			}
		}
		if ( same )  {
			cout << "\tNONE" << endl;
		}
	}

	num = b.attrDef.GetItemsInContainer();
  	if ( num != 0 )  {
		same = TRUE;
		cout << endl << "Attributes unique to " << b.name << endl;
		for( i = 0; i < num; i++ )  {
			if ( !attrDef.HasMember(b.attrDef[i]) )				  {
				cout << "\t" << b.attrDef[i].name << endl;
//				schemaBA.add(b.attrDef[i]);
				same = FALSE;
				error = TRUE;
			}
			else  {
				AttrDef tempAttrDef(b.attrDef[i].name);
				// If there are differences then add to schemaBA
				int index = attrDef.Find(b.attrDef[i]);
				if (b.attrDef[i].isDifferent(attrDef[index], tempAttrDef))  {
					schemaBA.add(tempAttrDef);
					error = TRUE;
				}
			}
		}
		if ( same )  {
			cout << "\tNONE" << endl;
		}
	}

	// Compare Syntax definitions
	num = syntaxDef.GetItemsInContainer();
  	if ( num != 0 )  {
		same = TRUE;
		cout << endl << "Syntaxes unique to " << name << endl;
		
		for( i = 0; i < num; i++ )  {
			if ( !b.syntaxDef.HasMember(syntaxDef[i]) )				  {
				cout << "\t" << syntaxDef[i].name << endl;
//				schemaAB.add(syntaxDef[i]);
				same = FALSE;
				error = TRUE;
			}
			else  {
				SyntaxDef tempSyntaxDef(syntaxDef[i].name);
				// If there are differences then add to schemaAB
				int index = b.syntaxDef.Find(syntaxDef[i]);
				if (syntaxDef[i].isDifferent(b.syntaxDef[index], tempSyntaxDef))  {
					schemaAB.add(tempSyntaxDef);
					error = TRUE;
				}
			}
		}
		if ( same )  {
			cout << "\tNONE" << endl;
		}
	}

	num = b.syntaxDef.GetItemsInContainer();
  	if ( num != 0 )  {
		same = TRUE;
		cout << endl << "Syntaxes unique to " << b.name << endl;
		for( i = 0; i < num; i++ )  {
			if ( !syntaxDef.HasMember(b.syntaxDef[i]) )  {
				cout << "\t" << b.syntaxDef[i].name << endl;
//				schemaBA.add(b.attrDef[i]);
				same = FALSE;
				error = TRUE;
			}
			else  {
				SyntaxDef tempSyntaxDef(b.syntaxDef[i].name);
				// If there are differences then add to schemaBA
				int index = syntaxDef.Find(b.syntaxDef[i]);
				if (b.syntaxDef[i].isDifferent(syntaxDef[index], tempSyntaxDef))  {
					schemaBA.add(tempSyntaxDef);
					error = TRUE;
				}
			}
		}
		if ( same )  {
			cout << "\tNONE" << endl;
		}
	}

	cout << endl << "Definition differences for " << name << endl;
	schemaAB.write();

	cout << endl << "Definition differences for " << b.name << endl;
	schemaBA.write();
	return(error);
	
}

//ostream& operator << (ostream& os, Schema &schema) {
//    	return os << schema.name;
//}

	



