/**
   * If the argument is true, make the port a multiport. If the argument is false, make the port not
   * a multiport. This method overrides the base class to make the same change on the mirror ports
   * in the controller and state refinments. This method invalidates the schedule and resolved types
   * of the director of the container, if there is one. It is write-synchronized on the workspace,
   * and increments the version of the workspace.
   *
   * @param isMultiport True to make the port a multiport.
   * @exception IllegalActionException If changing the port status is not permitted.
   */
  @Override
  public void setMultiport(boolean isMultiport) throws IllegalActionException {
    boolean disableStatus = _mirrorDisable;

    try {
      _workspace.getWriteAccess();

      if (_mirrorDisable || getContainer() == null) {
        // Have already called the super class.
        // This time, process the request.
        // process request for the sibling
        if (_hasSibling && isOutput() && getContainer() != null) {
          TransitionRefinement container = (TransitionRefinement) getContainer();
          TransitionRefinementPort sibling =
              (TransitionRefinementPort) container.getPort(getName() + "_in");

          sibling._mirrorDisable = true;
          sibling.setMultiport(isMultiport);
          sibling._mirrorDisable = false;
        }

        super.setMultiport(isMultiport);
      } else {
        _mirrorDisable = true;

        boolean success = false;
        Nameable container = getContainer();

        if (container != null) {
          Nameable modal = container.getContainer();

          if (modal instanceof ModalModel) {
            Port port = ((ModalModel) modal).getPort(getName());

            if (port instanceof IOPort) {
              ((IOPort) port).setMultiport(isMultiport);
              success = true;
            }
          }
        }

        if (!success) {
          super.setMultiport(isMultiport);
        }
      }
    } finally {
      _mirrorDisable = disableStatus;
      _workspace.doneWriting();
    }
  }
  /**
   * Set the name of the port, and mirror the change in all the mirror ports. This method is
   * write-synchronized on the workspace, and increments the version of the workspace.
   *
   * @exception IllegalActionException If the name has a period.
   * @exception NameDuplicationException If there is already a port with the same name in the
   *     container.
   */
  public void setName(String name) throws IllegalActionException, NameDuplicationException {
    boolean disableStatus = _mirrorDisable;

    try {
      _workspace.getWriteAccess();

      if (_mirrorDisable || (getContainer() == null)) {
        // change sibling
        if (_hasSibling && isOutput() && (getContainer() != null)) {
          TransitionRefinement container = (TransitionRefinement) getContainer();
          TransitionRefinementPort sibling =
              (TransitionRefinementPort) container.getPort(getName() + "_in");
          sibling._mirrorDisable = true;
          sibling.setName(name + "_in");
          sibling._mirrorDisable = false;
        }

        // Have already called the super class.
        // This time, process the request.
        super.setName(name);
      } else {
        _mirrorDisable = true;

        boolean success = false;
        Nameable container = getContainer();

        if (container != null) {
          Nameable modal = container.getContainer();

          if (modal instanceof ModalModel) {
            Port port = ((ModalModel) modal).getPort(getName());

            if (port != null) {
              port.setName(name);
              success = true;
            }
          }
        }

        if (!success) {
          super.setName(name);
        }
      }
    } finally {
      _mirrorDisable = disableStatus;
      _workspace.doneWriting();
    }
  }
  /**
   * If the argument is true, make the port an output port. If the argument is false, make the port
   * not an output port. In addition, if the container is an instance of Refinement, and the
   * argument is true, find the corresponding port of the controller and make it an input and not an
   * output. This makes it possible for the controller to see the outputs of the refinements. This
   * method overrides the base class to make the same change on the mirror ports in the controller
   * and state refinments. This method invalidates the schedule and resolved types of the director
   * of the container, if there is one. It is write-synchronized on the workspace, and increments
   * the version of the workspace.
   *
   * @param isOutput True to make the port an output.
   * @exception IllegalActionException If changing the port status is not permitted.
   */
  public void setOutput(boolean isOutput) throws IllegalActionException {
    boolean disableStatus = _mirrorDisable;

    // check first that this isn't an input sibling port,
    // if it is then it *cannot* be set as an output too
    if (_hasSibling && isInput() && !isOutput()) {
      if (isOutput) {
        throw new InternalErrorException(
            "TransitionRefinementPort.setOutput:"
                + " cannot set input sibling port to be an output");
      } else {
        return;
      }
    }

    try {
      _workspace.getWriteAccess();

      if (_mirrorDisable || (getContainer() == null)) {
        // Have already called the super class.
        // This time, process the request.
        super.setOutput(isOutput);

        // now create a sibling if we
        // don't otherwise have one
        if (!_hasSibling && isOutput) {
          try {
            TransitionRefinement container = (TransitionRefinement) getContainer();
            TransitionRefinementPort sibling =
                new TransitionRefinementPort(container, getName() + "_in");

            sibling._hasSibling = true;
            sibling._mirrorDisable = true;

            // set attributes of sibling
            sibling.setInput(true);
            sibling.setMultiport(isMultiport());

            sibling._mirrorDisable = false;

            // link the port relation should already exist
            // from this port's creation in newPort()
            String relationName = getName() + "Relation";
            ModalModel model = (ModalModel) container.getContainer();
            Relation relation = model.getRelation(relationName);

            if (relation != null) {
              sibling.link(relation);
            }

            _hasSibling = true;
          } catch (IllegalActionException ex) {
            throw new InternalErrorException(
                "TransitionRefinementPort.setOutput: Internal error: " + ex.getMessage());
          } catch (NameDuplicationException ex) {
            throw new InternalErrorException(
                "TransitionRefinementPort.setOutput: Internal error: " + ex.getMessage());
          }
        }
      } else {
        _mirrorDisable = true;

        boolean success = false;
        Nameable container = getContainer();

        if (container != null) {
          Nameable modal = container.getContainer();

          if (modal instanceof ModalModel) {
            Port port = ((ModalModel) modal).getPort(getName());

            if (port instanceof IOPort) {
              ((IOPort) port).setOutput(isOutput);
              success = true;
            }
          }
        }

        if (!success) {
          super.setOutput(isOutput);
        }
      }
    } finally {
      _mirrorDisable = disableStatus;
      _workspace.doneWriting();
    }
  }
  /**
   * Override the base class so that if the port is being removed from the current container, then
   * it is also removed from the controller and from each of the refinements.
   *
   * @param container The proposed container.
   * @exception IllegalActionException If the proposed container is not a ComponentEntity, doesn't
   *     implement Actor, or has no name, or the port and container are not in the same workspace.
   *     Or it's not null
   * @exception NameDuplicationException If the container already has a port with the name of this
   *     port.
   */
  public void setContainer(Entity container)
      throws IllegalActionException, NameDuplicationException {
    NamedObj oldContainer = getContainer();

    if (container == oldContainer) {
      // Nothing to do.
      return;
    }

    boolean disableStatus = _mirrorDisable;

    try {
      _workspace.getWriteAccess();

      if (_mirrorDisable || (getContainer() == null)) {
        // process request for the sibling
        if (_hasSibling && isOutput() && (getContainer() != null)) {
          TransitionRefinement transContainer = (TransitionRefinement) oldContainer;
          TransitionRefinementPort sibling =
              (TransitionRefinementPort) transContainer.getPort(getName() + "_in");

          sibling._mirrorDisable = true;
          sibling.setContainer(container);
          sibling._mirrorDisable = false;
        }

        // Have already called the super class.
        // This time, process the request.
        super.setContainer(container);
      } else {
        // if this is the input port of a pair of siblings,
        // then forward request to the output port of the pair
        _mirrorDisable = true;

        boolean success = false;
        String portName = getName();

        if (_hasSibling && isInput() && !isOutput()) {
          // we are the input sibling, extract "real" port name
          portName = getName().substring(0, getName().length() - 3);
        }

        if (oldContainer != null) {
          Nameable modal = oldContainer.getContainer();

          if (modal instanceof ModalModel) {
            Port port = ((ModalModel) modal).getPort(portName);

            if (port != null) {
              port.setContainer(null);
              success = true;
            }
          }
        }

        if (!success) {
          super.setContainer(container);
        }
      }
    } finally {
      _mirrorDisable = disableStatus;
      _workspace.doneWriting();
    }
  }