// Path: cip-core/src/main/java/com/digitalpetri/enip/cip/epath/EPath.java
// public abstract class EPath {
// 
//     private final EPathSegment[] segments;
// 
//     protected EPath(EPathSegment[] segments) {
//         this.segments = segments;
//     }
// 
//     public EPathSegment[] getSegments() {
//         return segments;
//     }
// 
//     public abstract boolean isPadded();
// 
//     public static ByteBuf encode(EPath path, ByteBuf buffer) {
//         // length placeholder...
//         int lengthStartIndex = buffer.writerIndex();
//         buffer.writeByte(0);
// 
//         // encode the path segments...
//         int dataStartIndex = buffer.writerIndex();
// 
//         for (EPathSegment segment : path.getSegments()) {
//             if (segment instanceof LogicalSegment) {
//                 LogicalSegment.encode((LogicalSegment) segment, path.isPadded(), buffer);
//             } else if (segment instanceof PortSegment) {
//                 PortSegment.encode((PortSegment) segment, path.isPadded(), buffer);
//             } else if (segment instanceof DataSegment) {
//                 DataSegment.encode((DataSegment) segment, path.isPadded(), buffer);
//             } else {
//                 throw new RuntimeException("no encoder for " + segment.getClass().getSimpleName());
//             }
//         }
// 
//         // go back and update the length
//         int bytesWritten = buffer.writerIndex() - dataStartIndex;
//         int wordsWritten = bytesWritten / 2;
//         buffer.markWriterIndex();
//         buffer.writerIndex(lengthStartIndex);
//         buffer.writeByte(wordsWritten);
//         buffer.resetWriterIndex();
// 
//         return buffer;
//     }
// 
//     public static final class PaddedEPath extends EPath {
// 
//         public PaddedEPath(List<EPathSegment> segments) {
//             this(segments.toArray(new EPathSegment[segments.size()]));
//         }
// 
//         public PaddedEPath(EPathSegment... segments) {
//             super(segments);
//         }
// 
//         @Override
//         public boolean isPadded() {
//             return true;
//         }
// 
//         public PaddedEPath append(PaddedEPath other) {
//             int aLen = getSegments().length;
//             int bLen = other.getSegments().length;
// 
//             EPathSegment[] newSegments = new EPathSegment[aLen + bLen];
// 
//             System.arraycopy(getSegments(), 0, newSegments, 0, aLen);
//             System.arraycopy(other.getSegments(), 0, newSegments, aLen, bLen);
// 
//             return new PaddedEPath(newSegments);
//         }
// 
//     }
// 
// }
// 
// Path: cip-core/src/main/java/com/digitalpetri/enip/util/TimeoutCalculator.java
// public class TimeoutCalculator {
// 
//     private static final int MIN_TIMEOUT = 1;
//     private static final int MAX_TIMEOUT = 8355840;
// 
//     public static int calculateTimeoutBytes(Duration timeout) {
//         int desiredTimeout = (int) timeout.toMillis();
// 
//         if (desiredTimeout < MIN_TIMEOUT) desiredTimeout = MIN_TIMEOUT;
//         if (desiredTimeout > MAX_TIMEOUT) desiredTimeout = MAX_TIMEOUT;
// 
//         boolean precisionLost = false;
//         int shifts = 0;
//         int multiplier = desiredTimeout;
// 
//         while (multiplier > 255) {
//             precisionLost |= (multiplier & 1) == 1;
//             multiplier >>= 1;
//             shifts += 1;
//         }
// 
//         if (precisionLost) {
//             multiplier += 1;
//             if (multiplier > 255) {
//                 multiplier >>= 1;
//                 shifts += 1;
//             }
//         }
// 
//         assert (shifts <= 15);
// 
//         int tick = (int) Math.pow(2, shifts);
// 
//         assert (tick >= 1 && tick <= 32768);
//         assert (multiplier >= 1 && multiplier <= 255);
// 
//         return shifts << 8 | multiplier;
//     }
// 
// }


import java.time.Duration;
import java.util.concurrent.TimeUnit;
import com.digitalpetri.enip.cip.epath.EPath;
import com.digitalpetri.enip.util.TimeoutCalculator;
import io.netty.buffer.ByteBuf;

    public int getConnectionTimeoutMultiplier() {
        return connectionTimeoutMultiplier;
    }

    public EPath.PaddedEPath getConnectionPath() {
        return connectionPath;
    }

    public Duration getO2tRpi() {
        return o2tRpi;
    }

    public NetworkConnectionParameters getO2tParameters() {
        return o2tParameters;
    }

    public Duration getT2oRpi() {
        return t2oRpi;
    }

    public NetworkConnectionParameters getT2oParameters() {
        return t2oParameters;
    }

    public int getTransportClassAndTrigger() {
        return transportClassAndTrigger;
    }

    public static ByteBuf encode(ForwardOpenRequest request, ByteBuf buffer) {
// Path: cip-core/src/main/java/com/digitalpetri/enip/cip/epath/EPath.java
// public abstract class EPath {
// 
//     private final EPathSegment[] segments;
// 
//     protected EPath(EPathSegment[] segments) {
//         this.segments = segments;
//     }
// 
//     public EPathSegment[] getSegments() {
//         return segments;
//     }
// 
//     public abstract boolean isPadded();
// 
//     public static ByteBuf encode(EPath path, ByteBuf buffer) {
//         // length placeholder...
//         int lengthStartIndex = buffer.writerIndex();
//         buffer.writeByte(0);
// 
//         // encode the path segments...
//         int dataStartIndex = buffer.writerIndex();
// 
//         for (EPathSegment segment : path.getSegments()) {
//             if (segment instanceof LogicalSegment) {
//                 LogicalSegment.encode((LogicalSegment) segment, path.isPadded(), buffer);
//             } else if (segment instanceof PortSegment) {
//                 PortSegment.encode((PortSegment) segment, path.isPadded(), buffer);
//             } else if (segment instanceof DataSegment) {
//                 DataSegment.encode((DataSegment) segment, path.isPadded(), buffer);
//             } else {
//                 throw new RuntimeException("no encoder for " + segment.getClass().getSimpleName());
//             }
//         }
// 
//         // go back and update the length
//         int bytesWritten = buffer.writerIndex() - dataStartIndex;
//         int wordsWritten = bytesWritten / 2;
//         buffer.markWriterIndex();
//         buffer.writerIndex(lengthStartIndex);
//         buffer.writeByte(wordsWritten);
//         buffer.resetWriterIndex();
// 
//         return buffer;
//     }
// 
//     public static final class PaddedEPath extends EPath {
// 
//         public PaddedEPath(List<EPathSegment> segments) {
//             this(segments.toArray(new EPathSegment[segments.size()]));
//         }
// 
//         public PaddedEPath(EPathSegment... segments) {
//             super(segments);
//         }
// 
//         @Override
//         public boolean isPadded() {
//             return true;
//         }
// 
//         public PaddedEPath append(PaddedEPath other) {
//             int aLen = getSegments().length;
//             int bLen = other.getSegments().length;
// 
//             EPathSegment[] newSegments = new EPathSegment[aLen + bLen];
// 
//             System.arraycopy(getSegments(), 0, newSegments, 0, aLen);
//             System.arraycopy(other.getSegments(), 0, newSegments, aLen, bLen);
// 
//             return new PaddedEPath(newSegments);
//         }
// 
//     }
// 
// }
// 
// Path: cip-core/src/main/java/com/digitalpetri/enip/util/TimeoutCalculator.java
// public class TimeoutCalculator {
// 
//     private static final int MIN_TIMEOUT = 1;
//     private static final int MAX_TIMEOUT = 8355840;
// 
//     public static int calculateTimeoutBytes(Duration timeout) {
//         int desiredTimeout = (int) timeout.toMillis();
// 
//         if (desiredTimeout < MIN_TIMEOUT) desiredTimeout = MIN_TIMEOUT;
//         if (desiredTimeout > MAX_TIMEOUT) desiredTimeout = MAX_TIMEOUT;
// 
//         boolean precisionLost = false;
//         int shifts = 0;
//         int multiplier = desiredTimeout;
// 
//         while (multiplier > 255) {
//             precisionLost |= (multiplier & 1) == 1;
//             multiplier >>= 1;
//             shifts += 1;
//         }
// 
//         if (precisionLost) {
//             multiplier += 1;
//             if (multiplier > 255) {
//                 multiplier >>= 1;
//                 shifts += 1;
//             }
//         }
// 
//         assert (shifts <= 15);
// 
//         int tick = (int) Math.pow(2, shifts);
// 
//         assert (tick >= 1 && tick <= 32768);
//         assert (multiplier >= 1 && multiplier <= 255);
// 
//         return shifts << 8 | multiplier;
//     }
// 
// }


// Path: cip-core/src/main/java/com/digitalpetri/enip/cip/structs/ForwardOpenRequest.java
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import com.digitalpetri.enip.cip.epath.EPath;
import com.digitalpetri.enip.util.TimeoutCalculator;
import io.netty.buffer.ByteBuf;


    public int getConnectionTimeoutMultiplier() {
        return connectionTimeoutMultiplier;
    }

    public EPath.PaddedEPath getConnectionPath() {
        return connectionPath;
    }

    public Duration getO2tRpi() {
        return o2tRpi;
    }

    public NetworkConnectionParameters getO2tParameters() {
        return o2tParameters;
    }

    public Duration getT2oRpi() {
        return t2oRpi;
    }

    public NetworkConnectionParameters getT2oParameters() {
        return t2oParameters;
    }

    public int getTransportClassAndTrigger() {
        return transportClassAndTrigger;
    }

    public static ByteBuf encode(ForwardOpenRequest request, ByteBuf buffer) {
        int priorityAndTimeoutBytes = TimeoutCalculator.calculateTimeoutBytes(request.timeout);