// Path: src/main/java/org/tools4j/hoverraft/config/ConsensusConfig.java
// public interface ConsensusConfig {
//     long minElectionTimeoutMillis();
//     long maxElectionTimeoutMillis();
//     long heartbeatTimeoutMillis();
//     Optional<String> ipcMulticastChannel();
//     int serverCount();
//     ServerConfig serverConfig(int index);
//     int sourceCount();
//     SourceConfig sourceConfig(int index);
//     ThreadingMode threadingMode();
// 
//     default ServerConfig serverConfigByIdOrNull(int id) {
//         for (int i = 0; i < serverCount(); i++) {
//             final ServerConfig config = serverConfig(i);
//             if (config.id() == id) {
//                 return config;
//             }
//         }
//         return null;
//     }
// 
//     default SourceConfig sourceConfigByIdOrNull(int id) {
//         for (int i = 0; i < sourceCount(); i++) {
//             final SourceConfig config = sourceConfig(i);
//             if (config.id() == id) {
//                 return config;
//             }
//         }
//         return null;
//     }
// }
// 
// Path: src/main/java/org/tools4j/hoverraft/event/EventHandler.java
// public interface EventHandler {
//     default Transition onTransition(ServerContext serverContext, Transition transition) {return Transition.STEADY;}
//     default Transition onCommand(ServerContext serverContext, Command command) {return Transition.STEADY;}
//     default Transition onVoteRequest(ServerContext serverContext, VoteRequest voteRequest) {return Transition.STEADY;}
//     default Transition onVoteResponse(ServerContext serverContext, VoteResponse voteResponse) {return Transition.STEADY;}
//     default Transition onAppendRequest(ServerContext serverContext, AppendRequest appendRequest) {return Transition.STEADY;}
//     default Transition onAppendResponse(ServerContext serverContext, AppendResponse appendResponse) {return Transition.STEADY;}
//     default Transition onTimeoutNow(ServerContext serverContext, TimeoutNow timeoutNow) {return Transition.STEADY;}
//     default Transition onTimerEvent(ServerContext serverContext, TimerEvent timerEvent) {return Transition.STEADY;};
// }
// 
// Path: src/main/java/org/tools4j/hoverraft/message/AppendRequest.java
// public interface AppendRequest extends Message {
// 
//     int term();
// 
//     AppendRequest term(int term);
// 
//     int leaderId();
// 
//     AppendRequest leaderId(int leaderId);
// 
//     LogKey prevLogKey();
// 
//     long leaderCommit();
// 
//     AppendRequest leaderCommit(long leaderCommit);
// 
//     Sequence<LogEntry> logEntries();
// 
//     default AppendRequest appendLogEntry(final LogEntry logEntry) {
//         logEntries().append(logEntry);
//         return this;
//     }
// 
//     @Override
//     default Transition accept(final ServerContext serverContext, final EventHandler eventHandler) {
//         return eventHandler.onAppendRequest(serverContext, this);
//     }
// }
// 
// Path: src/main/java/org/tools4j/hoverraft/message/VoteRequest.java
// public interface VoteRequest extends Message {
// 
//     int term();
// 
//     VoteRequest term(int term);
// 
//     int candidateId();
// 
//     VoteRequest candidateId(int candidateId);
// 
//     LogKey lastLogKey();
// 
//     @Override
//     default Transition accept(final ServerContext serverContext, final EventHandler eventHandler) {
//         return eventHandler.onVoteRequest(serverContext, this);
//     }
// }
// 
// Path: src/main/java/org/tools4j/hoverraft/message/VoteResponse.java
// public interface VoteResponse extends Message {
// 
//     int term();
// 
//     VoteResponse term(int term);
// 
//     boolean voteGranted();
// 
//     VoteResponse voteGranted(boolean granted);
// 
//     @Override
//     default Transition accept(final ServerContext serverContext, final EventHandler eventHandler) {
//         return eventHandler.onVoteResponse(serverContext, this);
//     }
// }
// 
// Path: src/main/java/org/tools4j/hoverraft/server/ServerContext.java
// public interface ServerContext {
// 
//     ServerConfig serverConfig();
// 
//     ConsensusConfig consensusConfig();
// 
//     Connections<Message> connections();
// 
//     DirectFactory directFactory();
// 
//     StateMachine stateMachine();
// 
//     Timer timer();
// 
//     ResendStrategy resendStrategy();
// 
//     void perform();
// 
//     default int id() {
//         return serverConfig().id();
//     }
// }
// 
// Path: src/main/java/org/tools4j/hoverraft/timer/TimerEvent.java
// public enum TimerEvent implements Event {
//     TIMEOUT;
// 
//     @Override
//     public final Transition accept(final ServerContext serverContext, final EventHandler eventHandler) {
//         return eventHandler.onTimerEvent(serverContext, this);
//     }
// }


import org.tools4j.hoverraft.config.ConsensusConfig;
import org.tools4j.hoverraft.event.EventHandler;
import org.tools4j.hoverraft.message.AppendRequest;
import org.tools4j.hoverraft.message.VoteRequest;
import org.tools4j.hoverraft.message.VoteResponse;
import org.tools4j.hoverraft.server.ServerContext;
import org.tools4j.hoverraft.timer.TimerEvent;
        startNewElection(serverContext);
        return Transition.STEADY;
    }

    private Transition onVoteResponse(final ServerContext serverContext, final VoteResponse voteResponse) {
        if (voteResponse.term() == currentTerm() && voteResponse.voteGranted()) {
            return incVoteCount(serverContext);
        }
        return Transition.STEADY;
    }


    protected Transition onAppendRequest(final ServerContext serverContext, final AppendRequest appendRequest) {
        final int appendRequestTerm = appendRequest.term();
        final int currentTerm = currentTerm();

        if (appendRequestTerm >= currentTerm) {
            serverContext.timer().reset();
            return Transition.TO_FOLLOWER;
        } else {
            return super.onAppendRequest(serverContext, appendRequest);
        }
    }

    private Transition onTimerEvent(final ServerContext serverContext, final TimerEvent timerEvent) {
        startNewElection(serverContext);
        return Transition.STEADY;
    }

    private void startNewElection(final ServerContext serverContext) {
// Path: src/main/java/org/tools4j/hoverraft/config/ConsensusConfig.java
// public interface ConsensusConfig {
//     long minElectionTimeoutMillis();
//     long maxElectionTimeoutMillis();
//     long heartbeatTimeoutMillis();
//     Optional<String> ipcMulticastChannel();
//     int serverCount();
//     ServerConfig serverConfig(int index);
//     int sourceCount();
//     SourceConfig sourceConfig(int index);
//     ThreadingMode threadingMode();
// 
//     default ServerConfig serverConfigByIdOrNull(int id) {
//         for (int i = 0; i < serverCount(); i++) {
//             final ServerConfig config = serverConfig(i);
//             if (config.id() == id) {
//                 return config;
//             }
//         }
//         return null;
//     }
// 
//     default SourceConfig sourceConfigByIdOrNull(int id) {
//         for (int i = 0; i < sourceCount(); i++) {
//             final SourceConfig config = sourceConfig(i);
//             if (config.id() == id) {
//                 return config;
//             }
//         }
//         return null;
//     }
// }
// 
// Path: src/main/java/org/tools4j/hoverraft/event/EventHandler.java
// public interface EventHandler {
//     default Transition onTransition(ServerContext serverContext, Transition transition) {return Transition.STEADY;}
//     default Transition onCommand(ServerContext serverContext, Command command) {return Transition.STEADY;}
//     default Transition onVoteRequest(ServerContext serverContext, VoteRequest voteRequest) {return Transition.STEADY;}
//     default Transition onVoteResponse(ServerContext serverContext, VoteResponse voteResponse) {return Transition.STEADY;}
//     default Transition onAppendRequest(ServerContext serverContext, AppendRequest appendRequest) {return Transition.STEADY;}
//     default Transition onAppendResponse(ServerContext serverContext, AppendResponse appendResponse) {return Transition.STEADY;}
//     default Transition onTimeoutNow(ServerContext serverContext, TimeoutNow timeoutNow) {return Transition.STEADY;}
//     default Transition onTimerEvent(ServerContext serverContext, TimerEvent timerEvent) {return Transition.STEADY;};
// }
// 
// Path: src/main/java/org/tools4j/hoverraft/message/AppendRequest.java
// public interface AppendRequest extends Message {
// 
//     int term();
// 
//     AppendRequest term(int term);
// 
//     int leaderId();
// 
//     AppendRequest leaderId(int leaderId);
// 
//     LogKey prevLogKey();
// 
//     long leaderCommit();
// 
//     AppendRequest leaderCommit(long leaderCommit);
// 
//     Sequence<LogEntry> logEntries();
// 
//     default AppendRequest appendLogEntry(final LogEntry logEntry) {
//         logEntries().append(logEntry);
//         return this;
//     }
// 
//     @Override
//     default Transition accept(final ServerContext serverContext, final EventHandler eventHandler) {
//         return eventHandler.onAppendRequest(serverContext, this);
//     }
// }
// 
// Path: src/main/java/org/tools4j/hoverraft/message/VoteRequest.java
// public interface VoteRequest extends Message {
// 
//     int term();
// 
//     VoteRequest term(int term);
// 
//     int candidateId();
// 
//     VoteRequest candidateId(int candidateId);
// 
//     LogKey lastLogKey();
// 
//     @Override
//     default Transition accept(final ServerContext serverContext, final EventHandler eventHandler) {
//         return eventHandler.onVoteRequest(serverContext, this);
//     }
// }
// 
// Path: src/main/java/org/tools4j/hoverraft/message/VoteResponse.java
// public interface VoteResponse extends Message {
// 
//     int term();
// 
//     VoteResponse term(int term);
// 
//     boolean voteGranted();
// 
//     VoteResponse voteGranted(boolean granted);
// 
//     @Override
//     default Transition accept(final ServerContext serverContext, final EventHandler eventHandler) {
//         return eventHandler.onVoteResponse(serverContext, this);
//     }
// }
// 
// Path: src/main/java/org/tools4j/hoverraft/server/ServerContext.java
// public interface ServerContext {
// 
//     ServerConfig serverConfig();
// 
//     ConsensusConfig consensusConfig();
// 
//     Connections<Message> connections();
// 
//     DirectFactory directFactory();
// 
//     StateMachine stateMachine();
// 
//     Timer timer();
// 
//     ResendStrategy resendStrategy();
// 
//     void perform();
// 
//     default int id() {
//         return serverConfig().id();
//     }
// }
// 
// Path: src/main/java/org/tools4j/hoverraft/timer/TimerEvent.java
// public enum TimerEvent implements Event {
//     TIMEOUT;
// 
//     @Override
//     public final Transition accept(final ServerContext serverContext, final EventHandler eventHandler) {
//         return eventHandler.onTimerEvent(serverContext, this);
//     }
// }


// Path: src/main/java/org/tools4j/hoverraft/state/CandidateState.java
import org.tools4j.hoverraft.config.ConsensusConfig;
import org.tools4j.hoverraft.event.EventHandler;
import org.tools4j.hoverraft.message.AppendRequest;
import org.tools4j.hoverraft.message.VoteRequest;
import org.tools4j.hoverraft.message.VoteResponse;
import org.tools4j.hoverraft.server.ServerContext;
import org.tools4j.hoverraft.timer.TimerEvent;

        startNewElection(serverContext);
        return Transition.STEADY;
    }

    private Transition onVoteResponse(final ServerContext serverContext, final VoteResponse voteResponse) {
        if (voteResponse.term() == currentTerm() && voteResponse.voteGranted()) {
            return incVoteCount(serverContext);
        }
        return Transition.STEADY;
    }


    protected Transition onAppendRequest(final ServerContext serverContext, final AppendRequest appendRequest) {
        final int appendRequestTerm = appendRequest.term();
        final int currentTerm = currentTerm();

        if (appendRequestTerm >= currentTerm) {
            serverContext.timer().reset();
            return Transition.TO_FOLLOWER;
        } else {
            return super.onAppendRequest(serverContext, appendRequest);
        }
    }

    private Transition onTimerEvent(final ServerContext serverContext, final TimerEvent timerEvent) {
        startNewElection(serverContext);
        return Transition.STEADY;
    }

    private void startNewElection(final ServerContext serverContext) {
        final ConsensusConfig config = serverContext.consensusConfig();