# open the class to add methods to size all HVAC equipment
class OpenStudio::Model::Model

  def add_hvac(building_type, building_vintage, climate_zone, prototype_input)

    OpenStudio::logFree(OpenStudio::Info, 'openstudio.model.Model', 'Started Adding HVAC')

    # Get the list of HVAC systems, as defined
    # for each building in the Prototype.building_name files.
    system_to_space_map = define_hvac_system_map(building_type, building_vintage, climate_zone)

    # Add each HVAC system
    system_to_space_map.each do |system|

    thermal_zones = get_zones_from_spaces_on_system(system)

    return_plenum = get_return_plenum_from_system(system)

      # Add the HVAC systems
      case system['type']
      when 'VAV'

        # Retrieve the existing hot water loop
        # or add a new one if necessary.
        hot_water_loop = nil
        if self.getPlantLoopByName('Hot Water Loop').is_initialized
          hot_water_loop = self.getPlantLoopByName('Hot Water Loop').get
        else
          hot_water_loop = self.add_hw_loop('NaturalGas', building_type)
        end

        # Retrieve the existing chilled water loop
        # or add a new one if necessary.
        chilled_water_loop = nil
        if self.getPlantLoopByName('Chilled Water Loop').is_initialized
          chilled_water_loop = self.getPlantLoopByName('Chilled Water Loop').get
        else
          condenser_water_loop = nil
          number_cooling_towers = 1
          num_chillers = 1
          if building_type == "Hospital" or building_type == "LargeOffice"
            case building_vintage
              when '90.1-2004', '90.1-2007', '90.1-2010', '90.1-2013'
                number_cooling_towers = 2
                num_chillers = 2
            end
          end
          if prototype_input['chiller_cooling_type'] == 'WaterCooled'
            condenser_water_loop = self.add_cw_loop(building_type, building_vintage, number_cooling_towers)
          end
          chilled_water_loop = self.add_chw_loop(
                                  building_vintage,
                                  prototype_input['chw_pumping_type'],
                                  prototype_input['chiller_cooling_type'],
                                  prototype_input['chiller_condenser_type'],
                                  prototype_input['chiller_compressor_type'],
                                  prototype_input['chiller_capacity_guess'],
                                  condenser_water_loop,
                                  building_type,
                                  num_chillers
                                )
        end

        # Add the VAV
        self.add_vav_reheat(building_vintage,
          system['name'],
          hot_water_loop,
          chilled_water_loop,
          thermal_zones,
          prototype_input['vav_operation_schedule'],
          prototype_input['vav_oa_damper_schedule'],
          prototype_input['vav_fan_efficiency'],
          prototype_input['vav_fan_motor_efficiency'],
          prototype_input['vav_fan_pressure_rise'],
          return_plenum,
          building_type
        )


      when 'CAV'

        # Retrieve the existing hot water loop
        # or add a new one if necessary.
        hot_water_loop = nil
        if self.getPlantLoopByName('Hot Water Loop').is_initialized
          hot_water_loop = self.getPlantLoopByName('Hot Water Loop').get
        else
          hot_water_loop = self.add_hw_loop('NaturalGas',building_type)
        end

        chilled_water_loop = nil
        if self.getPlantLoopByName('Chilled Water Loop').is_initialized
          chilled_water_loop = self.getPlantLoopByName('Chilled Water Loop').get
        elsif building_type == 'Hospital'
          condenser_water_loop = nil
          if prototype_input['chiller_cooling_type'] == 'WaterCooled'
            condenser_water_loop = self.add_cw_loop()
          end

          chilled_water_loop = self.add_chw_loop(building_vintage,
                                                prototype_input['chw_pumping_type'],
                                                prototype_input['chiller_cooling_type'],
                                                prototype_input['chiller_condenser_type'],
                                                prototype_input['chiller_compressor_type'],
                                                prototype_input['chiller_capacity_guess'],
                                                condenser_water_loop)
        end

        # Add the CAV
        self.add_cav(building_vintage,
                    system['name'],
                    hot_water_loop,
                    thermal_zones,
                    prototype_input['vav_operation_schedule'],
                    prototype_input['vav_oa_damper_schedule'],
                    prototype_input['vav_fan_efficiency'],
                    prototype_input['vav_fan_motor_efficiency'],
                    prototype_input['vav_fan_pressure_rise'],
                    chilled_water_loop,
                    building_type)

      when 'PSZ-AC'

        # Special logic to differentiate between operation schedules
        # that vary even inside of a system type for stripmall.
        hvac_op_sch = nil
        oa_sch = nil
        if system['hvac_op_sch_index'].nil? || system['hvac_op_sch_index'] == 1
          hvac_op_sch = prototype_input['pszac_operation_schedule']
          oa_sch = prototype_input['pszac_oa_damper_schedule']
        elsif system['hvac_op_sch_index'] == 2
          hvac_op_sch = prototype_input['pszac_operation_schedule_2']
          oa_sch = prototype_input['pszac_oa_damper_schedule_2']
        elsif system['hvac_op_sch_index'] == 3
          hvac_op_sch = prototype_input['pszac_operation_schedule_3']
          oa_sch = prototype_input['pszac_oa_damper_schedule_3']
        end

        # Special logic to make unitary heat pumps all blow-through
        fan_position = 'DrawThrough'
        if prototype_input['pszac_heating_type'] == 'Single Speed Heat Pump' ||
          prototype_input['pszac_heating_type'] == 'Water To Air Heat Pump'
          fan_position = 'BlowThrough'
        end

        # Special logic to make a heat pump loop if necessary
        heat_pump_loop = nil
        if prototype_input['pszac_heating_type'] == 'Water To Air Heat Pump'
          heat_pump_loop = add_hp_loop(building_type)
        end

        self.add_psz_ac(building_vintage,
                        system['name'],
                        heat_pump_loop, # Typically nil unless water source hp
                        heat_pump_loop, # Typically nil unless water source hp
                        thermal_zones,
                        hvac_op_sch,
                        oa_sch,
                        fan_position,
                        prototype_input['pszac_fan_type'],
                        prototype_input['pszac_heating_type'],
                        prototype_input['pszac_supplemental_heating_type'],
                        prototype_input['pszac_cooling_type'],
                        building_type)

      when 'PVAV'

        # Retrieve the existing hot water loop
        # or add a new one if necessary.
        hot_water_loop = nil
        if self.getPlantLoopByName('Hot Water Loop').is_initialized
          hot_water_loop = self.getPlantLoopByName('Hot Water Loop').get
        elsif building_type == 'MediumOffice'
          hot_water_loop = nil
        else
          hot_water_loop = self.add_hw_loop('NaturalGas',building_type)
        end

        self.add_pvav(building_vintage,
                      system['name'],
                      thermal_zones,
                      prototype_input['vav_operation_schedule'],
                      prototype_input['vav_oa_damper_schedule'],
                      hot_water_loop,
                      return_plenum,
                      building_type)

      when 'DOAS'

        # Retrieve the existing hot water loop
        # or add a new one if necessary.
        hot_water_loop = nil
        if self.getPlantLoopByName('Hot Water Loop').is_initialized
          hot_water_loop = self.getPlantLoopByName('Hot Water Loop').get
        else
          hot_water_loop = self.add_hw_loop('NaturalGas',building_type)
        end

        # Retrieve the existing chilled water loop
        # or add a new one if necessary.
        chilled_water_loop = nil
        if self.getPlantLoopByName('Chilled Water Loop').is_initialized
          chilled_water_loop = self.getPlantLoopByName('Chilled Water Loop').get
        else
          condenser_water_loop = nil
          if prototype_input['chiller_cooling_type'] == 'WaterCooled'
            condenser_water_loop = self.add_cw_loop()
          end

          chilled_water_loop = self.add_chw_loop(building_vintage,
                                                prototype_input['chw_pumping_type'],
                                                prototype_input['chiller_cooling_type'],
                                                prototype_input['chiller_condenser_type'],
                                                prototype_input['chiller_compressor_type'],
                                                prototype_input['chiller_capacity_guess'],
                                                condenser_water_loop)
        end

        self.add_doas(building_vintage,
                    system['name'],
                    hot_water_loop,
                    chilled_water_loop,
                    thermal_zones,
                    prototype_input['vav_operation_schedule'],
                    prototype_input['doas_oa_damper_schedule'],
                    prototype_input['doas_fan_maximum_flow_rate'],
                    prototype_input['doas_economizer_control_type'],
                    building_type)

      when 'DC' # Data Center

        # Retrieve the existing hot water loop
        # or add a new one if necessary.
        hot_water_loop = nil
        if self.getPlantLoopByName('Hot Water Loop').is_initialized
          hot_water_loop = self.getPlantLoopByName('Hot Water Loop').get
        else
          hot_water_loop = self.add_hw_loop('NaturalGas',building_type)
        end

        # Retrieve the existing heat pump loop
        # or add a new one if necessary.
        heat_pump_loop = nil
        if self.getPlantLoopByName('Heat Pump Loop').is_initialized
          heat_pump_loop = self.getPlantLoopByName('Heat Pump Loop').get
        else
          heat_pump_loop = self.add_hp_loop(building_type)
        end

        self.add_data_center_hvac(building_vintage,
                                nil,
                                hot_water_loop,
                                heat_pump_loop,
                                thermal_zones,
                                prototype_input['flow_fraction_schedule_name'],
                                prototype_input['flow_fraction_schedule_name'],
                                system['main_data_center'])

      when 'SAC'

        self.add_split_AC(building_vintage,
                          nil,
                          thermal_zones,
                          prototype_input['sac_operation_schedule'],
                          prototype_input['sac_operation_schedule_meeting'],
                          prototype_input['sac_oa_damper_schedule'],
                          prototype_input['sac_fan_type'],
                          prototype_input['sac_heating_type'],
                          prototype_input['sac_heating_type'],
                          prototype_input['sac_cooling_type'],
                          building_type)

      when 'UnitHeater'

        self.add_unitheater(building_vintage,
                            nil,
                            thermal_zones,
                            prototype_input['unitheater_operation_schedule'],
                            prototype_input['unitheater_fan_control_type'],
                            prototype_input['unitheater_fan_static_pressure'],
                            prototype_input['unitheater_heating_type'],
                            building_type)

      when 'PTAC'

        self.add_ptac(building_vintage,
                      nil,
                      nil,
                      thermal_zones,
                      prototype_input['ptac_fan_type'],
                      prototype_input['ptac_heating_type'],
                      prototype_input['ptac_cooling_type'],
                      building_type)

      when 'Exhaust Fan'

        self.add_exhaust_fan(system['availability_sch_name'],
                            system['flow_rate'],
                            system['flow_fraction_schedule_name'],
                            system['balanced_exhaust_fraction_schedule_name'],
                            thermal_zones)

      when 'Zone Ventilation'

        self.add_zone_ventilation(system['availability_sch_name'],
                                  system['flow_rate'],
                                  system['ventilation_type'],
                                  thermal_zones)

      when 'Refrigeration'

        self.add_refrigeration(building_vintage,
                              system['case_type'],
                              system['cooling_capacity_per_length'],
                              system['length'],
                              system['evaporator_fan_pwr_per_length'],
                              system['lighting_per_length'],
                              system['lighting_sch_name'],
                              system['defrost_pwr_per_length'],
                              system['restocking_sch_name'],
                              system['cop'],
                              system['cop_f_of_t_curve_name'],
                              system['condenser_fan_pwr'],
                              system['condenser_fan_pwr_curve_name'],
                              thermal_zones[0])
      else

        OpenStudio::logFree(OpenStudio::Error, 'openstudio.model.Model', "System type #{system['type']} is not recognized.  This system will not be added.")

      end

    end

    OpenStudio::logFree(OpenStudio::Info, 'openstudio.model.Model', 'Finished adding HVAC')

    return true

  end #add hvac

  private

  def get_zones_from_spaces_on_system(system)

    # Find all zones associated with these spaces
    thermal_zones = []
    system['space_names'].each do |space_name|
      space = self.getSpaceByName(space_name)
      if space.empty?
        OpenStudio::logFree(OpenStudio::Error, 'openstudio.model.Model', "No space called #{space_name} was found in the model")
        next
      end
      space = space.get
      zone = space.thermalZone
      if zone.empty?
        OpenStudio::logFree(OpenStudio::Error, 'openstudio.model.Model', "Space #{space_name} has no thermal zone; cannot add an HVAC system to this space.")
        next
      end
      thermal_zones << zone.get
    end

    return thermal_zones

  end

  def get_return_plenum_from_system(system)

    # Find the zone associated with the return plenum space name
    return_plenum = nil

    # Return nil if no return plenum
    return return_plenum if system['return_plenum'].nil?

    # Get the space
    space = self.getSpaceByName(system['return_plenum'])
    if space.empty?
      OpenStudio::logFree(OpenStudio::Error, 'openstudio.model.Model', "No space called #{space_name} was found in the model")
      return return_plenum
    end
    space = space.get

    # Get the space's zone
    zone = space.thermalZone
    if zone.empty?
      OpenStudio::logFree(OpenStudio::Error, 'openstudio.model.Model', "Space #{space_name} has no thermal zone; cannot be a return plenum.")
      return return_plenum
    end

    return zone.get

  end

end