models/TitleCollection.js

const objectAssignDeep = require('object-assign-deep')
const Title = require('./Title')
const FollowedUserTitle = require('./FollowedUserTitle')
const FollowedUserFavoriteEntry = require('./FollowedUserFavoriteEntry')
const DraftTitle = require('./DraftTitle')
const Question = require('./Question')
const CollectionBase = require('./CollectionBase')
const { DEFAULTS } = require('../constants')
const { TITLE_TYPES } = require('../enums')

/**
 * Title collection.
 *
 * @augments CollectionBase
 */
class TitleCollection extends CollectionBase {
  /**
   * Total title count, if type is followed user title = null.
   *
   * @type {(number|null)}
   */
  totalTitleCount

  /**
   * Total page count, if type is followed user title = null.
   *
   * @type {(number|null)}
   */
  pageCount

  /**
   * Title collection.
   *
   * @type {Array<(Title|FollowedUserTitle|DraftTitle)>}
   */
  titles

  /**
   * Create a title collection.
   *
   * @param {object}    request                       Axios client.
   * @param {string}    path                          Title path.
   * @param {object}    options                       Parameters that user can specify.
   * @param {number}    [options.page=1]              Page number.
   * @param {number}    [options.defaultEntryCount=1] Default entry count, using if entry count not provided.
   * @param {string}    [options.cookies=null]        Cookie string.
   * @param {TitleType} [options.type=1]              Type of title.
   */
  constructor (request, path, options) {
    super()
    // handle default options
    const _options = objectAssignDeep(
      {
        page: 1,
        cookies: null,
        defaultEntryCount: 1,
        type: TITLE_TYPES.TITLE
      },
      options
    )

    // todo : request objesini yerine sadece axios instance olusturup disari acabiliriz
    // bir suru _ ile disari acmak yerine sadece request acmak daha mantikli olacaktir

    this.currPage = _options.page
    this._request = request
    this._path = path
    this._defaultEntryCount = _options.defaultEntryCount
    this._cookies = _options.cookies
    this._type = _options.type
  }

  /**
   * Retrieve title collection.
   *
   * @returns {Promise} Promise.
   */
  retrieve () {
    return new Promise((resolve, reject) => {
      const requestOptions = {
        endpoint: this._path,
        ajax: true,
        cookie: this._cookies,
        params: {
          p: this.currPage
        }
      }

      this._request(requestOptions, $ => {
        const totalTitleCount = parseInt(
          $('div.clearfix.dropdown h2').attr('title')
        )

        const titles = []

        $('ul.topic-list.partial li').each((i, elm) => {
          let title

          // exit the loop if divider exist
          if ($(elm).find('div.seperator').length > 0) {
            return false
          }

          switch (this._type) {
            case TITLE_TYPES.TITLE:
              title = new Title(this._request)
              break

            case TITLE_TYPES.DRAFT:
              title = new DraftTitle(this._request, this._cookies)
              break

            case TITLE_TYPES.FOLLOWED_USER:
              title = new FollowedUserTitle(this._request, this._cookies)
              break

            case TITLE_TYPES.FOLLOWED_USER_FAVORITE_ENTRY:
              title = new FollowedUserFavoriteEntry(
                this._request,
                this._cookies
              )
              break

            case TITLE_TYPES.QUESTION:
              title = new Question()
              break
          }

          title.serialize($, elm)

          const isPlainTitle = this._type === TITLE_TYPES.TITLE

          // correct entry count
          if (isPlainTitle) {
            const entryCountStr = $(elm)
              .find('a small')
              .text()
              .trim()
            const entryCount = parseInt(entryCountStr)
            title.entryCount = entryCountStr.includes('b')
              ? 1000 * entryCount
              : entryCount || this._defaultEntryCount
          }

          titles.push(title)
        })

        this.totalTitleCount = totalTitleCount || null
        this.pageCount =
          Math.ceil(totalTitleCount / DEFAULTS.TITLE_COUNT_PER_PAGE) || null
        this.titles = titles

        resolve()
      })
    })
  }
}

module.exports = TitleCollection