#!/usr/bin/env dart
// Copyright (c) 2013, 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:convert';
import 'dart:io';

import 'package:args/args.dart';
import 'package:path/path.dart' as path;

import 'package:analyzer/src/services/formatter_impl.dart';

const BINARY_NAME = 'dartfmt';
final dartFileRegExp = new RegExp(r'^[^.].*\.dart$', caseSensitive: false);
final argParser = _initArgParser();
final defaultSelection = new Selection(-1, -1);

var formatterSettings;

CodeKind kind;
bool machineFormat;
bool overwriteFileContents;
Selection selection;
final List<String> paths = [];

const HELP_FLAG = 'help';
const KIND_FLAG = 'kind';
const MACHINE_FLAG = 'machine';
const WRITE_FLAG = 'write';
const SELECTION_FLAG = 'selection';
const TRANSFORM_FLAG = 'transform';
const MAX_LINE_FLAG = 'max_line_length';
const INDENT_FLAG = 'indent';

const FOLLOW_LINKS = false;

main(args) {
  var options = argParser.parse(args);
  if (options['help']) {
    _printUsage();
    return;
  }

  _readOptions(options);

  if (options.rest.isEmpty) {
    _formatStdin(kind);
  } else {
    paths.addAll(options.rest);
    _formatPaths(paths);
  }
}

_readOptions(options) {
  kind = _parseKind(options[KIND_FLAG]);
  machineFormat = options[MACHINE_FLAG];
  overwriteFileContents = options[WRITE_FLAG];
  selection = _parseSelection(options[SELECTION_FLAG]);
  formatterSettings = new FormatterOptions(
      codeTransforms: options[TRANSFORM_FLAG],
      tabsForIndent: _parseTabsForIndent(options[INDENT_FLAG]),
      spacesPerIndent: _parseSpacesPerIndent(options[INDENT_FLAG]),
      pageWidth: _parseLineLength(options[MAX_LINE_FLAG]));
}

/// Translate the indent option into spaces per indent.
int _parseSpacesPerIndent(String indentOption) {
  if (indentOption == 'tab') {
    return 1;
  }
  int spacesPerIndent = _toInt(indentOption);
  if (spacesPerIndent == null) {
    throw new FormatterException(
        'Indentation is specified as an Integer or ' 'the value "tab".');
  }
  return spacesPerIndent;
}

/// Translate the indent option into tabs for indent.
bool _parseTabsForIndent(String indentOption) => indentOption == 'tab';

CodeKind _parseKind(kindOption) {
  switch (kindOption) {
    case 'stmt':
      return CodeKind.STATEMENT;
    default:
      return CodeKind.COMPILATION_UNIT;
  }
}

int _parseLineLength(String lengthOption) {
  var length = _toInt(lengthOption);
  if (length == null) {
    var val = lengthOption.toUpperCase();
    if (val == 'INF' || val == 'INFINITY') {
      length = -1;
    } else {
      throw new FormatterException(
          'Line length is specified as an Integer or ' 'the value "Inf".');
    }
  }
  return length;
}

Selection _parseSelection(String selectionOption) {
  if (selectionOption == null) return null;

  var units = selectionOption.split(',');
  if (units.length == 2) {
    var offset = _toInt(units[0]);
    var length = _toInt(units[1]);
    if (offset != null && length != null) {
      return new Selection(offset, length);
    }
  }
  throw new FormatterException(
      'Selections are specified as integer pairs ' '(e.g., "(offset, length)".');
}

int _toInt(str) => int.parse(str, onError: (_) => null);

_formatPaths(paths) {
  paths.forEach((path) {
    if (FileSystemEntity.isDirectorySync(path)) {
      _formatDirectory(new Directory(path));
    } else {
      _formatFile(new File(path));
    }
  });
}

_formatResource(resource) {
  if (resource is Directory) {
    _formatDirectory(resource);
  } else if (resource is File) {
    _formatFile(resource);
  }
}

_formatDirectory(dir) => dir
    .listSync(followLinks: FOLLOW_LINKS)
    .forEach((resource) => _formatResource(resource));

_formatFile(file) {
  if (_isDartFile(file)) {
    if (_isPatchFile(file) && !paths.contains(file.path)) {
      _log('Skipping patch file "${file.path}"');
      return;
    }
    try {
      var rawSource = file.readAsStringSync();
      var formatted = _format(rawSource, CodeKind.COMPILATION_UNIT);
      if (overwriteFileContents) {
        // Only touch files files whose contents will be changed
        if (rawSource != formatted) {
          file.writeAsStringSync(formatted);
        }
      } else {
        print(formatted);
      }
    } catch (e) {
      _log('Unable to format "${file.path}": $e');
    }
  }
}

_isPatchFile(file) => file.path.endsWith('_patch.dart');

_isDartFile(file) => dartFileRegExp.hasMatch(path.basename(file.path));

_formatStdin(kind) {
  var input = new StringBuffer();
  stdin.transform(new Utf8Decoder()).listen((data) => input.write(data),
      onError: (error) => _log('Error reading from stdin'),
      onDone: () => print(_format(input.toString(), kind)));
}

/// Initialize the arg parser instance.
ArgParser _initArgParser() {
  // NOTE: these flags are placeholders only!
  var parser = new ArgParser();
  parser.addFlag(WRITE_FLAG,
      abbr: 'w',
      negatable: false,
      help: 'Write reformatted sources to files (overwriting contents).  '
      'Do not print reformatted sources to standard output.');
  parser.addFlag(TRANSFORM_FLAG,
      abbr: 't', negatable: false, help: 'Perform code transformations.');
  parser.addOption(MAX_LINE_FLAG,
      abbr: 'l', defaultsTo: '80', help: 'Wrap lines longer than this length. '
      'To never wrap, specify "Infinity" or "Inf" for short.');
  parser.addOption(INDENT_FLAG,
      abbr: 'i',
      defaultsTo: '2',
      help: 'Specify number of spaces per indentation. '
      'To indent using tabs, specify "--$INDENT_FLAG tab".' '--- [PROVISIONAL API].',
      hide: true);
  parser.addOption(KIND_FLAG,
      abbr: 'k',
      defaultsTo: 'cu',
      help: 'Specify source snippet kind ("stmt" or "cu") ' '--- [PROVISIONAL API].',
      hide: true);
  parser.addOption(SELECTION_FLAG,
      abbr: 's', help: 'Specify selection information as an offset,length pair '
      '(e.g., -s "0,4").', hide: true);
  parser.addFlag(MACHINE_FLAG,
      abbr: 'm',
      negatable: false,
      help: 'Produce output in a format suitable for parsing.');
  parser.addFlag(HELP_FLAG,
      abbr: 'h', negatable: false, help: 'Print this usage information.');
  return parser;
}

/// Displays usage information.
_printUsage() {
  var buffer = new StringBuffer();
  buffer
    ..write('$BINARY_NAME formats Dart programs.')
    ..write('\n\n')
    ..write('Without an explicit path, $BINARY_NAME processes the standard '
        'input.  Given a file, it operates on that file; given a '
        'directory, it operates on all .dart files in that directory, '
        'recursively. (Files starting with a period are ignored.) By '
        'default, $BINARY_NAME prints the reformatted sources to ' 'standard output.')
    ..write('\n\n')
    ..write('Usage: $BINARY_NAME [flags] [path...]\n\n')
    ..write('Supported flags are:\n')
    ..write('${argParser.usage}\n\n');
  _log(buffer.toString());
}

/// Format this [src], treating it as the given snippet [kind].
String _format(src, kind) {
  var formatResult = new CodeFormatter(formatterSettings).format(kind, src,
      selection: selection);
  if (machineFormat) {
    if (formatResult.selection == null) {
      formatResult.selection = defaultSelection;
    }
    return _toJson(formatResult);
  }
  return formatResult.source;
}

_toJson(formatResult) => // Actual JSON format TBD
    JSON.encode({
  'source': formatResult.source,
  'selection': {
    'offset': formatResult.selection.offset,
    'length': formatResult.selection.length
  }
});

/// Log the given [msg].
_log(String msg) {
  //TODO(pquitslund): add proper log support
  print(msg);
}
