/*--------------------------------------------------------------------------------------+
|
|     $Source: sdk/example/RebarSDKExample.cpp $
|
|  $Copyright: (c) 2019 Bentley Systems, Incorporated. All rights reserved. $
|
+--------------------------------------------------------------------------------------*/

#include "_ustation.h"
#include "RebarSDKExample.h"

#include "RebarCatalog.h"
#include "RebarElements.h"
#include "rebarSDK_2d.h"

/*=================================================================================**//**
* @bsiclass                                                               Bentley Systems
+===============+===============+===============+===============+===============+======*/
struct          RebarSDKExamplePlaceRebar : public DgnElementSetTool
{
private:

    DPoint3d m_origin;

protected: 

    RebarSDKExamplePlaceRebar (int toolID) : DgnElementSetTool (toolID)
        {
        }

    bool            _OnResetButton(DgnButtonEventCR ev) override                { _OnRestartTool(); return true;                        }
    bool            _DoGroups () override                                       {    return false;                                      }
    bool            _NeedAcceptPoint () override                                {    return true;                                       }
    bool            _NeedPointForSelection () override                          {    return false;                                      }
    StatusInt       _OnElementModify  ( EditElementHandleR  el ) override       {    return ERROR;                                      }

    virtual size_t  _GetAdditionalLocateNumRequired () override                 { return 1;                                             }
    virtual bool    _WantAdditionalLocate (DgnButtonEventCP ev) override        { return WantAdditionalLocateHelper (ev);               }
    virtual bool    _OnModifierKeyTransition (bool wentDown, int key) override  { return OnModifierKeyTransitionHelper (wentDown, key); }

    void            SetupForLocate ();
    void            _SetupAndPromptForNextAction () override;
    bool            _SetupForModify (DgnButtonEventCR ev, bool isDynamics) override;
    EditElementHandleP  _BuildLocateAgenda (HitPathCP path, DgnButtonEventCP ev) override;
    bool            _OnDataButton(DgnButtonEventCR ev) override;
    void            _OnDynamicFrame (DgnButtonEventCR ev) override;
    bool            IsSelectionValid (HitPathCP hitPath);
    bool            _OnPostLocate (HitPathCP path, WStringR cantAcceptReason) override;


/*---------------------------------------------------------------------------------**//**
* @bsimethod                                                              Bentley Systems
+---------------+---------------+---------------+---------------+---------------+------*/
    void            CreateRebarElement(EditElementHandleR tagEeh, bool isDynamics);
    StatusInt       _ProcessAgenda  ( DgnButtonEventCR  ev ) override;
    bool            _OnInstall  (  ) override;
    void            _OnRestartTool () override;

public:

/*---------------------------------------------------------------------------------**//**
* @bsimethod                                                              Bentley Systems
+---------------+---------------+---------------+---------------+---------------+------*/
    static void InstallNewInstance (int toolId);

};

/*---------------------------------------------------------------------------------**//**
* @bsimethod                                                              Bentley Systems
+---------------+---------------+---------------+---------------+---------------+------*/
void RebarSDKExamplePlaceRebar::SetupForLocate ()
    {
    UInt32      msgId;
    msgId = PROMPT_ACCEPTREJECT;

	switch (GetElementAgenda ().GetCount ())
		{
		case 0:
			msgId = PROMPT_SELECT_SMARTSOLID_ELEMENT;
			break;

		default:
			_BeginDynamics ();
			msgId = PROMPT_ACCEPTREJECT;
			break;
		}

		__super::_SetLocateCursor (GetElementAgenda ().GetCount () < 1);

    mdlOutput_rscPrintf (MSG_PROMPT, NULL, STRINGLISTID_RebarSDKExampleTextMessages, msgId);
    }

/*---------------------------------------------------------------------------------**//**
* @bsimethod                                                              Bentley Systems
+---------------+---------------+---------------+---------------+---------------+------*/
void RebarSDKExamplePlaceRebar::_SetupAndPromptForNextAction ()
    {
    SetupForLocate ();
    }

/*---------------------------------------------------------------------------------**//**
* @bsimethod                                                              Bentley Systems
+---------------+---------------+---------------+---------------+---------------+------*/
bool RebarSDKExamplePlaceRebar::_SetupForModify (DgnButtonEventCR ev, bool isDynamics)
    {
    if (GetElementAgenda ().GetCount () < 1)
        return false;

    DPoint3d    anchorPt;
    if (!_GetAnchorPoint (&anchorPt))
        return false;

    m_origin = anchorPt;

    return true;
    }

/*---------------------------------------------------------------------------------**//**
* @bsimethod                                                              Bentley Systems
+---------------+---------------+---------------+---------------+---------------+--*/
EditElementHandleP RebarSDKExamplePlaceRebar::_BuildLocateAgenda (HitPathCP path, DgnButtonEventCP ev)
    {
    EditElementHandle eeh (path->GetHeadElem (), path->GetRoot ());
    return GetElementAgenda().Insert(eeh);
    }

/*---------------------------------------------------------------------------------**//**
* @bsimethod                                                              Bentley Systems
+---------------+---------------+---------------+---------------+---------------+--*/
bool RebarSDKExamplePlaceRebar::_OnDataButton(DgnButtonEventCR ev)
    {

    //if(2 == GetElementAgenda ().GetCount ())
    //    m_userOrigin = *ev.GetPoint ();

    return __super::_OnDataButton (ev);;
    }

/*---------------------------------------------------------------------------------**//**
* @bsimethod                                                              Bentley Systems
+---------------+---------------+---------------+---------------+---------------+--*/
void RebarSDKExamplePlaceRebar::_OnDynamicFrame (DgnButtonEventCR ev)
    {
    if(2 == GetElementAgenda ().GetCount ())
        {
        EditElementHandle tagElem;
        CreateRebarElement (tagElem, true);
        if(tagElem.IsValid ())
            {
            RedrawElems redrawElems;
            redrawElems.SetDrawMode (DRAW_MODE_TempDraw);
            redrawElems.SetDrawPurpose (DrawPurpose::Dynamics);
            redrawElems.SetViewport (ev.GetViewport ());
            redrawElems.SetRedrawOp (this);
            redrawElems.DoRedraw (tagElem);
            }
        }
    }

#include <DgnPlatform/DgnECFinders.h>
#include <ECObjects/ECObjectsAPI.h>


/*----------------------------------------------------------------------------------**//**
* @bsimethod                                                    Bentley Systems
+---------------+---------------+---------------+---------------+---------------+--*/
void GetItemTypePropertyValue (WStringR value, ElementHandleCR eh, WCharCP itemType, WCharCP propertyName)
    {
#if defined (DISABLED_CODE)
    value.clear();

    ECQueryPtr ecQuery = ECQuery::CreateQuery (ECQUERY_PROCESS_SearchAllClasses);
    FindElementInstancesScopePtr   scope = FindElementInstancesScope::CreateScope(eh, FindInstancesScopeOption (DgnECHostType::Element, false));

    DgnElementInstanceIterable  iterable = DgnECManager::GetManager().FindElementInstances(*scope, *ecQuery);
    for (auto iter = iterable.begin(); iter != iterable.end(); ++iter)
        {
        WStringCR className = (*iter)->GetClass().GetName();

        if (!className.CompareToI (itemType))
            {
            (*iter)->GetValueAsString (value, propertyName, false, 0);
            break;
            }
        }
#endif
    }

/*----------------------------------------------------------------------------------**//**
* @bsimethod                                                              Bentley Systems
+---------------+---------------+---------------+---------------+---------------+--*/
bool RebarSDKExamplePlaceRebar::IsSelectionValid (HitPathCP hitPath)
    {
    if (!hitPath)
        return false;

    // Construct an element handle from the HitPath.
    ElementHandle eh (hitPath->GetHeadElem (), hitPath->GetRoot ());

	// we are working on brep solid elements
	IBRepQuery*             brepHandler = dynamic_cast <IBRepQuery*> (&eh.GetHandler());
	if (nullptr != brepHandler)
		return  true;

	return false;

	/*
    // Check if the selection is a ProConcrete element.

    DebugBreak();

    WString value;
    GetItemTypePropertyValue (value, eh, L"testitemtype", L"Property1");
    

#ifdef xxx
    //ECQueryPtr                     ecQuery = Bentley::DgnPlatform::ECQuery::CreateQuery (L"testlib", L"testitemtype", true);
    //ECQueryPtr                     ecQuery = ECQuery::CreateQuery (L"ExtendedElementSchema", L"MstnCustomItemType");
    //ECQueryPtr ecQuery = ECQuery::CreateQuery (L"ExtendedElementSchema", L"MstnCustomItemTypeLibrary");

    ECQueryPtr ecQuery = ECQuery::CreateQuery (ECQUERY_PROCESS_SearchAllClasses);


    FindElementInstancesScopePtr   scope = FindElementInstancesScope::CreateScope(eh, FindInstancesScopeOption (DgnECHostType::Element, false));

    DgnECManagerR dgnECManager = DgnECManager::GetManager();

    DgnElementInstanceIterable     iterable = dgnECManager.FindElementInstances(*scope, *ecQuery);
    for (DgnElementInstanceIterable::const_iterator iter = iterable.begin(); iter != iterable.end(); ++iter)
        {
        WString testName (L"testitemtype");

        DgnECInstanceCR     instance = **iter;
        ECN::ECClassCR classDef = instance.GetClass();

        WStringCR name = classDef.GetName();

        if (!name.CompareToI (testName))
            {
            WString testProperty (L"Property1");

            WString value;
            ECN::ECObjectsStatus status = instance.GetValueAsString (value, testProperty.c_str(), false, 0);
            status = instance.GetValueAsString (value, testProperty.c_str(), false, 0);


            
            }

        }
#endif

#if defined (NEEDS_WORK)
    ITextQueryCP textQuery = eh.GetITextQuery ();
    if (!textQuery || !textQuery->IsTextElement (eh))
        return false;

    return true;
#else
    return false;
#endif
*/
    }

/*---------------------------------------------------------------------------------**//**
* @bsimethod                                                              Bentley Systems
+---------------+---------------+---------------+---------------+---------------+--*/
bool RebarSDKExamplePlaceRebar::_OnPostLocate (HitPathCP path, WStringR cantAcceptReason)
    {
    if (!DgnElementSetTool::_OnPostLocate (path, cantAcceptReason))
        return false;

    //At the start we only want to select a text element.
    if(0 == GetElementAgenda ().GetCount ())
        {
        return IsSelectionValid(path);
        }

    return true;
    }

/*---------------------------------------------------------------------------------**//**
* @bsimethod                                                              Bentley Systems
+---------------+---------------+---------------+---------------+---------------+--*/
void RebarSDKExamplePlaceRebar::CreateRebarElement(EditElementHandleR eeh, bool isDynamics)
    {
	if (isDynamics || GetElementAgenda().GetCount() != 1)
		return;

	EditElementHandleCP eh = GetElementAgenda().GetFirstP();
	ElementId elemId = eh->GetElementId();
	DgnModelRefP modelRef = eh->GetModelRef();



    }

/*---------------------------------------------------------------------------------**//**
* @bsimethod                                                              Bentley Systems
+---------------+---------------+---------------+---------------+---------------+--*/
StatusInt RebarSDKExamplePlaceRebar::_ProcessAgenda  ( DgnButtonEventCR  ev )
    {
    EditElementHandle tagEeh;
    CreateRebarElement(tagEeh, false);

    return SUCCESS;
    }

/*---------------------------------------------------------------------------------**//**
* @bsimethod                                                              Bentley Systems
+---------------+---------------+---------------+---------------+---------------+--*/
bool RebarSDKExamplePlaceRebar::_OnInstall  (  )
    {
    _SetElemSource(SOURCE_Pick);
    return true;
    }

/*---------------------------------------------------------------------------------**//**
* @bsimethod                                                              Bentley Systems
+---------------+---------------+---------------+---------------+---------------+--*/
void RebarSDKExamplePlaceRebar::_OnRestartTool ()
    {
    InstallNewInstance (GetToolId ());
    }

/*---------------------------------------------------------------------------------**//**
* @bsimethod                                                              Bentley Systems
+---------------+---------------+---------------+---------------+---------------+--*/
void RebarSDKExamplePlaceRebar::InstallNewInstance (int toolId)
    {
    RebarSDKExamplePlaceRebar* tool = new RebarSDKExamplePlaceRebar (toolId);

    tool->InstallTool ();
    }

/*---------------------------------------------------------------------------------**//**
* @param[in]        unparsed        In this case unparsed is ignored.
* @bsimethod                                                              Bentley Systems
+---------------+---------------+---------------+---------------+---------------+--*/
Public void RebarSDKExample_placeRebar (WCharCP unparsed)
    {
    
    RebarSDKExamplePlaceRebar::InstallNewInstance (CMDNAME_RebarSDKExamplePlaceRebar);

    }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/*---------------------------------------------------------------------------------**//**
* Map: key-in to function
* Commands
+---------------+---------------+---------------+---------------+---------------+--*/
static MdlCommandNumber s_commandNumbers[] =
    {
        { (CmdHandler)RebarSDKExample_placeRebar, CMD_REBARSDK_PLACE_REBAR },
        { NULL, 0}
    };

static MdlCommandName s_commandNames[] =
{
    { RebarSDK_Test                 , "RebarSDK_Test" },
    { RebarSDK_Metro                , "RebarSDK_Metro" },
	{ RebarSDK_KRB                  , "RebarSDK_KRB" },
	{ RebarSDK_ARMA                 , "RebarSDK_ARMA" },
	{ RebarSDK_PierVase             , "RebarSDK_PierVase" },
	{ NULL, 0 }
};

SDK_RebarDetailer *s_sdk_rebar_detailer = nullptr;
RebarSDK_RexFactory *s_sdk_rebar_factory = nullptr;

bool TerminateSDKRebar(UnloadProgramReason unloadType)
{
    delete s_sdk_rebar_detailer;
    s_sdk_rebar_detailer = nullptr;

    RexFactory::UnRegister(*s_sdk_rebar_factory);
    delete s_sdk_rebar_factory;
    s_sdk_rebar_factory = nullptr;
    return true;
}

/*---------------------------------------------------------------------------------**//**
* MdlMain

* @bsimethod                                                              Bentley Systems
+---------------+---------------+---------------+---------------+---------------+--*/
static RscFileHandle s_rfHandle = NULL;

RscFileHandle GetResourceHandle()
{
    return s_rfHandle;
}

extern "C" DLLEXPORT  void MdlMain (int argc, WCharCP argv[])
    {
    /* Open the resource file.*/
    mdlResource_openFile (&s_rfHandle, nullptr, RSC_READONLY);

    /* Register commands */
    mdlSystem_registerCommandNumbers(s_commandNumbers);
    mdlSystem_registerCommandNames(s_commandNames);

    mdlParse_loadCommandTable (nullptr);

    SystemCallback::SetUnloadProgramFunction(TerminateSDKRebar);

    s_sdk_rebar_detailer = new SDK_RebarDetailer;
    RebarDetailer::SetRebarDetailer(s_sdk_rebar_detailer);

    s_sdk_rebar_factory = new RebarSDK_RexFactory;
    RexFactory::Register(*s_sdk_rebar_factory);
    };

/************************************************************************/
/* Generate a Generic XML file of a selection of rebars                 */
/************************************************************************/

void GenericXMLRebarSelection();

/*Public*/ /*cmdName*/ void RebarSDK_Test(WCharCP unparsedP)
/*cmdNumber CMD_REBAR_TEST*/
{
    GenericXMLRebarSelection();
}

/*Public*/ /*cmdName*/ void RebarSDK_Metro(WCharCP unparsedP)
/*cmdNumber CMD_REBAR_TEST*/
{
    GenericXMLRebarSelection();
}

void getCallerId()
{
	ElementHandle pickedEh(123L, ACTIVEMODEL);

	if (RebarElement::IsRebarElement(pickedEh))
	{
		RebarElementP rep = RebarElement::Fetch(pickedEh);
		if (rep != nullptr)
		{
			RebarSetCP rebar_set = rep->GetRebarSet(ACTIVEMODEL);
			ElementId callerId = rebar_set != nullptr ? rebar_set->GetCallerId() : rep->GetCallerId();

			ElementHandle eh(callerId, rep->GetModelRef());
			RebarAssembly *assem = RebarAssembly::Fetch(eh);
			if (assem != nullptr)
			{
				ElementHandle whatyouwant(assem->GetSelectedElement(), assem->GetSelectedModel());
			}
		}
	}
}