
// for us typescript ignorati, having an import makes this file a module
import * as fs from 'fs';
import * as process from 'process';
import * as ts from 'typescript';

// This file contains various utilities having to do with producing strings
// and managing output

// ------ create files
let dir = process.env['HOME'];
const srcDir = '/vscode-languageserver-node';
export const fnames = [
  `${dir}${srcDir}/protocol/src/common/protocol.ts`,
  `${dir}/${srcDir}/protocol/src/browser/main.ts`, `${dir}${srcDir}/types/src/main.ts`,
  `${dir}${srcDir}/jsonrpc/src/node/main.ts`
];
export const gitHash = 'dae62de921d25964e8732411ca09e532dde992f5';
let outFname = 'tsprotocol.go';
let fda: number, fdb: number, fde: number;  // file descriptors

export function createOutputFiles() {
  fda = fs.openSync('/tmp/ts-a', 'w');  // dump of AST
  fdb = fs.openSync('/tmp/ts-b', 'w');  // unused, for debugging
  fde = fs.openSync(outFname, 'w');     // generated Go
}
export function pra(s: string) {
  return (fs.writeSync(fda, s));
}
export function prb(s: string) {
  return (fs.writeSync(fdb, s));
}
export function prgo(s: string) {
  return (fs.writeSync(fde, s));
}

// Get the hash value of the git commit
export function git(): string {
  let a = fs.readFileSync(`${dir}${srcDir}/.git/HEAD`).toString();
  // ref: refs/heads/foo, or a hash like
  // cc12d1a1c7df935012cdef5d085cdba04a7c8ebe
  if (a.charAt(a.length - 1) == '\n') {
    a = a.substring(0, a.length - 1);
  }
  if (a.length == 40) {
    return a;  // a hash
  }
  if (a.substring(0, 5) == 'ref: ') {
    const fname = `${dir}${srcDir}/.git/` + a.substring(5);
    let b = fs.readFileSync(fname).toString();
    if (b.length == 41) {
      return b.substring(0, 40);
    }
  }
  throw new Error('failed to find the git commit hash');
}

// Produce a header for Go output files
export function computeHeader(pkgDoc: boolean): string {
  let lastMod = 0;
  let lastDate: Date;
  for (const f of fnames) {
    const st = fs.statSync(f);
    if (st.mtimeMs > lastMod) {
      lastMod = st.mtimeMs;
      lastDate = st.mtime;
    }
  }
  const cp = `// Copyright 2019 The Go Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style
  // license that can be found in the LICENSE file.

  `;
  const a =
    '// Package protocol contains data types and code for LSP jsonrpcs\n' +
    '// generated automatically from vscode-languageserver-node\n' +
    `// commit: ${gitHash}\n` +
    `// last fetched ${lastDate}\n`;
  const b = 'package protocol\n';
  const c = '\n// Code generated (see typescript/README.md) DO NOT EDIT.\n\n';
  if (pkgDoc) {
    return cp + a + b + c;
  }
  else {
    return cp + b + a + c;
  }
}

// Turn a typescript name into an exportable Go name, and appease lint
export function goName(s: string): string {
  let ans = s;
  if (s.charAt(0) == '_') {
    ans = 'Inner' + s.substring(1);
  }
  else { ans = s.substring(0, 1).toUpperCase() + s.substring(1); }
  ans = ans.replace(/Uri$/, 'URI');
  ans = ans.replace(/Id$/, 'ID');
  return ans;
}

// Generate JSON tag for a struct field
export function JSON(n: ts.PropertySignature): string {
  const json = `\`json:"${n.name.getText()}${
    n.questionToken != undefined ? ',omitempty' : ''}"\``;
  return json;
}

// Generate modifying prefixes and suffixes to ensure
// consts are unique. (Go consts are package-level, but Typescript's are
// not.) Use suffixes to minimize changes to gopls.
export function constName(nm: string, type: string): string {
  let pref = new Map<string, string>([
    ['DiagnosticSeverity', 'Severity'], ['WatchKind', 'Watch'],
    ['SignatureHelpTriggerKind', 'Sig'], ['CompletionItemTag', 'Compl'],
    ['Integer', 'INT_'], ['Uinteger', 'UINT_']
  ]);  // typeName->prefix
  let suff = new Map<string, string>([
    ['CompletionItemKind', 'Completion'], ['InsertTextFormat', 'TextFormat'],
    ['SymbolTag', 'Symbol'], ['FileOperationPatternKind', 'Op'],
  ]);
  let ans = nm;
  if (pref.get(type)) ans = pref.get(type) + ans;
  if (suff.has(type)) ans = ans + suff.get(type);
  return ans;
}

// Find the comments associated with an AST node
export function getComments(node: ts.Node): string {
  const sf = node.getSourceFile();
  const start = node.getStart(sf, false);
  const starta = node.getStart(sf, true);
  const x = sf.text.substring(starta, start);
  return x;
}


// --------- printing the AST, for debugging

export function printAST(program: ts.Program) {
  // dump the ast, for debugging
  const f = function (n: ts.Node) {
    describe(n, pra);
  };
  for (const sourceFile of program.getSourceFiles()) {
    if (!sourceFile.isDeclarationFile) {
      // walk the tree to do stuff
      ts.forEachChild(sourceFile, f);
    }
  }
  pra('\n');
  for (const key of Object.keys(seenThings).sort()) {
    pra(`${key}: ${seenThings[key]} \n`);
  }
}

// Used in printing the AST
let seenThings = new Map<string, number>();
function seenAdd(x: string) {
  seenThings[x] = (seenThings[x] === undefined ? 1 : seenThings[x] + 1);
}

// eslint-disable-next-line no-unused-vars
function describe(node: ts.Node, pr: (s: string) => any) {
  if (node === undefined) {
    return;
  }
  let indent = '';

  function f(n: ts.Node) {
    seenAdd(kinds(n));
    if (ts.isIdentifier(n)) {
      pr(`${indent} ${loc(n)} ${strKind(n)} ${n.text} \n`);
    }
    else if (ts.isPropertySignature(n) || ts.isEnumMember(n)) {
      pra(`${indent} ${loc(n)} ${strKind(n)} \n`);
    }
    else if (ts.isTypeLiteralNode(n)) {
      let m = n.members;
      pr(`${indent} ${loc(n)} ${strKind(n)} ${m.length} \n`);
    }
    else if (ts.isStringLiteral(n)) {
      pr(`${indent} ${loc(n)} ${strKind(n)} ${n.text} \n`);
    }
    else { pr(`${indent} ${loc(n)} ${strKind(n)} \n`); }
    indent += ' .';
    ts.forEachChild(n, f);
    indent = indent.slice(0, indent.length - 2);
  }
  f(node);
}


// For debugging, say where an AST node is in a file
export function loc(node: ts.Node): string {
  const sf = node.getSourceFile();
  const start = node.getStart();
  const x = sf.getLineAndCharacterOfPosition(start);
  const full = node.getFullStart();
  const y = sf.getLineAndCharacterOfPosition(full);
  let fn = sf.fileName;
  const n = fn.search(/-node./);
  fn = fn.substring(n + 6);
  return `${fn} ${x.line + 1}: ${x.character + 1} (${y.line + 1}: ${
    y.character + 1})`;
}
// --- various string stuff

// return a string of the kinds of the immediate descendants
// as part of printing the AST tree
function kinds(n: ts.Node): string {
  let res = 'Seen ' + strKind(n);
  function f(n: ts.Node): void { res += ' ' + strKind(n); }
  ts.forEachChild(n, f);
  return res;
}

// What kind of AST node is it? This would just be typescript's
// SyntaxKind[n.kind] except that the default names for some nodes
// are misleading
export function strKind(n: ts.Node): string {
  if (n == null || n == undefined) {
    return 'null';
  }
   return kindToStr(n.kind);
}

export function kindToStr(k: ts.SyntaxKind): string {
  if (k === undefined) return 'unDefined';
  const x = ts.SyntaxKind[k];
  // some of these have two names
  switch (x) {
    default:
      return x;
    case 'FirstAssignment':
      return 'EqualsToken';
    case 'FirstBinaryOperator':
      return 'LessThanToken';
    case 'FirstCompoundAssignment':
      return 'PlusEqualsToken';
    case 'FirstContextualKeyword':
      return 'AbstractKeyword';
    case 'FirstLiteralToken':
      return 'NumericLiteral';
    case 'FirstNode':
      return 'QualifiedName';
    case 'FirstTemplateToken':
      return 'NoSubstitutionTemplateLiteral';
    case 'LastTemplateToken':
      return 'TemplateTail';
    case 'FirstTypeNode':
      return 'TypePredicate';
  }
}
