// -----------------------------------------------------------------------------
// LockableReservationChangeHandler
//
//  lists the recent lockable object reservation changes in Teamwork
// -----------------------------------------------------------------------------
static GSErrCode __ACENV_CALL	LockableReservationChangeHandler (const API_Guid& objectId, short ownerId)
{
	GS::HashTable<short, API_UserInfo> userInfoTable;
	short myUserId = 0;

	GSErrCode err = GetTeamworkMembers (userInfoTable, myUserId);
	if (err != NoError)
		return err;

	GS::HashTable<API_Guid, GS::UniString> lockableObjectSets;
	lockableObjectSets.Add (APIGuidFromString ("5D8068E2-7430-4871-9D67-E06001F256A1"),				"Cities");
	lockableObjectSets.Add (APIGuidFromString ("A36401CC-77B1-4410-BCEB-A7684706A17F"),				"Composites");
	lockableObjectSets.Add (APIGuidFromString ("F97013BD-662E-42a1-A749-9C73CD2D0790"),				"Favorites");
	lockableObjectSets.Add (APIGuidFromString ("4C036A66-C2FF-4c3b-9FF4-F45A810B5F84"),				"Fill Types");
	lockableObjectSets.Add (ACAPI_TeamworkControl_FindLockableObjectSet ("LayerSettingsDialog"),	"Layer Settings");
	lockableObjectSets.Add (APIGuidFromString ("702A8569-EA8F-4de8-900C-696980FB13D6"),				"Line Types");
	lockableObjectSets.Add (APIGuidFromString ("156BCF98-CFA6-4be0-BC2C-8252D640A9FB"),				"Markup Styles");
	lockableObjectSets.Add (APIGuidFromString ("5B6A4F99-C72D-4811-90A5-6D696E1AB51F"),				"Surfaces");
	lockableObjectSets.Add (APIGuidFromString ("258B2630-3098-48ea-8923-F712214FBDAE"),				"MEP Systems");
	lockableObjectSets.Add (APIGuidFromString ("13E263C8-692B-494b-84E3-2B4BD0A77332"),				"Model View Options");
	lockableObjectSets.Add (APIGuidFromString ("0E6DC7E2-5AFC-4309-AB31-2A790CF57A53"),				"Operation Profiles");
	lockableObjectSets.Add (APIGuidFromString ("08B4B9BB-3DD6-4ea1-A084-80D80B8B7742"),				"Pen Tables");
	lockableObjectSets.Add (APIGuidFromString ("4779D92D-ACFB-429d-91E5-1D585B9D2CE5"),				"Profiles");
	lockableObjectSets.Add (APIGuidFromString ("D13F8A89-2AEC-4c32-B04E-85A5393F9C47"),				"Project Info");
	lockableObjectSets.Add (ACAPI_TeamworkControl_FindLockableObjectSet ("PreferencesDialog"),		"Project Preferences");
	lockableObjectSets.Add (APIGuidFromString ("B83F2FD1-0AD4-4c41-A8EB-6D7558B0A120"),				"Zone Categories");
	lockableObjectSets.Add (APIGuidFromString ("50477294-5E20-4349-920B-EFC18BF54A0C"),				"Building Materials");

	GS::UniString lockableObjectSetName;
	if (!lockableObjectSets.Get (objectId, &lockableObjectSetName))
		lockableObjectSetName = GS::UniString::Printf ("Unknown object {%T}", APIGuid2GSGuid (objectId).ToUniString ().ToPrintf ());

	ACAPI_WriteReport ("=== Attention: Workspace reservation has been changed ===============", false);

	GS::UniString actionByUserStr (ownerId > 0 ? "reserved" : "released");
	if (userInfoTable.ContainsKey (ownerId)) {
		if (ownerId == myUserId) {
			actionByUserStr.Append (" by me (");
			actionByUserStr.Append (userInfoTable[ownerId].fullName);
			actionByUserStr.Append (")");
		} else {
			actionByUserStr.Append (" by ");
			actionByUserStr.Append (userInfoTable[ownerId].fullName);
		}
	}

	GS::UniString reportString = GS::UniString::Printf ("=  %T got %T", lockableObjectSetName.ToPrintf (), actionByUserStr.ToPrintf ());
	ACAPI_WriteReport (reportString.ToCStr ().Get (), false);

    return NoError;
}		/* LockableReservationChangeHandler */
// -----------------------------------------------------------------------------
// PrintElementInfo
//
//  print reservation information of a given element
// -----------------------------------------------------------------------------
static void		PrintElementInfo (const GS::HashTable<short, API_UserInfo>&	userInfoTable,
								  short										myUserId,
								  const char*								actionStr,
								  const API_Guid&							guid,
								  short										elementOwnerId = 0)
{
	API_Elem_Head elemHead;
	BNZeroMemory (&elemHead, sizeof (API_Elem_Head));
	elemHead.guid = guid;

	if (ACAPI_Element_GetHeader (&elemHead) == NoError) {
		GS::UniString elemTypeName;
		ACAPI_Goodies (APIAny_GetElemTypeNameID, (void*) elemHead.typeID, &elemTypeName);

		GS::UniString actionByUserStr (actionStr);
		if (userInfoTable.ContainsKey (elementOwnerId)) {
			if (elementOwnerId == myUserId) {
				actionByUserStr.Append (" by me (");
				actionByUserStr.Append (userInfoTable[elementOwnerId].fullName);
				actionByUserStr.Append (")");
			} else {
				actionByUserStr.Append (" by ");
				actionByUserStr.Append (userInfoTable[elementOwnerId].fullName);
			}
		}

		const GS::UniString reportString = GS::UniString::Printf ("=  %T {%T} is %T", elemTypeName.ToPrintf (), APIGuidToString (guid).ToPrintf (), actionByUserStr.ToPrintf ());
		ACAPI_WriteReport (reportString.ToCStr ().Get (), false);
	}
}		/* PrintElementInfo */
// -----------------------------------------------------------------------------
// ElementReservationChangeHandler
//
//  lists the recent element reservation changes in Teamwork
// -----------------------------------------------------------------------------
static GSErrCode __ACENV_CALL	ElementReservationChangeHandler (const GS::HashTable<API_Guid, short>&	reserved,
																 const GS::HashSet<API_Guid>&			released,
																 const GS::HashSet<API_Guid>&			deleted)
{
	GS::HashTable<short, API_UserInfo> userInfoTable;
	short myUserId = 0;

	GSErrCode err = GetTeamworkMembers (userInfoTable, myUserId);
	if (err != NoError)
		return err;

	ACAPI_WriteReport ("=== Attention: Workspace reservation has been changed ===============", false);

	for (GS::HashTable<API_Guid, short>::ConstPairIterator it = reserved.EnumeratePairs (); it != NULL; ++it) {
		PrintElementInfo (userInfoTable, myUserId, "reserved", *(it->key), *(it->value));
	}

	for (GS::HashSet<API_Guid>::ConstIterator it = released.Enumerate (); it != NULL; ++it) {
		PrintElementInfo (userInfoTable, myUserId, "released", *it);
	}

	for (GS::HashSet<API_Guid>::ConstIterator it = deleted.Enumerate (); it != NULL; ++it) {
		PrintElementInfo (userInfoTable, myUserId, "deleted", *it);
	}

    return NoError;
}		/* ElementReservationChangeHandler */
void selectElement(){
	API_ElemTypeID		typeID;
	API_Guid			guid;
	API_Element			element;
	API_ElementMemo		memo;
	API_Coord3D			c3;
	GSErrCode			err = NoError;
	elementid			eleMsg;
	char buffer[256];
	while (!ClickAnElem("Click an element", API_ZombieElemID, NULL, &typeID, &guid, &c3)){
	}
	/*
	if (!ClickAnElem("Click an element", API_ZombieElemID, NULL, &typeID, &guid, &c3)) {
	WriteReport_Alert("Please click an element");
	return;
	}
	*/
	BNZeroMemory(&element, sizeof(API_Element));
	element.header.typeID = typeID;
	element.header.guid = guid;
	err = ACAPI_Element_Get(&element);
	if (err != NoError) {
		sprintf(buffer, ErrID_To_Name(err));
		ACAPI_WriteReport(buffer, true);
		return;
	}

	sendElementID(getClientSocket(), element);

}
void getColumns(){
	API_Element element;
	GSErrCode err;
	char buffer[256];
	columnrepeated columnMsg;
	API_StoryInfo		storyInfo;
	storyinfo* storyInfoMsg;

	err = ACAPI_Environment(APIEnv_GetStorySettingsID, &storyInfo, NULL);
	if (err != NoError) {
		ErrorBeep("APIEnv_GetStorySettingsID", err);
		return;
	}

	GS::Array<API_Guid> elemList;
	ACAPI_Element_GetElemList(API_ColumnID, &elemList);
	for (GS::Array<API_Guid>::ConstIterator it = elemList.Enumerate(); it != NULL; ++it) {

		BNZeroMemory(&element, sizeof(API_Element));
		element.header.guid = *it;
		err = ACAPI_Element_Get(&element);
		if (err == NoError) {
			columnMsg.add_px(element.column.origoPos.x);
			columnMsg.add_py(element.column.origoPos.y);

			storyInfoMsg = columnMsg.add_bottomlevel();
			storyInfoMsg->set_exists(true);
			storyInfoMsg->set_index(element.header.floorInd);
			storyInfoMsg->set_level((*storyInfo.data)[element.header.floorInd - storyInfo.firstStory].level);
			storyInfoMsg->set_name((*storyInfo.data)[element.header.floorInd - storyInfo.firstStory].name);

			storyInfoMsg = columnMsg.add_toplevel();
			storyInfoMsg->set_exists(true);
			storyInfoMsg->set_index(element.header.floorInd + 1);
			storyInfoMsg->set_level((*storyInfo.data)[element.header.floorInd + 1 - storyInfo.firstStory].level);
			storyInfoMsg->set_name((*storyInfo.data)[element.header.floorInd + 1 - storyInfo.firstStory].name);

			columnMsg.add_circular(element.column.circleBased);
			columnMsg.add_angle(element.column.angle);
			columnMsg.add_depth(element.column.coreDepth);
			columnMsg.add_width(element.column.coreWidth);
			columnMsg.add_slantangle(element.column.slantAngle);
			columnMsg.add_slantdirection(element.column.slantDirectionAngle);

			char s[64];
			APIGuid2GSGuid(element.header.guid).ConvertToString(s);
			columnMsg.add_guid(s);

		}
		else{
			sprintf(buffer, ErrID_To_Name(err));
			ACAPI_WriteReport(buffer, true);
		}
	}
	//writeDelimitedTo(wallInfo, raw_out);
	writeDelimitedTo(getClientSocket(), columnMsg);
	BMKillHandle(reinterpret_cast<GSHandle *> (&storyInfo.data));
}
void CCALL	WriteReport_End (GSErrCode err)
{
#if USE_DEBUG_WINDOW
	DBPrintf ("\n");
	if (err == NoError) {
		DBPrintf ("OK\n");
	} else {
		DBPrintf ("Error: %d\n", err);
	}
#else
	if (err == NoError)
		ACAPI_WriteReport ("OK", false);
	else {
		char buffer[256];
		sprintf (buffer, "Error: %d", err);
		ACAPI_WriteReport (buffer, false);
	}
#endif

	return;
}		// WriteReport_End
GSErrCode Attribute_Get (API_Attribute* attr, const API_AttrTypeID& typeID, const short index)
{
	GSErrCode err = NoError;
	BNZeroMemory (attr, sizeof (API_Attribute));
	attr->header.typeID = typeID;
	attr->header.index = index;
	// search by type and index
	err = ACAPI_Attribute_Get (attr);
	if (err != NoError)
		ACAPI_WriteReport ("ACAPI_Attribute_Get failed", true);
	return err;
}
void CCALL	WriteReport_Err (const char* info, GSErrCode err)
{
	char	buffer [512];

#if defined (macintosh)
	sprintf (buffer, "%s: %d", info, (int) err);
#else
	sprintf_s (buffer, sizeof (buffer), "%s: %d", info, (int) err);
#endif

	ACAPI_WriteReport (buffer, true);

	return;
}		// WriteReport_Err
void CCALL	WriteReport_Alert (const char* format, ...)
{
	char		buffer [512];
	va_list		argList;

	va_start (argList, format);
#if defined (macintosh)
	vsnprintf (buffer, sizeof (buffer), format, argList);
#else
	vsnprintf_s (buffer, sizeof (buffer), _TRUNCATE, format, argList);
#endif

	ACAPI_WriteReport (buffer, true);

	return;
}		// WriteReport_Alert
//TODO: See more file type that are define in API_FileOpenPars, fileTypeID
void openFile(){
	GSErrCode err;
	char buffer[256];
	API_FileOpenPars openPars;

	openmessage pathMsg;

	readDelimitedFrom(getClientSocket(), &pathMsg);

	BNZeroMemory(&openPars, sizeof(API_FileOpenPars));
	std::string extension = pathMsg.extension();

	if (extension == "pln"){
		openPars.fileTypeID = APIFType_PlanFile;
	}
	else if (extension == "pdf") {
		openPars.fileTypeID = APIFType_PdfFile;
	}
	else if (extension == "ifc"
		|| extension == "ifcxml"
		|| extension == "ifczip") {
		openPars.fileTypeID = APIFType_IfcFile;
	}
	else {
		openPars.fileTypeID = APIFType_None;
	}

	openPars.useStoredLib = true;

	IO::Location* folderLoc = new IO::Location(pathMsg.path().c_str());

	openPars.file = folderLoc;

	err = ACAPI_Automate(APIDo_OpenID, &openPars, NULL);

	delete openPars.file;

	if (err != NoError){
		sprintf(buffer, ErrID_To_Name(err));
		ACAPI_WriteReport(buffer, true);
		return;
	}

}
void elementChange(API_Element* element, API_ElementMemo* memo, API_Element* mask){
	char buffer[256];
	GSErrCode err;
	API_DatabaseInfo dbInfo;
	API_DatabaseInfo floorInfo;
	floorInfo.typeID = APIWind_FloorPlanID;
	floorInfo.index = 0;
	ACAPI_Database(APIDb_GetCurrentDatabaseID, &dbInfo);
	ACAPI_Database(APIDb_ChangeCurrentDatabaseID, &floorInfo);

	err = ACAPI_Element_Change(element, mask, memo, APIMemoMask_Polygon, true);

	if (err != NoError){
		sprintf(buffer, ErrID_To_Name(err));
		ACAPI_WriteReport(buffer, true);
		msgArchiCAD("In Element Change");
		quit();
	}

	ACAPI_Database(APIDb_ChangeCurrentDatabaseID, &dbInfo);
}
void elementRefresh(API_Element* element){
	char buffer[256];
	GSErrCode err;
	API_DatabaseInfo dbInfo;
	API_DatabaseInfo floorInfo;
	floorInfo.typeID = APIWind_FloorPlanID;
	floorInfo.index = 0;
	ACAPI_Database(APIDb_GetCurrentDatabaseID, &dbInfo);
	ACAPI_Database(APIDb_ChangeCurrentDatabaseID, &floorInfo);

	API_Element mask;
	ACAPI_ELEMENT_MASK_CLEAR(mask);
	err = ACAPI_Element_Change(element, &mask, NULL, 0, true);

	if (err != NoError){
		sprintf(buffer, ErrID_To_Name(err));
		ACAPI_WriteReport(buffer, true);
	}

	ACAPI_Database(APIDb_ChangeCurrentDatabaseID, &dbInfo);
}
void CCALL	WriteReport (const char* format, ...)
{
	char		buffer [512];
	va_list		argList;

	va_start (argList, format);
#if defined (macintosh)
	vsnprintf (buffer, sizeof (buffer), format, argList);
#else
	vsnprintf_s (buffer, sizeof (buffer), _TRUNCATE, format, argList);
#endif

#if USE_DEBUG_WINDOW
	GS::UniString bufferPercent (buffer);
	bufferPercent.ReplaceAll ("%", "%%");
	DBPrintf (bufferPercent.ToCStr ().Get ());
	DBPrintf ("\n");
#else
	ACAPI_WriteReport (buffer, false);
#endif

	return;
}		// WriteReport
// -----------------------------------------------------------------------------
// ElementEventHandlerProc
//
// -----------------------------------------------------------------------------
GSErrCode __ACENV_CALL	ElementEventHandlerProc (const API_NotifyElementType *elemType)
{
	GSErrCode		err = NoError;
	char			msgStr[256];
	char			elemStr[32];

	if (elemType->notifID == APINotifyElement_BeginEvents || elemType->notifID == APINotifyElement_EndEvents) {
		API_DatabaseInfo api_dbPars;
		BNZeroMemory (&api_dbPars, sizeof (API_DatabaseInfo));
		api_dbPars.databaseUnId = elemType->databaseId;
		ACAPI_Database (APIDb_GetDatabaseInfoID, &api_dbPars, NULL);
		sprintf (msgStr, "### Element_Manager: %s notification on database \"%s\"",
				(elemType->notifID == APINotifyElement_BeginEvents) ? "Begin Events" : "End Events",
				(const char *) GS::UniString (api_dbPars.title).ToCStr ());

	} else if (GetElementTypeString (elemType->elemHead.typeID, elemStr)) {
		char				elemGuidStr[64];
		char				parentElemGuidStr[64];
		API_Element			parentElement;
		API_ElementUserData	parentUserData;

		BNZeroMemory (&parentElement, sizeof (API_Element));
		BNZeroMemory (&parentUserData, sizeof (API_ElementUserData));
		ACAPI_Notify_GetParentElement (&parentElement, NULL, 0, &parentUserData);
		BMKillHandle (&parentUserData.dataHdl);

		CHTruncate (APIGuid2GSGuid (elemType->elemHead.guid).ToUniString ().ToCStr (), elemGuidStr, sizeof (elemGuidStr));
		CHTruncate (APIGuid2GSGuid (parentElement.header.guid).ToUniString ().ToCStr (), parentElemGuidStr, sizeof (parentElemGuidStr));

		switch (elemType->notifID) {
			case APINotifyElement_New:
						if (!allNewElements)
							break;

						if (parentElement.header.guid != APINULLGuid)
							sprintf (msgStr, "### Element_Manager: <%s> created {%s} as a copy of {%s}", elemStr, elemGuidStr, parentElemGuidStr);
						else
							sprintf (msgStr, "### Element_Manager: <%s> created {%s}", elemStr, elemGuidStr);

						err = ACAPI_Element_AttachObserver (const_cast<API_Elem_Head*> (&elemType->elemHead), 0);
						if (err == APIERR_LINKEXIST)
							err = NoError;
						break;

			case APINotifyElement_Copy:
						if (!allNewElements)
							break;

						if (parentElement.header.guid != APINULLGuid) {
							sprintf (msgStr, "### Element_Manager: <%s> copied {%s} from {%s}", elemStr, elemGuidStr, parentElemGuidStr);

							err = ACAPI_Element_AttachObserver (const_cast<API_Elem_Head*> (&elemType->elemHead), 0);
							if (err == APIERR_LINKEXIST)
								err = NoError;
						}
						break;

			case APINotifyElement_Change:
						if (parentElement.header.guid != APINULLGuid)
							sprintf (msgStr, "### Element_Manager: <%s> changed {%s} -> {%s}", elemStr, parentElemGuidStr, elemGuidStr);
						else
							sprintf (msgStr, "### Element_Manager: <%s> window/door changed {%s}", elemStr, elemGuidStr);
						break;

			case APINotifyElement_Edit:
						if (parentElement.header.guid != APINULLGuid)
							sprintf (msgStr, "### Element_Manager: <%s> edited {%s} -> {%s}", elemStr, parentElemGuidStr, elemGuidStr);
						else
							sprintf (msgStr, "### Element_Manager: <%s> edited in place {%s}", elemStr, elemGuidStr);

						err = Do_ElementEdit (&parentElement.header);
						break;

			case APINotifyElement_Delete:
						sprintf (msgStr, "### Element_Manager: <%s> deleted {%s}", elemStr, elemGuidStr);
						break;

			case APINotifyElement_Undo_Created:
						sprintf (msgStr, "### Element_Manager: undone <%s> created {%s} ", elemStr, elemGuidStr);
						break;

			case APINotifyElement_Undo_Modified:
						sprintf (msgStr, "### Element_Manager: undone <%s> modified {%s}", elemStr, elemGuidStr);
						break;

			case APINotifyElement_Undo_Deleted:
						sprintf (msgStr, "### Element_Manager: undone <%s> deleted {%s}", elemStr, elemGuidStr);
						break;

			case APINotifyElement_Redo_Created:
						sprintf (msgStr, "### Element_Manager: redone <%s> created {%s}", elemStr, elemGuidStr);
						break;

			case APINotifyElement_Redo_Modified:
						sprintf (msgStr, "### Element_Manager: redone <%s> modified {%s}", elemStr, elemGuidStr);
						break;

			case APINotifyElement_Redo_Deleted:
						sprintf (msgStr, "### Element_Manager: redone <%s> deleted {%s}", elemStr, elemGuidStr);
						break;

			default:
						break;
		}
	}

	ACAPI_WriteReport (msgStr, false);

	return err;
}	// ElementEventHandlerProc
void getObjects(){
	API_Element element;
	GSErrCode err;
	char buffer[256];
	objectrepeated objectMsg;
	API_StoryInfo		storyInfo;
	storyinfo* storyInfoMsg;

	err = ACAPI_Environment(APIEnv_GetStorySettingsID, &storyInfo, NULL);
	if (err != NoError) {
		ErrorBeep("APIEnv_GetStorySettingsID", err);
		return;
	}

	GS::Array<API_Guid> elemList;
	ACAPI_Element_GetElemList(API_ObjectID, &elemList);
	for (GS::Array<API_Guid>::ConstIterator it = elemList.Enumerate(); it != NULL; ++it) {

		BNZeroMemory(&element, sizeof(API_Element));
		element.header.guid = *it;
		err = ACAPI_Element_Get(&element);
		if (err == NoError) {

			std::string objectName = searchObjectsValue(element.object.libInd);

			if (objectName == "Not Found"){
				sprintf(buffer, "Found no material");
				ACAPI_WriteReport(buffer, true);
			}
			else{
				objectMsg.add_name(objectName);
			}


			objectMsg.add_px(element.object.pos.x);
			objectMsg.add_py(element.object.pos.y);

			storyInfoMsg = objectMsg.add_bottomlevel();
			storyInfoMsg->set_exists(true);
			storyInfoMsg->set_index(element.header.floorInd);
			storyInfoMsg->set_level((*storyInfo.data)[element.header.floorInd - storyInfo.firstStory].level);
			storyInfoMsg->set_name((*storyInfo.data)[element.header.floorInd - storyInfo.firstStory].name);

			objectMsg.add_angle(element.object.angle);
			objectMsg.add_xratio(element.object.xRatio);
			objectMsg.add_yratio(element.object.yRatio);
			objectMsg.add_bottomoffset(element.object.level);
			if (element.header.variationID == APIVarId_SymbStair){
				objectMsg.add_stairs(true);
			}
			else{
				objectMsg.add_stairs(false);
			}

			objectMsg.add_usexyfixsize(element.object.useXYFixSize);

			char s[64];
			APIGuid2GSGuid(element.header.guid).ConvertToString(s);
			objectMsg.add_guid(s);

		}
		else{
			sprintf(buffer, ErrID_To_Name(err));
			ACAPI_WriteReport(buffer, true);
		}
	}
	writeDelimitedTo(getClientSocket(), objectMsg);
	BMKillHandle(reinterpret_cast<GSHandle *> (&storyInfo.data));
}
void highlightElementByID(){
	GSErrCode err;
	API_NeigID neigID;
	API_Element element;
	elementidlist eleMsg;
	API_StoryCmdType	storyCmd;
	char buffer[256];

	readDelimitedFrom(getClientSocket(), &eleMsg);

	Int32 nItem = eleMsg.guid_size();
	bool add = true;

	//Clear all selected elements
	err = ACAPI_Element_Select(NULL, 0, add);

	API_Neig** neigHdl = reinterpret_cast<API_Neig**> (BMAllocateHandle(nItem * sizeof(API_Neig), ALLOCATE_CLEAR, 0));

	API_Neig neig;
	for (int i = 0; i < nItem; i++){
		BNZeroMemory(&element, sizeof(API_Element));
		element.header.guid = APIGuidFromString(eleMsg.guid(i).c_str());
		err = ACAPI_Element_Get(&element);
		if (err != NoError) {
			sprintf(buffer, ErrID_To_Name(err));
			ACAPI_WriteReport(buffer, true);
			return;
		}
		err = ACAPI_Goodies(APIAny_ElemTypeToNeigID, (void*)element.header.typeID, &neigID);

		(*neigHdl)[i].neigID = neigID;
		(*neigHdl)[i].guid = element.header.guid;
		(*neigHdl)[i].flags = API_NeigFlg_Normal;
		(*neigHdl)[i].elemPartType = APINeigElemPart_None;
	}

	//Add the current element to the selection
	err = ACAPI_Element_Select(neigHdl, nItem, add);
	if (err != NoError) {
		sprintf(buffer, ErrID_To_Name(err));
		ACAPI_WriteReport(buffer, true);
		return;
	}

	BMhKill((GSHandle*)&neigHdl);

	/*
	* In order for the GUI update, we need to create an element, and then
	* delete it.
	* By doing this we can have the selected element highlighted
	*/

	API_Element		wallElement;
	API_ElementMemo memo;
	BNZeroMemory(&memo, sizeof(API_ElementMemo));

	BNZeroMemory(&wallElement, sizeof(API_Element));

	wallElement.header.typeID = API_WallID;
	wallElement.header.layer = 1;

	err = ACAPI_Element_GetDefaults(&wallElement, &memo);
	if (err != NoError) {
		ErrorBeep("ACAPI_Element_GetMemo", err);
		return;
	}

	err = ACAPI_Element_Create(&wallElement, &memo);

	if (err != NoError){
		ErrorBeep("ACAPI_Element_Create", err);
		sprintf(buffer, ErrID_To_Name(err));
		ACAPI_WriteReport(buffer, true);
	}

	ACAPI_DisposeElemMemoHdls(&memo);

	API_Elem_Head* test;
	test = &wallElement.header;
	ACAPI_Element_Delete(&test, 1);

}
void getWalls(){
	API_Element element;
	GSErrCode err;
	char buffer[256];
	getwallmsg msg;
	wallmsg* aux;
	pointsmessage* pts;
	polyarcsmessage* arcs;

	GS::Array<API_Guid> elemList;
	ACAPI_Element_GetElemList(API_WallID, &elemList);

	for (GS::Array<API_Guid>::ConstIterator it = elemList.Enumerate(); it != NULL; ++it) {
		BNZeroMemory(&element, sizeof(API_Element));
		element.header.guid = *it;
		err = ACAPI_Element_Get(&element);
		if (err == NoError) {
			double x0 = element.wall.begC.x;
			double y0 = element.wall.begC.y;
			double x1 = element.wall.endC.x;
			double y1 = element.wall.endC.y;
			
			char s[256];
			APIGuid2GSGuid(element.header.guid).ConvertToString(s);
			msg.add_guid(s);

			aux = msg.add_walls();

			aux->set_bottomindex(element.header.floorInd);
			aux->set_thickness(element.wall.thickness);
			aux->set_upperindex(element.header.floorInd + 1);
			
			std::string materialName;

			if (element.wall.modelElemStructureType == API_BasicStructure){
				materialName = searchBuildingMaterialsValue(element.wall.buildingMaterial);
				aux->set_type("Basic");
			}
			else{
				materialName = searchCompositeMaterialsValue(element.wall.composite);
				aux->set_type("Composite");
			}

			if (materialName == "Not Found"){
				sprintf(buffer, "Found no material %d", element.wall.buildingMaterial);
				ACAPI_WriteReport(buffer, true);
			}
			else{
				aux->set_material(materialName);
			}

			if (element.wall.referenceLineLocation == APIWallRefLine_Center ||
				element.wall.referenceLineLocation == APIWallRefLine_CoreCenter){
				aux->set_referenceline("Center");
			}
			else if (element.wall.referenceLineLocation == APIWallRefLine_Outside ||
				element.wall.referenceLineLocation == APIWallRefLine_CoreOutside){
				aux->set_referenceline("Outside");
			}
			else if (element.wall.referenceLineLocation == APIWallRefLine_Inside ||
				element.wall.referenceLineLocation == APIWallRefLine_CoreInside){
				aux->set_referenceline("Inside");
			}
			else{
				sprintf(buffer, "Found no referenceLine %d", element.wall.buildingMaterial);
				ACAPI_WriteReport(buffer, true);
			}

			aux->set_alphaangle(element.wall.slantAlpha);
			aux->set_betaangle(element.wall.slantBeta);

			aux->set_profilename("");
			if (element.wall.profileType == APISect_Normal){
				aux->set_typeprofile("Normal");
			}
			else if (element.wall.profileType == APISect_Slanted){
				aux->set_typeprofile("Slanted");
			}
			else if (element.wall.profileType == APISect_Trapez){
				aux->set_typeprofile("DoubleSlanted");
			}
			else if (element.wall.profileType == APISect_Poly){
				aux->set_typeprofile("Poly");
				aux->set_profilename(searchProfileName(element.wall.profileAttr)); 
			}

			aux->set_height(element.wall.height);

			pts = new pointsmessage();
			pts->add_px(x0);
			pts->add_py(y0);
			pts->add_pz(0);
			pts->add_px(x1);
			pts->add_py(y1);
			pts->add_pz(0);
			aux->set_allocated_pts(pts);
			
			arcs = new polyarcsmessage();
			arcs->add_arcangle(element.wall.angle);
			arcs->add_begindex(0);
			arcs->add_endindex(1);
			aux->set_allocated_arcs(arcs);
			
			aux->set_flipped(!element.wall.flipped);

			aux->set_bottomoffset(element.wall.bottomOffset);
			
			aux->set_refoffset(element.wall.offset);

			if (element.wall.oppMat.overrideMaterial){
				aux->set_oppmat(searchOverrideMaterialsValue(element.wall.oppMat.material));
			}
			else{
				aux->set_oppmat("");
			}
			if (element.wall.refMat.overrideMaterial){
				aux->set_refmat(searchOverrideMaterialsValue(element.wall.refMat.material));
			}
			else{
				aux->set_refmat("");
			}
			if (element.wall.sidMat.overrideMaterial){
				aux->set_sidmat(searchOverrideMaterialsValue(element.wall.sidMat.material));
			}
			else{
				aux->set_sidmat("");
			}

			/*
			API_Attribute attr;
			attr.header.typeID = API_LayerID;
			attr.header.index = 1;
			err = ACAPI_Attribute_Get(&attr);
			if (hasError(err)){
				quit();
				return;
			}
			
			msgArchiCAD(attr.layer.head.name);
			aux->set_layer(attr.header.name);
			*/
			aux->set_layer(searchLayers(element.header.layer));

			GS::Array<API_Guid> windowList;
			ACAPI_Element_GetElemList(API_WindowID, &windowList);
			API_Element wElement;
			for (GS::Array<API_Guid>::ConstIterator it2 = windowList.Enumerate(); it2 != NULL; ++it2) {
				BNZeroMemory(&wElement, sizeof(API_Element));
				wElement.header.guid = *it2;
				err = ACAPI_Element_Get(&wElement);
				if (hasError(err)){
					quit();
					return;
				}
				if (wElement.window.owner == element.header.guid){
					windowmessage* wmsg = aux->add_windows();
					wmsg->set_height(wElement.window.openingBase.height);
					wmsg->set_width(wElement.window.openingBase.width);
					wmsg->set_objloc(wElement.window.objLoc);
					wmsg->set_zpos(wElement.window.lower);
					wmsg->set_guid(s);
					wmsg->set_name(searchObjectsValue(wElement.window.openingBase.libInd));
					wmsg->set_depthoffset(wElement.window.revealDepthOffset);
					wmsg->set_flipx(wElement.window.openingBase.oSide);
					wmsg->set_flipy(wElement.window.openingBase.reflected);
						
					aux->add_windoworder(0);

					API_ParamOwnerType   paramOwner;
					API_GetParamsType    getParams;

					BNZeroMemory(&paramOwner, sizeof(API_ParamOwnerType));
					paramOwner.guid = wElement.header.guid;
					paramOwner.libInd = 0;
					paramOwner.typeID = wElement.header.typeID;

					BNZeroMemory(&getParams, sizeof(API_GetParamsType));

					err = ACAPI_Goodies(APIAny_OpenParametersID, &paramOwner, NULL);
					if (err == NoError) {
						err = ACAPI_Goodies(APIAny_GetActParametersID, &getParams, NULL);
						if (err == NoError) {
							additionalparams* wparams = new additionalparams();
							prepareParams(wparams, &paramOwner, &getParams);
							wmsg->set_allocated_params(wparams);
						}
					}
				}
			}
		}
		else{
			sprintf(buffer, ErrID_To_Name(err));
			ACAPI_WriteReport(buffer, true);
		}
	}

	writeDelimitedTo(getClientSocket(), msg);
}
void getRoofs(){
	API_Element element;
	API_ElementMemo memo;
	GSErrCode err;
	char buffer[256];
	roofrepeated roofMsg;
	API_StoryInfo storyInfo;
	storyinfo* storyInfoMsg;
	pointsmessage* points;
	intlistmsg* subpolygons;

	err = ACAPI_Environment(APIEnv_GetStorySettingsID, &storyInfo, NULL);
	if (err != NoError) {
		ErrorBeep("APIEnv_GetStorySettingsID", err);
		return;
	}

	GS::Array<API_Guid> elemList;
	ACAPI_Element_GetElemList(API_RoofID, &elemList);
	for (GS::Array<API_Guid>::ConstIterator it = elemList.Enumerate(); it != NULL; ++it) {

		BNZeroMemory(&element, sizeof(API_Element));
		element.header.guid = *it;
		err = ACAPI_Element_Get(&element);
		if (err == NoError) {
			err = ACAPI_Element_GetMemo(element.header.guid, &memo);
			if (err == NoError){
				points = roofMsg.add_points();
				subpolygons = roofMsg.add_subpolygons();
				for (int i = 1; i <= element.roof.u.planeRoof.poly.nCoords; i++){
					points->add_px((*memo.coords)[i].x);
					points->add_py((*memo.coords)[i].y);
					points->add_pz((*storyInfo.data)[element.header.floorInd - storyInfo.firstStory].level);
				}

				for (int i = 1; i <= element.roof.u.planeRoof.poly.nSubPolys; i++){
					subpolygons->add_ilist((*memo.pends)[i]);
				}

				storyInfoMsg = roofMsg.add_bottomlevel();
				storyInfoMsg->set_exists(true);
				storyInfoMsg->set_index(element.header.floorInd);
				storyInfoMsg->set_level((*storyInfo.data)[element.header.floorInd - storyInfo.firstStory].level);
				storyInfoMsg->set_name((*storyInfo.data)[element.header.floorInd - storyInfo.firstStory].name);

				roofMsg.add_height(element.roof.shellBase.level);
				roofMsg.add_thickness(element.slab.thickness);

				std::string materialName;

				if (element.roof.shellBase.modelElemStructureType == API_BasicStructure){
					materialName = searchBuildingMaterialsValue(element.roof.shellBase.buildingMaterial);
					roofMsg.add_type("Basic");
				}
				else{
					materialName = searchCompositeMaterialsValue(element.roof.shellBase.composite);
					roofMsg.add_type("Composite");
				}
				if (materialName == "Not Found"){
					sprintf(buffer, "Found no material");
					ACAPI_WriteReport(buffer, true);
				}
				else{
					roofMsg.add_material(materialName);
				}
				char s[64];
				APIGuid2GSGuid(element.header.guid).ConvertToString(s);
				roofMsg.add_guid(s);

			}
		}
		else{
			sprintf(buffer, ErrID_To_Name(err));
			ACAPI_WriteReport(buffer, true);
		}
	}
	writeDelimitedTo(getClientSocket(), roofMsg);
	BMKillHandle(reinterpret_cast<GSHandle *> (&storyInfo.data));
}