import * as fs from 'fs';

import * as Util from '@dra2020/util';
import * as FSM from '@dra2020/fsm';

import * as Poly from '../lib/poly';
import * as PP from '../lib/polypack';
import * as BB from '../lib/boundbox';
import * as Q from '../lib/quad';

let data: any = null;

function loadData(): void
{
  if (process.argv.length > 2)
  {
    try
    {
      let s: string = fs.readFileSync(process.argv[process.argv.length-1], 'utf8');
      data = JSON.parse(s);
    }
    catch (err)
    {
      console.error(`File load/parse failed: ${err}`);
      process.exit(1);
    }
  }
  else
  {
    console.error('No data file specified.');
    process.exit(1);
  }
}

function forceGC(): void
{
 if (global.gc)
   global.gc();
 else
   console.warn('No GC hook! Start your program as `node --expose-gc file.js`.');
}

loadData();
PP.featurePack(data);
let rMax: any = { r: undefined, a: undefined, ba: undefined };
let rMin: any = { r: undefined, a: undefined, ba: undefined };

for (let i: number = 0; i < data.features.length; i++)
{
  let f: any = data.features[i];
  let a = Poly.polyArea(f);
  let ba = BB.boundboxArea(f);
  if (a > 0 && ba > 0)
  {
    let r = a/ba;
    if (rMax.r === undefined || r > rMax.r) rMax = { r: r, a: a, ba: ba };
    if (rMin.r === undefined || r < rMin.r) rMin = { r: r, a: a, ba: ba };
  }
}
console.log(`min: r: ${rMin.r}, a: ${rMin.a}, ba: ${rMin.ba}`);
console.log(`max: r: ${rMax.r}, a: ${rMax.a}, ba: ${rMax.ba}`);

/*

TODO: Rewrite with FSM

function runTest(env: FSM.FsmEnvironment, options: Poly.TickOptions)
{
  let elapsed = new Util.Elapsed();
  let tree = new Q.FsmQuadTree(env, options, data);
  let u = tree.union();
  console.log(`union at granularity ${options.maxLeafCount}: ${elapsed.ms()}`);
}

function runTests()
{
  let sizes: number[] = [ 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768 ];

  for (let i: number = 0; i < sizes.length; i++)
    runTest({ maxLeafCount: sizes[i], maxDepth: 20 });

}

runTests();

*/

function timeQuadTree(): void
{
  // For timing quadtree performance
  let asyncTime = new Util.Elapsed();
  let env: FSM.FsmEnvironment = { fsmManager: new FSM.FsmManager() };
  let fsm = new Q.FsmQuadTree(env, { maxLeafCount: 256, maxDepth: 32 }, data);
  new FSM.FsmOnDone(env, fsm, (q: Q.FsmQuadTree) => {
      console.log(`asyncUnion at granularity 256: ${asyncTime.ms()}`);
    });
}

function pretty(n: number): string
{
  if (n === null || n === undefined || isNaN(n)) return String(n);
  if (n < 1000) return String(n);
  return `${pretty(Math.trunc(n / 1000))},${String(n % 1000)}`;
}

function recordMemoryUse(event: string): void
{
  forceGC();

  // Record high water memory usage
  let mem: any = process.memoryUsage();
  if (mem && mem.rss)
  {
    console.log(event);
    if (mem.rss)
      console.log(`memory usage: rss: ${pretty(mem.rss)}`);
    if (mem.heapTotal)
      console.log(`memory usage: heapTotal: ${pretty(mem.heapTotal)}`);
    if (mem.heapUsed)
      console.log(`memory usage: heapUsed: ${pretty(mem.heapUsed)}`);
    if (mem.external)
      console.log(`memory usage: external: ${pretty(mem.external)}`);
  }
}

