/*<section title="Intro">
# NAV Quick Start Tutorial for JavaScript <br /> in Node.js

#### DESCRIPTION
This tutorial is a quick introduction to FairCom's JavaScript c-tree Database API (ctdb),
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. Delete records
4. Insert records
5. Look up records

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

### 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. Reference __``ctdbsdk``__ in your code.
2. Put __``mtclient.dll``__ from the __``<...database...>\drivers\ctree.drivers\lib\``__ directory in your project and make sure it is distributed with your application.
3. In your project folder, execute: __``npm init --yes``__
4. Next, issue the following command: __``npm --save install <path to \drivers\nodejs.nav\>``__
5. Finally, execute __``node ctdb_tutorial1.js``__ to run this tutorial.

These steps provide the modules to access the FairCom Database Engine.
This is the communication layer between your application and the FairCom Database engine.

For convenience, this tutorial creates the __``ctdb``__ object to manage a database session, table, and records.

<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">

const ctdb = require('ctdbsdk');
const ref = require('ref-napi');

//</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="connect">
## SESSION

Create a session object to log on and manage the database.
Create a Database object in memory to allow for table management.
Connect to the indicated database on the server.

</comments> */
//<code title="Connect" name="connect">

const hSession = ctdb.AllocSession(ctdb.CTSESSION_CTDB);
ctdb.Logon(hSession, 'FAIRCOMS', 'admin', 'ADMIN');
const hDatabase = ctdb.AllocDatabase(hSession);
ctdb.Connect(hDatabase, 'ctreeSQL');

//</code>

/* <comments for="allocate">
## Allocate the table

Create a Table object in memory to facilitate record management.

Create a Record object in memory, to facilitate record creation, reading, updating, and deletion.

</comments> */
//<code title="Allocate" name="allocate">

const hTable = ctdb.AllocTable(hDatabase);
hRecord = ctdb.AllocRecord(hTable);

//</code>

/* <comments for="open">
## Open or create the table

1. Attempt to open the "custmast" table.
2. If the table does not exist, an exception will be thrown.
3. When processing this exception, the program creates the table and continues execution.

</comments> */
//<code title="Open table" name="open">

try {
  console.log('Open table...');
  ctdb.OpenTable(hTable, 'custmast', ctdb.CTOPEN_NORMAL);
} catch (e) {
  console.log('Add fields...\n');
  ctdb.AddField(hTable, 'cm_custnumb', ctdb.CT_FSTRING, 4);
  ctdb.AddField(hTable, 'cm_custzipc', ctdb.CT_FSTRING, 9);
  ctdb.AddField(hTable, 'cm_custstat', ctdb.CT_FSTRING, 2);
  ctdb.AddField(hTable, 'cm_custratg', ctdb.CT_FSTRING, 1);
  ctdb.AddField(hTable, 'cm_custname', ctdb.CT_STRING, 47);
  ctdb.AddField(hTable, 'cm_custaddr', ctdb.CT_STRING, 47);
  ctdb.AddField(hTable, 'cm_custcity', ctdb.CT_STRING, 47);

  console.log('Create table...\n');
  ctdb.CreateTable(hTable, 'custmast', ctdb.CTCREATE_NORMAL);
  ctdb.OpenTable(hTable, 'custmast', ctdb.CTOPEN_NORMAL);
}

//</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="data">
## Data Array

Create an array of 4 customer records.

</comments> */
//<code title="Data" name="data">

const data = [
  { number: '1000', zipcode: '92867', state: 'CA', rating: '1', name: 'Bryan Williams', address: '2999 Regency', city: 'Orange' },
  { number: '1001', zipcode: '61434', state: 'CT', rating: '1', name: 'Michael Jordan', address: '13 Main', city: 'Harford' },
  { number: '1002', zipcode: '73677', state: 'GA', rating: '1', name: 'Joshua Brown', address: '4356 Cambridge', city: 'Atlanta' },
  { number: '1003', zipcode: '10034', state: 'MO', rating: '1', name: 'Keyon Dooling', address: '19771 Park Avenue', city: 'Columbia' }
];

//</code>

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

This function will:

1. Find the first record
2. If the record was successfully found, delete it
3. Find the next record
4. Repeat steps 2 and 3 until it reaches the end of the file (table)

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

let empty;

console.log('Delete records...\n');

empty = false;
let retval = ctdb.ctdbFirstRecord(hRecord);
if (retval !== ctdb.CTDBRET_OK) {
  if (retval === ctdb.END_OF_FILE)
    empty = true;
  else
    throw('Delete_Records(): ctdbFirstRecord()');
}

while (empty === false) {
  ctdb.DeleteRecord(hRecord);

  retval = ctdb.NextRecord(hRecord);
  if (retval !== ctdb.CTDBRET_OK) {
    if (retval === ctdb.END_OF_FILE)
      empty = true;
    else
      throw('Delete_Records(): ctdbNextRecord()');
  }
}

//</code>

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

This function will:

1. Loop through every element in the `data` array
2. Load the data from the array into the record
3. Add the record to the database

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

console.log('Add records...\n');

for (let i = 0; i < data.length; i++) {
  ctdb.ClearRecord(hRecord);

  retval = 0;
  retval |= ctdb.SetFieldAsString(hRecord, 0, data[i].number);
  retval |= ctdb.SetFieldAsString(hRecord, 1, data[i].zipcode);
  retval |= ctdb.SetFieldAsString(hRecord, 2, data[i].state);
  retval |= ctdb.SetFieldAsString(hRecord, 3, data[i].rating);
  retval |= ctdb.SetFieldAsString(hRecord, 4, data[i].name);
  retval |= ctdb.SetFieldAsString(hRecord, 5, data[i].address);
  retval |= ctdb.SetFieldAsString(hRecord, 6, data[i].city);

  if (retval)
    Handle_Error('Add_Records(): ctdbSetFieldAsString()');

  if (ctdb.WriteRecord(hRecord))
    Handle_Error('Add_Records(): ctdbWriteRecord()');
}

//</code>

/* <comments for="display">
## Display all records

Go through each record in the table to display the customer number and name.

</comments> */
//<code title="Display records" name="display">

const custnumb = Buffer.alloc(4 + 1);
const custname = Buffer.alloc(47 + 1);

retval = ctdb.FirstRecord(hRecord);
while (retval !== ctdb.END_OF_FILE) {
  retval = 0;
  retval |= ctdb.GetFieldAsString(hRecord, 0, custnumb, custnumb.length);
  retval |= ctdb.GetFieldAsString(hRecord, 4, custname, custname.length);
  if (retval) {
    console.log('Display_Records(): ctdbGetFieldAsString()');
    break;
  }
  let custnumbStr = ref.readCString(custnumb, 0);
  let custnameStr = ref.readCString(custname, 0);

  console.log(custnumbStr + ', ' + custnameStr);

  retval = ctdb.NextRecord(hRecord);
  if (retval === ctdb.END_OF_FILE)
    break;

  if (retval) {
    console.log('Display_Records(): ctdbNextRecord()');
    break;
  }
}

//</code>


/* <comments for="disconnect">
## Clean up

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>

</comments> */
//<code title="Disconnect" name="disconnect">

ctdb.CloseTable(hTable);

console.log('Logout...\n');
ctdb.Logout(hSession);

ctdb.FreeRecord(hRecord);
ctdb.FreeTable(hTable);
ctdb.FreeDatabase(hDatabase);
ctdb.FreeSession(hSession);

//</code>
