boost::optional<IdfObject> ForwardTranslator::translateScheduleTypeLimits( ScheduleTypeLimits & modelObject )
{
  IdfObject idfObject(openstudio::IddObjectType::ScheduleTypeLimits);
  m_idfObjects.push_back(idfObject);

  idfObject.setString(ScheduleTypeLimitsFields::Name, modelObject.name().get());

  OptionalDouble d = modelObject.getDouble(OS_ScheduleTypeLimitsFields::LowerLimitValue, false);
  if (d){
    idfObject.setDouble(ScheduleTypeLimitsFields::LowerLimitValue, *d);
  }

  d = modelObject.getDouble(OS_ScheduleTypeLimitsFields::UpperLimitValue, false);
  if (d){
    idfObject.setDouble(ScheduleTypeLimitsFields::UpperLimitValue, *d);
  }

  OptionalString s = modelObject.getString(OS_ScheduleTypeLimitsFields::NumericType, false, true);
  if (s){
    idfObject.setString(ScheduleTypeLimitsFields::NumericType, *s);
  }

  s = modelObject.getString(OS_ScheduleTypeLimitsFields::UnitType, false, true);
  if (s){
    std::string unitType = *s;
    boost::to_lower(unitType);
    if ((unitType == "clothinginsulation") ||
        (unitType == "rotationsperminute") ||
        (unitType == "massflowrate") ||
        (unitType == "pressure") ||
        (unitType == "solarenergy"))
    {
      // unit type key is unsupported in EnergyPlus--fall back on 'Any Number'
      m_idfObjects.pop_back();
      if (!m_anyNumberScheduleTypeLimits) {
        IdfObject anyNumberLimits(IddObjectType::ScheduleTypeLimits);
        m_idfObjects.push_back(anyNumberLimits);
        anyNumberLimits.setName("Any Number");
        m_anyNumberScheduleTypeLimits = anyNumberLimits;
      }
      return m_anyNumberScheduleTypeLimits;
    }
    idfObject.setString(ScheduleTypeLimitsFields::UnitType, unitType);
  }

  return boost::optional<IdfObject>(idfObject);
}
TEST_F(ModelFixture, ScheduleTypeRegistry_UseInSetSchedule) {
  Model model;

  // create a schedule
  ScheduleConstant schedule(model);

  // set a minimal schedule type limits
  ScheduleTypeLimits anyNumber(model);
  anyNumber.setName("Any Number");
  bool ok = schedule.setScheduleTypeLimits(anyNumber);
  EXPECT_TRUE(ok);

  // try to set Lights schedule--should fail b/c needs between 0 and 1
  LightsDefinition definition(model);
  definition.setLightingLevel(100.0);
  Lights light(definition);
  ok = light.setSchedule(schedule);
  EXPECT_FALSE(ok);

  // set Availablity schedule type limits
  ScheduleType scheduleType = ScheduleTypeRegistry::instance().getScheduleType("CoilCoolingDXSingleSpeed","Availability");
  ScheduleTypeLimits availabilityLimits = ScheduleTypeRegistry::instance().getOrCreateScheduleTypeLimits(scheduleType,model);
  ok = schedule.setScheduleTypeLimits(availabilityLimits);
  EXPECT_TRUE(ok);

  // try to set Lights schedule--used to fail b/c lights schedule is Dimensionless, not Availability, now passes
  ok = light.setSchedule(schedule);
  EXPECT_TRUE(ok);

  // clear conflicting information
  availabilityLimits.resetNumericType();
  availabilityLimits.resetUnitType();

  // set Lights schedule--should succeed b/c not in conflict
  ok = light.setSchedule(schedule);
  EXPECT_TRUE(ok);

  // try to clear schedule type limits--should fail b/c in use
  ok = schedule.resetScheduleTypeLimits();
  EXPECT_FALSE(ok);

  // reset Lights schedule
  light.resetSchedule();

  // try to clear schedule type limits--should succeed
  ok = schedule.resetScheduleTypeLimits();
  EXPECT_TRUE(ok);
  EXPECT_FALSE(schedule.scheduleTypeLimits());

  // set Lights schedule--should succeed and assign an appropriate ScheduleTypeLimits
  ok = light.setSchedule(schedule);
  EXPECT_TRUE(ok);
  ASSERT_TRUE(schedule.scheduleTypeLimits());
  ScheduleTypeLimits lightsLimits = schedule.scheduleTypeLimits().get();
  EXPECT_EQ("Fractional",lightsLimits.name().get());
  ASSERT_TRUE(lightsLimits.numericType());
  EXPECT_EQ("Continuous",lightsLimits.numericType().get());
  EXPECT_EQ("Dimensionless",lightsLimits.unitType());
  EXPECT_TRUE(lightsLimits.isUnitTypeDefaulted());
  ASSERT_TRUE(lightsLimits.lowerLimitValue());
  EXPECT_DOUBLE_EQ(0.0,lightsLimits.lowerLimitValue().get());
  ASSERT_TRUE(lightsLimits.upperLimitValue());
  EXPECT_DOUBLE_EQ(1.0,lightsLimits.upperLimitValue().get());
}
TEST_F(ModelFixture, ScheduleTypeRegistry_GetOrCreateScheduleTypeLimits) {
  {
    Model model;

    ScheduleType scheduleType = ScheduleTypeRegistry::instance().getScheduleType("People", "Activity Level");

    ASSERT_TRUE(scheduleType.lowerLimitValue);
    EXPECT_EQ(0.0, scheduleType.lowerLimitValue.get());
    EXPECT_FALSE(scheduleType.upperLimitValue);

    ScheduleTypeLimits limits = ScheduleTypeRegistry::instance().getOrCreateScheduleTypeLimits(scheduleType, model);
    ScheduleTypeLimits limits2 = ScheduleTypeRegistry::instance().getOrCreateScheduleTypeLimits(scheduleType, model);

    EXPECT_EQ(limits.handle(), limits2.handle());

    EXPECT_TRUE(isCompatible(scheduleType, limits));
  }

  {
    Model model;

    ScheduleType scheduleType = ScheduleTypeRegistry::instance().getScheduleType("RefrigerationCase", "Refrigerated Case Restocking");

    ASSERT_TRUE(scheduleType.lowerLimitValue);
    EXPECT_EQ(0.0, scheduleType.lowerLimitValue.get());
    EXPECT_FALSE(scheduleType.upperLimitValue);

    ScheduleTypeLimits limits = ScheduleTypeRegistry::instance().getOrCreateScheduleTypeLimits(scheduleType, model);
    ScheduleTypeLimits limits2 = ScheduleTypeRegistry::instance().getOrCreateScheduleTypeLimits(scheduleType, model);

    EXPECT_EQ(limits.handle(), limits2.handle());

    EXPECT_TRUE(isCompatible(scheduleType, limits));
  }

  {
    Model model;

    ScheduleType scheduleType = ScheduleTypeRegistry::instance().getScheduleType("ThermostatSetpointDualSetpoint", "Heating Setpoint Temperature");
    
    EXPECT_FALSE(scheduleType.lowerLimitValue);
    EXPECT_FALSE(scheduleType.upperLimitValue);

    ScheduleTypeLimits limits = ScheduleTypeRegistry::instance().getOrCreateScheduleTypeLimits(scheduleType, model);
    ScheduleTypeLimits limits2 = ScheduleTypeRegistry::instance().getOrCreateScheduleTypeLimits(scheduleType, model);

    EXPECT_EQ(limits.handle(), limits2.handle());
    EXPECT_EQ("Temperature", limits.name().get());

    EXPECT_TRUE(isCompatible(scheduleType, limits));

    ASSERT_EQ(1u, model.getConcreteModelObjectsByName<ScheduleTypeLimits>("Temperature").size());
    EXPECT_EQ("Temperature", model.getConcreteModelObjectsByName<ScheduleTypeLimits>("Temperature")[0].name().get());

    ModelObject scheduleType2 = limits.clone();
    EXPECT_EQ("Temperature 1", scheduleType2.name().get());

    EXPECT_EQ(2u, model.getConcreteModelObjectsByName<ScheduleTypeLimits>("Temperature").size());

    limits.remove();

    ASSERT_EQ(1u, model.getConcreteModelObjectsByName<ScheduleTypeLimits>("Temperature").size());
    EXPECT_EQ("Temperature 1", model.getConcreteModelObjectsByName<ScheduleTypeLimits>("Temperature 1")[0].name().get());

    limits = ScheduleTypeRegistry::instance().getOrCreateScheduleTypeLimits(scheduleType, model);
    EXPECT_EQ(limits.handle(), scheduleType2.handle());
    EXPECT_EQ("Temperature 1", limits.name().get());
  }

  {
    Model model;
    for (auto className : ScheduleTypeRegistry::instance().classNames()){
      for (auto scheduleType : ScheduleTypeRegistry::instance().getScheduleTypesByClassName(className)){
        ScheduleTypeLimits limits = ScheduleTypeRegistry::instance().getOrCreateScheduleTypeLimits(scheduleType, model);
        ScheduleTypeLimits limits2 = ScheduleTypeRegistry::instance().getOrCreateScheduleTypeLimits(scheduleType, model);

        EXPECT_EQ(limits.handle(), limits2.handle());

        EXPECT_EQ(ScheduleTypeLimits::units(scheduleType.unitType, false), ScheduleTypeLimits::units(limits.unitType(), false));

        EXPECT_TRUE(isCompatible(scheduleType, limits));
      }
    }
  }

}