class Proposer (object):
    _sync = {}
    _async = ['set_multi', 'prepare', 'promise', 'set_proposal']
    _ref = ['set_multi']
    _parallel = []
    

    def __init__(self,  quorum_size):
        self.quorum_size = quorum_size
        self.proposed_value       = None
        self.last_accepted_id     = None
        self.next_proposal_number = 1
    #async, ref
    def set_multi(self, list_acceptors):
        self.list_acceptors = list_acceptors
        self.amulti = AMulti(self.list_acceptors)
        self.smulti = SMulti(self.list_acceptors, self._atom)
    def set_proposal(self, value):
        '''
        Sets the proposal value for this node if this node is not already aware of
        another proposal having already been accepted. 
        '''
        if self.proposed_value is None:
            self.proposed_value = value


    def prepare(self):
        '''
        Sends a prepare request to all Acceptors as the first step in attempting to
        acquire leadership of the Paxos instance. 
        '''
        self.promises_rcvd = set()
        self.proposal_id   = ProposalID(self.next_proposal_number, self.id)
        print 'holaa', self.proposal_id
        self.next_proposal_number += 1
        #multi to all acceptors!! 
        result = self.smulti.onPrepare(self.proxy, self.proposal_id)
        self.promise(result)
    
    def promise(self, infoAcceptors):
        ''' 
        Called when a Promise message is received from an Acceptor
        '''
        for a in infoAcceptors:
            # Ignore the message if it's for an old proposal or we have already received
            # a response from this Acceptor
            if a[1] != self.proposal_id or a[0] in self.promises_rcvd:
                None
            else:
                self.promises_rcvd.add( a[0] )
                
                if a[2] > self.last_accepted_id:
                    self.last_accepted_id = a[2]
                    # If the Acceptor has already accepted a value, we MUST set our proposal
                    # to that value.
                    if a[2] is not None:
                        self.proposed_value = a[3]
        
                if len(self.promises_rcvd) > self.quorum_size/2:
                    if self.proposed_value is not None:
                        self.amulti.accept(self.id, self.proposal_id, self.proposed_value)
                        break