
const assert = require('assert');
const moment = require('moment');
const cbor = require('cbor');
const express = require('express');
const fs = require('fs');
const http = require('http');
const https = require('https');

const certificate = fs.readFileSync(process.env.CLIENT_CRT || 'cert/client.crt', 'utf8');
const privateKey = fs.readFileSync(process.env.CLIENT_KEY || 'cert/client.key', 'utf8');

const opt = {
  key: privateKey,
  cert: certificate,
  minVersion: process.env.MIN_TLS_VERSION || "TLSv1.1",
  sessionTimeout: 2
};

const dbcontroller = require('./db');
const routes = require('./routes')

const app = express();
const http_port = parseInt(process.env.HTTP_PORT, 10) || 80;
const https_port = parseInt(process.env.HTTPS_PORT, 10) || 443;
const environment = process.env.CONFIGURATION || 'develop';

const httpServer = http.createServer(app);
const httpsServer = https.createServer(credentials, app);

///// Splashscreen
console.log('    _   __       __ _                        ');
console.log('   / | / /___   / /(_)_____ _____ ___   ____ ');
console.log('  /  |/ // _ \\ / // // ___// ___// _ \\ / __ \\');
console.log(' / /|  //  __// // /(__  )(__  )/  __// / / /');
console.log('/_/ |_/ \\___//_//_//____//____/ \\___//_/ /_/ ');
console.log('                                             ');
console.log('                      T E C H N O L O G I E S');
console.log('');
console.log('');

///// Startup MongoDB Client
dbcontroller.init()
  .then((err) => {
    if (err) { console.log('Unable to connect to database'); }
    else {
      console.log('-------------------------------------------------------');
      console.log(Date().toString());
      console.log('MongoDB Client initialized');
      console.log('-------------------------------------------------------');

      ///// Startup HTTP Server
      httpServer.listen(http_port, () => {
        console.log('-------------------------------------------------------');
        console.log(`Server listening at http://localhost:${http_port}`);
        console.log('Environment: ' + environment);
        console.log('HTTP Port: ' + http_port);
        console.log('-------------------------------------------------------');
      });

      ///// Startup HTTPS Server
      httpsServer.listen(https_port, () => {
        console.log('-------------------------------------------------------');
        console.log(`Server listening at https://localhost:${https_port}`);
        console.log('Environment: ' + environment);
        console.log('HTTPS Port: ' + https_port);
        console.log('-------------------------------------------------------');
      });
    }
  })

app.use(express.json());
app.use(express.raw({ type: 'application/cbor' }));
app.use(express.urlencoded({ extended: true }));

app.use(function (req, res, next) {
  // Log request
  console.log('-------------------------------------------------------');
  console.log(req.method + ' ' + req.url + ' from ' + req.ip);
  next();
});

app.use(function (req, res, next) {
  if (!req.body.length) {
    // No body
    //////////
    console.log('Got empty frame');

    ///// Next handler
    next();

  } else if (req.is('application/cbor')) {
    // CBOR frame
    /////////////
    console.log('Got CBOR frame');
    console.log('Encoded:');
    console.log(req.body.toString('hex'))
    ///// Decode CBOR body
    cbor.decodeFirst(req.body, (err, decoded) => {
      ///// Assign decoded data
      req.body = decoded;

      ///// Next handler
      console.log('Decoded:');
      console.log(req.body)
      next();
    });

  } else {
    // JSON frame
    /////////////
    console.log('Got JSON frame');
    console.log(req.body)

    ///// Next handler
    next();
  }
});

app.use(function (req, res, next) {
  var length = 0;
  var send = res.send;

  /////////////////////////
  // Redefine send function
  res.send = function (body) {
    if (req.is('application/cbor') || req.acceptsEncodings("application/cbor") || req.acceptsEncodings("cbor")) {
      // CBOR Frame
      /////////////
      console.log('Send CBOR frame');
      console.log('Decoded:');
      console.log(body)

      ///// Set header
      res.set('Content-Type', 'application/cbor');
      length = JSON.stringify(body).length;

      ///// Convert ' to "
      if (body.data) { body.data = cbor.encode(JSON.parse(body.data.replace(/'/g, '"'))); }

      ///// Encode JSON to CBOR
      body = cbor.encode(body);

      // Log statistics
      console.log('Encoded:');
      console.log(body.toString('hex'))
      console.log(length + ' Bytes (JSON) -> ' + body.length + ' Bytes (CBOR) -> ' + Math.round((1 - length / body.length) * 100) + '% reduction');
    }
    
    ///// Send frame
    send.call(this, body);
  };

  ///// Next handler
  next();
});

app.use(function (req, res, next) {
  // Add formatted-date header
  res.setHeader("Formatted-Date", moment().format());
  next();
});

app.use(routes)


