// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:ffi';
import 'dart:io';

import 'package:path/path.dart' as p;
import 'package:ffi/ffi.dart';
import 'package:ffigen/src/code_generator.dart';
import 'package:ffigen/src/header_parser/data.dart';
import 'package:ffigen/src/header_parser/includer.dart';
import 'package:logging/logging.dart';

import '../clang_bindings/clang_bindings.dart' as clang_types;
import '../data.dart';
import '../utils.dart';

var _logger = Logger('ffigen.header_parser.macro_parser');

/// Saved macros, Key: prefixedName, Value originalName.
final _savedMacros = <String, String>{};

/// Adds a macro definition to be parsed later.
void saveMacroDefinition(Pointer<clang_types.CXCursor> cursor) {
  final originalMacroName = cursor.spelling();
  if (shouldIncludeMacro(originalMacroName) &&
      !isSeenMacro(originalMacroName) &&
      clang.clang_Cursor_isMacroBuiltin_wrap(cursor) == 0 &&
      clang.clang_Cursor_isMacroFunctionLike_wrap(cursor) == 0) {
    // Parse macro only if it's not builtin or function-like.
    _logger.fine(
        "++++ Saved Macro '$originalMacroName' for later : ${cursor.completeStringRepr()}");
    final prefixedName = config.macroDecl.getPrefixedName(originalMacroName);
    addMacroToSeen(originalMacroName, prefixedName);
    _saveMacro(prefixedName, originalMacroName);
  }
}

/// Saves a macro to be parsed later.
///
/// Macros are parsed later in [parseSavedMacros()].
void _saveMacro(String name, String originalName) {
  _savedMacros[name] = originalName;
}

List<Constant> _bindings;

/// Macros cannot be parsed directly, so we create a new `.hpp` file in which
/// they are assigned to a variable after which their value can be determined
/// by evaluating the value of the variable.
List<Constant> parseSavedMacros() {
  _bindings = [];

  if (_savedMacros.keys.isEmpty) {
    return _bindings;
  }

  // Create a file for parsing macros;
  final file = createFileForMacros();

  final index = clang.clang_createIndex(0, 0);
  Pointer<Pointer<Utf8>> clangCmdArgs = nullptr;
  var cmdLen = 0;
  if (config.compilerOpts != null) {
    clangCmdArgs = createDynamicStringArray(config.compilerOpts);
    cmdLen = config.compilerOpts.length;
  }
  final tu = clang.clang_parseTranslationUnit(
    index,
    Utf8.toUtf8(file.path).cast(),
    clangCmdArgs.cast(),
    cmdLen,
    nullptr,
    0,
    clang_types.CXTranslationUnit_Flags.CXTranslationUnit_KeepGoing,
  );

  if (tu == nullptr) {
    _logger.severe('Unable to parse Macros.');
  } else {
    final rootCursor = clang.clang_getTranslationUnitCursor_wrap(tu);

    final resultCode = clang.clang_visitChildren_wrap(
      rootCursor,
      Pointer.fromFunction(_macroVariablevisitor,
          clang_types.CXChildVisitResult.CXChildVisit_Break),
      uid,
    );

    visitChildrenResultChecker(resultCode);
    rootCursor.dispose();
  }

  clang.clang_disposeTranslationUnit(tu);
  clang.clang_disposeIndex(index);
  // Delete the temp file created for macros.
  file.deleteSync();

  return _bindings;
}

/// Child visitor invoked on translationUnitCursor for parsing macroVariables.
int _macroVariablevisitor(Pointer<clang_types.CXCursor> cursor,
    Pointer<clang_types.CXCursor> parent, Pointer<Void> clientData) {
  Constant constant;
  try {
    if (isFromGeneratedFile(cursor) &&
        _macroVarNames.contains(cursor.spelling()) &&
        cursor.kind() == clang_types.CXCursorKind.CXCursor_VarDecl) {
      final e = clang.clang_Cursor_Evaluate_wrap(cursor);
      final k = clang.clang_EvalResult_getKind(e);
      _logger.fine('macroVariablevisitor: ${cursor.completeStringRepr()}');

      /// Get macro name, the variable name starts with '<macro-name>_'.
      final macroName = MacroVariableString.decode(cursor.spelling());
      switch (k) {
        case clang_types.CXEvalResultKind.CXEval_Int:
          constant = Constant(
            originalName: _savedMacros[macroName],
            name: macroName,
            rawType: 'int',
            rawValue: clang.clang_EvalResult_getAsLongLong(e).toString(),
          );
          break;
        case clang_types.CXEvalResultKind.CXEval_Float:
          constant = Constant(
            originalName: _savedMacros[macroName],
            name: macroName,
            rawType: 'double',
            rawValue: clang.clang_EvalResult_getAsDouble(e).toString(),
          );
          break;
        case clang_types.CXEvalResultKind.CXEval_StrLiteral:
          var value = Utf8.fromUtf8(clang.clang_EvalResult_getAsStr(e).cast());
          // Escape $ character.
          value = value.replaceAll(r'$', r'\$');
          // Escape ' character, because our strings are enclosed with '.
          value = value.replaceAll("'", r"\'");
          constant = Constant(
            originalName: _savedMacros[macroName],
            name: macroName,
            rawType: 'String',
            rawValue: "'${value}'",
          );
          break;
      }
      clang.clang_EvalResult_dispose(e);

      if (constant != null) {
        _bindings.add(constant);
      }
    }
    cursor.dispose();
    parent.dispose();
  } catch (e, s) {
    _logger.severe(e);
    _logger.severe(s);
    rethrow;
  }
  return clang_types.CXChildVisitResult.CXChildVisit_Continue;
}

/// Returns true if cursor is from generated file.
bool isFromGeneratedFile(Pointer<clang_types.CXCursor> cursor) {
  final s = cursor.sourceFileName();
  if (s == null || s.isEmpty) {
    return false;
  } else {
    return p.basename(s) == _generatedFileBaseName;
  }
}

/// Base name of generated file.
String _generatedFileBaseName;

/// Generated macro variable names.
///
/// Used to determine if macro should be included in bindings or not.
Set<String> _macroVarNames = {};

/// Creates a temporary file for parsing macros in current directory.
File createFileForMacros() {
  final fileNameBase = 'temp_for_macros';
  final fileExt = 'hpp';

  // Find a filename which doesn't already exist.
  var file = File('$fileNameBase.$fileExt');
  var i = 0;
  while (file.existsSync()) {
    i++;
    file = File('${fileNameBase.split('.')[0]}_$i.$fileExt');
  }

  // Create file.
  file.createSync();
  // Save generted name.
  _generatedFileBaseName = p.basename(file.path);

  // Write file contents.
  final sb = StringBuffer();
  for (final h in config.headers.entryPoints) {
    sb.writeln('#include "$h"');
  }

  _macroVarNames = {};
  for (final prefixedMacroName in _savedMacros.keys) {
    // Write macro.
    final macroVarName = MacroVariableString.encode(prefixedMacroName);
    sb.writeln('auto ${macroVarName} = ${_savedMacros[prefixedMacroName]};');
    // Add to _macroVarNames.
    _macroVarNames.add(macroVarName);
  }
  final macroFileContent = sb.toString();
  // Log this generated file for debugging purpose.
  // We use the finest log because this file may be very big.
  _logger.finest('=====FILE FOR MACROS====');
  _logger.finest(macroFileContent);
  _logger.finest('========================');

  file.writeAsStringSync(macroFileContent);
  return file;
}

/// Deals with encoding/decoding name of the variable generated for a Macro.
class MacroVariableString {
  static String encode(String s) {
    return '_${s.length}_${s}_generated_macro_variable';
  }

  static String decode(String s) {
    // Remove underscore.
    s = s.substring(1);
    final intReg = RegExp('[0-9]+');
    final lengthEnd = intReg.matchAsPrefix(s).end;
    final len = int.parse(s.substring(0, lengthEnd));

    // Name starts after an unerscore.
    final nameStart = lengthEnd + 1;
    return s.substring(nameStart, nameStart + len);
  }
}
