package lsr.service;

import lsr.paxos.replica.Replica;
import lsr.paxos.replica.SnapshotListener;

/**
 * This interface represents state machine with possibility to save current
 * state (snapshot). It is used by {@link Replica} to execute commands from
 * clients, for making snapshots, and also to update the state from other
 * snapshot (received from other replica).
 * <p>
 * All methods are called from the same thread, so it is not necessary to
 * synchronize them.
 * <p>
 * After creating new snapshot by this <code>Service</code>, all
 * <code>SnapshotListener</code> should be called. They shouldn't be called
 * after updating state machine from snapshot (see <code>updateToSnapshot</code>
 * for more details).
 * <p>
 * This interface provides two methods used for notifying that the snapshot
 * should be made. First is only asking for snapshot, which can be ignored if
 * for service it is bad moment for creating snapshot. Second methods is called
 * when logs are much bigger than estimated size of next snapshot.
 * <p>
 * For some methods, also request sequential number is provided. It is used to
 * determine when the snapshot by <code>Service</code> was made. The number of
 * created snapshot is last executed request.
 * 
 * @see Replica
 * @see SnapshotListener
 */
public interface Service {

    /**
     * Informs the service that the recovery process has been finished, i.e.
     * that the service is at least at the state later than by crashing.
     * 
     * Please notice, for some crash-recovery approaches this can mean that the
     * service is a lot further than by crash.
     */
    void recoveryFinished();

    /**
     * Executes one command from client on this state machine. This method will
     * be called by {@link Replica} in proper order. The number of request is
     * needed only for snapshot mechanism.
     * 
     * @param value - value of instance to execute on this service
     * @param executeSeqNo - ordinal number of this requests
     * @return generated reply which will be sent to client
     */
    byte[] execute(byte[] value, int executeSeqNo);

    /**
     * Notifies service that it would be good to create snapshot now.
     * <code>Service</code> should check whether this is good moment, and create
     * snapshot if needed.
     * 
     * @param lastSnapshotNextRequestSeqNo - specified last known snapshot; is
     *            used to determine duplicate calling of method
     */
    void askForSnapshot(int lastSnapshotNextRequestSeqNo);

    /**
     * Notifies service that size of logs are much bigger than estimated size of
     * snapshot. Not implementing this method may cause slowing down the
     * algorithm, especially in case of network problems and also recovery in
     * case of crash can take more time.
     * 
     * @param lastSnapshotNextRequestSeqNo - specified last known snapshot; is
     *            used to determine duplicate calling of method
     */
    void forceSnapshot(int lastSnapshotNextRequestSeqNo);

    /**
     * Registers new listener which will be called every time new snapshot is
     * created by this <code>Service</code>.
     * 
     * @param listener - the listener to register
     */
    void addSnapshotListener(SnapshotListener listener);

    /**
     * Unregisters the listener from this service. It will not be called when
     * new snapshot is created by this <code>Service</code>.
     * 
     * @param listener - the listener to unregister
     */
    void removeSnapshotListener(SnapshotListener listener);

    /**
     * Restores the service state from snapshot
     * 
     * @param nextRequestSeqNo (last executed request sequential number + 1)
     *            before snapshot was made (i.e. next request to be executed no)
     * @param snapshot the snapshot itself
     */
    void updateToSnapshot(int nextRequestSeqNo, byte[] snapshot);
}