docs: def substitute_state(target_state_m, state_m_to_insert, as_template=False):
      """ Substitutes the target state
  
      Both, the state to be replaced (the target state) and the state to be inserted (the new state) are passed via
      parameters.
      The new state adapts the size and position of the target state.
      State elements of the new state are resized but kepp their proportion.
  
      :param rafcon.gui.models.container_state.AbstractStateModel target_state_m: State Model of state to be substituted
      :param rafcon.gui.models.container_state.StateModel state_m_to_insert: State Model of state to be inserted
      :return:
      """
      # print("substitute_state")
  
      state_to_insert = state_m_to_insert.state
      action_parent_m = target_state_m.parent
      old_state_m = target_state_m
      old_state = old_state_m.state
      state_id = old_state.state_id
  
      # BEFORE MODEL
      tmp_meta_data = {'transitions': {}, 'data_flows': {}, 'state': None}
      old_state_m = action_parent_m.states[state_id]
      # print("EMIT-BEFORE ON OLD_STATE ", state_id)
      old_state_m.action_signal.emit(ActionSignalMsg(action='substitute_state', origin='model',
                                                     action_parent_m=action_parent_m,
                                                     affected_models=[old_state_m, ], after=False,
                                                     kwargs={'state_id': state_id, 'state': state_to_insert}))
      related_transitions, related_data_flows = action_parent_m.state.related_linkage_state(state_id)
      tmp_meta_data['state'] = old_state_m.meta
      # print("old state meta", old_state_m.meta)
      for t in related_transitions['external']['ingoing'] + related_transitions['external']['outgoing']:
          tmp_meta_data['transitions'][t.transition_id] = action_parent_m.get_transition_m(t.transition_id).meta
      for df in related_data_flows['external']['ingoing'] + related_data_flows['external']['outgoing']:
          tmp_meta_data['data_flows'][df.data_flow_id] = action_parent_m.get_data_flow_m(df.data_flow_id).meta
      action_parent_m.substitute_state.__func__.tmp_meta_data_storage = tmp_meta_data
      action_parent_m.substitute_state.__func__.old_state_m = old_state_m
  
      # put old state size and rel_pos onto new state
      previous_state_size = state_m_to_insert.get_meta_data_editor()['size']
      state_m_to_insert.set_meta_data_editor('size', old_state_m.get_meta_data_editor()['size'])
      state_m_to_insert.set_meta_data_editor('rel_pos', old_state_m.get_meta_data_editor()['rel_pos'])
      # scale the meta data according new size
      prepare_state_m_for_insert_as(state_m_to_insert, previous_state_size)
  
      # CORE
      new_state = e = None
      # print("state to insert", state_to_insert)
      try:
          # if as_template:  # TODO remove this work around if the models are loaded correctly
          #     # the following enforce the creation of a new model (in needed depth) and transfer of meta data
          #     import rafcon.gui.action
          #     meta_dict = rafcon.gui.action.get_state_element_meta(state_m_to_insert)
          #     new_state = action_parent_m.state.substitute_state(state_id, state_to_insert)
          #     sm_m = action_parent_m.get_state_machine_m()
          #     rafcon.gui.action.insert_state_meta_data(meta_dict, sm_m.get_state_model_by_path(new_state.get_path()))
          # else:
          action_parent_m.expected_future_models.add(state_m_to_insert)
          new_state = action_parent_m.state.substitute_state(state_id, state_to_insert)
          # assert new_state.state_id is state_id
          assert new_state is state_to_insert
      except Exception as e:
          logger.exception("State substitution failed")
  
      if new_state:
          # AFTER MODEL
          # print("AFTER MODEL", new_state)
          new_state_m = action_parent_m.states[new_state.state_id]
          update_models_recursively(state_m=new_state_m)
          tmp_meta_data = action_parent_m.substitute_state.__func__.tmp_meta_data_storage
          old_state_m = action_parent_m.substitute_state.__func__.old_state_m
          changed_models = []
          new_state_m.meta = tmp_meta_data['state']
          changed_models.append(new_state_m)
          for t_id, t_meta in tmp_meta_data['transitions'].items():
              if action_parent_m.get_transition_m(t_id) is not None:
                  action_parent_m.get_transition_m(t_id).meta = t_meta
                  changed_models.append(action_parent_m.get_transition_m(t_id))
              elif t_id in action_parent_m.state.substitute_state.__func__.re_create_io_going_t_ids:
                  logger.warning("Transition model with id {0} to set meta data could not be found.".format(t_id))
          for df_id, df_meta in tmp_meta_data['data_flows'].items():
              if action_parent_m.get_data_flow_m(df_id) is not None:
                  action_parent_m.get_data_flow_m(df_id).meta = df_meta
                  changed_models.append(action_parent_m.get_data_flow_m(df_id))
              elif df_id in action_parent_m.state.substitute_state.__func__.re_create_io_going_df_ids:
                  logger.warning("Data flow model with id {0} to set meta data could not be found.".format(df_id))
  
          msg = ActionSignalMsg(action='substitute_state', origin='model', action_parent_m=action_parent_m,
                                affected_models=changed_models, after=True, result=e)
          # print("EMIT-AFTER OLDSTATE", msg)
          old_state_m.action_signal.emit(msg)
  
      del action_parent_m.substitute_state.__func__.tmp_meta_data_storage
      del action_parent_m.substitute_state.__func__.old_state_m