/*<section title="Intro">
# NAV Quick Start Tutorial for C++

#### DESCRIPTION
This tutorial is a quick introduction to FairCom's c-tree Database API for C++ (cpp), <br />
which is a NAV API that makes it easy to navigate your data.

It shows how to:

1. Connect to the database
2. Create a table
3. Insert records
4. Look up records

It creates a console application that outputs each step to standard out.

<br />

### Why use a NAV API?
1. __NAV makes it easy to achieve unequaled performance.__

    - NAV gives you complete control over data processing.
        1. Navigate records in any order.
        2. Save record positions.
        3. Jump back to saved positions.
        4. Control how each record is locked and participates in transactions.

    - Algorithms are the secret to fast performance.
      - You are not limited to the algorithms built into SQL. 
      - NAV allows you to implement any algorithm to process data, 
        including algorithms for hierarchies, graphs, objects, documents, etc.
        
2. __NAV is the easiest way to solve complex data problems.__
    - You can walk through tough problems by navigating through the data step by step.
    - You can debug database data step by step in your favorite programming language.
    - You can leverage the power of your programming language to encapsulate complexity.  
    
3. __NAV literally makes the database an extension of your favorite programming language.__
    - NAV makes working with data no different than working with native collections of objects.
    - NAV makes complex data processing easy to implement, debug, and maintain.
  

### Why use SQL?
- The easier the problem, the more ideal SQL is.
  - SQL makes it easy to do simple queries and joins.
  - SQL solves many difficult issues with prebuilt SQL syntax, such as JOIN, ORDER BY, GROUP BY, etc.
  - SQL becomes exponentially more difficult to program as data processing becomes more complicated.
  
## Use NAV _and_ SQL
- SQL and NAV are equal partners in the FairCom Database Engine.
- You can use both at any time (and at the same time).
- Together, they make working with data easy and fun.

<br />
<br />
<br />

Copyright (C) 2020 by FairCom Corporation, 6300 West Sugar Creek Drive, Columbia, MO 65203 USA

</section> */

/* <comments for="references">

## Adding NAV to your project
Connecting to the NAV APIs in the FairCom Database Engine requires the application to use FairCom's client driver.
1. Put the __``mtclient.dll``__ in your project and make sure it is distributed with your application.
   It is the communication layer between your application and the FairCom Database engine.
   
This file is located in the folder: __``<...database...>\drivers\ctree.drivers\bin``__

For convenience, this tutorial creates three global variables to manage a database session, table, and records.
- __``MySession``__
- __``MyTable``__
- __``MyRecord``__

<br />

<div style="text-align: center; line-height: normal;">

## You can now leverage the full power of the world's leading _binary structure database_

</div>

</comments> */
//<code title="References" name="references">

#include "ctdbsdk.hpp"

#ifdef ctPortAppleiOS
#define main my_main
#endif

CTSession   *MySession = (CTSession *)0;
CTTable     *MyTable = (CTTable *)0;
CTRecord    *MyRecord = (CTRecord *)0;

VOID Initialize(VOID), Define(VOID), Manage(VOID), Done(VOID);
VOID Add_Records(VOID), Display_Records(VOID), Delete_Records(VOID);
VOID Check_Table_Mode(CTTable *);
VOID Handle_Exception(CTException);

//</code>

/* <comments for="main">
## MAIN

The tutorial is organized into four functions:

1. __``Initialize()``__
   - Connects to the database.

2. __``Define()``__
   - Opens an existing table or creates a new table.

3. __``Manage()``__
   - Deletes existing records (if any).
   - Adds records to the table.
   - Queries the table and outputs the results to stdout.

4. __``Done()``__
   - Disconnects from the database.

When the tutorial has finished running, 
you can press the ENTER key to close the console.


</comments> */
//<code title="Main" name="main">

int main (NINT argc, pTEXT argv[])
{
   Initialize();

   Define();

   Manage();

   Done();

   printf("\nPress <ENTER> key to exit . . .\n");
   getchar();

   return(0);
}

//</code>

/*<section title="Prep">
# Preparation
This section shows how to connect to the database and create tables.

<br />

<div style="line-height: normal;">

## _Use your favorite programming language to completely control all database functions_

</div>

</section> */

/* <comments for="Initialize">
## Initialize

__``Initialize()``__ does the following:
1. Starts an embedded FairCom Database Engine.
2. Initializes global session object that stores session state.
3. Logs into the session.
4. Initializes empty global table and record objects for later use.

#### NOTES
1. __Logging in__
   - The default user name and password are both __``ADMIN``__
   - The default name for the database server is __``FAIRCOMS``__

2. __Starting the database engine__
   - Starting the database engine from within your application is only required 
     when you embed the database into your application
     by compiling it in or by linking to it statically or dynamically.


3. __Embedding the database in your application__
   - The FairCom Database Engine has the unique ability to be embedded in an application.
   - The entire database engine can run as a DLL in the application.
   - This is useful for creating self-contained applications for:
      - Devices
      - Desktop Applications
      - Mobile apps
   - When the application connects to an external FairCom Database Engine (as in an N-tier Application Model), 
     comment out the following line of code:
      - __``ctdbStartDatabaseEngine();``__
  

<br />

<div style="text-align: center; line-height: normal;">
  
## _You can connect to many FairCom databases and simultaneously "remote control" all of them_

</div>

</comments> */
//<code title="Connect to Database" name="Initialize">

VOID Initialize(VOID)
{
   printf("INIT\n");

   try
   {
      ctdbStartDatabaseEngine();
      
      MySession = new CTSession(CTSESSION_CTREE);

      MyTable =  new CTTable(MySession);

      MyRecord =  new CTRecord(MyTable);

      printf("\tLogon to server...\n");
      MySession->Logon("FAIRCOMS", "ADMIN", "ADMIN");
   }
   catch(CTException E)
   {
      Handle_Exception(E);
   }
}

//</code>

/* <comments for="Define">
## Define

__``Define()``__ shows how to:
1. Open the table, if it exists. 
2. Otherwise create the table and then open it.

#### NOTES

1. A typical pattern in NAV is to first open an object,   
   and if it doesn't exist, create it.
   
2. Another common pattern in NAV is to configure an object and then apply it.
   - For example, the __``AddField()``__ method populates the __``MyTable object``__ with field definitions.
     and then the __``Create()``__ method creates the table containing those fields.

3. Another pattern is for the NAV API to throw an error when something does not work.
   - Everything in a database is stateful and all state changes follow rules. 
   - Many database operations change state and can potentially break rules. 
   - When an operation breaks a rule, such as trying to add a table or a record that already exists,
     the operation throws an exception to indicate that it did not change state.
   - Thus, NAV code wraps each major operation in __``try / catch``__. 

<br />

<div style="text-align: center; line-height: normal;">

## _NAV leverages object-oriented patterns_

</div>

</comments> */
//<code title="Create a Table" name="Define">

VOID Define(VOID)
{
   CTBOOL do_create = NO;

   printf("DEFINE\n");
   try
   {
      printf("\tOpen table...\n");
      MyTable->Open("custmast", CTOPEN_NORMAL);
   }
   catch (...)
   {
      do_create = YES;
   }

   if (do_create)
   {
      printf("\tAdd fields...\n");
      try
      {
         MyTable->AddField("cm_custnumb", CT_FSTRING, 4);
         MyTable->AddField("cm_custzipc", CT_FSTRING, 9);
         MyTable->AddField("cm_custstat", CT_FSTRING, 2);
         MyTable->AddField("cm_custrtng", CT_FSTRING, 1);
         MyTable->AddField("cm_custname", CT_STRING, 47);
         MyTable->AddField("cm_custaddr", CT_STRING, 47);
         MyTable->AddField("cm_custcity", CT_STRING, 47);

         printf("\tCreate table...\n");
         MyTable->Create("custmast", CTCREATE_NORMAL);

         MyTable->Open("custmast", CTOPEN_NORMAL);
      }
      catch (CTException E)
      {
         Handle_Exception(E);
      }
   }
   else
      Check_Table_Mode(MyTable);
}

//</code>

/*<section title="Process">
# Processing Data
This section shows how to 

1. Delete Records

2. Insert Records

3. Display Records

<br />

## _NAV eliminates double processing of your data_
  
  - A SQL database loops through your data and then returns the data so your application can loop through it again.
  
  - In NAV, your application loops through the data once by "remote controlling" the database.

</section> */

/* <comments for="Manage">
## Process Data

Manage() calls a separate function to do each of the following:

1. Delete records

2. Insert records

3. Display records


<br />
  
## _Literally extend your app directly into the database_

</comments> */
//<code title="Process Data" name="Manage">

VOID Manage(VOID)
{
   printf("MANAGE\n");

   Delete_Records();

   Add_Records();

   Display_Records();
}

//</code>

/* <comments for="Delete_Records">
## Delete Records

__``Delete_Records()``__ shows how to 
1. Find the first record in a table.
2. Delete all records in a table one by one.

<br />

#### Algorithm
  - Find the first record
  - When a record is found: 
    - Delete it
    - Move to next record
  - Repeat

<br />

#### NOTES
 - Working with data is the same as working with collections of objects. 
   Your code controls every step.

 - The FairCom Database Engine is designed specifically to give your application complete control,
   and do it with unrivaled speed.
   
 - Everything about the database engine is designed to navigate data:
   - The indexes have a special structure to make  
     __``First()``__, __``Next()``__, __``Prev()``__, and  __``Last()``__ very fast.
   - The communication protocols are highly optimized to minimize latency and marshalling. 

<br />

<div style="text-align: center; line-height: normal;">

## _The database becomes an extension of the application &mdash; doing exactly what the application tells it to do_

</div>

</comments> */
//<code title="Delete Records" name="Delete_Records">

VOID Delete_Records(VOID)
{
   CTBOOL   found;

   printf("\tDelete records...\n");

   try
   {
      found = MyRecord->First();
      while (found)
      {
         MyRecord->Delete();
         found = MyRecord->Next();
      }
   }
   catch(CTException E)
   {
      Handle_Exception(E);
   }
}

//</code>

/* <comments for="Add_Records">
## Add Records

__``Add_Records()``__ shows how to insert records into a table.

1. It uses the __``DATA_RECORD``__ structure to hold customer data.

2. It creates an array of __``DATA_RECORD``__ structures and populates them with data.
   
3. It uses that array of structures to insert records into the "custmast" table.

<br />

#### NOTES

This example illustrates how NAV makes the FairCom Database Engine an extension of the objects in your code.
In fact, in C and C++ you can literally write the binary data in object memory directly into records 
and read binary data out of records directly into object memory. This completely eliminates data transformation.

In all programming languages, the c-tree Database API makes it easy and fast 
to extract data from an object and put it into a record.
It is fast and efficient because under the hood, its driver writes data into a binary buffer, and 
that buffer goes directly into and out of the database without translation.
In other words, the application does all the work of mapping and formatting data,
and the database simply processes all data as simple binary data stored in records.

This approach distributes the processing load between the client and the database. 
This is much more effective than SQL databases because a SQL database must do all the work 
of translating client data into proprietary internal database structures and vice-versa.

<br />

<div style="text-align: center; line-height: normal;">

## _Achieve extreme speed by minimizing and distributing data&nbsp;transformation across app servers_

</div>

</comments> */
//<code title="Add Records" name="Add_Records">

VOID Add_Records(VOID)
{
   typedef struct {
      cpTEXT number, zipcode, state, rating, name, address, city;
   } DATA_RECORD;

   DATA_RECORD data[] = {
      "1000", "92867", "CA", "1", "Bryan Williams", "2999 Regency",      "Orange",
      "1001", "61434", "CT", "1", "Michael Jordan", "13 Main",           "Harford",
      "1002", "73677", "GA", "1", "Joshua Brown",   "4356 Cambridge",    "Atlanta",
      "1003", "10034", "MO", "1", "Keyon Dooling",  "19771 Park Avenue", "Columbia"
   };
   CTSIGNED nRecords = sizeof(data) / sizeof(DATA_RECORD);

   printf("\tAdd records...\n");

   try
   {
      for(CTSIGNED i = 0; i < nRecords; i++)
      {
         MyRecord->Clear();
         MyRecord->SetFieldAsString(0, data[i].number);
         MyRecord->SetFieldAsString(1, data[i].zipcode);
         MyRecord->SetFieldAsString(2, data[i].state);
         MyRecord->SetFieldAsString(3, data[i].rating);
         MyRecord->SetFieldAsString(4, data[i].name);
         MyRecord->SetFieldAsString(5, data[i].address);
         MyRecord->SetFieldAsString(6, data[i].city);

         MyRecord->Write();
      }
   }
   catch(CTException E)
   {
      Handle_Exception(E);
   }
}

//</code>

/* <comments for="Display_Records">
## Display Records

__``Display_Records()``__ shows how to retrieve records from a table,
process them, and output results.

1. __``First()``__ retrieves the first record.

2. __``Next()``__ retrieves the next record.

3. Two fields are retrieved as a string and displayed.


#### NOTES

__``First()``__ and __``Next()``__ process data in table or index order:
 
- Table order returns records very quickly in non-deterministic order.
  - This is the order used in __``Display_Records()``__.
  - This is the fastest way to traverse records.

- Index order returns records in the order the index stores them.
  - Index order always retrieves records in sorted order.
  - Indexes are ordered by one or more fields in the record.
    Each field can be independently sorted in ascending or descending order.
  - The FairCom Database Engine has a unique index structure so that it can walk records quickly.
  - As long as your table has an index, your application does not need to do the expensive operation of sorting records.
  - Create only the indexes you need because each index requires the database to do extra work. 

- The FairCom Database Engine creates two indexes by default: __``ROWID``__ and __``RECBYT``__

  1. __``ROWID``__ orders records by an automatically generated ascending integer
     - Thus, __``ROWID``__ order is always in original insert order
     - Because an index can be navigated forward or backward,
       you can use the ROWID index to walk data in oldest to newest order or vice-versa.

  2. __``RECBYT``__ orders records by their offset in the file.
      - Thus, __``RECBYT``__ order is always the order records are stored in a file.
      - This index is used to track the physical byte offset
        of records in files that contain variable-length records.
      - It is not needed when all table fields have a fixed length.


<div style="text-align: center; line-height: normal;">

## _Leverage FairCom's unique ability to process fixed-length records extremely quickly_ 

</div>

</comments> */
//<code title="Display Records" name="Display_Records">

VOID Display_Records(VOID)
{
   CTBOOL   found;
   TEXT     custnumb[47+1];
   TEXT     custname[47+1];

   printf("\tDisplay records...");

   try
   {
      found = MyRecord->First();

      while (found)
      {
         strcpy(custnumb, MyRecord->GetFieldAsString(0).c_str());
         strcpy(custname, MyRecord->GetFieldAsString(4).c_str());

         printf("\n\t\t%-8s%-20s\n",custnumb, custname);

         found = MyRecord->Next();
      }
   }
   catch(CTException E)
   {
      Handle_Exception(E);
   }
}

//</code>

/*<section title="Cleanup">
# Cleanup
This section shows how to close tables and disconnect from the database.

<br />
<div style="text-align: center; line-height: normal;">

## Release database objects <br /> when your code is done with them <br /> &mdash; just like any other resource in your code &mdash; 

</div>

</section> */

/* <comments for="Done">
## Done

__``Done()``__ shows how to 

1. Close an open table.

2. Log out from the FairCom Database Engine.

3. Stop an embedded FairCom Database Engine.

<br />

#### NOTES
- You only need to stop the database engine when the database is embedded in the application.

</comments> */
//<code title="Disconnect from Database" name="Done">

VOID Done(VOID)
{
   printf("DONE\n");

   try
   {
      printf("\tClose table...\n");
      MyTable->Close();
      printf("\tLogout...\n");
      MySession->Logout();
   }
   catch(CTException E)
   {
      Handle_Exception(E);
   }

   ctdbStopDatabaseEngine();
}

//</code>

/*<section title="General">
# General
This section contains helper functions:

1. to handle exceptions.

2. to change the table transaction processing mode.

<br />

<div style="line-height: normal;">

## _Encapsulate and extend the NAV API using your favorite programming language features_

</div>

</section> */

/* <comments for="Handle_Exception">
## Handling General Exceptions

__``Handle_Exception()``__ is invoked by all of the __``catch``__ statements in this tutorial, and does the following:

1. Writes an unexpected error to standard out.

2. Prompts the user to press ENTER.

3. Waits for the user to press ENTER.

4. Exits the application with an error code of 1.

</comments> */
//<code title="Handling General Exceptions" name="Handle_Exception">

VOID Handle_Exception(CTException err)
{
   printf ("\nERROR: [%d] - %s\n", err.GetErrorCode(), err.GetErrorMsg());
   printf("*** Execution aborted *** \nPress <ENTER> key to exit...");
   getchar();

   exit(1);
}

//</code>

/* <comments for="Check_Table_Mode">
## Changing Table Transaction Mode

__``Check_Table_Mode()``__ is a helper function 
used during table creation to disable transaction processing.
It illustrates how you can control the transaction processing characteristics of each individual table.

Transaction control ensures full ACID durability and, like all other ACID-compliant SQL databases, 
it comes with the performance cost of writing transactions into transaction logs on disk.

Turning off transaction control increases the speed of all database inserts, updates, and deletes, 
but it also increases the risk of data loss if the hardware or software fails unexpectedly.

<br />

### Function Process
- It gets the create mode of a table.
- If the table is created with transaction logs turned on,  
  it updates the table to turn them off.   
- A table's creation mode is a set of bit flags. This code turns off the "transaction&nbsp;control" bit flag.

<br />

### NOTES
- Transaction control is turned off in this tutorial to illustrate one of many low-level table features
  that you can individually control in each table.
- The tutorial works equally well with transaction control turned on or off.
- When transaction logging is turned on for a table, all transactions are fully ACID compliant.
- When transaction logging is turned off for a table, all transactions execute faster, 
  but there is a slightly higher risk of losing data in a database crash 
  and data cannot be automatically replicated between databases.

<br />
  
<div style="text-align: center; line-height: normal;">

## _NAV makes it easy <br /> to take complete control of your data_

</div>
  
</comments> */
//<code title="Changing Table Transaction Mode" name="Check_Table_Mode">

VOID Check_Table_Mode(CTTable *table)
{
   try
   {
      CTCREATE_MODE mode = table->GetCreateMode();
      if ((mode & CTCREATE_TRNLOG))
      {
         mode ^= CTCREATE_TRNLOG;
         table->UpdateCreateMode(mode);
      }
   }
   catch (CTException E)
   {
      Handle_Exception(E);
   }
}

//</code>
