<commit_before>/**
 *
 * wechaty: Wechat for Bot. and for human who talk to bot/robot
 *
 * Licenst: ISC
 * https://github.com/zixia/wechaty
 *
 */
const co = require('co')

const Contact = require('./contact')
const Room    = require('./room')

const webUtil  = require('./web-util')
const log       = require('./npmlog-env')

class Message {
  constructor(rawObj) {
    Message.counter++

    this.rawObj = rawObj = rawObj || {}
    this.obj = this.parse(rawObj)
    this.id = this.obj.id
  }

  // Transform rawObj to local m
  parse(rawObj) {
    const obj = {
      id:             rawObj.MsgId
      , type:         rawObj.MsgType
      , from:         rawObj.MMActualSender
      , to:           rawObj.ToUserName
      , content:      rawObj.MMActualContent // Content has @id prefix added by wx
      , status:       rawObj.Status
      , digest:       rawObj.MMDigest
      , date:         rawObj.MMDisplayTime  // Javascript timestamp of milliseconds
    }

    // FIXME: has ther any better method to know the room ID?
    if (rawObj.MMIsChatRoom) {
      if (/^@@/.test(rawObj.FromUserName)) {
        obj.room =  rawObj.FromUserName // MMPeerUserName always eq FromUserName ?
      } else if (/^@@/.test(rawObj.ToUserName)) {
        obj.room = rawObj.ToUserName
      } else {
        log.error('Message', 'parse found a room message, but neither FromUserName nor ToUserName is a room(/^@@/)')
        obj.room = null // bug compatible
      }
    } else {
      obj.room = null
    }
    return obj
  }
  toString() {
    return webUtil.plainText(this.obj.content)
  }
  toStringDigest() {
    const text = webUtil.digestEmoji(this.obj.digest)
    return '{' + this.typeEx() + '}' + text
  }

  toStringEx() {
    var s = `${this.constructor.name}#${Message.counter}`
    s += '(' + this.getSenderString()
    s += ':' + this.getContentString() + ')'
    return s
  }
  getSenderString() {
    const name  = Contact.load(this.obj.from).toStringEx()
    const room = this.obj.room ? Room.load(this.obj.room).toStringEx() : null
    return '<' + name + (room ? `@${room}` : '') + '>'
  }
  getContentString() {
    let content = webUtil.plainText(this.obj.content)
    if (content.length > 20) { content = content.substring(0,17) + '...' }
    return '{' + this.type() + '}' + content
  }

  from()    { return this.obj.from }
  to()      { return this.obj.to }
  content() { return this.obj.content }
  room()    { return this.obj.room }

  type()    { return this.obj.type }
  typeEx()  { return Message.Type[this.obj.type] }
  count()   { return Message.counter }

  ready() {
    log.silly('Message', 'ready()')

    return co.call(this, function* () {
      const from  = Contact.load(this.obj.from)
      const to    = Contact.load(this.obj.to)
      const room  = this.obj.room ? Room.load(this.obj.room) : null

      yield from.ready()                // Contact from
      yield to.ready()                  // Contact to
      if (room) { yield room.ready() }  // Room member list

      return this         // return this for chain
    }).catch(e => { // Exception
        log.error('Message', 'ready() exception: %s', e.message)
        throw e
    })<commit_msg>add shortcut for instantiate Contact from from/to/room<commit_after>/**
 *
 * wechaty: Wechat for Bot. and for human who talk to bot/robot
 *
 * Licenst: ISC
 * https://github.com/zixia/wechaty
 *
 */
const co = require('co')

const Contact = require('./contact')
const Room    = require('./room')

const webUtil  = require('./web-util')
const log       = require('./npmlog-env')

class Message {
  constructor(rawObj) {
    Message.counter++

    this.rawObj = rawObj = rawObj || {}
    this.obj = this.parse(rawObj)
    this.id = this.obj.id
  }

  // Transform rawObj to local m
  parse(rawObj) {
    const obj = {
      id:             rawObj.MsgId
      , type:         rawObj.MsgType
      , from:         rawObj.MMActualSender
      , to:           rawObj.ToUserName
      , content:      rawObj.MMActualContent // Content has @id prefix added by wx
      , status:       rawObj.Status
      , digest:       rawObj.MMDigest
      , date:         rawObj.MMDisplayTime  // Javascript timestamp of milliseconds
    }

    // FIXME: has ther any better method to know the room ID?
    if (rawObj.MMIsChatRoom) {
      if (/^@@/.test(rawObj.FromUserName)) {
        obj.room =  rawObj.FromUserName // MMPeerUserName always eq FromUserName ?
      } else if (/^@@/.test(rawObj.ToUserName)) {
        obj.room = rawObj.ToUserName
      } else {
        log.error('Message', 'parse found a room message, but neither FromUserName nor ToUserName is a room(/^@@/)')
        obj.room = null // bug compatible
      }
    } else {
      obj.room = null
    }
    return obj
  }
  toString() {
    return webUtil.plainText(this.obj.content)
  }
  toStringDigest() {
    const text = webUtil.digestEmoji(this.obj.digest)
    return '{' + this.typeEx() + '}' + text
  }

  toStringEx() {
    var s = `${this.constructor.name}#${Message.counter}`
    s += '(' + this.getSenderString()
    s += ':' + this.getContentString() + ')'
    return s
  }
  getSenderString() {
    const name  = Contact.load(this.obj.from).toStringEx()
    const room = this.obj.room ? Room.load(this.obj.room).toStringEx() : null
    return '<' + name + (room ? `@${room}` : '') + '>'
  }
  getContentString() {
    let content = webUtil.plainText(this.obj.content)
    if (content.length > 20) { content = content.substring(0,17) + '...' }
    return '{' + this.type() + '}' + content
  }

  from()    { return Contact.load(this.obj.from) }
  to()      { return Contact.load(this.obj.to) }
  content() { return this.obj.content }
  room()    { return Room.load(this.obj.room) }

  type()    { return this.obj.type }
  typeEx()  { return Message.Type[this.obj.type] }
  count()   { return Message.counter }

  ready() {
    log.silly('Message', 'ready()')

    return co.call(this, function* () {
      const from  = Contact.load(this.obj.from)
      const to    = Contact.load(this.obj.to)
      const room  = this.obj.room ? Room.load(this.obj.room) : null

      yield from.ready()                // Contact from
      yield to.ready()                  // Contact to
      if (room) { yield room.ready() }  // Room member list

      return this         // return this for chain
    }).catch(e => { // Exception
        log.error('Message', 'ready() exception: %s', e.message)
        throw e
    })
{'fraction_non_alphanumeric': 0.14978314745972737, 'fraction_numerical': 0.0015489467162329617, 'mean_word_length': 2.222055888223553, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 9, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7099350', 'n_tokens_mistral': 2121, 'n_tokens_neox': 2080, 'n_words': 484}