import {StringWrapper, RegExpWrapper, isJsObject} from 'angular2/src/facade/lang';

var IS_FIELD = RegExpWrapper.create('^\\w+[\\.|\\#]\\w+=?$');
var IS_INTERFACE = RegExpWrapper.create('^\\{.+\\}');
var IS_DART = RegExpWrapper.create('\\:dart$');
var IS_JS = RegExpWrapper.create('\\:js$');
var IS_OPTIONAL = RegExpWrapper.create('\\:optional$');
var JS = 'JS';
var DART = 'Dart';
var MODE = isJsObject({}) ? JS : DART;

export class SymbolsDiff {
  missing: string[] = [];
  extra: string[] = [];
  errors: string[] = [];

  constructor(public actual: string[], public expected: string[]) {
    this.actual.sort(compareIgnoreLang);
    this.expected.sort(compareIgnoreLang);
    this.computeDiff();
  }

  computeDiff(): void {
    for (var i = 0, j = 0, length = this.expected.length + this.actual.length; i + j < length;) {
      var expectedName: string = i < this.expected.length ? this.expected[i] : '~';
      var actualName: string = j < this.actual.length ? this.actual[j] : '~';
      if (stripLang(expectedName) == stripLang(actualName)) {
        i++;
        j++;
      } else if (StringWrapper.compare(stripLang(expectedName), stripLang(actualName)) > 0) {
        // JS does not see fields so ignore none method symbols
        if (!this.shouldIgnore(expectedName)) {
          this.extra.push(actualName);
          this.errors.push('+ ' + actualName);
        }
        j++;
      } else {
        if (!this.shouldIgnore(expectedName)) {
          this.missing.push(expectedName);
          this.errors.push('- ' + expectedName);
        }
        i++;
      }
    }
  }

  shouldIgnore(expected: string): boolean {
    var ignore = false;
    if (MODE == JS) {
      ignore = RegExpWrapper.test(IS_FIELD, expected) ||
               RegExpWrapper.test(IS_INTERFACE, expected) ||
               RegExpWrapper.test(IS_DART, expected) || RegExpWrapper.test(IS_OPTIONAL, expected)
    } else {
      ignore = RegExpWrapper.test(IS_JS, expected) || RegExpWrapper.test(IS_OPTIONAL, expected)
    }
    return ignore;
  }
}

function stripLang(text: string): string {
  var index = text.indexOf(':');
  if (index >= 0) text = text.substring(0, index);
  return text;
}

function compareIgnoreLang(a: string, b: string): number {
  return StringWrapper.compare(stripLang(a), stripLang(b));
}
