/* Function   : registerCommand 
 * Arguments  : command - id to register
 * Description: register command with given id in daemon core
 */
void
ReplicatorStateMachine::registerCommand(int command)
{
    daemonCore->Register_Command(
        command, const_cast<char*>( utilToString( command ) ),
        (CommandHandlercpp) &ReplicatorStateMachine::commandHandler,
        "commandHandler", this, DAEMON );
}
// sending command to remote replication daemon; specified command function
// allows to specify which data is to be sent to the remote daemon
void
AbstractReplicatorStateMachine::sendCommand(
    int command, char* daemonSinfulString, CommandFunction function )
{
    dprintf( D_ALWAYS, "AbstractReplicatorStateMachine::sendCommand %s to %s\n",
               utilToString( command ), daemonSinfulString );
    Daemon  daemon( DT_ANY, daemonSinfulString );
    ReliSock socket;

    // no retries after 'm_connectionTimeout' seconds of unsuccessful connection
    socket.timeout( m_connectionTimeout );
    socket.doNotEnforceMinimalCONNECT_TIMEOUT( );

    if( ! socket.connect( daemonSinfulString, 0, false ) ) {
        dprintf( D_ALWAYS, "AbstractReplicatorStateMachine::sendCommand "
                            "unable to connect to %s\n",
                   daemonSinfulString );
		socket.close( );

        return ;
    }
// General actions for any command sending
    if( ! daemon.startCommand( command, &socket, m_connectionTimeout ) ) {
        dprintf( D_ALWAYS, "AbstractReplicatorStateMachine::sendCommand "
                            "cannot start command %s to %s\n",
                   utilToString( command ), daemonSinfulString );
		socket.close( );

        return ;
    }

    char const* sinfulString = daemonCore->InfoCommandSinfulString();
    if(! socket.put( sinfulString )/* || ! socket.end_of_message( )*/) {
        dprintf( D_ALWAYS, "AbstractReplicatorStateMachine::sendCommand "
                            "unable to code the local sinful string or eom%s\n",
                   sinfulString );
		socket.close( );

        return ;
    }
    else {
        dprintf( D_FULLDEBUG, "AbstractReplicatorStateMachine::sendCommand "
                              "local sinful string coded successfully\n" );
    }
// End of General actions for any command sending

// Command-specific actions
	if( ! ((*this).*(function))( socket ) ) {
    	socket.close( );

		return ;
	}
// End of Command-specific actions
	if( ! socket.end_of_message( ) ) {
		socket.close( );
       	dprintf( D_ALWAYS, "AbstractReplicatorStateMachine::sendCommand "
                            "unable to code the end of message\n" );
       	return ;
   	}

	socket.close( );
   	dprintf( D_ALWAYS, "AbstractReplicatorStateMachine::sendCommand "
                       "%s command sent to %s successfully\n",
             utilToString( command ), daemonSinfulString );
}
/* Function   : commandHandler 
 * Arguments  : command - command to handle request
 * 				stream  - socket, through which the data for the command
						  arrived
 * Description: handles various commands sent to this replication daemon
 */
void
ReplicatorStateMachine::commandHandler( int command, Stream* stream )
{
    char* daemonSinfulString = 0;
   
    stream->decode( );

    if( ! stream->code( daemonSinfulString ) 
		/*|| ! stream->end_of_message( )*/ ) 
	{
        dprintf( D_NETWORK, "ReplicatorStateMachine::commandHandler "
                            "cannot read remote daemon sinful string for %s\n",
                 utilToString( command ) );
	    free( daemonSinfulString );

		return;
    }

    dprintf( /*D_COMMAND*/
             D_FULLDEBUG, "ReplicatorStateMachine::commandHandler received "
			"command %s from %s\n", utilToString(command), daemonSinfulString );
    switch( command ) {
        case REPLICATION_LEADER_VERSION:
            onLeaderVersion( stream );
            
            break;
        case REPLICATION_TRANSFER_FILE:
            onTransferFile( daemonSinfulString );
            
            break;
        case REPLICATION_SOLICIT_VERSION:
            onSolicitVersion( daemonSinfulString );

            break;
        case REPLICATION_SOLICIT_VERSION_REPLY:
            onSolicitVersionReply( stream );

            break;
        case REPLICATION_NEWLY_JOINED_VERSION:
            onNewlyJoinedVersion( stream );
            
            break;
        case REPLICATION_GIVING_UP_VERSION:
            onGivingUpVersion( stream );
            
            break;
        case HAD_BEFORE_PASSIVE_STATE:
            beforePassiveStateHandler();

            break;
        case HAD_AFTER_ELECTION_STATE:
            afterElectionStateHandler();

            break;
        case HAD_AFTER_LEADER_STATE:
            afterLeaderStateHandler();

            break;
        case HAD_IN_LEADER_STATE:
            inLeaderStateHandler();

            break;
    }
	free( daemonSinfulString );

    if( ! stream->end_of_message( ) ) {
        dprintf( D_NETWORK, "ReplicatorStateMachine::commandHandler "
                            "cannot read the end of the message\n" );
    }
}