import { makeError, guid } from '../common.js'
import { constants as C, list as constantList } from '../constants'
import { locale as L } from '../lang/zh_TW'
import Block from './ADBlock'
import Layer from './ADLayer'
import Unit from './ADUnit'
import Collection from './ADCollection'
import $ from 'jquery'

import './ADPage.css'

const _properties = new WeakMap()

/**
  *   Page 頁面物件
  * @memberof AD.Layout.Types
  * @class Page
  * @constructor
  * @param property {Object}
  * @param [target] {JQuery|HTMLElement}
  */

function Page (property = {}, target) {
  /**
   *   Page實體的jQuery
   * @private {jQuery}
   */
  var _$this = (function (p) {
    for (var k = 0, l = p.length; k < l; k++) {
      if (p[k] instanceof $) return p[k]
      if (p[k] instanceof window.HTMLElement) return $(p[k])
    }
    return false
  })([target, property, property && property.target])

  if (_$this && _$this.length === 0) {
    return null
  }
  _properties.set(this || _$this[0].adlpage, {
    $this: _$this,
    preset: ''
  })
  const _ = _properties.get(this)
  if (_$this && _$this.length > 0) {
    if (_$this[0].adlpage && _$this[0].adlpage instanceof Page) {
      return _$this[0].adlpage
    } else {
      if (!(this instanceof Page)) {
        return new Page(property, _$this)
      } else {
        var a = _$this
        var d = _$this.find('div')
        if (a.prop('tagName') === 'DIV') {
          if (!a.hasClass('page')) {
            a.addClass('page')
          }
          if (d.length === 0 && property.pure !== true) {
            this
              .append(new Layer({ type: C`LAYER_BACKGROUND` }))
              .append(new Layer({ type: C`LAYER_CONTENT` }))
              .append(new Layer({ type: C`LAYER_FOREGROUND` }))
          } else if (d.length === 3) {
            d.removeClass().addClass('layer')
            d.eq(0).attr('data-type', C`LAYER_BACKGROUND`)
            d.eq(1).attr('data-type', C`LAYER_CONTENT`)
            d.eq(2).attr('data-type', C`LAYER_FOREGROUND`)
          } else {
            return null
          }
        } else {
          return null
        }
        return null
      }
    }
  } else if (!_$this) {
    if (!(this instanceof Page)) {
      return new Page(property)
    }
    _.$this = $('<div class="page" id="page' + guid() + '">')
    if (property.pure !== true) {
      this
        .append(new Layer({ type: C`LAYER_BACKGROUND` }))
        .append(new Layer({ type: C`LAYER_CONTENT` }))
        .append(new Layer({ type: C`LAYER_FOREGROUND` }))
    }
  }

  _.$this[0].adlpage = this
  this.update(property)
}

const prototype = Page.prototype
/**
 * 更新頁面相關的參數
 * @function
 * @public
 * @param {object} property
 */
prototype.update = function update (property) {
  const _ = _properties.get(this) || {}
  var _$this = _.$this
  if ($.isPlainObject(property)) {
    for (const attribute in property) {
      switch (attribute) {
        case 'id':
          _$this.attr('id', property.id)
          break
        case 'w':
        case 'width':
          if (!this.preset() || this.preset() === C`PAGE_CUSTOM`) _$this.width(Unit(property.width).px)
          break
        case 'h':
        case 'height':
          if (!this.preset() || this.preset() === C`PAGE_CUSTOM`) _$this.height(Unit(property.height).px)
          break
        case 'backgroundColor':
          _$this.css('background-color', property.backgroundColor)
          break
        case 'preset':
          if (C`${property.preset}`) {
            _$this.addClass(C`${property.preset}`)
            this.preset(property.preset)
          }
          break
      }
    }
  }
  if (!(this.preset() === undefined)) {
    this.preset(C`PAGE_CUSTOM`)
  }
}

/**
   * 取得或設定頁面的預設尺寸
   * @function
   * @public
   * @param {string} newVal
   * @see AD.Layout.Constant
   */
prototype.preset = function preset (newVal) {
  const _ = _properties.get(this) || {}
  if (newVal === undefined) {
    return _.preset
  } else {
    var preset = (function () {
      if (newVal !== undefined) {
        for (const k in constantList) {
          if (k === newVal) return k
        }
      }
      return 'PAGE_CUSTOM'
    })()
    _.$this.attr('data-preset', preset)
    return this
  }
}

Object.defineProperty(prototype, 'index', {
  get: function () {
    const _ = _properties.get(this) || {}
    return $('.page').index(_.$this) + 1
  },
  set: function (n) {
    const _ = _properties.get(this) || {}
    if (typeof n === 'number') {
      var index = n - 1
      if (_.$this.parent().length === 0) {
        makeError('ERR_NO_INSTANCE', L`_STR_ERR_NO_INSTANCE`)
        return false
      } else if (index < 0 || index >= _properties.get(this).$this.parent().find('.page').length) {
        makeError('ERR_OUT_OF_INDEX', L`_STR_ERR_OUT_OF_INDEX`)
        return false
      }
      if (index < this.index) {
        _.$this.parent().find('.page:nth(' + index + ')').before(_properties.get(this).$this)
      } else {
        _.$this.parent().find('.page:nth(' + index + ')').after(_properties.get(this).$this)
      }
    } else {
      makeError('ERR_BAD_PARAMENTS', L`_STR_ERR_BAD_PARAMETERS`)
    }
  }
})

prototype.id = function id (newId) {
  const _ = _properties.get(this) || {}
  if (newId === undefined) {
    return _.$this.attr('id')
  } else {
    _.$this.attr('id', newId)
    return this
  }
}

prototype.width = function width (newVal) {
  const _ = _properties.get(this) || {}
  if (newVal === undefined) {
    return _.$this.width()
  } else {
    var v = new Unit(newVal)
    _.$this.width(v)
    return this
  }
}

prototype.height = function height (newVal) {
  const _ = _properties.get(this) || {}
  if (newVal === undefined) {
    return _.$this.height()
  } else {
    var v = new Unit(newVal)
    _.$this.height(v.px)
    return this
  }
}

prototype.size = function size (a, b) {
  if (a === undefined && b === undefined) {
    return { width: this.width(), height: this.height() }
  } else if (a !== undefined && b === undefined) {
    var v = new Unit(a)
    this.width(v.px).height(v.px)
    return this
  } else {
    var v1 = new Unit(a)
    var v2 = new Unit(b)
    this.width(v1.px).height(v2.px)
    return this
  }
}

prototype.append = function append (a, b) {
  const _ = _properties.get(this) || {}
  var target = b || a
  var toLayer = b ? a : C`LAYER_CONTENT`
  if (target instanceof Block) {
    this.layer(toLayer).append(target)
  } else if (target instanceof Layer) {
    target.appendTo(_.$this)
  } else {
    makeError('ERR_WORONG_TYPE', L`_STR_ERR_UNSUPPORT_TYPE`)
    return false
  }
  return this
}

prototype.appendTo = function appendTo (container) {
  const _ = _properties.get(this) || {}
  if (container instanceof $) {
    container.append(_.$this)
    return this
  } else {
    makeError('ERR_WORONG_TYPE', L`_STR_ERR_UNSUPPORT_TYPE`)
    return false
  }
}

prototype.remove = function remove () {
  const _ = _properties.get(this) || {}
  _.$this.remove()
  return this
}

prototype.moveTo = function moveTo (n) {
  if (typeof n === 'number') {
    this.index = n
  } else if (typeof n === 'string') {
    if (n.charAt(0) === '+') {
      this.index += parseInt(n.substr(1))
    } else if (n.charAt(0) === '-') {
      this.index -= parseInt(n.substr(1))
    } else {
      makeError('ERR_BAD_PARAMENTS', L`_STR_ERR_BAD_PARAMETERS`)
    }
  }
  return this
}

prototype.layer = function layer (id) {
  const _ = _properties.get(this) || {}
  switch (typeof id) {
    case 'number':
      return Layer(_.$this.find('.layer:eq(' + id + ')'))
    case 'string':
      return Layer(_.$this.find('.layer[data-type=' + id + ']'))
    case 'undefined':
      var layers = new Collection(Layer)
      _.$this.find('.layer').each(function () {
        layers.push(Layer(this))
      })
      return layers
  }
}

prototype.block = function block (id) {
  const _ = _properties.get(this) || {}
  switch (typeof id) {
    case 'number':
      return new Block(_.$this.find('.block:nth(' + id + ')'))
    case 'string':
      return new Block(_.$this.find('#' + 'block_' + this.index + '_' + id))
    case 'undefined':
      var blocks = new Collection(Block)
      _.$this.find('.block').each(function () {
        blocks.push(Block(this))
      })
      return blocks
  }
}

prototype.toJSON = function toJSON (stringify) {
  const _ = _properties.get(this) || {}
  var obj = {}
  var _$this = _.$this[0]
  var _style = _$this.style
  obj.id = this.id()
  obj.w = _style.width
  obj.h = _style.height
  obj.preset = _$this.attributes['data-preset'].value
  obj.backgroundColor = _style['background-color']
  obj.layer = this.layer().toJSON(false)
  return stringify === false ? obj : JSON.stringify(obj)
}

export default Page
