OptionalModelObject ReverseTranslator::translateEnergyManagementSystemSubroutine(const WorkspaceObject & workspaceObject)
{
  if (workspaceObject.iddObject().type() != IddObjectType::EnergyManagementSystem_Subroutine) {
    LOG(Error, "WorkspaceObject is not IddObjectType: EnergyManagementSystem_Subroutine");
    return boost::none;
  }

  OptionalString s = workspaceObject.getString(EnergyManagementSystem_SubroutineFields::Name);
  if (!s) {
    LOG(Error, "WorkspaceObject EnergyManagementSystem_Subroutine has no Name");
    return boost::none;
  }

  // Make sure we translate the objects that can be referenced here
  for (const WorkspaceObject& workspaceObject : m_workspace.objects()) {

    // Note: JM 2018-08-17
    // I think an EMS:Subroutine can reference another EMS:Subroutine, we might get problems from that:
    // The one that is being referenced would need be translated before the one that references before the name/uuid substitution happen.
    // But it's harder to control that order*, and this is really an edge case though, so not handling it.
    // * Can't add this condition without getting into a loop:
    // (workspaceObject.iddObject().type() == IddObjectType::EnergyManagementSystem_Subroutine)
    if (
        // These I'm sure we do need.
        (workspaceObject.iddObject().type() == IddObjectType::EnergyManagementSystem_Actuator)
        || (workspaceObject.iddObject().type() == IddObjectType::EnergyManagementSystem_Sensor)
        || (workspaceObject.iddObject().type() == IddObjectType::EnergyManagementSystem_ConstructionIndexVariable)
        || (workspaceObject.iddObject().type() == IddObjectType::EnergyManagementSystem_CurveOrTableIndexVariable)
        || (workspaceObject.iddObject().type() == IddObjectType::EnergyManagementSystem_GlobalVariable)
        || (workspaceObject.iddObject().type() == IddObjectType::EnergyManagementSystem_InternalVariable)
        || (workspaceObject.iddObject().type() == IddObjectType::EnergyManagementSystem_TrendVariable)
       ) {
      translateAndMapWorkspaceObject(workspaceObject);
    }
  }
  openstudio::model::EnergyManagementSystemSubroutine emsProgram(m_model);
  emsProgram.setName(*s);

  // Get all model objects that can be referenced int he EMS Program so we can do name / uid substitution
  const std::vector<IddObjectType> validIddObjectTypes{
    IddObjectType::OS_EnergyManagementSystem_Subroutine,
    IddObjectType::OS_EnergyManagementSystem_Actuator,
    IddObjectType::OS_EnergyManagementSystem_Sensor,
    IddObjectType::OS_EnergyManagementSystem_ConstructionIndexVariable,
    IddObjectType::OS_EnergyManagementSystem_CurveOrTableIndexVariable,
    IddObjectType::OS_EnergyManagementSystem_GlobalVariable,
    IddObjectType::OS_EnergyManagementSystem_InternalVariable,
    IddObjectType::OS_EnergyManagementSystem_TrendVariable
  };

  std::vector<model::ModelObject> modelObjects;
  for (const model::ModelObject& mo: m_model.modelObjects()) {
    if( std::find(validIddObjectTypes.begin(), validIddObjectTypes.end(), mo.iddObjectType()) != validIddObjectTypes.end() ) {
      modelObjects.push_back(mo);
    }
  }


  // Now, we should do the actual name/uid substitution on all lines of the program

  size_t pos, len;
  std::string newline, uid;

  unsigned n = workspaceObject.numExtensibleGroups();
  OptionalString line;

  // Loop on each line of the program
  for (unsigned i = 0; i < n; ++i) {
    line = workspaceObject.getExtensibleGroup(i).cast<WorkspaceExtensibleGroup>().getString(EnergyManagementSystem_SubroutineExtensibleFields::ProgramLine);
    if (line) {
      newline = line.get();

      // Split line to get 'tokens' and look for ModelObject names
      // splitEMSLineToTokens returns already sanitized tokens (excludes reserved keywords, blank ones, functions, removes parenthesis, etc)
      std::vector<std::string> tokens = splitEMSLineToTokens(newline);

      for (std::string& token: tokens) {
        for (const model::ModelObject& mo: modelObjects) {
          // Check if program item is the name of a model object
          boost::optional<std::string> _name = mo.name();
          if ( _name && (_name.get() == token) ) {
            // replace model object's name with its handle
            pos = newline.find(token);
            len = token.length();
            uid = toString(mo.handle());
            newline.replace(pos, len, uid);
            // Now that we have done the replacement, no need to keep looping.
            // Plus, we should break out of the nested loop and go to the next "j"
            // Otherwise pos could become giberish if there's another object named the same
            // since it won't be able to find the already-replaced string (this shouldn't happen though)
            break;
          }
        } // end loop on all modelObjects

      } // end loop on all results in line
      emsProgram.addLine(newline);
    } // end if(line)
  } // End loop on each line of the program

  return emsProgram;

}
OptionalModelObject ReverseTranslator::translateConstruction( const WorkspaceObject & workspaceObject )
{
  if( workspaceObject.iddObject().type() != IddObjectType::Construction ){
    LOG(Error, "WorkspaceObject is not IddObjectType: Construction");
    return boost::none;
  }

  Construction construction(m_model);
  OS_ASSERT(construction.numLayers() == 0u);
  OptionalString optS = workspaceObject.name();
  if (optS) {
    construction.setName(*optS);
  }

  unsigned n = workspaceObject.numExtensibleGroups();
  // now we get the workspace objects and try to find them and place them in the model object
  // Loop over all the fields except the first, which is the name
  OptionalWorkspaceObject owo;
  OptionalModelObject temp;
  for( unsigned i = 0; i < n; ++i) {
    owo = workspaceObject.getExtensibleGroup(i).cast<WorkspaceExtensibleGroup>().getTarget(ConstructionExtensibleFields::Layer);
    if( owo ) {
      temp = translateAndMapWorkspaceObject( *owo );
    }
    if( ! (owo && temp) )
    {
      LOG(Error, "Finding Construction Layer in workspace failed.");
      construction.remove();
      return boost::none;
    }
    // Assuming names of materials are unique
    OptionalMaterial mat = temp->optionalCast<Material>();

    bool inserted(false);
    if (mat) {
      OptionalOpaqueMaterial opaqueMaterial = mat->optionalCast<OpaqueMaterial>();
      if(opaqueMaterial) {
        inserted = construction.insertLayer(i, *opaqueMaterial);
      }
      else {
        OptionalFenestrationMaterial fenestrationMaterial = mat->optionalCast<FenestrationMaterial>();
        if (fenestrationMaterial) {
          inserted = construction.insertLayer(i, *fenestrationMaterial );
        }
        else {
          OptionalModelPartitionMaterial modelPartitionMaterial = mat->optionalCast<ModelPartitionMaterial>();
          if (modelPartitionMaterial) {
            if (construction.numLayers() == 0u) {
              inserted = construction.setLayer(*modelPartitionMaterial);
            }
          }
        }
      }
    }

    if( !inserted ) {
      LOG(Error, "Insertion of Construction Layer failed.");
      construction.remove();
      return boost::none;
    }
  }

  return construction;
}