//================================================================================================
// Plugin for EQUINOX-3D
//
// Interactive chemical element navigator
//
// AUTHOR:  Gabor Nagy
// DATE:    2026-Jan-07 02:46:23
//
// Copyright (C) 1996-2026 by Gabor Nagy. All rights reserved.
//================================================================================================
#include <assert.h>
#include <stdio.h>

#include <ELists.h>
#include <EMalloc.h>
#include <EPlugins.h>

#include <E3D/Scene.h>

#include <E3D/UI/Panel.h>

#include <Xe/PushButton.h>
#include <Xe/Dialog.h>
#include <Xe/Shell.h>

char*                E_PluginInfo = "Chemical element navigator";

static EPlugin*      _Plugin = NULL;

static XeWidget      _DialogW = NULL;
static EPluginLock*  _DialogLock = NULL;

static XeDWidget      _ToolBarButtons[16];static int  __ToolBarButtons_Count = 0;


typedef struct
{
	int     AtomicNumber;
	double  AtomicMass;
	char*   ElectronsStr;

	char*   Symbol;
	char*   Name;

	double  MeltingPoint, BoilingPoint, Density, Electronegativity;
	char    OxydadionStates[8];
	EBool   Radioactive;
} ChemElement;



ChemElement	_Elements[]=
{
	{ .AtomicNumber= 1,  .AtomicMass=  1.01,  .Symbol= "H",   .Name= "Hydrogen",  .ElectronsStr= "1s"         },
	{ .AtomicNumber= 2,  .AtomicMass=  4.00,  .Symbol= "He",  .Name= "Helium",    .ElectronsStr= "1s2"        },
	{ .AtomicNumber= 3,  .AtomicMass=  6.94,  .Symbol= "Li",  .Name= "Lithium",   .ElectronsStr= "1s2 2s"     },
	{ .AtomicNumber= 4,  .AtomicMass=  9.01,  .Symbol= "Be",  .Name= "Berylium",  .ElectronsStr= "1s2 2s2"    },
	{ .AtomicNumber= 5,  .AtomicMass= 10.81,  .Symbol= "B",   .Name= "Boron",     .ElectronsStr= "1s2 2s2 2p" }
};


enum
{
	CR_TEST = XeCR_CUSTOM0,
};


//========================================
// Dialog box callback
//========================================
static void _DCB(XeWidget PI, EPointer PClientData, EPointer PCallData)
{
	E3dScene*  LScene = E3d_Scene;

/*
	{
		E3dObjectComponentClass*  LClass = E3dObjectComponent_ClassByName("Box");if(LClass)
		{
			E3dObjectComponent*  LInfo = E3dObjectComponent_New(LClass);if(LInfo)
			{
				EObject_NamedResourceSet1f(LInfo, "UEdgeLength", 16.0);

				{
					E3dModel*  LModel = E3dModel_CustomObjectNewInit(LInfo, NULL, E3dUpdateALL, NULL);

					E3dObjectComponent_Free(LInfo);

					E3dScene_NodeHrcAdd(LScene, (E3dNode*)LModel, E3dCallSCENE_CALLBACKS);
					E3dScene_ObjectsUpdateModelList(LScene);
					E3dScene_LayoutOnSchematics(LScene);
					E3dWindows_RedrawByChangeFlags(E3dChgADD_HIERARCHY);
				}
			}
		}
	}
*/


// Create customized Spheres
//
	{
		E3dObjectComponentClass*  LClass = E3dObjectComponent_ClassByName("Sphere");if(LClass)
		{
			E3dObjectComponent*  LInfo = E3dObjectComponent_New(LClass);if(LInfo)
			{
				E3dModel*     LModel;
				EChangeFlags  LChanged = 0;

				EObject_NamedResourceSet1f(LInfo, "Radius", 2.0);
				EObject_NamedResourceSet1i(LInfo, "USections", 8);
				EObject_NamedResourceSet1i(LInfo, "VSections", 6);
				LModel = E3dModel_CustomObjectNewInit(LScene, LInfo, NULL, NULL, FALSE);
				LModel->TransformSet.Translation.X = -5.0;
				E3dNodeHrc_UpdateMatrices((E3dNode*)LModel, TRUE);
				E3dScene_NodeHrcAdd(E3d_Scene, (E3dNode*)LModel, E3dCallSCENE_CALLBACKS);
				LChanged |= E3dModel_GetChangeFlagsByObjects(LModel)|E3dChgHIERARCHY;

				EObject_NamedResourceSet1f(LInfo, "Radius", 3.0);
				EObject_NamedResourceSet1i(LInfo, "USections", 16);
				EObject_NamedResourceSet1i(LInfo, "VSections", 12);
				LModel = E3dModel_CustomObjectNewInit(LScene, LInfo, NULL, NULL, FALSE);
				LModel->TransformSet.Translation.X = 0.0;
				E3dNodeHrc_UpdateMatrices((E3dNode*)LModel, TRUE);
				E3dScene_NodeHrcAdd(E3d_Scene, (E3dNode*)LModel, E3dCallSCENE_CALLBACKS);
				LChanged |= E3dModel_GetChangeFlagsByObjects(LModel)|E3dChgHIERARCHY;

				EObject_NamedResourceSet1f(LInfo, "Radius", 2.0);
				EObject_NamedResourceSet1i(LInfo, "USections", 12);
				EObject_NamedResourceSet1i(LInfo, "VSections", 8);
				EObject_NamedResourceSet1b(LInfo, "Triangles", TRUE);
				LModel = E3dModel_CustomObjectNewInit(LScene, LInfo, NULL, NULL, FALSE);
				LModel->TransformSet.Translation.X = 5.0;
				E3dNodeHrc_UpdateMatrices((E3dNode*)LModel, TRUE);
				E3dScene_NodeHrcAdd(E3d_Scene, (E3dNode*)LModel, E3dCallSCENE_CALLBACKS);
				LChanged |= E3dModel_GetChangeFlagsByObjects(LModel)|E3dChgHIERARCHY;

				E3dObjectComponent_Free(LInfo);

				E3dScene_ObjectsUpdateModelList(LScene);
				E3dScene_LayoutOnSchematics(LScene, TRUE);

				E3dWindows_RedrawByChangeFlags(LScene, LChanged);
			}
		}
	}
}


//========================================
// Dialog box callback
//========================================
static void _DCB_Close(XeWidget PW, EPointer PClientData, EPointer PCallData)
{
	XeCallbackStruct*  LCBS = (XeCallbackStruct*)PCallData;
	if(LCBS->Reason == XeCR_PROTOCOLS)  // Check this because this callback may receive XeCR_FULLSCREEN_OFF/ON calls, too
	{
// Un-display dialog box
//
		XeWidget_Unmap(_DialogW);

// Delete plugin lock
//
		EPluginLock_Del(_Plugin, &_DialogLock, FALSE);
	}
}


static int _DialogLockDel(EPlugin* PPlugin, EPluginLock* PLock)
{
	XeWidget_Unmap(_DialogW);

	return(E_SUCCESS);
}


//================================================
// ToolBar icon callback handler
//================================================
static void _CB(XeWidget PW, EPointer PClientData, EPointer PCallData)
{
// We'll be displaying a dialog box, so we'll lock the plugin to prevent unloading
// it (and pulling the rag out from beneath our global variables).
// When the application exits, or the user forces the plugin to unload, _DialogLockDel will get called before E_PluginExit.
// This two-pass exit (unlock & unload) of plugins is necessary to avoid certain inter-dependencies from breaking.
//
	if(_DialogLock == NULL) _DialogLock = EPluginLock_Add(_Plugin, "ElementsDialog", _DialogLockDel);

	if(_DialogW == NULL)
	{
		EArg  Args[32];int  ArgCnt;

		EXeStart;
		EXeSetArg(XeNAllowShellResize, TRUE);
		EXeSetArg(XeNButtonsStretch, FALSE);
		EXeSetArg(XeNWorkAreaType, XeMATRIX);
		EXeSetArg(XeNWMDecorations, XeWMDecorCLOSE|XeWMDecorBORDER|XeWMDecorRESIZEH|XeWMDecorTITLE);
		EXeSetArg(XeNTitle, "Spheres");EXeSetArg(XeNIconName, "Spheres");
		XeWidget  LDialogW = XeDialog_New(XeDIALOG_TEMPLATE, "Hierarchy", E3dp_TopShellW,  Args, ArgCnt);if(LDialogW == NULL) return;
		XeAddCallback(LDialogW, XeNWMCallback, _DCB_Close, (EPointer)NULL);

		_DialogW = LDialogW;

		XeWidget  LTopMatrixW = XeDialog_GetChild(LDialogW, XeDIALOG_WORK_AREA);

		EXeStart;
		EXeSetArg(XeNHighlightThickness, 0);
		EXeSetArg(XeNMarginSizeX, 8);EXeSetArg(XeNMarginSizeY, 8);
		EXeSetArg(XeNResizableX, TRUE);
		Xe_SetValues(LTopMatrixW, Args, ArgCnt);

		EXeStart;
		EXeSetArg(XeNHighlightThickness, 0);
		EXeSetArg(XeNResizableX, FALSE);EXeSetArg(XeNAlignmentX, XeAlignCENTER);
		EXeSetArg(XeNResizableY, FALSE);
		XeWidget  LW = XeWidget_ManagedNew("Create spheres", XePushButton_class, LTopMatrixW, Args, ArgCnt);
		XeAddCallback(LW, XeNActivateCallback, _DCB, (EPointer)NULL);


		XeShell_Raise(_DialogW);
		XeShell_CenterToWidget(_DialogW, E3dp_TopShellW);
	}
	else XeShell_Raise(_DialogW);
}


//========================================
// Entry point of the plugin
//========================================
int E_PluginInit(EPlugin* PPlugin)
{
	_Plugin = PPlugin;
printf("%s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__);fflush(stdout);
// Use default plugin icon
//
	XePushButton_AddImg3(_ToolBarButtons[__ToolBarButtons_Count++], Plugin, "Tool->Create", "Elements", '\0', NULL, NULL, FALSE, "Chemical element navigator", _CB, (EPointer)0);

	return(E_SUCCESS);
}


//========================================
// Exit method of the plugin
//========================================
int E_PluginExit(const EBool PExiting)
{
	if(!PExiting || Xe_GUIFreeOnExit)
	{
		int  LC = 0;for(;LC < __ToolBarButtons_Count;LC++) { XeItemFree(_ToolBarButtons[LC]); } __ToolBarButtons_Count = 0;
	}

	return(E_SUCCESS);
}
