// Copyright (c) 2014, 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 'package:analyzer/src/generated/interner.dart';
import 'package:analyzer/src/generated/java_core.dart';

export 'package:analyzer/exception/exception.dart';

/**
 * A predicate is a one-argument function that returns a boolean value.
 */
typedef bool Predicate<E>(E argument);

class FileNameUtilities {
  static String getExtension(String fileName) {
    if (fileName == null) {
      return "";
    }
    int index = fileName.lastIndexOf('.');
    if (index >= 0) {
      return fileName.substring(index + 1);
    }
    return "";
  }
}

class StringUtilities {
  static const String EMPTY = '';
  static const List<String> EMPTY_ARRAY = const <String>[];

  static Interner INTERNER = new NullInterner();

  /**
   * Compute line starts for the given [content].
   * Lines end with `\r`, `\n` or `\r\n`.
   */
  static List<int> computeLineStarts(String content) {
    List<int> lineStarts = <int>[0];
    int length = content.length;
    int unit;
    for (int index = 0; index < length; index++) {
      unit = content.codeUnitAt(index);
      // Special-case \r\n.
      if (unit == 0x0D /* \r */) {
        // Peek ahead to detect a following \n.
        if ((index + 1 < length) && content.codeUnitAt(index + 1) == 0x0A) {
          // Line start will get registered at next index at the \n.
        } else {
          lineStarts.add(index + 1);
        }
      }
      // \n
      if (unit == 0x0A) {
        lineStarts.add(index + 1);
      }
    }
    return lineStarts;
  }

  static endsWith3(String str, int c1, int c2, int c3) {
    var length = str.length;
    return length >= 3 &&
        str.codeUnitAt(length - 3) == c1 &&
        str.codeUnitAt(length - 2) == c2 &&
        str.codeUnitAt(length - 1) == c3;
  }

  static endsWithChar(String str, int c) {
    int length = str.length;
    return length > 0 && str.codeUnitAt(length - 1) == c;
  }

  static int indexOf1(String str, int start, int c) {
    int index = start;
    int last = str.length;
    while (index < last) {
      if (str.codeUnitAt(index) == c) {
        return index;
      }
      index++;
    }
    return -1;
  }

  static int indexOf2(String str, int start, int c1, int c2) {
    int index = start;
    int last = str.length - 1;
    while (index < last) {
      if (str.codeUnitAt(index) == c1 && str.codeUnitAt(index + 1) == c2) {
        return index;
      }
      index++;
    }
    return -1;
  }

  static int indexOf4(
      String string, int start, int c1, int c2, int c3, int c4) {
    int index = start;
    int last = string.length - 3;
    while (index < last) {
      if (string.codeUnitAt(index) == c1 &&
          string.codeUnitAt(index + 1) == c2 &&
          string.codeUnitAt(index + 2) == c3 &&
          string.codeUnitAt(index + 3) == c4) {
        return index;
      }
      index++;
    }
    return -1;
  }

  static int indexOf5(
      String str, int start, int c1, int c2, int c3, int c4, int c5) {
    int index = start;
    int last = str.length - 4;
    while (index < last) {
      if (str.codeUnitAt(index) == c1 &&
          str.codeUnitAt(index + 1) == c2 &&
          str.codeUnitAt(index + 2) == c3 &&
          str.codeUnitAt(index + 3) == c4 &&
          str.codeUnitAt(index + 4) == c5) {
        return index;
      }
      index++;
    }
    return -1;
  }

  /**
   * Return the index of the first not letter/digit character in the [string]
   * that is at or after the [startIndex]. Return the length of the [string] if
   * all characters to the end are letters/digits.
   */
  static int indexOfFirstNotLetterDigit(String string, int startIndex) {
    int index = startIndex;
    int last = string.length;
    while (index < last) {
      int c = string.codeUnitAt(index);
      if (!Character.isLetterOrDigit(c)) {
        return index;
      }
      index++;
    }
    return last;
  }

  static String intern(String string) => INTERNER.intern(string);
  static bool isEmpty(String s) {
    return s == null || s.isEmpty;
  }

  static bool isTagName(String s) {
    if (s == null || s.isEmpty) {
      return false;
    }
    int sz = s.length;
    for (int i = 0; i < sz; i++) {
      int c = s.codeUnitAt(i);
      if (!Character.isLetter(c)) {
        if (i == 0) {
          return false;
        }
        if (!Character.isDigit(c) && c != 0x2D) {
          return false;
        }
      }
    }
    return true;
  }

  /**
   * Produce a string containing all of the names in the given array, surrounded by single quotes,
   * and separated by commas. The list must contain at least two elements.
   *
   * @param names the names to be printed
   * @return the result of printing the names
   */
  static String printListOfQuotedNames(List<String> names) {
    if (names == null) {
      throw new ArgumentError("The list must not be null");
    }
    int count = names.length;
    if (count < 2) {
      throw new ArgumentError("The list must contain at least two names");
    }
    StringBuffer buffer = new StringBuffer();
    buffer.write("'");
    buffer.write(names[0]);
    buffer.write("'");
    for (int i = 1; i < count - 1; i++) {
      buffer.write(", '");
      buffer.write(names[i]);
      buffer.write("'");
    }
    buffer.write(" and '");
    buffer.write(names[count - 1]);
    buffer.write("'");
    return buffer.toString();
  }

  static startsWith2(String str, int start, int c1, int c2) {
    return str.length - start >= 2 &&
        str.codeUnitAt(start) == c1 &&
        str.codeUnitAt(start + 1) == c2;
  }

  static startsWith3(String str, int start, int c1, int c2, int c3) {
    return str.length - start >= 3 &&
        str.codeUnitAt(start) == c1 &&
        str.codeUnitAt(start + 1) == c2 &&
        str.codeUnitAt(start + 2) == c3;
  }

  static startsWith4(String str, int start, int c1, int c2, int c3, int c4) {
    return str.length - start >= 4 &&
        str.codeUnitAt(start) == c1 &&
        str.codeUnitAt(start + 1) == c2 &&
        str.codeUnitAt(start + 2) == c3 &&
        str.codeUnitAt(start + 3) == c4;
  }

  static startsWith5(
      String str, int start, int c1, int c2, int c3, int c4, int c5) {
    return str.length - start >= 5 &&
        str.codeUnitAt(start) == c1 &&
        str.codeUnitAt(start + 1) == c2 &&
        str.codeUnitAt(start + 2) == c3 &&
        str.codeUnitAt(start + 3) == c4 &&
        str.codeUnitAt(start + 4) == c5;
  }

  static startsWith6(
      String str, int start, int c1, int c2, int c3, int c4, int c5, int c6) {
    return str.length - start >= 6 &&
        str.codeUnitAt(start) == c1 &&
        str.codeUnitAt(start + 1) == c2 &&
        str.codeUnitAt(start + 2) == c3 &&
        str.codeUnitAt(start + 3) == c4 &&
        str.codeUnitAt(start + 4) == c5 &&
        str.codeUnitAt(start + 5) == c6;
  }

  static startsWithChar(String str, int c) {
    return str.isNotEmpty && str.codeUnitAt(0) == c;
  }

  static String substringBefore(String str, String separator) {
    if (str == null || str.isEmpty) {
      return str;
    }
    if (separator == null) {
      return str;
    }
    int pos = str.indexOf(separator);
    if (pos < 0) {
      return str;
    }
    return str.substring(0, pos);
  }

  static String substringBeforeChar(String str, int c) {
    if (isEmpty(str)) {
      return str;
    }
    int pos = indexOf1(str, 0, c);
    if (pos < 0) {
      return str;
    }
    return str.substring(0, pos);
  }
}

class UUID {
  static int __nextId = 0;
  final String id;
  UUID(this.id);
  String toString() => id;
  static UUID randomUUID() => new UUID((__nextId).toString());
}
