/**
 * Floor plan light source.
 */
beestat.component.floor_plan_entity.light_source = function() {
  this.enabled_ = true;
  this.snap_lines_ = {};

  beestat.component.floor_plan_entity.apply(this, arguments);
};
beestat.extend(beestat.component.floor_plan_entity.light_source, beestat.component.floor_plan_entity);

/**
 * Decorate.
 *
 * @param {SVGGElement} parent
 */
beestat.component.floor_plan_entity.light_source.prototype.decorate_ = function(parent) {
  this.decorate_circle_(parent);

  if (this.active_ === true && this.enabled_ === true) {
    this.set_draggable_(true);
    this.update_snap_points_();
  }
};

/**
 * Draw the light-source circle.
 *
 * @param {SVGGElement} parent
 */
beestat.component.floor_plan_entity.light_source.prototype.decorate_circle_ = function(parent) {
  const self = this;

  this.circle_ = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
  this.circle_.setAttribute('r', 7);
  this.circle_.style.strokeWidth = '2';
  parent.appendChild(this.circle_);

  const fill_color = '#f0cf59';

  if (this.active_ === true) {
    this.circle_.style.cursor = 'pointer';
    this.circle_.style.fillOpacity = '0.7';
    this.circle_.style.fill = fill_color;
    this.circle_.style.stroke = '#ffffff';
    this.circle_.style.filter = 'brightness(1.15)';
  } else if (this.enabled_ === true) {
    this.circle_.style.cursor = 'pointer';
    this.circle_.style.fillOpacity = '0.58';
    this.circle_.style.fill = fill_color;
    this.circle_.style.stroke = beestat.style.color.gray.base;
    this.circle_.style.filter = 'none';
  } else {
    this.circle_.style.cursor = 'default';
    this.circle_.style.fillOpacity = '0.25';
    this.circle_.style.fill = beestat.style.color.gray.base;
    this.circle_.style.stroke = beestat.style.color.gray.dark;
    this.circle_.style.filter = 'none';
  }

  if (this.enabled_ === true) {
    this.circle_.addEventListener('click', function(e) {
      e.stopPropagation();
      self.set_active(true);
    });
    this.circle_.addEventListener('touchstart', function(e) {
      e.stopPropagation();
      self.set_active(true);
    });
  }

  this.update_circle_();
};

/**
 * Update circle geometry.
 */
beestat.component.floor_plan_entity.light_source.prototype.update_circle_ = function() {
  this.circle_.setAttribute('cx', 0);
  this.circle_.setAttribute('cy', 0);
};

/**
 * Set light source.
 *
 * @param {object} light_source
 *
 * @return {beestat.component.floor_plan_entity.light_source}
 */
beestat.component.floor_plan_entity.light_source.prototype.set_light_source = function(light_source) {
  this.light_source_ = light_source;

  this.light_source_.light_source_id = this.light_source_.light_source_id || window.crypto.randomUUID();
  this.light_source_.x = Number(this.light_source_.x || 0);
  this.light_source_.y = Number(this.light_source_.y || 0);
  this.light_source_.elevation = Number(this.light_source_.elevation !== undefined ? this.light_source_.elevation : 72);
  if (this.light_source_.name === undefined) {
    this.light_source_.name = '';
  }
  this.light_source_.intensity = ['dim', 'normal', 'bright'].includes(this.light_source_.intensity)
    ? this.light_source_.intensity
    : 'normal';
  this.light_source_.temperature_k = Math.max(1000, Math.min(12000, Math.round(Number(this.light_source_.temperature_k || 4000))));

  this.x_ = this.light_source_.x;
  this.y_ = this.light_source_.y;

  return this;
};

/**
 * Set group.
 *
 * @param {object} group
 *
 * @return {beestat.component.floor_plan_entity.light_source}
 */
beestat.component.floor_plan_entity.light_source.prototype.set_group = function(group) {
  this.group_ = group;
  return this;
};

/**
 * Set enabled.
 *
 * @param {boolean} enabled
 *
 * @return {beestat.component.floor_plan_entity.light_source}
 */
beestat.component.floor_plan_entity.light_source.prototype.set_enabled = function(enabled) {
  this.enabled_ = enabled;
  return this;
};

/**
 * Get light source.
 *
 * @return {object}
 */
beestat.component.floor_plan_entity.light_source.prototype.get_light_source = function() {
  return this.light_source_;
};

/**
 * Set active state.
 *
 * @param {boolean} active
 *
 * @return {beestat.component.floor_plan_entity.light_source}
 */
beestat.component.floor_plan_entity.light_source.prototype.set_active = function(active) {
  if (active === true && this.enabled_ !== true) {
    return this;
  }

  if (active !== this.active_) {
    this.active_ = active;

    if (this.active_ === true) {
      if (
        this.state_.active_light_source_entity !== undefined &&
        this.state_.active_light_source_entity.get_light_source().light_source_id !== this.light_source_.light_source_id
      ) {
        this.state_.active_light_source_entity.set_active(false);
      }

      if (this.state_.active_point_entity !== undefined) {
        this.state_.active_point_entity.set_active(false);
      }
      if (this.state_.active_wall_entity !== undefined) {
        this.state_.active_wall_entity.set_active(false);
      }
      if (this.state_.active_room_entity !== undefined) {
        this.state_.active_room_entity.set_active(false);
      }
      if (this.state_.active_surface_entity !== undefined) {
        this.state_.active_surface_entity.set_active(false);
      }
      if (this.state_.active_opening_entity !== undefined) {
        this.state_.active_opening_entity.set_active(false);
      }
      if (this.state_.active_tree_entity !== undefined) {
        this.state_.active_tree_entity.set_active(false);
      }

      this.state_.active_light_source_entity = this;
      this.dispatchEvent('activate');
      this.update_snap_points_();
      this.bring_to_front_();
    } else {
      delete this.state_.active_light_source_entity;
      this.clear_snap_lines_();
      this.dispatchEvent('inactivate');
    }

    if (this.rendered_ === true) {
      this.rerender();
    }
  }

  return this;
};

/**
 * Set position and clamp to grid.
 *
 * @param {number} x
 * @param {number} y
 * @param {string} event
 *
 * @return {beestat.component.floor_plan_entity.light_source}
 */
beestat.component.floor_plan_entity.light_source.prototype.set_xy = function(x, y, event = 'lesser_update') {
  if (event === 'update') {
    this.floor_plan_.save_buffer();
  }

  const half_grid = this.floor_plan_.get_grid_pixels() / 2;
  let clamped_x = Math.round(Number(x || 0));
  let clamped_y = Math.round(Number(y || 0));
  clamped_x = Math.min(clamped_x, half_grid);
  clamped_x = Math.max(clamped_x, -half_grid);
  clamped_y = Math.min(clamped_y, half_grid);
  clamped_y = Math.max(clamped_y, -half_grid);

  this.light_source_.x = clamped_x;
  this.light_source_.y = clamped_y;

  this.dispatchEvent(event);

  return beestat.component.floor_plan_entity.prototype.set_xy.apply(this, [clamped_x, clamped_y]);
};

/**
 * Drag start.
 */
beestat.component.floor_plan_entity.light_source.prototype.after_mousedown_handler_ = function() {
  this.drag_start_entity_ = {
    'x': this.light_source_.x,
    'y': this.light_source_.y
  };
};

/**
 * Drag move with snap-point behavior.
 *
 * @param {Event} e
 */
beestat.component.floor_plan_entity.light_source.prototype.after_mousemove_handler_ = function(e) {
  if (this.drag_start_entity_ === undefined) {
    return;
  }

  const snap_distance = 6;
  let desired_x = this.drag_start_entity_.x + (((e.clientX || e.touches[0].clientX) - this.drag_start_mouse_.x) * this.floor_plan_.get_scale());
  let desired_y = this.drag_start_entity_.y + (((e.clientY || e.touches[0].clientY) - this.drag_start_mouse_.y) * this.floor_plan_.get_scale());

  if (this.state_.snapping === true) {
    let best_x;
    let best_x_distance = Number.POSITIVE_INFINITY;
    let best_y;
    let best_y_distance = Number.POSITIVE_INFINITY;

    for (let i = 0; i < this.get_snap_x().length; i++) {
      const candidate_x = this.get_snap_x()[i];
      const distance_x = Math.abs(candidate_x - desired_x);
      if (distance_x <= snap_distance && distance_x < best_x_distance) {
        best_x = candidate_x;
        best_x_distance = distance_x;
      }
    }
    for (let i = 0; i < this.get_snap_y().length; i++) {
      const candidate_y = this.get_snap_y()[i];
      const distance_y = Math.abs(candidate_y - desired_y);
      if (distance_y <= snap_distance && distance_y < best_y_distance) {
        best_y = candidate_y;
        best_y_distance = distance_y;
      }
    }

    if (best_x !== undefined) {
      desired_x = best_x;
    }
    if (best_y !== undefined) {
      desired_y = best_y;
    }

    this.update_snap_lines_();
  } else {
    this.clear_snap_lines_();
  }

  this.set_xy(desired_x, desired_y);
};

/**
 * Drag stop.
 */
beestat.component.floor_plan_entity.light_source.prototype.after_mouseup_handler_ = function() {
  if (this.dragged_ === true) {
    this.clear_snap_lines_();
    this.update_snap_points_();
  }
};

/**
 * Pre-generate snap points.
 */
beestat.component.floor_plan_entity.light_source.prototype.update_snap_points_ = function() {
  const self = this;
  const group_below = this.floor_plan_.get_group_below(this.group_);
  const groups = [this.group_];
  if (group_below !== undefined) {
    groups.push(group_below);
  }
  const snap_points = this.collect_snap_points_({
    'groups': groups,
    'shape_specs': [
      {
        'collection': 'rooms',
        'point_mode': 'relative'
      },
      {
        'collection': 'surfaces',
        'point_mode': 'relative'
      },
      {
        'collection': 'openings',
        'point_mode': 'absolute'
      },
      {
        'collection': 'light_sources',
        'point_mode': 'point'
      }
    ],
    'should_skip_shape': function(shape, shape_spec) {
      return (
        shape_spec.collection === 'light_sources' &&
        shape.light_source_id !== undefined &&
        self.light_source_ !== undefined &&
        self.light_source_.light_source_id === shape.light_source_id
      );
    }
  });
  this.snap_x_ = snap_points.snap_x;
  this.snap_y_ = snap_points.snap_y;
};

/**
 * Get snap x values.
 *
 * @return {number[]}
 */
beestat.component.floor_plan_entity.light_source.prototype.get_snap_x = function() {
  return this.snap_x_ || [];
};

/**
 * Get snap y values.
 *
 * @return {number[]}
 */
beestat.component.floor_plan_entity.light_source.prototype.get_snap_y = function() {
  return this.snap_y_ || [];
};

/**
 * Update snap lines.
 */
beestat.component.floor_plan_entity.light_source.prototype.update_snap_lines_ = function() {
  const point_x = this.light_source_.x;
  if (this.get_snap_x().includes(point_x) === true) {
    if (this.snap_lines_.x === undefined) {
      this.snap_lines_.x = document.createElementNS('http://www.w3.org/2000/svg', 'line');
      this.snap_lines_.x.style.strokeDasharray = '7, 3';
      this.snap_lines_.x.style.stroke = beestat.style.color.yellow.base;
      this.snap_lines_.x.setAttribute('y1', this.floor_plan_.get_grid_pixels() / -2);
      this.snap_lines_.x.setAttribute('y2', this.floor_plan_.get_grid_pixels() / 2);
      this.floor_plan_.get_g().appendChild(this.snap_lines_.x);
    }
    this.snap_lines_.x.setAttribute('x1', point_x);
    this.snap_lines_.x.setAttribute('x2', point_x);
  } else if (this.snap_lines_.x !== undefined) {
    if (this.snap_lines_.x.parentNode !== undefined && this.snap_lines_.x.parentNode !== null) {
      this.snap_lines_.x.parentNode.removeChild(this.snap_lines_.x);
    }
    delete this.snap_lines_.x;
  }

  const point_y = this.light_source_.y;
  if (this.get_snap_y().includes(point_y) === true) {
    if (this.snap_lines_.y === undefined) {
      this.snap_lines_.y = document.createElementNS('http://www.w3.org/2000/svg', 'line');
      this.snap_lines_.y.style.strokeDasharray = '7, 3';
      this.snap_lines_.y.style.stroke = beestat.style.color.yellow.base;
      this.snap_lines_.y.setAttribute('x1', this.floor_plan_.get_grid_pixels() / -2);
      this.snap_lines_.y.setAttribute('x2', this.floor_plan_.get_grid_pixels() / 2);
      this.floor_plan_.get_g().appendChild(this.snap_lines_.y);
    }
    this.snap_lines_.y.setAttribute('y1', point_y);
    this.snap_lines_.y.setAttribute('y2', point_y);
  } else if (this.snap_lines_.y !== undefined) {
    if (this.snap_lines_.y.parentNode !== undefined && this.snap_lines_.y.parentNode !== null) {
      this.snap_lines_.y.parentNode.removeChild(this.snap_lines_.y);
    }
    delete this.snap_lines_.y;
  }
};

/**
 * Clear snap lines.
 */
beestat.component.floor_plan_entity.light_source.prototype.clear_snap_lines_ = function() {
  if (this.snap_lines_.x !== undefined) {
    if (this.snap_lines_.x.parentNode !== undefined && this.snap_lines_.x.parentNode !== null) {
      this.snap_lines_.x.parentNode.removeChild(this.snap_lines_.x);
    }
    delete this.snap_lines_.x;
  }
  if (this.snap_lines_.y !== undefined) {
    if (this.snap_lines_.y.parentNode !== undefined && this.snap_lines_.y.parentNode !== null) {
      this.snap_lines_.y.parentNode.removeChild(this.snap_lines_.y);
    }
    delete this.snap_lines_.y;
  }
};
