<commit_before>/**
 *
 * wechaty: Wechat for Bot. and for human who talk to bot/robot
 *
 * Licenst: ISC
 * https://github.com/zixia/wechaty
 *
 */
const log   = require('./brolog-env')
const UtilLib  = require('./util-lib')

class Room {
  constructor(id) {
    log.silly('Room', `constructor(${id})`)
    this.id = id
    this.obj = {}
    this.dirtyObj = {} // when refresh, use this to save dirty data for query
    if (!Room.puppet) {
      throw new Error('no puppet attached to Room')
    }
  }

  toString()   { return this.id }
  toStringEx() { return `Room(${this.obj.name}[${this.id}])` }

  isReady() {
    return this.obj.memberList && this.obj.memberList.length
  }

  refresh() {
    this.dirtyObj = this.obj
    this.obj = {}
    return this.ready()
  }

  ready(contactGetter) {
    log.silly('Room', 'ready(%s)', contactGetter ? contactGetter.constructor.name : '')
    if (!this.id) {
      const e = new Error('ready() on a un-inited Room')
      log.warn('Room', e.message)
      return Promise.reject(e)
    } else if (this.isReady()) {
      return Promise.resolve(this)
    } else if (this.obj.id) {
      log.warn('Room', 'ready() has obj.id but memberList empty in room %s. reloading', this.obj.name)
    }

    contactGetter = contactGetter || Room.puppet.getContact.bind(Room.puppet)
    return contactGetter(this.id)
    .then(data => {
      log.silly('Room', `contactGetter(${this.id}) resolved`)
      this.rawObj = data
      this.obj    = this.parse(data)
      return this
    }).catch(e => {
      log.error('Room', 'contactGetter(%s) exception: %s', this.id, e.message)
      throw e
    })
  }

  name() { return UtilLib.plainText(this.obj.name) }
  get(prop) { return this.obj[prop] || this.dirtyObj[prop] }

  parse(rawObj) {
    if (!rawObj) {
      return {}
    }
    return {
      id:         rawObj.UserName
      , encryId:  rawObj.EncryChatRoomId // ???
      , name:     rawObj.NickName
      , memberList:  this.parseMemberList(rawObj.MemberList)
    }
  }

  parseMemberList(memberList) {
    if (!memberList || !memberList.map) {
      return []
    }
    return memberList.map(m => {
      return {
        id:       m.UserName
        , name:   m.DisplayName // nick name for this room?
      }
    })
  }

  dumpRaw() {
    console.error('======= dump raw Room =======')
    Object.keys(this.rawObj).forEach(k => console.error(`${k}: ${this.rawObj[k]}`))
  }
  dump()    {
    console.error('======= dump Room =======')
    Object.keys(this.obj).forEach(k => console.error(`${k}: ${this.obj[k]}`))
  }

  del(contact) {
    log.verbose('Room', 'del(%s) from %s', contact, this)

    if (!contact) {
      throw new Error('contact not found')
    }
    return Room.puppet.roomDelMember(this, contact)
                      .then(r => this.delLocal(contact))
  }

  delLocal(contact) {
    log.verbose('Room', 'delLocal(%s)', contact)

    const memberList = this.obj.memberList
    if (!memberList || memberList.length === 0) {
      return true // already in refreshing
    }

    let i
    for (i=0; i<memberList.length; i++) {
// XXX
// console.log('########################')
// console.log(i)
// console.log(memberList[i].id)
// console.log(contact.get('id'))
// console.log('!!!!!!!!!!!!!!!!!!!!!!!!!!')
      if (memberList[i].id === contact.get('id')) {
        break
      }
    }
// console.log('found i=' + i)
    if (i < memberList.length) {
// console.log('splicing before: ' + memberList.length)
      memberList.splice(i, 1)
// console.log('splicing after: ' + memberList.length)
      return true
    }
    return false
  }

  quit() {
    throw new Error('wx web not implement yet')
    // WechatyBro.glue.chatroomFactory.quit("@@1c066dfcab4ef467cd0a8da8bec90880035aa46526c44f504a83172a9086a5f7"
  }

  add(contact) {
    log.verbose('Room', 'add(%s) to %s', contact, this)

    if (!contact) {
      throw new Error('contact not found')
    }

    return Room.puppet.roomAddMember(this, contact)
  }

  modTopic(topic) {
    log.verbose('Room', 'modTopic(%s)', topic)

    return Room.puppet.roomModTopic(this, topic)
  }

  static create(contactList) {
    log.verbose('Room', 'create(%s)', contactList.join(','))

    if (!contactList || ! typeof contactList === 'array') {
      throw new Error('contactList not found')
    }
    return Room.puppet.roomCreate(contactList)
  }

  // private
  static _find({
    name
  }) {
    log.silly('Room', '_find(%s)', name)

    if (!name) {
      throw new Error('name not found')
    }

    let filterFunction
    if (name instanceof RegExp) {
      filterFunction = `c => ${name.toString()}.test(c)`
    } else if (typeof name === 'string') {
      filterFunction = `c => c === ${name}`<commit_msg>fix string query bug<commit_after>/**
 *
 * wechaty: Wechat for Bot. and for human who talk to bot/robot
 *
 * Licenst: ISC
 * https://github.com/zixia/wechaty
 *
 */
const log   = require('./brolog-env')
const UtilLib  = require('./util-lib')

class Room {
  constructor(id) {
    log.silly('Room', `constructor(${id})`)
    this.id = id
    this.obj = {}
    this.dirtyObj = {} // when refresh, use this to save dirty data for query
    if (!Room.puppet) {
      throw new Error('no puppet attached to Room')
    }
  }

  toString()    { return this.id }
  toStringEx()  { return `Room(${this.obj.name}[${this.id}])` }

  isReady() {
    return this.obj.memberList && this.obj.memberList.length
  }

  refresh() {
    this.dirtyObj = this.obj
    this.obj = {}
    return this.ready()
  }

  ready(contactGetter) {
    log.silly('Room', 'ready(%s)', contactGetter ? contactGetter.constructor.name : '')
    if (!this.id) {
      const e = new Error('ready() on a un-inited Room')
      log.warn('Room', e.message)
      return Promise.reject(e)
    } else if (this.isReady()) {
      return Promise.resolve(this)
    } else if (this.obj.id) {
      log.warn('Room', 'ready() has obj.id but memberList empty in room %s. reloading', this.obj.name)
    }

    contactGetter = contactGetter || Room.puppet.getContact.bind(Room.puppet)
    return contactGetter(this.id)
    .then(data => {
      log.silly('Room', `contactGetter(${this.id}) resolved`)
      this.rawObj = data
      this.obj    = this.parse(data)
      return this
    }).catch(e => {
      log.error('Room', 'contactGetter(%s) exception: %s', this.id, e.message)
      throw e
    })
  }

  name() { return UtilLib.plainText(this.obj.name) }
  get(prop) { return this.obj[prop] || this.dirtyObj[prop] }

  parse(rawObj) {
    if (!rawObj) {
      return {}
    }
    return {
      id:         rawObj.UserName
      , encryId:  rawObj.EncryChatRoomId // ???
      , name:     rawObj.NickName
      , memberList:  this.parseMemberList(rawObj.MemberList)
    }
  }

  parseMemberList(memberList) {
    if (!memberList || !memberList.map) {
      return []
    }
    return memberList.map(m => {
      return {
        id:       m.UserName
        , name:   m.DisplayName // nick name for this room?
      }
    })
  }

  dumpRaw() {
    console.error('======= dump raw Room =======')
    Object.keys(this.rawObj).forEach(k => console.error(`${k}: ${this.rawObj[k]}`))
  }
  dump()    {
    console.error('======= dump Room =======')
    Object.keys(this.obj).forEach(k => console.error(`${k}: ${this.obj[k]}`))
  }

  del(contact) {
    log.verbose('Room', 'del(%s) from %s', contact, this)

    if (!contact) {
      throw new Error('contact not found')
    }
    return Room.puppet.roomDelMember(this, contact)
                      .then(r => this.delLocal(contact))
  }

  delLocal(contact) {
    log.verbose('Room', 'delLocal(%s)', contact)

    const memberList = this.obj.memberList
    if (!memberList || memberList.length === 0) {
      return true // already in refreshing
    }

    let i
    for (i=0; i<memberList.length; i++) {
// XXX
// console.log('########################')
// console.log(i)
// console.log(memberList[i].id)
// console.log(contact.get('id'))
// console.log('!!!!!!!!!!!!!!!!!!!!!!!!!!')
      if (memberList[i].id === contact.get('id')) {
        break
      }
    }
// console.log('found i=' + i)
    if (i < memberList.length) {
// console.log('splicing before: ' + memberList.length)
      memberList.splice(i, 1)
// console.log('splicing after: ' + memberList.length)
      return true
    }
    return false
  }

  quit() {
    throw new Error('wx web not implement yet')
    // WechatyBro.glue.chatroomFactory.quit("@@1c066dfcab4ef467cd0a8da8bec90880035aa46526c44f504a83172a9086a5f7"
  }

  add(contact) {
    log.verbose('Room', 'add(%s) to %s', contact, this)

    if (!contact) {
      throw new Error('contact not found')
    }

    return Room.puppet.roomAddMember(this, contact)
  }

  modTopic(topic) {
    log.verbose('Room', 'modTopic(%s)', topic)

    return Room.puppet.roomModTopic(this, topic)
  }

  static create(contactList) {
    log.verbose('Room', 'create(%s)', contactList.join(','))

    if (!contactList || ! typeof contactList === 'array') {
      throw new Error('contactList not found')
    }
    return Room.puppet.roomCreate(contactList)
  }

  // private
  static _find({
    name
  }) {
    log.silly('Room', '_find(%s)', name)

    if (!name) {
      throw new Error('name not found')
    }

    let filterFunction
    if (name instanceof RegExp) {
      filterFunction = `c => ${name.toString()}.test(c)`
    } else if (typeof name === 'string') {
      filterFunction = `c => c === '${name}'`
{'fraction_non_alphanumeric': 0.1814716781365802, 'fraction_numerical': 0.009105346744309158, 'mean_word_length': 2.68984375, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 19, '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': '3334986', 'n_tokens_mistral': 3299, 'n_tokens_neox': 3197, 'n_words': 664}