/*--------------------------------------------------------------------------------------+
|
|     $Source: MstnExamples/Databases/oracledemo/oracledemo.cpp $
|
|  $Copyright: (c) 2020 Bentley Systems, Incorporated. All rights reserved. $
|
+--------------------------------------------------------------------------------------*/
/*----------------------------------------------------------------------+
|                                                                       |
|   $Workfile:   oracledemo.cpp  $                                      |
|   $Revision: 1.1 $                                                    |
|       $Date: 2020/02/10 14:20:05 $                                    |
|                                                                       |
+----------------------------------------------------------------------*/
/*--------------------------------------------------------------------------------------------------+
|                                                                                                   |
|   Function -                                                                                      |
|                                                                                                   |
|   Example MDL program to show database interface                                                  |
|                                                                                                   |
|   - - - - - - - - - - - - - - - - - - - - - - - - - - - - -                                       |
|                                                                                                   |
|   Public Routine Summary -                                                                        |
|                                                                                                   |
|   main - main entry point                                                                         |
|                                                                                                   |
|   Commands:                                                                                       |
|   oracledemo_connectToDb - Connect to an oracle database                                          |
|   oracledemo_createTableMSCATALOG - Create table MSCATALOG                                        |
|   oracledemo_createTableELEMENTS - Create table ELEMENTS                                          |
|   oracledemo_attachAndCheckLinkage - Attach and check the created linkage                         |
|   oracledemo_disconnect - Disconnect the database                                                 |
|                                                                                                   |
|   Local Functions:                                                                                |
|   oracledemo_setupGlobalData - Set up global data                                                 |
|   oracledemo_MessageCenter - Show messages                                                        |
|   oracledemo_appendLinkage - Append a linkage to an element                                       |
|   oracledemo_checkLinkage - Check the linkage on an element                                       |
|                                                                                                   |
+--------------------------------------------------------------------------------------------------*/
#include    <Mstn\MdlApi\MdlApi.h>
#include    <Mstn\MdlApi\rdbmslib.fdf>
#include    <Mstn\MdlApi\dbdefs.h>
#include    <Mstn\ISessionMgr.h>
#include    <DgnPlatform\DgnModel.h>
#include    <DgnPlatform\ElementHandle.h>
#include    <DgnPlatform\LinearHandlers.h>
#include    "oracledemoid.h"   /* resource IDs */
#include    "oracledemocmd.h"  /* generated by resource compiler */

USING_NAMESPACE_BENTLEY
USING_NAMESPACE_BENTLEY_DGNPLATFORM
USING_NAMESPACE_BENTLEY_MSTNPLATFORM
USING_NAMESPACE_BENTLEY_MSTNPLATFORM_ELEMENT

/*----------------------------------------------------------------------+
|                                                                       |
|   Public Global variables                                             |
|                                                                       |
+----------------------------------------------------------------------*/
WChar   mscatalogName[MAXFILELENGTH];
UShort  entityNum(1);

/*----------------------------------------------------------------------+
|                                                                       |
|   Local Functions Section                                             |
|                                                                       |
+----------------------------------------------------------------------*/

/*---------------------------------------------------------------------------------**//**
* @bsimethod                                                              Bentley Systems
+---------------+---------------+---------------+---------------+---------------+------*/
static void oracledemo_setupGlobalData
(
void
)
    {
    /* Copy the mscatalog table name. Use the value in env var if it exists, */
    /* else default to "mscatalog". */
    mdlDB_getMscatalogName(mscatalogName);
    }

/*---------------------------------------------------------------------------------**//**
* @bsimethod                                                              Bentley Systems
+---------------+---------------+---------------+---------------+---------------+------*/
static void oracledemo_MessageCenter
(
DgnPlatform::OutputMessagePriority     messagePriority,
MsgId msgId,
DgnPlatform::OutputMessageAlert        openAlertBox
)
    {
    WString BriefMessage;
    mdlResource_loadWString (BriefMessage, NULL, MESSAGELISTID_ORACLEDEMOMessages, msgId);
    mdlOutput_messageCenter(messagePriority, BriefMessage.GetWCharCP(), NULL, openAlertBox);
    }

/*---------------------------------------------------------------------------------**//**
* @bsimethod                                                              Bentley Systems
+---------------+---------------+---------------+---------------+---------------+------*/
static int     oracledemo_appendLinkage
(
    EditElementHandle & eeh,
    UInt32      mslink,
    WCharCP     tableNameP
)
    {
    short       attributes[MAX_ATTRIBSIZE];
    LinkProps   props;
    int         status;
    int         length;

    memset ( &props, 0, sizeof ( props ) );

    status = mdlDB_buildLink ( attributes, &length, ORACLE_LINKAGE, &props, tableNameP, mslink, 0 );
    if ( SUCCESS == status )
        {
        MSElementP  el = eeh.GetElementP ();
        ElementRefP elemRef = eeh.GetElementRef ();

        MSElementP  elBuffer;
        elBuffer = (MSElementP)_alloca ( sizeof ( MSElement ) );
        el->CopyTo ( *elBuffer );

        status = mdlElement_appendAttributes ( elBuffer, length, attributes );
        if ( SUCCESS != status )
            return status;

        eeh.ReplaceElement ( elBuffer );
        status = eeh.ReplaceInModel ( elemRef );
        }

    return  (status);
    }

/*---------------------------------------------------------------------------------**//**
* @bsimethod                                                              Bentley Systems
+---------------+---------------+---------------+---------------+---------------+------*/
static void oracledemo_checkLinkage ( EditElementHandle& eeh )
    {
    MSElementP elmP = eeh.GetElementP ();

    /* check if this attribute linkage belongs to us */
    if ( mdlDB_elementFilter ( elmP ) )
        {
        DatabaseLink    *link = NULL;
        int linkCount ( 0 );
        int status = mdlDB_extractLinkages ( &link, &linkCount, elmP );

        if ( status == SUCCESS )
            {
            BeAssert ( linkCount == 1 );
            WChar   sqlStatement[256];
            swprintf ( sqlStatement, L"select name from elements where mslink = %d", link[0].mslink );

            CursorID        cursorID;
            if ( SUCCESS == mdlDB_openCursorWithID ( &cursorID, sqlStatement ) )
                {
                bool found ( false );
                MS_sqlda        tableSQLDA;
                int statusFetch = QUERY_NOT_FINISHED;
                while ( statusFetch == QUERY_NOT_FINISHED )
                    {
                    statusFetch = mdlDB_fetchRowByID ( &tableSQLDA, cursorID );
                    if ( QUERY_NOT_FINISHED == statusFetch )
                        {
                        /* step through every column returned from the query */
                        for ( int i = 0; i < tableSQLDA.numColumns; i++ )
                            {
                            std::wstring column ( tableSQLDA.name[i] );
                            std::wstring value ( tableSQLDA.value[i] );

                            if ( wcsicmp ( column.c_str (), L"name" ) == 0 )
                                {
                                if ( wcscmp ( value.c_str (), L"line" ) == 0 )
                                    {
                                    found = true;
                                    break;
                                    }
                                }
                            }
                        if ( found )
                            break;
                        }
                    }

                mdlDB_closeCursorByID ( cursorID );
                mdlDB_freeSQLDADescriptor ( &tableSQLDA );

                if ( !found )
                    {
                    oracledemo_MessageCenter ( OutputMessagePriority::Warning, MSG_FailedCheckingLinkage, OutputMessageAlert::Dialog );
                    return;
                    }

                oracledemo_MessageCenter ( OutputMessagePriority::Warning, MSG_succeededCheckingLinkage, OutputMessageAlert::Dialog );
                }
            }
        }
    }

/*----------------------------------------------------------------------+
|                                                                       |
|   Command Functions Section                                           |
|                                                                       |
+----------------------------------------------------------------------*/
/*---------------------------------------------------------------------------------**//**
* @bsimethod                                                              Bentley Systems
+---------------+---------------+---------------+---------------+---------------+------*/
static void oracledemo_disconnect(WCharCP)
    {
    mdlDB_activeDatabase(L" ");

    /* Unload the Visual SQL Query Builder and Builder apps */
    mdlSystem_unloadMdlProgram(L"VSQL");
    mdlSystem_unloadMdlProgram(L"VSQLGEO");
    }

/*---------------------------------------------------------------------------------**//**
* @bsimethod                                                              Bentley Systems
+---------------+---------------+---------------+---------------+---------------+------*/
static void oracledemo_connectToDb(WCharCP loginString)
    {
    oracledemo_disconnect(NULL);
    mdlDB_changeDatabase(DATABASESERVERID_Oracle, loginString);//This line also create table "MSFORMS"

    }

/*---------------------------------------------------------------------------------**//**
* @bsimethod                                                              Bentley Systems
+---------------+---------------+---------------+---------------+---------------+------*/
static void oracledemo_createTableMSCATALOG(WCharCP)
    {
    if (!mdlDB_isActive())
        {
        oracledemo_MessageCenter(OutputMessagePriority::Warning, MSG_databaseIsNotActive, OutputMessageAlert::Dialog);
        return;
        }

    WChar           sqlStatement[256];
    CursorID        cursorID;

    //Judge if table "mscatalog" is exist
    swprintf(sqlStatement, L"select * from %ls", mscatalogName);
    if (SUCCESS == mdlDB_openCursorWithID(&cursorID, sqlStatement))
        {
        mdlDB_closeCursorByID(cursorID);
        oracledemo_MessageCenter(OutputMessagePriority::Info, MSG_tableMSCATALOGIsExist, OutputMessageAlert::Dialog);
        return;
        }

    swprintf(sqlStatement, L"create table %ls (tablename char(32), entitynum integer, screenform char(64), reporttable char(64), sqlreview char(240), fencefilter char(240), dastable char(32), formtable char(64))", mscatalogName);
    if (SUCCESS != mdlDB_processSQL(sqlStatement))
        {
        oracledemo_MessageCenter(OutputMessagePriority::Warning, MSG_failedCreatingTableMSCATALOG, OutputMessageAlert::Dialog);
        return;
        }
    else
        {
        oracledemo_MessageCenter(OutputMessagePriority::Info, MSG_succeededCreatingTableMSCATALOG, OutputMessageAlert::None);
        }
    }

/*---------------------------------------------------------------------------------**//**
* @bsimethod                                                              Bentley Systems
+---------------+---------------+---------------+---------------+---------------+------*/
static void oracledemo_createTableELEMENTS()
    {
    WChar           sqlStatement[256];
    CursorID        cursorID;

    //Judge if table "ELEMENTS" is exist. If it is exist, clear its rows.
    swprintf(sqlStatement, L"select * from %ls", L"ELEMENTS");
    if (SUCCESS == mdlDB_openCursorWithID(&cursorID, sqlStatement))
        {
        mdlDB_closeCursorByID(cursorID);
        swprintf ( sqlStatement, L"TRANCATE TABLE ELEMENTS" );
        mdlDB_processSQL ( sqlStatement );
        }
    else
        {
        swprintf ( sqlStatement, L"create table ELEMENTS (mslink NUMBER(10,4), name char(64))" );
        if ( SUCCESS != mdlDB_processSQL ( sqlStatement ) )
            {
            oracledemo_MessageCenter ( OutputMessagePriority::Warning, MSG_failedCreatingTableELEMENTS, OutputMessageAlert::Dialog );
            mdlDB_closeCursorByID ( cursorID );
            return;
            }
        }

    //Check if "ELEMENTS" is in table "MSCATALOG"
    swprintf ( sqlStatement, L"select * from %ls where tablename = '%hs'", L"MSCATALOG", "ELEMENTS" );
    if ( SUCCESS != mdlDB_openCursorWithID ( &cursorID, sqlStatement ) )
        {
        //Insert a row into MSCATALOG to record the table ELEMENTS
        swprintf ( sqlStatement, L"insert into %ls (tablename, entitynum) values('ELEMENTS', %hu)", mscatalogName, entityNum++ );
        if ( SUCCESS != mdlDB_processSQL ( sqlStatement ) )
            {
            oracledemo_MessageCenter ( OutputMessagePriority::Warning, MSG_failedInsertingRowIntoMSCATALOG, OutputMessageAlert::Dialog );
            mdlDB_closeCursorByID ( cursorID );
            return;
            }
        }

    oracledemo_MessageCenter ( OutputMessagePriority::Warning, MSG_succeededCreatingTableELEMENTS, OutputMessageAlert::Dialog );

    mdlDB_closeCursorByID ( cursorID );
    mdlDB_processSQL(L"reload");//Need to reload the db, if the table is newly created.
    }

/*---------------------------------------------------------------------------------**//**
* @bsimethod                                                              Bentley Systems
+---------------+---------------+---------------+---------------+---------------+------*/
static void oracledemo_attachAndCheckLinkage ()
    {
    WChar   sqlStatement[256];

    //Create a line
    bool is3d = ACTIVEMODEL->Is3d ();
    DSegment3d  segment;
    segment.Init ( 0.0, 0.0, 0.0, 3.0, 3.0, 0.0 );
    EditElementHandle  eeh;
    BentleyStatus status = LineHandler::CreateLineElement ( eeh, nullptr, segment, is3d, *ACTIVEMODEL );
    if ( SUCCESS != status )
        oracledemo_MessageCenter ( OutputMessagePriority::Warning, MSG_failedCreatingLineElement, OutputMessageAlert::Dialog );
    StatusInt addStatus = eeh.AddToModel ();
    if ( SUCCESS != addStatus )
        oracledemo_MessageCenter ( OutputMessagePriority::Warning, MSG_failedCreatingLineElement, OutputMessageAlert::Dialog );

    //Insert a row into table Elements
    UInt32  mslink ( 0 );
    mdlDB_largestMslink ( &mslink, L"elements" );
    mslink++;
    swprintf ( sqlStatement, L"insert into %ls (mslink, name) values(%hu, '%ls')", L"ELEMENTS", mslink, L"line" );
    if ( SUCCESS != mdlDB_processSQL ( sqlStatement ) )
        {
        oracledemo_MessageCenter ( OutputMessagePriority::Warning, MSG_failedInsertingRowIntoTableELEMENTS, OutputMessageAlert::Dialog );
        return;
        }

    //Attach a linkage to DB row
    if ( SUCCESS != oracledemo_appendLinkage ( eeh, mslink, L"elements" ) )
        {
        oracledemo_MessageCenter ( OutputMessagePriority::Warning, MSG_failedAppendingLinkage, OutputMessageAlert::Dialog );
        return;
        }

    //Check the linkage again
    oracledemo_checkLinkage ( eeh );    
    }

Public MdlCommandNumber commandNumbers[] =
    {
        { (CmdHandler)oracledemo_connectToDb,               CMD_ORACLEDEMO_CONNECTDB },
        { (CmdHandler)oracledemo_createTableMSCATALOG,      CMD_ORACLEDEMO_CREATETABLEMSCATALOG },
        { (CmdHandler)oracledemo_createTableELEMENTS,       CMD_ORACLEDEMO_CREATETABLEELEMENTS },
        { (CmdHandler)oracledemo_attachAndCheckLinkage,     CMD_ORACLEDEMO_ATTACHCHECKLINKAGE },
        { (CmdHandler)oracledemo_disconnect,                CMD_ORACLEDEMO_DISCONNECT },
        0           /* The table must be NULL-terminated */
    };

/*---------------------------------------------------------------------------------**//**
* @bsimethod                                                              Bentley Systems
+---------------+---------------+---------------+---------------+---------------+------*/
extern "C" DLLEXPORT void MdlMain
(
int         argc,
WCharCP     argv[]
)
    {
    mdlSystem_registerCommandNumbers (commandNumbers);

    /* setup global variables */
    oracledemo_setupGlobalData();

    RscFileHandle   rfHandle;

    /* open our application file for access to our dialogs */
    mdlResource_openFile (&rfHandle, NULL, RSC_READ);

    if (mdlParse_loadCommandTable (NULL) != NULL)
        mdlOutput_rscPrintf(MSG_MESSAGE, NULL, MESSAGELISTID_ORACLEDEMOMessages, MSG_commandsLoaded);

    }

