/**
 * A root panel can hold components. The root panel must be initialized with
 * a DOM element as container.
 * @param {HTMLElement} container
 * @param {Object} [options]    Available parameters: see RootPanel.setOptions.
 * @constructor RootPanel
 * @extends Panel
 */
function RootPanel(container, options) {
  this.id = util.randomUUID();
  this.container = container;

  this.options = options || {};
  this.defaultOptions = {
    autoResize: true
  };

  // create the HTML DOM
  this._create();

  // attach the root panel to the provided container
  if (!this.container) throw new Error('Cannot repaint root panel: no container attached');
  this.container.appendChild(this.getFrame());


  this._initWatch();
}

RootPanel.prototype = new Panel();

/**
 * Create the HTML DOM for the root panel
 */
RootPanel.prototype._create = function _create() {
  // create frame
  this.frame = document.createElement('div');

  // create event listeners for all interesting events, these events will be
  // emitted via emitter
  this.hammer = Hammer(this.frame, {
    prevent_default: true
  });
  this.listeners = {};

  var me = this;
  var events = [
    'touch', 'pinch', 'tap', 'doubletap', 'hold',
    'dragstart', 'drag', 'dragend',
    'mousewheel', 'DOMMouseScroll' // DOMMouseScroll is for Firefox
  ];
  events.forEach(function (event) {
    var listener = function () {
      var args = [event].concat(Array.prototype.slice.call(arguments, 0));
      me.emit.apply(me, args);
    };
    me.hammer.on(event, listener);
    me.listeners[event] = listener;
  });
};

/**
 * Set options. Will extend the current options.
 * @param {Object} [options]    Available parameters:
 *                              {String | function} [className]
 *                              {String | Number | function} [left]
 *                              {String | Number | function} [top]
 *                              {String | Number | function} [width]
 *                              {String | Number | function} [height]
 *                              {Boolean | function} [autoResize]
 */
RootPanel.prototype.setOptions = function setOptions(options) {
  if (options) {
    util.extend(this.options, options);

    this.repaint();

    this._initWatch();
  }
};

/**
 * Get the frame of the root panel
 */
RootPanel.prototype.getFrame = function getFrame() {
  return this.frame;
};

/**
 * Repaint the root panel
 */
RootPanel.prototype.repaint = function repaint() {
  // update class name
  var options = this.options;
  var editable = options.editable.updateTime || options.editable.updateGroup;
  var className = 'vis timeline rootpanel ' + options.orientation + (editable ? ' editable' : '');
  if (options.className) className += ' ' + util.option.asString(className);
  this.frame.className = className;

  // repaint the child components
  var childsResized = this._repaintChilds();

  // update frame size
  this.frame.style.maxHeight = util.option.asSize(this.options.maxHeight, '');
  this._updateSize();

  // if the root panel or any of its childs is resized, repaint again,
  // as other components may need to be resized accordingly
  var resized = this._isResized() || childsResized;
  if (resized) {
    setTimeout(this.repaint.bind(this), 0);
  }
};

/**
 * Initialize watching when option autoResize is true
 * @private
 */
RootPanel.prototype._initWatch = function _initWatch() {
  var autoResize = this.getOption('autoResize');
  if (autoResize) {
    this._watch();
  }
  else {
    this._unwatch();
  }
};

/**
 * Watch for changes in the size of the frame. On resize, the Panel will
 * automatically redraw itself.
 * @private
 */
RootPanel.prototype._watch = function _watch() {
  var me = this;

  this._unwatch();

  var checkSize = function checkSize() {
    var autoResize = me.getOption('autoResize');
    if (!autoResize) {
      // stop watching when the option autoResize is changed to false
      me._unwatch();
      return;
    }

    if (me.frame) {
      // check whether the frame is resized
      if ((me.frame.clientWidth != me.lastWidth) ||
          (me.frame.clientHeight != me.lastHeight)) {
        me.lastWidth = me.frame.clientWidth;
        me.lastHeight = me.frame.clientHeight;
        me.repaint();
        // TODO: emit a resize event instead?
      }
    }
  };

  // TODO: automatically cleanup the event listener when the frame is deleted
  util.addEventListener(window, 'resize', checkSize);

  this.watchTimer = setInterval(checkSize, 1000);
};

/**
 * Stop watching for a resize of the frame.
 * @private
 */
RootPanel.prototype._unwatch = function _unwatch() {
  if (this.watchTimer) {
    clearInterval(this.watchTimer);
    this.watchTimer = undefined;
  }

  // TODO: remove event listener on window.resize
};