export function fromBondAddition()

in packages/ketcher-core/src/application/editor/actions/bond.ts [50:213]


export function fromBondAddition(
  reStruct: ReStruct,
  bond: Partial<BondAttributes>,
  begin: number | AtomAttributes,
  end: number | AtomAttributes,
  beginAtomPos?: Vec2,
  endAtomPos?: Vec2,
): [Action, number, number, number] {
  const action = new Action();
  const struct = reStruct.molecule;

  const mouseDownNothingAndUpNothing = (
    beginAtomAttr: AtomAttributes,
    endAtomAttr: AtomAttributes,
  ) => {
    const newFragmentId = (
      action.addOp(new FragmentAdd().perform(reStruct)) as FragmentAdd
    ).frid;

    const newBeginAtomId: number = (
      action.addOp(
        new AtomAdd(
          { ...beginAtomAttr, fragment: newFragmentId },
          beginAtomPos,
        ).perform(reStruct),
      ) as AtomAdd
    ).data.aid;

    const newEndAtomId: number = (
      action.addOp(
        new AtomAdd(
          { ...endAtomAttr, fragment: newFragmentId },
          endAtomPos,
        ).perform(reStruct),
      ) as AtomAdd
    ).data.aid;

    return [newBeginAtomId, newEndAtomId] as const;
  };

  const mouseDownNothingAndUpAtom = (
    beginAtomAttr: AtomAttributes,
    endAtomId: number,
  ) => {
    const fragmentId = atomGetAttr(reStruct, endAtomId, 'fragment');

    const newBeginAtomId: number = (
      action.addOp(
        new AtomAdd(
          { ...beginAtomAttr, fragment: fragmentId },
          beginAtomPos,
        ).perform(reStruct),
      ) as AtomAdd
    ).data.aid;

    const endAtom = struct.atoms.get(endAtomId);
    if (
      endAtom &&
      !FunctionalGroup.isAtomInContractedFunctionalGroup(
        endAtom,
        struct.sgroups,
        struct.functionalGroups,
        false,
      )
    ) {
      mergeSgroups(action, reStruct, [newBeginAtomId], endAtomId);
    }
    return [newBeginAtomId, endAtomId] as const;
  };

  const mouseDownAtomAndUpNothing = (
    beginAtomId: number,
    endAtomAttr: AtomAttributes,
  ) => {
    const fragmentId = atomGetAttr(reStruct, beginAtomId, 'fragment');

    const newEndAtomId: number = (
      action.addOp(
        new AtomAdd(
          {
            ...endAtomAttr,
            fragment: fragmentId,
          },
          endAtomPos ?? atomForNewBond(reStruct, begin, bond).pos,
        ).perform(reStruct),
      ) as AtomAdd
    ).data.aid;

    const beginAtom = struct.atoms.get(beginAtomId);
    if (
      beginAtom &&
      !FunctionalGroup.isAtomInContractedFunctionalGroup(
        beginAtom,
        struct.sgroups,
        struct.functionalGroups,
        false,
      )
    ) {
      mergeSgroups(action, reStruct, [newEndAtomId], beginAtomId);
    }

    return [beginAtomId, newEndAtomId] as const;
  };

  let beginAtomId: number, endAtomId: number;

  const startsOnAtom = typeof begin === 'number';
  const endsOnAtom = typeof end === 'number';

  if (!startsOnAtom && !endsOnAtom) {
    [beginAtomId, endAtomId] = mouseDownNothingAndUpNothing(begin, end);
  } else if (!startsOnAtom && endsOnAtom) {
    [beginAtomId, endAtomId] = mouseDownNothingAndUpAtom(begin, end);
  } else if (startsOnAtom && !endsOnAtom) {
    [beginAtomId, endAtomId] = mouseDownAtomAndUpNothing(begin, end);
  } else {
    [beginAtomId, endAtomId] = [begin as number, end as number];

    if (reStruct.sgroups && reStruct.sgroups.size > 0) {
      reStruct.sgroups.forEach((sgroup) => {
        if (sgroup.item?.type && sgroup.item?.type === 'SUP') {
          addAttachmentPointToSuperatom(sgroup, beginAtomId, endAtomId);
        }
      });
    }
  }

  if (atomGetAttr(reStruct, beginAtomId, 'label') === '*') {
    action.addOp(new AtomAttr(beginAtomId, 'label', 'C').perform(reStruct));
  }

  if (atomGetAttr(reStruct, endAtomId, 'label') === '*') {
    action.addOp(new AtomAttr(endAtomId, 'label', 'C').perform(reStruct));
  }

  const newBondId = (
    action.addOp(
      new BondAdd(beginAtomId, endAtomId, bond).perform(reStruct),
    ) as BondAdd
  ).data.bid;
  const newBond = struct.bonds.get(newBondId);
  if (newBond) {
    action.addOp(
      new CalcImplicitH([newBond.begin, newBond.end]).perform(reStruct),
    );
    action.mergeWith(fromBondStereoUpdate(reStruct, newBond));
  }

  action.operations.reverse();

  const mergedFragmentId = mergeFragmentsIfNeeded(
    action,
    reStruct,
    beginAtomId,
    endAtomId,
  );
  if (struct.frags.get(mergedFragmentId || 0)?.stereoAtoms && !bond.stereo) {
    action.addOp(
      new FragmentStereoFlag(mergedFragmentId || 0).perform(reStruct),
    );
  }

  return [action, beginAtomId, endAtomId, newBondId];
}