text: 'use strict'
  
  const fs = require('fs')
  const StringScanner = require('StringScanner')
  
  const utils = require('./utils')
  const Metadata = require('./metadata')
  
  /**
   * This constructor parses a given file path and returns
   * a Metadata object with information about the file's
   * constructor, methods, properties, etc...
   *
   * @author Aumard Jimmy <jimmy.aumard@gmail.com>
   */
  module.exports = class Parser {
    /**
     * foo(){}
     */
    static get T_FUNCTION() {
      return /(\w+)(.*)\((.*)\)/
    }
  
    /**
     * foo = 'some variable'
     */
    static get T_PROPERTY() {
      return /(\w+)(.*)= (.*)\n/
    }
  
    /**
     * class MyClass extends Parent
     */
    static get T_CLASS_DEFINITION() {
      return /(.*)class (\w+)( extends (\w+))?/
    }
  
    /**
     * constructor(){}
     */
    static get T_CONSTRUCTOR_FUNCTION() {
      return /constructor\((.*?)\)/
    }
  
    /**
     * Parse the Metadata from a given javascript file path
     *
     * @param {String} path
     * @returns {Metadata}
     */
    parseFile(path) {
      const stat = fs.lstatSync(path)
      if (!stat || !stat.isFile()) {
        return null
      }
      const metadata = this.parseSource(fs.readFileSync(path).toString())
      metadata.path = path
      return metadata
    }
  
    /**
     * Parse the Metadata from a file content string
     *
     * @param {String} source
     * @returns {Metadata}
     */
    parseSource(source) {
  
      const metadata = new Metadata()
      const ss = new StringScanner(source)
  
      let foundConstructor = false
      let className = null
  
      while (!ss.eos()) {
  
        const cs = ss.scanUntil(/\/\*\*/)
        if (cs == null) break
        const csp = ss.pointer() - 3
        ss.scanUntil(/\*\/(\r\n|\n|\r)/)
        const cep = ss.pointer()
        const comment = source.substring(csp, cep)
        const lineNumber = utils.findLineNumberOfPosition(source, csp)
        const nextLine = ss.scanUntil(/(\r\n|\n|\r)/).split('\r').join('')
  
        if (nextLine === null || nextLine.trim() == '') {
          metadata.fileComment = comment
          continue
        }
  
        let match
  
        // class
        match = nextLine.match(Parser.T_CLASS_DEFINITION)
        if (match != null) {
          metadata.definition = {
            comment: comment,
            line: lineNumber,
            name: match[2]
          }
          className = match[2]
          continue
        }
  
        if (foundConstructor == false) {
  
          // function(){}
          match = nextLine.match(Parser.T_CONSTRUCTOR_FUNCTION)
  
          if (match != null) {
  
            metadata.constructor = {
              type: Metadata.CONSTRUCTOR_FUNCTION,
              line: lineNumber,
              comment: comment,
              className: className,
              name: 'constructor',
              arguments: match[1] !== '' ? match[1].split(',') : null
            }
            foundConstructor = true
            continue
          }
        }
  
        // foo: function(){}
        match = nextLine.match(Parser.T_FUNCTION)
  
        if (match != null) {
  
          metadata.methods.push({
            comment: comment,
            line: lineNumber,
            name: match[1],
            className: className,
            arguments: match[3] !== '' ? match[3].split(',') : null
          })
  
        }
        else {
  
          // foo: 'my property'
          match = nextLine.match(Parser.T_PROPERTY)
          if (match != null) {
            metadata.properties.push({
              comment: comment,
              line: lineNumber,
              className: className,
              name: match[1],
              body: match[3]
            })
          }
        }
      }
  
      return metadata
    }
  }
  