/******************************************************************************
 *
 * Project:  Oracle Spatial Driver
 * Purpose:  Test mainline for fast loading.
 * Author:   Frank Warmerdam, warmerdam@pobox.com
 *
 ******************************************************************************
 * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.com>
 *
 * SPDX-License-Identifier: MIT
 ****************************************************************************/

#include <stdio.h>
#include "ogr_oci.h"

int main()

{
    OGROCISession oSession;

    if (!oSession.EstablishSession("warmerda", "LetoKing",
                                   "gdal800.dreadfest.com"))
    {
        exit(1);
    }

    printf("Session established.\n");

    OGROCIStatement oStatement(&oSession);

    oStatement.Execute("DROP TABLE fasttest");
    oStatement.Execute("CREATE TABLE fasttest (ifld INTEGER, "
                       "cfld VARCHAR(4000), shape mdsys.sdo_geometry)");
    //    oStatement.Execute( "CREATE TABLE fasttest (ifld INTEGER, cfld
    //    VARCHAR(4000))" );

    /* -------------------------------------------------------------------- */
    /*      Prepare insert statement.                                       */
    /* -------------------------------------------------------------------- */

    oStatement.Prepare("INSERT INTO fasttest VALUES "
                       "(:field_1, :field_2, :field_3)");
    //    oStatement.Prepare( "INSERT INTO fasttest VALUES "
    //                        "(:field_1, :field_2)" );

    /* -------------------------------------------------------------------- */
    /*      Do a conventional bind.                                         */
    /* -------------------------------------------------------------------- */
    int anField1[100];
    char szField2[100 * 4];
    int anGType[100];
    int anSRID[100];
    OCIArray *aphElemInfos[100];
    OCIArray *aphOrdinates[100];
    SDO_GEOMETRY_TYPE aoGeometries[100];
    SDO_GEOMETRY_ind aoGeometryIndicators[100];
    SDO_GEOMETRY_TYPE *apoGeomMap[100];
    SDO_GEOMETRY_ind *apoGeomIndMap[100];
    // double adfX[100], adfY[100];

    memset(aphElemInfos, 0, sizeof(OCIArray *) * 100);
    memset(aphOrdinates, 0, sizeof(OCIArray *) * 100);
    memset(aoGeometries, 0, sizeof(SDO_GEOMETRY) * 100);
    memset(aoGeometryIndicators, 0, sizeof(SDO_GEOMETRY_ind) * 100);

    if (oStatement.BindScalar(":field_1", anField1, sizeof(int), SQLT_INT) !=
        CE_None)
        exit(1);

    if (oStatement.BindScalar(":field_2", szField2, 4, SQLT_STR) != CE_None)
        exit(1);

    if (oStatement.BindObject(":field_3", apoGeomMap, oSession.hGeometryTDO,
                              (void **)apoGeomIndMap) != CE_None)
        exit(1);

    /* -------------------------------------------------------------------- */
    /*      Create array of arrays for elem_info and ordinates.             */
    /* -------------------------------------------------------------------- */
    int iBindRow;
    for (iBindRow = 0; iBindRow < 100; iBindRow++)
    {
        if (oSession.Failed(
                OCIObjectNew(
                    oSession.hEnv, oSession.hError, oSession.hSvcCtx,
                    OCI_TYPECODE_VARRAY, oSession.hElemInfoTDO,
                    static_cast<dvoid *>(NULL), OCI_DURATION_SESSION, FALSE,
                    reinterpret_cast<dvoid **>(aphElemInfos + iBindRow)),
                "OCIObjectNew()"))
            exit(1);

        if (oSession.Failed(
                OCIObjectNew(
                    oSession.hEnv, oSession.hError, oSession.hSvcCtx,
                    OCI_TYPECODE_VARRAY, oSession.hOrdinatesTDO,
                    static_cast<dvoid *>(NULL), OCI_DURATION_SESSION, FALSE,
                    reinterpret_cast<dvoid **>(aphOrdinates + iBindRow)),
                "OCIObjectNew()"))
            exit(1);
    }

    /* -------------------------------------------------------------------- */
    /*      Populate VARRAYs                                                */
    /* -------------------------------------------------------------------- */
    int iRow;

    for (iRow = 0; iRow < 100; iRow++)
    {
        // cppcheck-suppress unreadVariable
        anField1[iRow] = iRow;
        sprintf(szField2 + iRow * 4, "%3d", iRow);
        anGType[iRow] = 3001;
        anSRID[iRow] = -1;
        // adfX[iRow] = 100.0 + iRow;
        // adfY[iRow] = 100.0 - iRow;

        //---------------------------------------------------------------
        int anElemInfo[3], nElemInfoCount;
        OCINumber oci_number;
        int i;

        nElemInfoCount = 3;
        anElemInfo[0] = 1;
        anElemInfo[1] = 1;
        anElemInfo[2] = 1;

        // Prepare the VARRAY of ordinate values.
        for (i = 0; i < nElemInfoCount; i++)
        {
            if (oSession.Failed(
                    OCINumberFromInt(
                        oSession.hError, static_cast<dvoid *>(anElemInfo + i),
                        (uword)sizeof(int), OCI_NUMBER_SIGNED, &oci_number),
                    "OCINumberFromInt"))
                exit(1);

            if (oSession.Failed(OCICollAppend(oSession.hEnv, oSession.hError,
                                              (dvoid *)&oci_number, (dvoid *)0,
                                              aphElemInfos[iRow]),
                                "OCICollAppend"))
                exit(1);
        }

        //---------------------------------------------------------------
        double adfOrdinates[6];
        int nOrdCount;

        nOrdCount = 3;
        adfOrdinates[0] = iRow + 100;
        adfOrdinates[1] = iRow - 100;
        adfOrdinates[2] = 0.0;
        adfOrdinates[3] = iRow + 100;
        adfOrdinates[4] = iRow - 100;
        adfOrdinates[5] = 0.0;

        // Prepare the VARRAY of ordinate values.
        for (i = 0; i < nOrdCount; i++)
        {
            if (oSession.Failed(
                    OCINumberFromReal(oSession.hError,
                                      static_cast<dvoid *>(adfOrdinates + i),
                                      (uword)sizeof(double), &oci_number),
                    "OCINumberFromReal"))
                exit(1);

            if (oSession.Failed(OCICollAppend(oSession.hEnv, oSession.hError,
                                              static_cast<dvoid *>(&oci_number),
                                              static_cast<dvoid *>(NULL),
                                              aphOrdinates[iRow]),
                                "OCICollAppend"))
                exit(1);
        }

        // -------------------------------------------------------------
        SDO_GEOMETRY_TYPE *poGeom = aoGeometries + iRow;
        SDO_GEOMETRY_ind *poInd = aoGeometryIndicators + iRow;

        poInd->sdo_point._atomic = OCI_IND_NULL;

        if (oSession.Failed(
                OCINumberFromInt(oSession.hError,
                                 static_cast<dvoid *>(anGType + iRow),
                                 (uword)sizeof(int), OCI_NUMBER_SIGNED,
                                 &(poGeom->sdo_gtype)),
                "OCINumberFromInt"))
            exit(1);

        if (oSession.Failed(
                OCINumberFromInt(
                    oSession.hError, static_cast<dvoid *>(anSRID + iRow),
                    (uword)sizeof(int), OCI_NUMBER_SIGNED, &(poGeom->sdo_srid)),
                "OCINumberFromInt"))
            exit(1);

        poGeom->sdo_elem_info = aphElemInfos[iRow];
        poGeom->sdo_ordinates = aphOrdinates[iRow];

        apoGeomMap[iRow] = poGeom;
        apoGeomIndMap[iRow] = poInd;
    }

    /* -------------------------------------------------------------------- */
    /*      Execute the statement.                                          */
    /* -------------------------------------------------------------------- */
    int iGroup;

    for (iGroup = 0; iGroup < 2; iGroup++)
    {
        if (oSession.Failed(
                OCIStmtExecute(oSession.hSvcCtx, oStatement.GetStatement(),
                               oSession.hError, (ub4)100, (ub4)0,
                               (OCISnapshot *)NULL, (OCISnapshot *)NULL,
                               (ub4)OCI_COMMIT_ON_SUCCESS),
                "OCIStmtExecute"))
            exit(1);
    }

    printf("Successful completion\n");
    exit(0);
}
