/**
 * @license
 * Copyright Google LLC All Rights Reserved.
 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://angular.io/license
 */

/// <reference types="node" />
import * as os from 'os';
import ts from 'typescript';

import {absoluteFrom} from './helpers';
import {FileSystem} from './types';

export class NgtscCompilerHost implements ts.CompilerHost {
  constructor(protected fs: FileSystem, protected options: ts.CompilerOptions = {}) {}

  getSourceFile(fileName: string, languageVersion: ts.ScriptTarget): ts.SourceFile|undefined {
    const text = this.readFile(fileName);
    return text !== undefined ? ts.createSourceFile(fileName, text, languageVersion, true) :
                                undefined;
  }

  getDefaultLibFileName(options: ts.CompilerOptions): string {
    return this.fs.join(this.getDefaultLibLocation(), ts.getDefaultLibFileName(options));
  }

  getDefaultLibLocation(): string {
    return this.fs.getDefaultLibLocation();
  }

  writeFile(
      fileName: string, data: string, writeByteOrderMark: boolean,
      onError: ((message: string) => void)|undefined,
      sourceFiles?: ReadonlyArray<ts.SourceFile>): void {
    const path = absoluteFrom(fileName);
    this.fs.ensureDir(this.fs.dirname(path));
    this.fs.writeFile(path, data);
  }

  getCurrentDirectory(): string {
    return this.fs.pwd();
  }

  getCanonicalFileName(fileName: string): string {
    return this.useCaseSensitiveFileNames() ? fileName : fileName.toLowerCase();
  }

  useCaseSensitiveFileNames(): boolean {
    return this.fs.isCaseSensitive();
  }

  getNewLine(): string {
    switch (this.options.newLine) {
      case ts.NewLineKind.CarriageReturnLineFeed:
        return '\r\n';
      case ts.NewLineKind.LineFeed:
        return '\n';
      default:
        return os.EOL;
    }
  }

  fileExists(fileName: string): boolean {
    const absPath = this.fs.resolve(fileName);
    return this.fs.exists(absPath) && this.fs.stat(absPath).isFile();
  }

  readFile(fileName: string): string|undefined {
    const absPath = this.fs.resolve(fileName);
    if (!this.fileExists(absPath)) {
      return undefined;
    }
    return this.fs.readFile(absPath);
  }

  realpath(path: string): string {
    return this.fs.realpath(this.fs.resolve(path));
  }
}
