require 'mittsu/core'
require 'mittsu/math'

module Mittsu
  class BoxGeometry < Geometry
    def initialize(width, height, depth, width_segments = nil, height_segments = nil, depth_segments = nil)
      super()

      @type = 'BoxGeometry'

      @parameters = {
        width: width,
        height: height,
        depth: depth,
        width_segments: width_segments,
        height_segments: height_segments,
        depth_segments: depth_segments
      }

      @width_segments = width_segments || 1
      @height_segments = height_segments || 1
      @depth_segments = depth_segments || 1

      width_half = width / 2.0
      height_half = height / 2.0
      depth_half = depth / 2.0

      build_plane(:z, :y, -1, -1, depth.to_f, height.to_f, width_half,   0) # px
      build_plane(:z, :y,  1, -1, depth.to_f, height.to_f, -width_half,  1) # nx
      build_plane(:x, :z,  1,  1, width.to_f, depth.to_f,  height_half,  2) # py
      build_plane(:x, :z,  1, -1, width.to_f, depth.to_f,  -height_half, 3) # ny
      build_plane(:x, :y,  1, -1, width.to_f, height.to_f, depth_half,   4) # pz
      build_plane(:x, :y, -1, -1, width.to_f, height.to_f, -depth_half,  5) # nz

      merge_vertices
    end

    private

    def build_plane(u, v, udir, vdir, width, height, depth, material_index)
      grid_x = @width_segments
      grid_y = @height_segments
      width_half = width / 2.0
      height_half = height / 2.0
      offset = @vertices.length

      if (u == :x && v == :y) || (u == :y && v == :x)
        w = :z
      elsif (u == :x && v == :z) || (u == :z && v == :x)
        w = :y
        grid_y = @depth_segments
      elsif (u == :z && v == :y) || (u == :y && v == :z)
        w = :x
        grid_x = @depth_segments
      end

      grid_x1 = grid_x + 1
      grid_y1 = grid_y + 1
      segment_width = width / grid_x
      segment_height = height / grid_y
      normal = Vector3.new

      normal[w] = depth > 0 ? 1.0 : -1.0

      grid_y1.times do |iy|
        grid_x1.times do |ix|
          vector = Vector3.new
          vector[u] = (ix * segment_width - width_half) * udir
          vector[v] = (iy * segment_height - height_half) * vdir
          vector[w] = depth

          @vertices.push(vector)
        end
      end

      grid_y.times do |iy|
        grid_x.times do |ix|
          a = ix + grid_x1 * iy
          b = ix + grid_x1 * (iy + 1)
          c = (ix + 1) + grid_x1 * (iy + 1)
          d = (ix + 1) + grid_x1 * iy

          uva = Vector2.new(ix / grid_x.to_f, 1.0 - iy / grid_y.to_f)
          uvb = Vector2.new(ix / grid_x.to_f, 1.0 - (iy + 1.0) / grid_y.to_f)
          uvc = Vector2.new((ix + 1.0) / grid_x.to_f, 1.0 - (iy + 1.0) / grid_y.to_f)
          uvd = Vector2.new((ix + 1.0) / grid_x.to_f, 1.0 - iy / grid_y.to_f)

          face = Face3.new(a + offset, b + offset, d + offset)
          face.normal.copy(normal)
          face.vertex_normals << normal.clone << normal.clone << normal.clone
          face.material_index = material_index

          faces << face
          face_vertex_uvs[0] << [uva, uvb, uvd]

          face = Face3.new(b + offset, c + offset, d + offset)
          face.normal.copy(normal)
          face.vertex_normals << normal.clone << normal.clone << normal.clone
          face.material_index = material_index

          faces << face
          face_vertex_uvs[0] << [uvb.clone, uvc, uvd.clone]
        end
      end

    end
  end
end
