/**
 * Scene methods split from scene.js.
 */


/**
 * Get a finite bounding box for scene layout. Empty floor plans can report
 * Infinity bounds; clamp those to a reasonable fallback around origin.
 *
 * @return {{left:number,right:number,top:number,bottom:number,width:number,height:number,x:number,y:number}}
 */
beestat.component.scene.prototype.get_scene_bounding_box_ = function() {
  const bounding_box = beestat.floor_plan.get_bounding_box(this.floor_plan_id_);

  const is_finite_box =
    Number.isFinite(bounding_box.left) &&
    Number.isFinite(bounding_box.right) &&
    Number.isFinite(bounding_box.top) &&
    Number.isFinite(bounding_box.bottom);

  if (is_finite_box === true) {
    return bounding_box;
  }

  const fallback_half_size = 180;
  return {
    'left': -fallback_half_size,
    'right': fallback_half_size,
    'top': -fallback_half_size,
    'bottom': fallback_half_size,
    'width': fallback_half_size * 2,
    'height': fallback_half_size * 2,
    'x': -fallback_half_size,
    'y': -fallback_half_size
  };
};


/**
 * Add a group containing all of the extruded geometry that can be transformed
 * all together.
 */
beestat.component.scene.prototype.add_main_group_ = function() {
  const bounding_box = this.get_scene_bounding_box_();

  // Main group handles orientation and centering
  this.main_group_ = new THREE.Group();

  // Center the floor plan at origin (accounting for bounding box offset)
  this.main_group_.position.set(
    (bounding_box.right + bounding_box.left) / -2,
    0,
    (bounding_box.bottom + bounding_box.top) / -2
  );

  // Apply X rotation to orient the floor plan
  this.main_group_.rotation.x = Math.PI / 2;

  this.scene_.add(this.main_group_);
};


/**
 * Add the floor plan to the scene.
 */
beestat.component.scene.prototype.add_floor_plan_ = function() {
  const self = this;
  const floor_plan = beestat.cache.floor_plan[this.floor_plan_id_];

  // Initialize layers if not already done
  if (this.layers_ === undefined) {
    this.layers_ = {};
  }

  // Create floor plan group for walls, rooms, and roofs
  this.floor_plan_group_ = new THREE.Group();
  this.main_group_.add(this.floor_plan_group_);
  this.layers_['floor_plan'] = this.floor_plan_group_;

  const walls_layer = new THREE.Group();
  self.floor_plan_group_.add(walls_layer);
  self.layers_['walls'] = walls_layer;

  floor_plan.data.groups.forEach(function(group) {
    const layer = new THREE.Group();
    self.floor_plan_group_.add(layer);
    self.layers_[group.group_id] = layer;
    group.rooms.forEach(function(room) {
      self.add_room_(layer, group, room);
    });
    self.add_walls_(walls_layer, group);
  });

  this.apply_opening_cuts_(walls_layer, floor_plan);

  const openings_layer = new THREE.Group();
  this.floor_plan_group_.add(openings_layer);
  this.layers_['openings'] = openings_layer;
  floor_plan.data.groups.forEach(function(group) {
    self.add_opening_fixtures_(openings_layer, group);
  });

  this.light_sources_ = [];
  const light_sources_layer = new THREE.Group();
  this.floor_plan_group_.add(light_sources_layer);
  this.layers_['light_sources'] = light_sources_layer;
  floor_plan.data.groups.forEach(function(group) {
    self.add_light_sources_(light_sources_layer, group);
  });

  // Add roofs using straight skeleton
  this.add_roofs_();

  this.add_environment_();
};

