// RecordHandler.h for MiniCad
//
// Copyright © Diehl Graphsoft, Inc. 1996.
// All Rights Reserved.
//
// Declares classes to simplify working with Records and Formats
//
//	** NOTES: for External Programmers **
//	The Record handler functions use MiniCad call backs and assume the 
//	existance of the global variable: CallBackPtr gCBP;
//
//	Also, before using the RecordHandler Library you must call SetUpRecordHander(). 
// 	Before exiting the external call SetDownRecordHandler(). These calls maintain
//	the RecordHandler's global data. 
//
//	Use TFormatBase and TFormatHandler for manipulating formats. These classes are constructed with 
// 	either a handle to a kFormatNode or a string. 
//
//	RecordHandler is used for editing the fields of a Record instance attached to a drawing object.
//	RecordHandlers are constructed with a handle to a recordNode. The RecordHandler's Get and Set 
//	functions pass around TRecordItems.
//
//	TRecordItems are passed a fieldStyle parameter to their constructor. They provide a way to get and 
//	set the individual data fields within a record node.
//	 
//
// Started 5/8/96 by Darick DeHart
//
// SourceSafe information for this version:
//    $Revision: 8 $
//    $Date: 7/28/00 3:34p $
//    $Author: Andrewb $

#ifndef _RECORD_HANDLER_
#define _RECORD_HANDLER_

#pragma once

#include <stddef.h>
#include "MiniCadCallBacks.h"

#ifdef _MINICAD_EXTERNAL_
	
	#if !COMPILING_RECORD_LIBRARY
	typedef MCObjectHandle RecordHandle;
	typedef MCObjectHandle FormatHandle;
	#endif		
	
	struct TextRefType {
		short						size;
		short						offset;
	};
	
	struct RecordItemType {
		union {
			double_gs				realView;
			long					longView;
			long					longlongView[2];
			Boolean 				boolView;
			TextRefType 			textView;
			TextRefType 			calcView;
			GSCharsHandle 			handleView;
		};
	};
	typedef RecordItemType		   *RecordItemPtr;

// The "enum EFieldStyle" for field type constants has been moved to MiniCadCallbacks.h, 9/1/98 JAK.
#else
	#include "RecordItemType.h" // Used to be MObject.h
	#include "Objs.Misc.h"
	PREDECLARE(Format)
	PREDECLARE(Record)
#endif // _MINICAD_EXTERNAL_

// Instead of using this typedef, code should probably use enum EFieldStyle as defined in MiniCadCallbacks.h, but don't have time to mess with it now.
typedef long FieldStyle;		

class TSmartFormat;



class TRecordItem {				// holds a temp copy of the field data
//
// TRecordItem is a handler class for safe and easy access to RecordItemType unions.
// TRecordItem's are created with a field style variable.
// The record data can be accessed with the proper get and set function.
//
public:
									
	TRecordItem( FieldStyle aFieldStyle, TNumStyleClass ns = nsGeneral, Byte accuracy = 0); 	
	// sets fields to 0 and nil
	~TRecordItem();							// delete fTextP & fUserTextP;

	TRecordItem(const TRecordItem& r)		{fTextP = nil; fUserTextP = nil; CopyTRecordItem_(r, *this); }
	TRecordItem& operator=(const TRecordItem& r) { CopyTRecordItem_(r, *this); return *this; }

	FieldStyle GetFieldStyle() const { return fFieldStyle;}
	
	// Get Functions, returns false if error
	Boolean GetFieldValue( long& theValue) const;
	Boolean GetFieldValue( long& lowValue, long& highValue) const;
	Boolean GetFieldValue( Boolean& theValue) const;
	Boolean GetFieldValue( double_gs& theValue) const;
	Boolean GetFieldValue( char*& text, size_t& size);	// I create new space for string
														// that is pointed to by text and fUserText; 
														// the class owns the space and deletes it  
	Boolean GetFieldValueAsString (Str255 theString) const;  // Do not use for text fields, as
	                                                         //  maximum of 255 characters returned 
	void GetNumStyle(TNumStyleClass& numStyle, Byte& accuracy) const;	// sets the parameters to fNumStyle
	
	// Set Functions, returns false if error
	Boolean SetFieldValue( long theValue);
	Boolean SetFieldValue( long lowValue, long highValue);
	Boolean SetFieldValue( Boolean theValue);
	Boolean SetFieldValue( double_param theValue);
	Boolean SetFieldValue( const char* text, size_t size);	// Copies text to fTextP
	
	// XXX: This short version was declared but apparently isn't implemented anywhere!  -DLD 4/30/2000
	//Boolean SetFieldValue( short theValue);	// JAK
	
	Boolean SetFieldValueAsString (Str255 theString);  // Do not use for text fields, as
	                                                   //  maximum of 255 characters passed
	void SetNumStyle(TNumStyleClass numStyle, Byte accuracy);	//Sets fNumStyle with the given paramters
	
private:
	
	RecordItemType	fValue;				// data for individual field (union)
	FieldStyle		fFieldStyle;		// type constant for theValue
	TNumStyle		fNumStyle;			// the number style and the accuracy for the data
	size_t			fSize;				// size of character data
	char*			fTextP;				// points to copy of character data &
										// takes the place of fValue for text types
	char*			fUserTextP;			// a buffer for text fields that the user can modify
										// this pointer is owned by the class and will be deleted when
										// the class is deleted or goes out of scope

	static void CopyTRecordItem_(const TRecordItem& from, TRecordItem& to);
};


class TFormatBase {
//
//	TFormatBase is constructed with a kFormatNode handle.
// 	It provides access to some basic functionality which is shared
//	between RecordHandler and FormatHandler
//
public:		
	TFormatBase(MCObjectHandle f);									// sets fFormat = f	
	virtual ~TFormatBase(); 
	
	void GetNameOfFormat( Str63 nameOfFormat)const;			// GetObjectName(fFormat) 
	short GetNumOfFields()const;							// returns 0 if fFormat = nil
	void GetNameOfField( short fieldIndex, Str20 nameOfField)const; // '' if index out of range
	short GetFieldIndex( const Str20 nameOfField)const; 	// returns 0 if fails
	FieldStyle GetFieldStyle( short fieldIndex)const; 
	Boolean GetFieldNumStyle( short fieldIndex, TNumStyleClass& numStyle, Byte& accuracy);
	Boolean SetFieldNumStyle( short fieldIndex, TNumStyleClass numStyle, Byte accuracy);

	void SetIsParametric(Boolean is = true);
	Boolean IsParametric() const;
	void SetParametricVersion(short ver);
	short GetParametricVersion();
	
	void HideFromUserInterface(Boolean inHideIt);
	Boolean IsHiddenFromUserInterface() const;

protected: 
	void SetFormat(FormatHandle f);  		
	MCObjectHandle GetFormatHandle() {return (MCObjectHandle) fFormat;} 	
	TSmartFormat* 	sFormat;			
					
private:
	FormatHandle 	fFormat; 	
};


class TRecordHandler : public TFormatBase {	
//
//	RecordHandler is used for editing the fields of a Record instance attached to a drawing object.
//	RecordHandlers are constructed with a handle to a recordNode. The RecordHandlers Get and Set 
//	functions pass around TRecordItems.
//
public:
	TRecordHandler (MCObjectHandle r);	// Creates a handler, given the record;
								//  uses GetDefinition to SetFormat in TFormatBase
#ifndef _MINICAD_EXTERNAL_
	TRecordHandler (MCObjectHandle r, MCObjectHandle fmtDef);	// Creates a handler, given the record and format; can use
												//  most methods when record and/or format not in document
												//  (TFormatBase::GetNameOfFormat is not useable)
#endif
	
	// Returns false if fieldIndex is out of range or the fieldStyle is wrong
	//  Otherwise it gives you a TRecordItem object for editing record data
	Boolean GetFieldObject( short fieldIndex, TRecordItem& value, Boolean needsByteSwap=false);	
	Boolean SetFieldObject( short fieldIndex, TRecordItem& value); 

	// Returns true if the fields are identical between the objects's record and the passed in record
	Boolean RecordsEqual(MCObjectHandle rec, Boolean thisRecNeedsByteSwap);
		
	// Returns true if all fields are identical between the two records
	static Boolean RecordsEqual(MCObjectHandle rec1, MCObjectHandle rec2);

private:
	RecordHandle fRecord;	
};


class TFormatHandler : public TFormatBase {
// 
// TFormatHandler is constructed with a handle to a kFormatNode or with a string. If the string
// is not the name of an existing format then a new format is created using that name.
// 
public:
	TFormatHandler(MCObjectHandle f);			// set fFormat = f
										
	TFormatHandler(Str63 name);			// sets fFormat to format named name. If there is no name, then						
										// creates a new Format. If name is already in use, then name is 
										// modified so that it is unique and a new format is created
	void DeleteFormat();				// calls DeleteObject - removes format and its records
	short AddField( const Str20 fieldName, TRecordItem& defaultValue, Boolean updateExistingRecords = true); // 
										// returns index of new field, 0 if fails
	void DeleteField( short fieldIndex);// deletes field in format and all records
	 
	// returns false if fieldIndex is out of range
	Boolean GetFieldDefault( short fieldIndex, TRecordItem& theValue); 
	Boolean SetFieldDefault( short fieldIndex, TRecordItem& theValue);

	void RemoveRecordFromObject(MCObjectHandle object);	//removes record from graphic object
	MCObjectHandle AttachRecordToObject(MCObjectHandle object); 
										//attaches a new record with default settings to object,
										// and returns a handle to the new record.
	Boolean CountExistingRecords(long& count);	// count number of existing records which use this format.

protected:
	TFormatHandler(Str63 name, Boolean inIsParametric);	
};

void SetUpRecordHandler();		// call once at the begining of your external, before using the RecordHandler library
void SetDownRecordHandler();	// call at the end of your external, when finished using the RecordHandler library


// Place a locus at the specified point with a debug message in a record format.		
#if !defined(BUG) || defined(_MINICAD_EXTERNAL_)

	#define DLOCUS(params)	DEBUG_DO_NOTHING
	
#else

	#define DLOCUS(params)	::__DebugLocus params
	
	void GSDEBUG_EXPORT __DebugLocus(			  			 const WorldPt&  inPt, const char *inFormat, ...);
	void GSDEBUG_EXPORT __DebugLocus(Boolean inExpression, const WorldPt&  inPt, const char *inFormat, ...);
	void GSDEBUG_EXPORT __DebugLocus(			  			 const WorldPt3& inPt, const char *inFormat, ...);
	void GSDEBUG_EXPORT __DebugLocus(Boolean inExpression, const WorldPt3& inPt, const char *inFormat, ...);
	
#endif	// BUG

#define GET_PARAM_STR255_VAL(success, getStr255Val, index, rh, fh) \
		{ TRecordItem item(fh.GetFieldStyle(index)); \
		if (rh.GetFieldObject(index, item)) { \
			item.GetFieldValueAsString(getStr255Val); \
			success = true; \
		} \
		else { \
			success = false; \
		} }

#define GET_PARAM_COORD_VAL(success, getcoordvalue, index, rh, fh) \
		{ WorldCoord coordValue; \
		TRecordItem item(fh.GetFieldStyle(index)); \
		if (rh.GetFieldObject(index, item)) { \
			item.GetFieldValue(coordValue); \
			getcoordvalue = coordValue;  \
			success = true; \
		} \
		else { \
			success = false; \
		} }

#define GET_PARAM_BOOLEAN_VAL(success, getbooleanvalue, index, rh, fh) \
		{ Boolean booleanValue; \
		TRecordItem item(fh.GetFieldStyle(index)); \
		if (rh.GetFieldObject(index, item)) { \
			item.GetFieldValue(booleanValue); \
			getbooleanvalue = booleanValue;  \
			success = true; \
		} \
		else { \
			success = false; \
		} }

#define GET_PARAM_LONG_VAL(success, getvalue, index, rh, fh) \
		{ long	longValue; \
		TRecordItem item(fh.GetFieldStyle(index));	\
		if (rh.GetFieldObject(index, item)) { \
			item.GetFieldValue(longValue); \
			getvalue = longValue; \
			success = true; \
		} \
		else { \
			success = false; \
		} }

#define SET_PARAM_VAL(success, setvalue, index, rh, fh) \
		{ TRecordItem item(fh.GetFieldStyle(index));	\
		if (rh.GetFieldObject(index, item)) { \
			item.SetFieldValue(setvalue); \
			rh.SetFieldObject(index, item); \
			success = true; \
		} \
		else { \
			success = false; \
		} }

#define SET_PARAM_STR255_VAL(success, setstrvalue, index, rh, fh) \
		{ TRecordItem item(fh.GetFieldStyle(index));	\
		if (rh.GetFieldObject(index, item)) { \
			item.SetFieldValueAsString(setstrvalue); \
			rh.SetFieldObject(index, item); \
			success = true; \
		} \
		else { \
			success = false; \
		} }

#define SET_PARAM_COORD_VAL(success, setcoordvalue, index, rh, fh) 		SET_PARAM_VAL(success, setcoordvalue, index, rh, fh)
#define SET_PARAM_BOOLEAN_VAL(success, setbooleanvalue, index, rh, fh) 	SET_PARAM_VAL(success, setbooleanvalue, index, rh, fh)
#define SET_PARAM_LONG_VAL(success, setlongvalue, index, rh, fh) 	SET_PARAM_VAL(success, setlongvalue, index, rh, fh)


#endif //_RECORD_HANDLER_
