# open the class to add methods to apply HVAC efficiency standards
class OpenStudio::Model::SubSurface

  # Determine the component infiltration rate for this surface
  #
  # @param type [String] choices are 'baseline' and 'advanced'
  # @return [Double] infiltration rate
  #   @units cubic meters per second (m^3/s)
  def component_infiltration_rate(type)
       
    comp_infil_rate_m3_per_s = 0.0   
       
    # Define the envelope component infiltration rates
    component_infil_rates_cfm_per_ft2 = {
      'baseline'=>{
        'opaque_door'=>0.40,
        'loading_dock_door'=>0.40,
        'swinging_or_revolving_glass_door'=>1.0,
        'vestibule'=>1.0,
        'sliding_glass_door'=>0.40,
        'window'=>0.40,
        'skylight'=>0.40
      },
      'advanced'=>{
        'opaque_door'=>0.20,
        'loading_dock_door'=>0.20,
        'swinging_or_revolving_glass_door'=>1.0,
        'vestibule'=>1.0,
        'sliding_glass_door'=>0.20,
        'window'=>0.20,
        'skylight'=>0.20
      }
    }
    
    boundary_condition = self.outsideBoundaryCondition
    # Skip non-outdoor surfaces
    return comp_infil_rate_m3_per_s unless self.outsideBoundaryCondition == 'Outdoors' || self.outsideBoundaryCondition == 'Ground'
    
    # Per area infiltration rate for this surface
    surface_type = self.subSurfaceType 
    infil_rate_cfm_per_ft2 = nil
    case boundary_condition
    when 'Outdoors'
      case surface_type
      when 'Door'
        infil_rate_cfm_per_ft2 = component_infil_rates_cfm_per_ft2[type]['opaque_door']
      when 'OverheadDoor'
        infil_rate_cfm_per_ft2 = component_infil_rates_cfm_per_ft2[type]['loading_dock_door']
      when 'GlassDoor'
        OpenStudio::logFree(OpenStudio::Info, "openstudio.Standards.Model", "For #{self.name}, assuming swinging_or_revolving_glass_door for infiltration calculation.")
        infil_rate_cfm_per_ft2 = component_infil_rates_cfm_per_ft2[type]['swinging_or_revolving_glass_door']
      when 'FixedWindow','OperableWindow'
        infil_rate_cfm_per_ft2 = component_infil_rates_cfm_per_ft2[type]['window']
      when 'Skylight','TubularDaylightDome','TubularDaylightDiffuser'
        infil_rate_cfm_per_ft2 = component_infil_rates_cfm_per_ft2[type]['skylight']
      end
    end
    if infil_rate_cfm_per_ft2.nil?
      OpenStudio::logFree(OpenStudio::Warn, "openstudio.Standards.Model", "For #{self.name}, could not determine surface type for infiltration, will not be included in calculation.")
      return comp_infil_rate_m3_per_s
    end
      
    # Area of the surface
    area_m2 = self.netArea
    area_ft2 = OpenStudio.convert(area_m2,'m^2','ft^2').get
    
    # Rate for this surface
    comp_infil_rate_cfm = area_ft2 * infil_rate_cfm_per_ft2

    comp_infil_rate_m3_per_s = OpenStudio.convert(comp_infil_rate_cfm,'cfm','m^3/s').get

    #OpenStudio::logFree(OpenStudio::Debug, "openstudio.Standards.Model", "......#{self.name}, infil = #{comp_infil_rate_cfm.round(2)} cfm @ rate = #{infil_rate_cfm_per_ft2} cfm/ft2, area = #{area_ft2.round} ft2.")
    
    return comp_infil_rate_m3_per_s
    
  end
  
  # Reduce the area of the subsurface by raising the
  # sill height.
  #
  # @param percent_reduction [Double] the fractional amount
  # to reduce the area.
  def reduce_area_by_percent_by_raising_sill(percent_reduction)
  
    mult = 1-percent_reduction
    
    # Calculate the original area
    area_original = self.netArea

    # Find the min and max z values
    min_z_val = 99999
    max_z_val = -99999
    self.vertices.each do |vertex|
      # Min z value
      if vertex.z < min_z_val
        min_z_val = vertex.z
      end
      # Max z value
      if vertex.z > max_z_val
        max_z_val = vertex.z
      end
    end
    
    # Calculate the window height
    height = max_z_val - min_z_val
    
    # Calculate the new sill height
    new_sill_z = max_z_val - (height * mult)    
    
    # Reset the z value of the lowest points
    new_vertices = []
    self.vertices.each do |vertex|
      new_x = vertex.x
      new_y = vertex.y
      new_z = vertex.z
      if new_z == min_z_val
        new_z = new_sill_z
      end
      new_vertices << OpenStudio::Point3d.new(new_x, new_y, new_z)
    end
    
    # Reset the vertices
    self.setVertices(new_vertices)
    
    # Compare the new area to the old for validation
    act_pct_red = 1.0 - (self.netArea / area_original)
    
    return true
  
  end

  # Reduce the area of the subsurface by shrinking it
  # in the x direction.  Designed to work on skylights.
  #
  # @param percent_reduction [Double] the fractional amount
  # to reduce the area.
  def reduce_area_by_percent_by_shrinking_x(percent_reduction)
  
    mult = 1-percent_reduction
    
    # Calculate the original area
    area_original = self.netArea

    # Find the min and max x values
    min_x_val = 99999
    max_x_val = -99999
    self.vertices.each do |vertex|
      # Min x value
      if vertex.x < min_x_val
        min_x_val = vertex.x
      end
      # Max x value
      if vertex.x > max_x_val
        max_x_val = vertex.x
      end
    end
    
    # Calculate the skylight width
    width = max_x_val - min_x_val
    
    # Calculate the new sill width
    new_width_x = max_x_val - (width * mult)    
    
    # Reset the z value of the lowest points
    new_vertices = []
    self.vertices.each do |vertex|
      new_x = vertex.x
      if new_x == min_x_val
        new_x = new_width_x
      end
      new_y = vertex.y
      new_z = vertex.z
      new_vertices << OpenStudio::Point3d.new(new_x, new_y, new_z)
    end
    
    # Reset the vertices
    self.setVertices(new_vertices)
    
    # Compare the new area to the old for validation
    act_pct_red = 1.0 - (self.netArea / area_original)
    
    return true
  
  end
 
end