/*--------------------------------------------------------------------------------------+
|  $Copyright: (c) 2019 Bentley Systems, Incorporated. All rights reserved. $
+--------------------------------------------------------------------------------------*/
#include "_ustation.h"
#include "RebarSDKExample.h"
#include "BeXMLNode.h"
#include "SelectionRebar.h"
#include "rebarSDK_PierVase.h"
#include "dialogs.h"
#include "english/dialogstxt.h"

using namespace RebarSpace;

static class RebarSDK_PierVaseTool *s_pTool = nullptr;

class RebarSDK_PierVaseTool : public SelectionRebar
{
public:
    enum TieType
    {
        kBend,
        kCog,
        kHook
    };

private:
    RebarSDKPierVaseData piervase_data;
    RebarSDKPierVase *piervase_elem;
    int		m_count;

	CPoint3D	m_origin;
	CPoint3D	m_X;

    BE_DATA_VALUE(MSDialogP, Dialog)

public:
    RebarSDKPierVaseData *operator->()
    {
        return &piervase_data;
    }
    const RebarSDKPierVaseData *operator->() const
    {
        return &piervase_data;
    }
    virtual StatusInt DataPoint(DPoint3dCP point, int view) override
	{
		if (m_count == 0)
		{
            DgnModelRefP modelRef = ACTIVEMODEL;
            ULong filepos = mdlLocate_findElement(point, view, FALSE, ComponentMode::None, FALSE);
            ElementRefP elemRef = mdlModelRef_getElementRef(modelRef, filepos);

            if (elemRef != nullptr && elemRef->GetElementType() == 106)
            {
                ElementHandle eh(elemRef);
                piervase_elem = REA::Load<RebarSDKPierVase>(eh.GetElementId(), modelRef);
                if (piervase_elem != nullptr)
                {
                    m_origin = piervase_elem->GetPlacement().GetTranslation();
                    m_count = 1;
                    piervase_elem->Setup(m_origin, m_X, piervase_data);
                }
                else
                    m_count = 0;
            }
            else
            {
                // we create a new pierVase
                // if you have selected solid set pass it as args below
                piervase_elem = REA::Create<RebarSDKPierVase>(modelRef);
                mdlOutput_prompt(L"Rebar SDK: Please input the second point for PierVase :");
                m_origin = *point;
                m_count = 1;
            }
		}
		else if (m_count == 1)
		{
			m_X = *point;
            m_X.z = m_origin.z;

			EditElementHandle tagEeh;

            CreatePierVase(tagEeh, false);

            m_count = 0;
		}

		return SUCCESS;
	}

	virtual StatusInt DataReset() override
	{
        m_count = 0;
        //delete piervase_elem;          // do not delete the piervase, as a RebarAssembly it belongs to the RebarModel now
        piervase_elem = nullptr;
        SelectionRebar::EndSelectElement(true);
        s_pTool = nullptr;
        if (m_Dialog != nullptr)
        {
            mdlDialog_closeCommandQueue(m_Dialog);
        }
		return SUCCESS;	
	}

	virtual StatusInt Dynamic(DPoint3dCP point, int view, DgnDrawMode drawMode) override
	{
		if (m_count != 1)
			return ERROR;

		m_X = *point;
        m_X.z = m_origin.z;         // keep it vertical

		EditElementHandle tagElem;
		CreatePierVase(tagElem, true);
		if (tagElem.IsValid())
		{
			RedrawElems redrawElems;
			redrawElems.SetDrawMode(DRAW_MODE_TempDraw);
			redrawElems.SetDrawPurpose(DrawPurpose::Dynamics);
			redrawElems.SetViews(IViewManager::GetActiveViewSet(), 0xffff);
			redrawElems.DoRedraw(tagElem);
		}

		return ERROR;
	}

	virtual StatusInt Process(RebarElementP rep) override
	{
		return SUCCESS;
	}

	virtual void Prompt() override
	{
		mdlOutput_prompt(L"Rebar SDK: Please input Two Points for PierVase or Select the PierVase :");
	}

	bool CreatePierVase(EditElementHandleR tagEeh, bool isDynamics);

public:
    RebarSDK_PierVaseTool()
        : piervase_elem(nullptr)
        , m_count(0)
        , m_Dialog(nullptr)
    {}

    // get the general information
    StatusInt ReadDialog()
    {
        StatusInt ret = ERROR;
        if (piervase_elem != nullptr)
        {
            piervase_elem->GetData(piervase_data);
        }
        else
        {
            TCHAR xml_fileName[256];
            if (mdlModelRef_getFileName(ACTIVEMODEL, xml_fileName, COUNT_OF(xml_fileName)) == SUCCESS)
            {
                _tcscat(xml_fileName, L".xml");
                BeXMLRoot dialog_xml_node;
                if (dialog_xml_node.ReadFile(xml_fileName, false))
                {
                    DgnModelRefP modelRef = ACTIVEMODEL;
                    double uorfactor = modelRef->GetModelInfoCP()->GetUorPerStorage();
                    AStrStream dlg_data;
                    double val;
                    dialog_xml_node.FindValue(dlg_data, L"Height");
                    dlg_data.ResetPos(); dlg_data >> val; piervase_data.SetHeight(val * uorfactor);
                    dialog_xml_node.FindValue(dlg_data, L"Depth");
                    dlg_data.ResetPos(); dlg_data >> val; piervase_data.SetDepth(val * uorfactor);
                    dialog_xml_node.FindValue(dlg_data, L"CapHeight");
                    dlg_data.ResetPos(); dlg_data >> val; piervase_data.SetCapHeight(val * uorfactor);
                    dialog_xml_node.FindValue(dlg_data, L"CapWidth");
                    dlg_data.ResetPos(); dlg_data >> val; piervase_data.SetCapWidth(val * uorfactor);
                    dialog_xml_node.FindValue(dlg_data, L"FootHeight");
                    dlg_data.ResetPos(); dlg_data >> val; piervase_data.SetFootHeight(val * uorfactor);
                    dialog_xml_node.FindValue(dlg_data, L"FootWidth");
                    dlg_data.ResetPos(); dlg_data >> val; piervase_data.SetFootWidth(val * uorfactor);
                    dialog_xml_node.FindValue(dlg_data, L"Cover");
                    dlg_data.ResetPos(); dlg_data >> val; piervase_data.SetCover(val * uorfactor);
                    dialog_xml_node.FindValue(dlg_data, L"ShearSpacing");
                    dlg_data.ResetPos(); dlg_data >> val; piervase_data.SetShearSpacing(val * uorfactor);
                    dialog_xml_node.FindValue(piervase_data.PopShearBarSize(), L"ShearBarSize");
                    dialog_xml_node.FindValue(dlg_data, L"LongitudinalSpacing");
                    dlg_data.ResetPos(); dlg_data >> val; piervase_data.SetLongitudinalSpacing(val * uorfactor);
                    dialog_xml_node.FindValue(piervase_data.PopLongitudinalBarSize(), L"LongitudinalBarSize");
                    dialog_xml_node.FindValue(dlg_data, L"TieType");
                    if (dlg_data == L"Bend")
                        piervase_data.SetTieType(RebarSDKPierVaseData::kBend);
                    else if (dlg_data == L"Cog")
                        piervase_data.SetTieType(RebarSDKPierVaseData::kCog);
                    else if (dlg_data == L"Hook")
                        piervase_data.SetTieType(RebarSDKPierVaseData::kHook);

                    ret = SUCCESS;
                }
            }
        }
        return ret;
    }

    StatusInt WriteDialog()
    {
        StatusInt ret = ERROR;
        BeXMLRoot dialog_xml_node;

        TCHAR xml_fileName[256];
        if (mdlModelRef_getFileName(ACTIVEMODEL, xml_fileName, COUNT_OF(xml_fileName)) == SUCCESS)
        {
            _tcscat(xml_fileName, L".xml");
            dialog_xml_node.SetName(L"PierVase");
            AStrStream dlg_data;
            Ben::Units currUnits = GetModelRefUnits(ACTIVEMODEL);

            ToDlgStr(dlg_data, piervase_data.GetHeight(), currUnits, 0);
            dialog_xml_node.AddXMLData(L"Height", dlg_data);
            ToDlgStr(dlg_data, piervase_data.GetDepth(), currUnits, 0);
            dialog_xml_node.AddXMLData(L"Depth", dlg_data);
            ToDlgStr(dlg_data, piervase_data.GetCapHeight(), currUnits, 0);
            dialog_xml_node.AddXMLData(L"CapHeight", dlg_data);
            ToDlgStr(dlg_data, piervase_data.GetCapWidth(), currUnits, 0);
            dialog_xml_node.AddXMLData(L"CapWidth", dlg_data);
            ToDlgStr(dlg_data, piervase_data.GetFootHeight(), currUnits, 0);
            dialog_xml_node.AddXMLData(L"FootHeight", dlg_data);
            ToDlgStr(dlg_data, piervase_data.GetFootWidth(), currUnits, 0);
            dialog_xml_node.AddXMLData(L"FootWidth", dlg_data);
            ToDlgStr(dlg_data, piervase_data.GetCover(), currUnits, 0);
            dialog_xml_node.AddXMLData(L"Cover", dlg_data);
            ToDlgStr(dlg_data, piervase_data.GetShearSpacing(), currUnits, 0);
            dialog_xml_node.AddXMLData(L"ShearSpacing", dlg_data);
            dialog_xml_node.AddXMLData(L"ShearBarSize", piervase_data.GetShearBarSize());
            ToDlgStr(dlg_data, piervase_data.GetLongitudinalSpacing(), currUnits, 0);
            dialog_xml_node.AddXMLData(L"LongitudinalSpacing", dlg_data);
            dialog_xml_node.AddXMLData(L"LongitudinalBarSize", piervase_data.GetLongitudinalBarSize());
            switch (piervase_data.GetTieType())
            {
            case (RebarSDKPierVaseData::kBend):
                    dlg_data = L"Bend";
                    break;
            case (RebarSDKPierVaseData::kCog):
                    dlg_data = L"Cog";
                    break;
            case (RebarSDKPierVaseData::kHook):
                    dlg_data = L"Hook";
                    break;
            }
            dialog_xml_node.AddXMLData(L"TieType", dlg_data);
            if (dialog_xml_node.WriteFile(xml_fileName))
            {
                ret = SUCCESS;
            }
        }
        return ret;
    }

    void SetPierVaseElement(RebarSDKPierVase *elem)
    {
        piervase_elem = elem;
    }
};

bool RebarSDK_PierVaseTool::CreatePierVase(EditElementHandleR tagEeh, bool isDynamics)
{
	if (m_count!= 1)
	{
		return false;
	}

	if (piervase_elem == nullptr || !piervase_elem->Setup(m_origin, m_X, piervase_data))
		return false;
	
    DgnModelRefP modelRef = ACTIVEMODEL;

    if (!isDynamics)
    {
        // rebar
        piervase_elem->MakeRebars(modelRef);
        // must save after creating stirrups
        piervase_elem->Save(modelRef);
        // we're done
        DataReset();
    }
    else
    {
        piervase_elem->CreatePierVaseSolid(tagEeh, *modelRef);
    }
	return true;
}

/*=================================================================================**/ /**
* @bsiclass
+===============+===============+===============+===============+===============+======*/
class PierVaseDialog
{
private:

    /*---------------------------------------------------------------------------------**/ /**
    * @bsimethod
    +---------------+---------------+---------------+---------------+---------------+------*/
    static void DialogHook(DialogMessage *dmP)
    {
        dmP->msgUnderstood = true;

        switch (dmP->messageType)
        {
        case DIALOG_MESSAGE_INIT:
        {
            DialogItem *diP = mdlDialog_itemGetByTypeAndId(dmP->db, RTYPE_OptionButton, OPTIONBUTTONID_PierVase_RebarTieType, 0);
            if (diP && s_pTool != nullptr)
            {
                s_pTool->ReadDialog();
                const RebarSDK_PierVaseTool &the_tool = *s_pTool;

                MSValueDescr value;
                mdlDialog_itemSetValue(NULL, value, dmP->db, diP->itemIndex);

                bool changedValue = false;
                AStrStream dlg_data;
                Ben::Units currUnits = GetModelRefUnits(ACTIVEMODEL);

                if (NULL != (diP = mdlDialog_itemGetByTypeAndId(dmP->db, RTYPE_OptionButton, OPTIONBUTTONID_PierVase_RebarTieType, 0)))
                {
                    value.SetInt32((int)the_tool->GetTieType());
                    mdlDialog_itemSetValue(&changedValue, value, dmP->db, diP->itemIndex);
                }
                if (NULL != (diP = mdlDialog_itemGetByTypeAndId(dmP->db, RTYPE_Text, TEXTID_PierVase_Height, 0)))
                {
                    ToDlgStr(dlg_data, the_tool->GetHeight(), currUnits, 0);

                    value.SetWChar(dlg_data);
                    mdlDialog_itemSetValue(&changedValue, value, dmP->db, diP->itemIndex);
                }
                if (NULL != (diP = mdlDialog_itemGetByTypeAndId(dmP->db, RTYPE_Text, TEXTID_PierVase_Depth, 0)))
                {
                    ToDlgStr(dlg_data, the_tool->GetDepth(), currUnits, 0);

                    value.SetWChar(dlg_data);
                    mdlDialog_itemSetValue(&changedValue, value, dmP->db, diP->itemIndex);
                }
                if (NULL != (diP = mdlDialog_itemGetByTypeAndId(dmP->db, RTYPE_Text, TEXTID_PierVase_CapHeight, 0)))
                {
                    ToDlgStr(dlg_data, the_tool->GetCapHeight(), currUnits, 0);

                    value.SetWChar(dlg_data);
                    mdlDialog_itemSetValue(&changedValue, value, dmP->db, diP->itemIndex);
                }
                if (NULL != (diP = mdlDialog_itemGetByTypeAndId(dmP->db, RTYPE_Text, TEXTID_PierVase_CapWidth, 0)))
                {
                    ToDlgStr(dlg_data, the_tool->GetCapWidth(), currUnits, 0);

                    value.SetWChar(dlg_data);
                    mdlDialog_itemSetValue(&changedValue, value, dmP->db, diP->itemIndex);
                }
                if (NULL != (diP = mdlDialog_itemGetByTypeAndId(dmP->db, RTYPE_Text, TEXTID_PierVase_FootHeight, 0)))
                {
                    ToDlgStr(dlg_data, the_tool->GetFootHeight(), currUnits, 0);

                    value.SetWChar(dlg_data);
                    mdlDialog_itemSetValue(&changedValue, value, dmP->db, diP->itemIndex);
                }
                if (NULL != (diP = mdlDialog_itemGetByTypeAndId(dmP->db, RTYPE_Text, TEXTID_PierVase_FootWidth, 0)))
                {
                    ToDlgStr(dlg_data, the_tool->GetFootWidth(), currUnits, 0);

                    value.SetWChar(dlg_data);
                    mdlDialog_itemSetValue(&changedValue, value, dmP->db, diP->itemIndex);
                }
                if (NULL != (diP = mdlDialog_itemGetByTypeAndId(dmP->db, RTYPE_Text, TEXTID_PierVase_RebarCover, 0)))
                {
                    ToDlgStr(dlg_data, the_tool->GetCover(), currUnits, 0);

                    value.SetWChar(dlg_data);
                    mdlDialog_itemSetValue(&changedValue, value, dmP->db, diP->itemIndex);
                }
                if (NULL != (diP = mdlDialog_itemGetByTypeAndId(dmP->db, RTYPE_Text, TEXTID_PierVase_ShearRebarSpacing, 0)))
                {
                    ToDlgStr(dlg_data, the_tool->GetShearSpacing(), currUnits, 0);

                    value.SetWChar(dlg_data);
                    mdlDialog_itemSetValue(&changedValue, value, dmP->db, diP->itemIndex);
                }
                if (NULL != (diP = mdlDialog_itemGetByTypeAndId(dmP->db, RTYPE_Text, TEXTID_PierVase_ShearRebarSize, 0)))
                {
                    value.SetWChar(the_tool->GetShearBarSize());
                    mdlDialog_itemSetValue(&changedValue, value, dmP->db, diP->itemIndex);
                }
                if (NULL != (diP = mdlDialog_itemGetByTypeAndId(dmP->db, RTYPE_Text, TEXTID_PierVase_LongitudinalRebarSpacing, 0)))
                {
                    ToDlgStr(dlg_data, the_tool->GetLongitudinalSpacing(), currUnits, 0);

                    value.SetWChar(dlg_data);
                    mdlDialog_itemSetValue(&changedValue, value, dmP->db, diP->itemIndex);
                }
                if (NULL != (diP = mdlDialog_itemGetByTypeAndId(dmP->db, RTYPE_Text, TEXTID_PierVase_LongitudinalRebarSize, 0)))
                {
                    value.SetWChar(the_tool->GetLongitudinalBarSize());
                    mdlDialog_itemSetValue(&changedValue, value, dmP->db, diP->itemIndex);
                }
            }
            break;
        }

        case DIALOG_MESSAGE_ACTIONBUTTON:
        {
            if (s_pTool != nullptr && ACTIONBUTTON_OK == dmP->u.actionButton.actionType)
            {
                RebarSDK_PierVaseTool &the_tool = *s_pTool;

                DialogItem *diP;
                MSValueDescr value;
                AStrStream dlg_data;
                DgnModelRefP modelRef = ACTIVEMODEL;
                double uorfactor = modelRef->GetModelInfoCP()->GetUorPerStorage();
                double val;
                if (NULL != (diP = mdlDialog_itemGetByTypeAndId(dmP->db, RTYPE_OptionButton, OPTIONBUTTONID_PierVase_RebarTieType, 0)))
                {
                    mdlDialog_itemGetValue(value, dmP->db, diP->itemIndex);
                    the_tool->SetTieType((RebarSDKPierVaseData::TieType) value.GetULong());
                }
                if (NULL != (diP = mdlDialog_itemGetByTypeAndId(dmP->db, RTYPE_Text, TEXTID_PierVase_Height, 0)))
                {
                    mdlDialog_itemGetValue(value, dmP->db, diP->itemIndex);
                    dlg_data = value.GetWCharCP();
                    dlg_data.ResetPos(); dlg_data >> val;  the_tool->SetHeight(val * uorfactor);
                }
                if (NULL != (diP = mdlDialog_itemGetByTypeAndId(dmP->db, RTYPE_Text, TEXTID_PierVase_Depth, 0)))
                {
                    mdlDialog_itemGetValue(value, dmP->db, diP->itemIndex);
                    dlg_data = value.GetWCharCP();
                    dlg_data.ResetPos(); dlg_data >> val;  the_tool->SetDepth(val * uorfactor);
                }
                if (NULL != (diP = mdlDialog_itemGetByTypeAndId(dmP->db, RTYPE_Text, TEXTID_PierVase_CapHeight, 0)))
                {
                    mdlDialog_itemGetValue(value, dmP->db, diP->itemIndex);
                    dlg_data = value.GetWCharCP();
                    dlg_data.ResetPos(); dlg_data >> val; the_tool->SetCapHeight(val * uorfactor);
                }
                if (NULL != (diP = mdlDialog_itemGetByTypeAndId(dmP->db, RTYPE_Text, TEXTID_PierVase_CapWidth, 0)))
                {
                    mdlDialog_itemGetValue(value, dmP->db, diP->itemIndex);
                    dlg_data = value.GetWCharCP();
                    dlg_data.ResetPos(); dlg_data >> val; the_tool->SetCapWidth(val * uorfactor);
                }
                if (NULL != (diP = mdlDialog_itemGetByTypeAndId(dmP->db, RTYPE_Text, TEXTID_PierVase_FootHeight, 0)))
                {
                    mdlDialog_itemGetValue(value, dmP->db, diP->itemIndex);
                    dlg_data = value.GetWCharCP();
                    dlg_data.ResetPos(); dlg_data >> val; the_tool->SetFootHeight(val * uorfactor);
                }
                if (NULL != (diP = mdlDialog_itemGetByTypeAndId(dmP->db, RTYPE_Text, TEXTID_PierVase_FootWidth, 0)))
                {
                    mdlDialog_itemGetValue(value, dmP->db, diP->itemIndex);
                    dlg_data = value.GetWCharCP();
                    dlg_data.ResetPos(); dlg_data >> val; the_tool->SetFootWidth(val * uorfactor);
                }
                if (NULL != (diP = mdlDialog_itemGetByTypeAndId(dmP->db, RTYPE_Text, TEXTID_PierVase_RebarCover, 0)))
                {
                    mdlDialog_itemGetValue(value, dmP->db, diP->itemIndex);
                    dlg_data = value.GetWCharCP();
                    dlg_data.ResetPos(); dlg_data >> val; the_tool->SetCover(val * uorfactor);
                }
                if (NULL != (diP = mdlDialog_itemGetByTypeAndId(dmP->db, RTYPE_Text, TEXTID_PierVase_ShearRebarSpacing, 0)))
                {
                    mdlDialog_itemGetValue(value, dmP->db, diP->itemIndex);
                    dlg_data = value.GetWCharCP();
                    dlg_data.ResetPos(); dlg_data >> val; the_tool->SetShearSpacing(val * uorfactor);
                }
                if (NULL != (diP = mdlDialog_itemGetByTypeAndId(dmP->db, RTYPE_Text, TEXTID_PierVase_ShearRebarSize, 0)))
                {
                    mdlDialog_itemGetValue(value, dmP->db, diP->itemIndex);
                    the_tool->PopShearBarSize() = value.GetWCharCP();
                }
                if (NULL != (diP = mdlDialog_itemGetByTypeAndId(dmP->db, RTYPE_Text, TEXTID_PierVase_LongitudinalRebarSpacing, 0)))
                {
                    mdlDialog_itemGetValue(value, dmP->db, diP->itemIndex);
                    dlg_data = value.GetWCharCP();
                    dlg_data.ResetPos(); dlg_data >> val; the_tool->SetLongitudinalSpacing(val * uorfactor);
                }
                if (NULL != (diP = mdlDialog_itemGetByTypeAndId(dmP->db, RTYPE_Text, TEXTID_PierVase_LongitudinalRebarSize, 0)))
                {
                    mdlDialog_itemGetValue(value, dmP->db, diP->itemIndex);
                    the_tool->PopLongitudinalBarSize() = value.GetWCharCP();
                }

                s_pTool->WriteDialog();
            }
            break;
        }

        default:
            dmP->msgUnderstood = false;
            break;
        }
    }

public:
    /*---------------------------------------------------------------------------------**/ /**
    * @bsimethod
    +---------------+---------------+---------------+---------------+---------------+------*/
    static MSDialogP OpenDialog()
    {
        int lastAction = PUSHBUTTONID_Cancel;
        MSDialogP dialog = mdlDialog_open(GetResourceHandle(), DIALOGID_PierVase);
        return dialog;
    }

    /*---------------------------------------------------------------------------------**/ /**
    * @bsimethod
    +---------------+---------------+---------------+---------------+---------------+------*/
    static void Initialize()
    {
        static bool hooks_published = false;

        //if (!hooks_published)
        {
            static DialogHookInfo uHooks[] =
            {
                {HOOKDIALOGID_PierVase, (PFDialogHook)DialogHook},
            };

            mdlDialog_hookPublish(sizeof(uHooks) / sizeof(DialogHookInfo), uHooks);
            hooks_published = true;
        }
    }
}; // PierVaseDialog


void RebarSDK_PierVase(WCharCP cmd)
{
    s_pTool = new RebarSDK_PierVaseTool;
    if (cmd != nullptr && *cmd > 0)
    {
        ElementId elemId = 0;
        BrString selected;
        AStrStream cmd_stream = cmd;
        cmd_stream.Breaks(L"=");
        cmd_stream >> selected >> elemId;
        RebarSDKPierVase *pier = REA::Load<RebarSDKPierVase>(elemId, ACTIVEMODEL);
        if (pier != nullptr)
        {
            s_pTool->SetPierVaseElement(pier);
        }
    }
	AccuDraw::GetInstance().Activate();
    AccuSnap::GetInstance().EnableSnap(true);
    PierVaseDialog::Initialize();
    s_pTool->SetDialog(PierVaseDialog::OpenDialog());
    SelectionRebar::SelectElement(*s_pTool);
}

RebarExtendedElementP RebarSDK_RexFactory::Make(BrStringCR rex_name) const
{
    RebarExtendedElementP ret = nullptr;
    if (rex_name == RebarSDKPierVase::GetVClassName())
    {
        ret = new RebarSDKPierVase(0, nullptr);
    }
    return ret;
}