import {
  ddescribe,
  describe,
  it,
  iit,
  xit,
  expect,
  beforeEach,
  afterEach
} from 'angular2/testing_internal';
import {HtmlTokenType} from 'angular2/src/compiler/html_lexer';
import {HtmlParser, HtmlParseTreeResult, HtmlTreeError} from 'angular2/src/compiler/html_parser';
import {
  HtmlAst,
  HtmlAstVisitor,
  HtmlElementAst,
  HtmlAttrAst,
  HtmlTextAst,
  HtmlCommentAst,
  htmlVisitAll
} from 'angular2/src/compiler/html_ast';
import {ParseError, ParseLocation} from 'angular2/src/compiler/parse_util';
import {humanizeDom, humanizeDomSourceSpans, humanizeLineColumn} from './html_ast_spec_utils';
export function main() {
  describe('HtmlParser', () => {
    var parser: HtmlParser;
    beforeEach(() => { parser = new HtmlParser(); });
    describe('parse', () => {
      describe('text nodes', () => {
        it('should parse root level text nodes', () => {
          expect(humanizeDom(parser.parse('a', 'TestComp'))).toEqual([[HtmlTextAst, 'a', 0]]);
        });
        it('should parse text nodes inside regular elements', () => {
          expect(humanizeDom(parser.parse('
a
', 'TestComp')))
              .toEqual([[HtmlElementAst, 'div', 0], [HtmlTextAst, 'a', 1]]);
        });
        it('should parse text nodes inside template elements', () => {
          expect(humanizeDom(parser.parse('a ', 'TestComp')))
              .toEqual([[HtmlElementAst, 'template', 0], [HtmlTextAst, 'a', 1]]);
        });
        it('should parse CDATA', () => {
          expect(humanizeDom(parser.parse('', 'TestComp')))
              .toEqual([[HtmlTextAst, 'text', 0]]);
        });
      });
      describe('elements', () => {
        it('should parse root level elements', () => {
          expect(humanizeDom(parser.parse('
', 'TestComp')))
              .toEqual([[HtmlElementAst, 'div', 0]]);
        });
        it('should parse elements inside of regular elements', () => {
          expect(humanizeDom(parser.parse('
', 'TestComp')))
              .toEqual([[HtmlElementAst, 'div', 0], [HtmlElementAst, 'span', 1]]);
        });
        it('should parse elements inside of template elements', () => {
          expect(humanizeDom(parser.parse(' - obsolete
             //  - obsolete
             ['
', '
', '
',
              '', '
',
             ].forEach((html) => { expect(parser.parse(html, 'TestComp').errors).toEqual([]); });
           });
        it('should close void elements on text nodes', () => {
          expect(humanizeDom(parser.parse('before
', 'TestComp')))
              .toEqual([
                [HtmlElementAst, 'p', 0],
                [HtmlTextAst, 'before', 1],
                [HtmlElementAst, 'br', 1],
                [HtmlTextAst, 'after', 1],
              ]);
        });
        it('should support optional end tags', () => {
          expect(humanizeDom(parser.parse('', 'TestComp')))
              .toEqual([
                [HtmlElementAst, 'div', 0],
                [HtmlElementAst, 'p', 1],
                [HtmlTextAst, '1', 2],
                [HtmlElementAst, 'p', 1],
                [HtmlTextAst, '2', 2],
              ]);
        });
        it('should support nested elements', () => {
          expect(humanizeDom(parser.parse('', 'TestComp')))
              .toEqual([
                [HtmlElementAst, 'ul', 0],
                [HtmlElementAst, 'li', 1],
                [HtmlElementAst, 'ul', 2],
                [HtmlElementAst, 'li', 3],
              ]);
        });
        it('should add the requiredParent', () => {
          expect(
              humanizeDom(parser.parse(
                  '',
                  'TestComp')))
              .toEqual([
                [HtmlElementAst, 'table', 0],
                [HtmlElementAst, 'thead', 1],
                [HtmlElementAst, 'tr', 2],
                [HtmlAttrAst, 'head', ''],
                [HtmlElementAst, 'tbody', 1],
                [HtmlElementAst, 'tr', 2],
                [HtmlAttrAst, 'noparent', ''],
                [HtmlElementAst, 'tbody', 1],
                [HtmlElementAst, 'tr', 2],
                [HtmlAttrAst, 'body', ''],
                [HtmlElementAst, 'tfoot', 1],
                [HtmlElementAst, 'tr', 2],
                [HtmlAttrAst, 'foot', '']
              ]);
        });
        it('should not add the requiredParent when the parent is a template', () => {
          expect(humanizeDom(parser.parse('
\n
\n\n \n\n ',
                     'TestComp')))
              .toEqual([
                [HtmlElementAst, 'p', 0],
                [HtmlTextAst, '\n', 1],
                [HtmlElementAst, 'textarea', 0],
                [HtmlElementAst, 'pre', 0],
                [HtmlTextAst, '\n', 1],
                [HtmlElementAst, 'listing', 0],
                [HtmlTextAst, '\n', 1],
              ]);
        });
      });
      describe('attributes', () => {
        it('should parse attributes on regular elements case sensitive', () => {
          expect(humanizeDom(parser.parse('
', 'TestComp')))
              .toEqual([
                [HtmlElementAst, 'div', 0],
                [HtmlAttrAst, 'kEy', 'v'],
                [HtmlAttrAst, 'key2', 'v2'],
              ]);
        });
        it('should parse attributes without values', () => {
          expect(humanizeDom(parser.parse('
', 'TestComp')))
              .toEqual([[HtmlElementAst, 'div', 0], [HtmlAttrAst, 'k', '']]);
        });
        it('should parse attributes on svg elements case sensitive', () => {
          expect(humanizeDom(parser.parse('
', 'TestComp')))
              .toEqual([[HtmlCommentAst, 'comment', 0], [HtmlElementAst, 'div', 0]]);
        });
      });
      describe('source spans', () => {
        it('should store the location', () => {
          expect(humanizeDomSourceSpans(parser.parse(
                     '\na\n
', 'TestComp')))
              .toEqual([
                [HtmlElementAst, 'div', 0, ''],
                [HtmlAttrAst, '[prop]', 'v1', '[prop]="v1"'],
                [HtmlAttrAst, '(e)', 'do()', '(e)="do()"'],
                [HtmlAttrAst, 'attr', 'v2', 'attr="v2"'],
                [HtmlAttrAst, 'noValue', '', 'noValue'],
                [HtmlTextAst, '\na\n', 1, '\na\n'],
              ]);
        });
        it('should set the start and end source spans', () => {
          let node = 
parser.parse('a
', 'TestComp').rootNodes[0];
          expect(node.startSourceSpan.start.offset).toEqual(0);
          expect(node.startSourceSpan.end.offset).toEqual(5);
          expect(node.endSourceSpan.start.offset).toEqual(6);
          expect(node.endSourceSpan.end.offset).toEqual(12);
        });
      });
      describe('errors', () => {
        it('should report unexpected closing tags', () => {
          let errors = parser.parse('
', 'TestComp').errors;
          expect(errors.length).toEqual(1);
          expect(humanizeErrors(errors)).toEqual([['p', 'Unexpected closing tag "p"', '0:5']]);
        });
        it('should report closing tag for void elements', () => {
          let errors = parser.parse('
', 'TestComp').errors;
          expect(errors.length).toEqual(1);
          expect(humanizeErrors(errors))
              .toEqual([['p', 'Only void and foreign elements can be self closed "p"', '0:0']]);
        });
        it('should report self closing custom element', () => {
          let errors = parser.parse('
', 'TestComp').errors;
          expect(errors.length).toEqual(2);
          expect(humanizeErrors(errors))
              .toEqual([
                [HtmlTokenType.COMMENT_START, 'Unexpected character "e"', '0:3'],
                ['p', 'Unexpected closing tag "p"', '0:14']
              ]);
        });
      });
    });
  });
}
export function humanizeErrors(errors: ParseError[]): any[] {
  return errors.map(error => {
    if (error instanceof HtmlTreeError) {
      // Parser errors
      return [error.elementName, error.msg, humanizeLineColumn(error.span.start)];
    }
    // Tokenizer errors
    return [(error).tokenType, error.msg, humanizeLineColumn(error.span.start)];
  });
}