// Copyright (c) 2012, 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.

part of pipeline;

List log;
var replyPort;
int _procId = 1;
Map _procs = {};

/**
 * Create a file path for a temporary file. The file will be in the
 * [tmpDir] directory, with name [basis], but with any extension
 * stripped and replaced by [suffix].
 */
String createTempName(String tmpDir, String basis, [String suffix='']) {
  var p = new Path(basis);
  return '$tmpDir${Platform.pathSeparator}'
      '${p.filenameWithoutExtension}${suffix}';
}

/**
 * Given a file path [file], make it absolute if it is relative,
 * and return the result as a [Path].
 */
Path getAbsolutePath(String file) {
  var p = new Path(file).canonicalize();
  if (p.isAbsolute) {
    return p;
  } else {
    var cwd = new Path(Directory.current.path);
    return cwd.join(p);
  }
}

/** Get the directory that contains a [file]. */
String getDirectory(String file) =>
    getAbsolutePath(file).directoryPath.toString();

/** Create a file [fileName] and populate it with [contents]. */
void writeFile(String fileName, String contents) {
  var file = new File(fileName);
  file.writeAsStringSync(contents);
}

/*
 * Run an external process [cmd] with command line arguments [args].
 * [timeout] can be used to forcefully terminate the process after
 * some number of seconds. This is used by runCommand and startProcess.
 * If [procId] is non-zero (i.e. called from startProcess) then a reference
 * to the [Process] will be put in a map with key [procId]; in this case
 * the process can be terminated later by calling [stopProcess] and
 * passing in the [procId].
 * [outputMonitor] is an optional function that will be called back with each
 * line of output from the process.
 * Returns a [Future] for when the process terminates.
 */
Future _processHelper(String command, List<String> args,
    List stdout, List stderr,
    [int timeout = 30, int procId = 0, Function outputMonitor]) {
  var timer = null;
  if (Platform.operatingSystem == 'windows' && command.endsWith('.bat')) {
    var oldArgs = args;
    args = new List();
    args.add('/c');
    // TODO(gram): We may need some escaping here if any of the
    // components contain spaces.
    args.add("$command ${oldArgs.join(' ')}");
    command='cmd.exe';
  }
  log.add('Running $command ${args.join(" ")}');
  
  return Process.start(command, args)
      .then((process) {
        _procs[procId.toString()] = process;

        var stdoutFuture = _pipeStream(process.stdout, stdout, outputMonitor);
        var stderrFuture = _pipeStream(process.stderr, stderr, outputMonitor);

        timer = new Timer(new Duration(seconds: timeout), () {
          timer = null;
          process.kill();
        });
        return Future.wait([process.exitCode, stdoutFuture, stderrFuture])
            .then((values) {
              if (timer != null) {
                timer.cancel();
              }
              return values[0];
            });
      })
      .catchError((e) {
        stderr.add("Error starting process:");
        stderr.add("  Command: $command");
        stderr.add("  Error: ${e.toString()}");
        return new Future.value(-1);
      });
}

Future _pipeStream(Stream stream, List<String> destination,
                 Function outputMonitor) {
  return stream
    .transform(new StringDecoder())
    .transform(new LineTransformer())
    .listen((String line) {
      if (config["immediate"] && line.startsWith('###')) {
        print(line.substring(3));
      }
      if (outputMonitor != null) {
        outputMonitor(line);
      }
      destination.add(line);
    })
    .asFuture();
}

/**
 * Run an external process [cmd] with command line arguments [args].
 * [timeout] can be used to forcefully terminate the process after
 * some number of seconds.
 * Returns a [Future] for when the process terminates.
 */
Future runCommand(String command, List<String> args,
                  List stdout, List stderr,
                  [int timeout = 30, Function outputMonitor]) {
  return _processHelper(command, args, stdout, stderr, 
      timeout, 0, outputMonitor);
}

/**
 * Start an external process [cmd] with command line arguments [args].
 * Returns an ID by which it can later be stopped.
 */
int startProcess(String command, List<String> args, List stdout, List stderr,
                 [Function outputMonitor]) {
  int id = _procId++;
  var f = _processHelper(command, args, stdout, stderr, 3000, id,
      outputMonitor);
  if (f != null) {
    f.then((e) {
      _procs.remove(id.toString());
    });
  }
  return id;
}

/** Checks if a process is still running. */
bool isProcessRunning(int id) {
  return _procs.containsKey(id.toString());
}

/**
 * Stop a process previously started with [startProcess] or [runCommand],
 * given the id string.
 */
void stopProcess(int id) {
  var sid = id.toString();
  if (_procs.containsKey(sid)) {
    Process p = _procs.remove(sid);
    p.kill();
  }
}

/** Delete a file named [fname] if it exists. */
bool cleanup(String fname) {
  if (fname != null && config['clean-files']) {
    var f = new File(fname);
    try {
      if (f.existsSync()) {
        logMessage('Removing $fname');
        f.deleteSync();
      }
    } catch (e) {
      return false;
    }
  }
  return true;
}

/** Delete a directory named [dname] if it exists. */
bool cleanupDir(String dname) {
  if (dname != null && config['clean-files']) {
    var d = new Directory(dname);
    try {
      if (d.existsSync()) {
        logMessage('Removing $dname');
        d.deleteSync(recursive: true);
      }
    } catch (e) {
      return false;
    }
  }
  return true;
}

initPipeline(port) {
  replyPort = port;
  stdout = new List();
  stderr = new List();
  log = new List();
}

void completePipeline(List stdout, List stderr, [exitCode = 0]) {
  replyPort.send([stdout, stderr, log, exitCode]);
}

/** Utility function to log diagnostic messages. */
void logMessage(msg) => log.add(msg);

/** Turn file paths into standard form with forward slashes. */
String normalizePath(String p) => (new Path(p)).toString();
