class Section
  include SimplyStored::Couch
  include Qwaiter::Distribution
  include ActiveModel::SerializerSupport

  property :title
  property :path, type: Array, default: [[0.0, 0.0], [20.0, 0.0], [20.0, 30.0], [0.0, 30.0]] # default width 20m height 30m

  belongs_to :supplier
  has_many :tables
  has_many :lists
  has_many :orders
  has_many :section_elements
  has_many :section_areas

  validates :title, presence: true
  validates :supplier_id, presence: true

  view :by_supplier_id_and_id, key: [:supplier_id, :_id]

  def occupied_tables
    return @occupied_tables if @occupied_tables.present?
    @active_lists = List.active_for_section(self)
    @active_lists.include_relation(:table)
    @occupied_tables = @active_lists.map(&:table)
  end

  def active_lists
    return @active_lists if @active_lists.present?
    @active_lists = List.active_for_section(self)
  end

  def active_orders
    @active_orders ||= Order.active_for_supplier_and_section(supplier_id, id)
  end

  def width
    x_coords = path.map(&:first)
    x_coords.max - x_coords.min
  end

  def height
    y_coords = path.map(&:last)
    y_coords.max - y_coords.min
  end

  def width=(val)
    val = val.to_f
    return val if width == val
    self.path[0] ||= [0.0, 0.0]
    self.path[1] ||= [0.0, 0.0]
    self.path[2] ||= [0.0, 0.0]
    self.path[3] ||= [0.0, 0.0]
    path[0][0] = 0
    path[1][0] = val
    path[2][0] = val
    path[3][0] = 0
    path_will_change!
    val
  end

  def height=(val)
    val = val.to_f
    return val if height == val
    self.path[0] ||= [0.0, 0.0]
    self.path[1] ||= [0.0, 0.0]
    self.path[2] ||= [0.0, 0.0]
    self.path[3] ||= [0.0, 0.0]
    path[0][1] = 0
    path[1][1] = 0
    path[2][1] = val
    path[3][1] = val
    path_will_change!
    val
  end

  def tables_with_active_list_id
    Table.enrich_active_list_id(tables)
  end

  #def as_json(*)
    #super.merge(width: width, height: height)
  #end

  def for_tables_as_json
    return @for_tables_as_json if @for_tables_as_json.present?
    h = as_json
    h[:tables] = []
    for table in tables
      ht = table.as_json
      table_list = active_lists.find{|l| l.table_id == table.id}
      ht[:occupied] = occupied_tables.include?(table)
      ht[:needs_help] = ht[:occupied] && table_list ? table_list.needs_help? : false
      ht[:needs_payment] = ht[:occupied] && table_list ? table_list.needs_payment? : false
      ht[:active_order] = ht[:occupied] && table_list ? active_orders.any?{|o| o.list_id == table_list.id } : false
      h[:tables] << ht
    end
    @for_tables_as_json = h
  end

  def arrange_tables_in_grid(tables = self.tables)
    w = width
    h = height
    n = tables.size
    return false unless w > 0 && h > 0 && n > 0
    lx, ly = distribute_lattice(w, h, n)
    x0 = lx/2
    x = x0
    y = ly/2
    saves = []
    for table in tables.sort_by(&:number)
      if x > w + (1e4*epsilon) # New row,  error = epsilon times possible tables in a row
        x = x0
        y += ly
      end
      table.position_x = x  - (table.width/2) # Starting point of square + half the square (center) minus half the table size
      table.position_y = y  - (table.height/2)
      saves << table.save
      x += lx
    end
    saves.all?
  end

  def arrange_tables_in_rows_of(n)
    return false unless n.present?
    n = n.to_i
    return false unless n > 0
    dx = width / n
    dy = height / (tables.size.to_f/n).ceil
    x = 0.0
    y = 0.0
    saves = []
    tables.sort_by(&:number).each.with_index do |table, i|
      table.position_x = x + (dx/2) - (table.width/2)
      table.position_y = y + (dy/2) - (table.height/2)
      x += dx
      if (i + 1).multiple_of?( n )
        x = 0.0
        y += dy
      end
      saves << table.save
    end
    return saves.all?
  end

  def arrange_tables_in_columns_of(n)
    return unless n.present?
    n = n.to_i
    return unless n > 0
    dx = width / (tables.size.to_f/n).ceil
    dy = height / n
    x = 0.0
    y = 0.0
    tables.sort_by(&:number).each.with_index do |table, i|
      table.position_x = x + (dx/2) - (table.width/2)
      table.position_y = y + (dy/2) - (table.height/2)
      y += dy
      if (i + 1).multiple_of?( n )
        y = 0.0
        x += dx
      end
      table.save
    end
  end

end
