// You usually wouldn't want to use this, since if the transaction failed, the opening number
// is already burned and gone. But there might be cases where it's not, and you want to retrieve it.
// So I added this function.
//
void OTAgreement::HarvestOpeningNumber(OTPseudonym & theNym)
{
    // since we overrode the parent, we give it a chance to harvest also.
    // IF theNym is the original sender, the opening number will be harvested
    // inside this call.
    //
    OTCronItem::HarvestOpeningNumber(theNym);

    // The Nym is the original recipient. (If Compares true).
    // IN CASES where GetTransactionNum() isn't already burned, we can harvest it here.
    //
    if (theNym.CompareID(GetRecipientUserID()))
    {
        // This function will only "add it back" if it was really there in the first place.
        // (Verifies it is on issued list first, before adding to available list.)
        //
        theNym.ClawbackTransactionNumber(GetServerID(), GetRecipientOpeningNum(), true); //bSave=true
    }
    
    // NOTE: if the message failed (transaction never actually ran) then the sender AND recipient
    // can both reclaim their opening numbers. But if the message SUCCEEDED and the transaction FAILED,
    // then only the recipient can claim his opening number -- the sender's is already burned. So then,
    // what if you mistakenly call this function and pass the sender, when that number is already burned?
    // There's nothing this function can do, because we have no way of telling, from inside here,
    // whether the message succeeded or not, and whether the transaction succeeded or not. Therefore,
    // ==> we MUST rely on the CALLER to know this, and to avoid calling this function in the first place, 
    // if he's sitting on a sender with a failed transaction.
}
// Used for adding transaction numbers back to a Nym, after deciding not to use this agreement
// or failing in trying to use it. Client side.
//
void OTAgreement::HarvestClosingNumbers(OTPseudonym & theNym)
{
    // since we overrode the parent, we give it a chance to harvest also.
    //
    OTCronItem::HarvestClosingNumbers(theNym);

    // The Nym is the original recipient. (If Compares true).
	// FYI, if Nym is the original sender, then the above call will handle him.
	//
    // GetTransactionNum() is burned, but we can harvest the closing
    // numbers from the "Closing" list, which is only for the sender's numbers.
    // Subclasses will have to override this function for recipients, etc.
    //
    if (theNym.CompareID(GetRecipientUserID()))
    {
        const OTString strServerID(GetServerID());
        
        for (int i = 0; i < GetRecipientCountClosingNumbers(); i++)
        {
			if (theNym.VerifyIssuedNum(strServerID, GetRecipientClosingTransactionNoAt(i))) // we only "add it back" if it was really there in the first place.
				theNym.AddTransactionNum(theNym, strServerID, GetRecipientClosingTransactionNoAt(i), 
                                     (i == (GetRecipientCountClosingNumbers()-1) ? true : false)); // bSave=true only on the last iteration.
        }
    }
}
/// See if theNym has rights to remove this item from Cron.
///
bool OTAgreement::CanRemoveItemFromCron(OTPseudonym & theNym)
{
    // You don't just go willy-nilly and remove a cron item from a market unless you check first
    // and make sure the Nym who requested it actually has said number (or a related closing number)
    // signed out to him on his last receipt...
    //
    if (true == OTCronItem::CanRemoveItemFromCron(theNym))
        return true;
    
    const OTString strServerID(GetServerID());

    // Usually the Nym is the originator. (Meaning GetTransactionNum() on this agreement
    // is still verifiable as an issued number on theNum, and belongs to him.) In that case,
    // the above call will discover this, and return true.
    // In other cases, theNym has the right to Remove the item even though theNym didn't originate it.
    // (Like if he is the recipient -- not the sender -- in a payment plan.) We check such things
    // HERE in this function (see below.)
    //
    if (false == theNym.CompareID(GetRecipientUserID()))
    {
        OTLog::Output(0, "OTAgreement::CanRemoveItemFromCron Weird: Nym tried to remove agreement (payment plan), even "
                      "though he apparently wasn't the sender OR recipient.\n");
        return false;
    }
    
    else if (this->GetRecipientCountClosingNumbers() < 2)
    {
        OTLog::vOutput(0, "OTAgreement::CanRemoveItemFromCron Weird: Recipient tried to remove agreement "
                       "(or payment plan); expected 2 closing numbers to be available--that weren't. (Found %d).\n", 
                       this->GetRecipientCountClosingNumbers());
        return false;
    }
    
    if (false == theNym.VerifyIssuedNum(strServerID, this->GetRecipientClosingNum()))
    {
        OTLog::Output(0, "OTAgreement::CanRemoveItemFromCron: Recipient Closing number didn't verify (for removal from cron).\n");
        return false;
    }
    
    // By this point, we KNOW theNym is the sender, and we KNOW there are the proper number of transaction
    // numbers available to close. We also know that this cron item really was on the cron object, since
    // that is where it was looked up from, when this function got called! So I'm pretty sure, at this point,
    // to authorize removal, as long as the transaction num is still issued to theNym (this check here.)
    //
    return theNym.VerifyIssuedNum(strServerID, this->GetRecipientOpeningNum());
    
    // Normally this will be all we need to check. The originator will have the transaction
    // number signed-out to him still, if he is trying to close it. BUT--in some cases, someone
    // who is NOT the originator can cancel. Like in a payment plan, the sender is also the depositor,
    // who would normally be the person cancelling the plan. But technically, the RECIPIENT should
    // also have the ability to cancel that payment plan.  BUT: the transaction number isn't signed
    // out to the RECIPIENT... In THAT case, the below VerifyIssuedNum() won't work! In those cases,
    // expect that the special code will be in the subclasses override of this function. (OTPaymentPlan::CanRemoveItem() etc)
    
    // P.S. If you override this function, MAKE SURE to call the parent (OTCronItem::CanRemoveItem) first, 
    // for the VerifyIssuedNum call above. Only if that fails, do you need to dig deeper...

}
// You usually wouldn't want to use this, since if the transaction failed, the opening number
// is already burned and gone. But there might be cases where it's not, and you want to retrieve it.
// So I added this function.
//
void OTAgreement::HarvestOpeningNumber(OTPseudonym & theNym)
{
    // since we overrode the parent, we give it a chance to harvest also.
    //
    OTCronItem::HarvestOpeningNumber(theNym);

    // The Nym is the original sender. (If Compares true).
    // IN CASES where GetTransactionNum() isn't already burned, we can harvest it here.
    // Subclasses will have to override this function for recipients, etc.
    //
    if (theNym.CompareID(GetRecipientUserID()))
    {
        const OTString strServerID(GetServerID());
		
		if (theNym.VerifyIssuedNum(strServerID, GetRecipientOpeningNum())) // we only "add it back" if it was really there in the first place.
			theNym.AddTransactionNum(theNym, strServerID, GetRecipientOpeningNum(), true); // bSave=true
    }
}
// Used for adding transaction numbers back to a Nym, after deciding not to use this agreement
// or failing in trying to use it. Client side.
//
void OTAgreement::HarvestClosingNumbers(OTPseudonym & theNym)
{
    // Since we overrode the parent, we give it a chance to harvest also.
    // If theNym is the sender, then his closing numbers will be harvested
    // inside here. But what if the transaction was a success? The numbers
    // will still be harvested, since they are still on the sender's issued
    // list, but they should not have been harvested, regardless, since the
    // transaction was a success and the server therefore has them marked as
    // "used." So clearly you cannot just blindly call this function unless
    // you know beforehand whether the message and transaction were a success.
    //
    OTCronItem::HarvestClosingNumbers(theNym);

    // The Nym is the original recipient. (If Compares true).
	// FYI, if Nym is the original sender, then the above call will handle him.
	//
    // GetTransactionNum() is burned, but we can harvest the closing
    // numbers from the "Closing" list, which is only for the sender's numbers.
    // Subclasses will have to override this function for recipients, etc.
    //
    if (theNym.CompareID(GetRecipientUserID()))
    {
        for (int i = 0; i < GetRecipientCountClosingNumbers(); i++)
        {
            // This function will only "add it back" if it was really there in the first place.
            // (Verifies it is on issued list first, before adding to available list.)
            //
            const bool bClawedBack = 
                theNym.ClawbackTransactionNumber(GetServerID(), 
                                                 GetRecipientClosingTransactionNoAt(i), 
                                                 (i == (GetRecipientCountClosingNumbers()-1) ? true : false)); // bSave=true only on the last iteration.
			if (!bClawedBack)
            {
//				OTLog::vError("OTAgreement::HarvestClosingNumbers: Number (%ld) failed as issued. (Thus didn't bother 'adding it back'.)\n",
//							  GetRecipientClosingTransactionNoAt(i));
            }
        }
    }
}
// This is called by OTCronItem::HookRemovalFromCron
// (After calling this method, HookRemovalFromCron then calls onRemovalFromCron.)
//
void OTAgreement::onFinalReceipt(OTCronItem & theOrigCronItem,
                                 const long & lNewTransactionNumber,
                                 OTPseudonym & theOriginator,
                                 OTPseudonym * pRemover)
{    
    OTCron * pCron  = GetCron();
    OT_ASSERT(NULL != pCron);
    
    OTPseudonym * pServerNym = pCron->GetServerNym();
    OT_ASSERT(NULL != pServerNym);
    
    // -------------------------------------------------
    
    // The finalReceipt Item's ATTACHMENT contains the UPDATED Cron Item.
    // (With the SERVER's signature on it!)
    //
    OTString strUpdatedCronItem(*this);
    OTString * pstrAttachment=&strUpdatedCronItem;
    
    const OTString strOrigCronItem(theOrigCronItem);
    // -----------------------------------------------------------------

    
    OTPseudonym theRecipientNym; // Don't use this... use the pointer just below.
    
    // The Nym who is actively requesting to remove a cron item will be passed in as pRemover.
    // However, sometimes there is no Nym... perhaps it just expired and pRemover is NULL.
    // The originating Nym (if different than remover) is loaded up. Otherwise the originator
    // pointer just pointers to *pRemover.
    //
    OTPseudonym * pRecipient = NULL;
    
    if (pServerNym->CompareID(this->GetRecipientUserID()))
    {
        pRecipient = pServerNym; // Just in case the recipient Nym is also the server Nym.
    }
    // *******************************************************
    //
    // If pRemover is NOT NULL, and he has the Recipient's ID...
    // then set the pointer accordingly.
    //
    else if ((NULL != pRemover) && (true == pRemover->CompareID(this->GetRecipientUserID())))
    {
        pRecipient = pRemover; // <======== now both pointers are set (to same Nym). DONE!
    }
    // --------------------------------------------------------------------------------------------------

    if (NULL == pRecipient)
    {
        // GetSenderUserID() should be the same on THIS (updated version of the same cron item) 
        // but for whatever reason, I'm checking the userID on the original version. Sue me.
        //
        const OTIdentifier NYM_ID(this->GetRecipientUserID());
        
        theRecipientNym.SetIdentifier(NYM_ID);  
        
        if (false == theRecipientNym.LoadPublicKey())
        {
            OTString strNymID(NYM_ID);
            OTLog::vError("OTAgreement::onFinalReceipt: Failure loading Recipient's public key:\n%s\n", strNymID.Get());
        }		
        else if (theRecipientNym.VerifyPseudonym() && 
                 theRecipientNym.LoadSignedNymfile(*pServerNym)) // ServerNym here is merely the signer on this file.
        {
            pRecipient = &theRecipientNym; //  <=====
        }
        else 
        {
            OTString strNymID(NYM_ID);
            OTLog::vError("OTAgreement::onFinalReceipt: Failure verifying Recipient's public key or loading signed nymfile: %s\n",
                          strNymID.Get());
        }
    }
    
    // -------------------------------

    // First, we are closing the transaction number ITSELF, of this cron item,
    // as an active issued number on the originating nym. (Changing it to CLOSED.)
    //
    // Second, we're verifying the CLOSING number, and using it as the closing number
    // on the FINAL RECEIPT (with that receipt being "InReferenceTo" this->GetTransactionNum())
    //
    const long lRecipientOpeningNumber = this->GetRecipientOpeningNum();
    const long lRecipientClosingNumber = this->GetRecipientClosingNum();
    
    // -----------------------------------------------------------------------------------
    const long lSenderOpeningNumber = theOrigCronItem.GetTransactionNum();

    const long lSenderClosingNumber = (theOrigCronItem.GetCountClosingNumbers() > 0) ? 
        theOrigCronItem.GetClosingTransactionNoAt(0) : 0; // index 0 is closing number for sender, since GetTransactionNum() is his opening #.
    
    // ----------------------------------
        
    const OTString strServerID(GetServerID());
    
    // -----------------------------------------------------------------
    //
    
    if ((lSenderOpeningNumber > 0) &&
        theOriginator.VerifyIssuedNum(strServerID, lSenderOpeningNumber))
    {
        // The Nym (server side) stores a list of all opening and closing cron #s.
        // So when the number is released from the Nym, we also take it off that list.
        //
        std::set<long> & theIDSet = theOriginator.GetSetOpenCronItems();
        theIDSet.erase(lSenderOpeningNumber);
        
        // the RemoveIssued call means the original transaction# (to find this cron item on cron) is now CLOSED.
        // But the Transaction itself is still OPEN. How? Because the CLOSING number is still signed out.
        // The closing number is also USED, since the NotarizePaymentPlan or NotarizeMarketOffer call, but it
        // remains ISSUED, until the final receipt itself is accepted during a process inbox.
        //
        theOriginator.RemoveIssuedNum(*pServerNym, strServerID, lSenderOpeningNumber, false); //bSave=false
        theOriginator.SaveSignedNymfile(*pServerNym);
        // ------------------------------------
        
        OTPseudonym *   pActualNym = NULL;  // use this. DON'T use theActualNym.
        OTPseudonym     theActualNym; // unused unless it's really not already loaded. (use pActualNym.)
        const OTIdentifier ACTUAL_NYM_ID = GetSenderUserID();
        
        if ( (NULL != pServerNym) && pServerNym->CompareID(ACTUAL_NYM_ID) )
            pActualNym = pServerNym;
        else if (theOriginator.CompareID(ACTUAL_NYM_ID))
            pActualNym = &theOriginator;
        else if ( (NULL != pRemover) && pRemover->CompareID(ACTUAL_NYM_ID) )
            pActualNym = pRemover;
        // --------------------------
        else    // We couldn't find the Nym among those already loaded--so we have to load
        {       // it ourselves (so we can update its NymboxHash value.)
            theActualNym.SetIdentifier(ACTUAL_NYM_ID);
            
            if (false == theActualNym.LoadPublicKey()) // Note: this step may be unnecessary since we are only updating his Nymfile, not his key.
            {
                OTString strNymID(ACTUAL_NYM_ID);
                OTLog::vError("OTAgreement::onFinalReceipt: Failure loading public key for Nym: %s. "
                              "(To update his NymboxHash.) \n", strNymID.Get());
            }
            else if (theActualNym.VerifyPseudonym()	&& // this line may be unnecessary.
                     theActualNym.LoadSignedNymfile(*pServerNym)) // ServerNym here is not theActualNym's identity, but merely the signer on this file.
            {
                OTLog::Output(0, "OTAgreement::onFinalReceipt: Loading actual Nym, since he wasn't already loaded. "
                              "(To update his NymboxHash.)\n");
                pActualNym = &theActualNym; //  <=====
            }
            else
            {
                OTString strNymID(ACTUAL_NYM_ID);
                OTLog::vError("OTAgreement::onFinalReceipt: Failure loading or verifying Actual Nym public key: %s. "
                              "(To update his NymboxHash.)\n", strNymID.Get());
            }
        }
        // -------------
        
        if (false == this->DropFinalReceiptToNymbox(GetSenderUserID(),
                                                    lNewTransactionNumber,
                                                    strOrigCronItem,
                                                    NULL,
                                                    pstrAttachment,
                                                    pActualNym))
        {
            OTLog::Error("OTAgreement::onFinalReceipt: Failure dropping sender final receipt into nymbox.\n");
        }        
    }
    else
    {
        OTLog::Error("OTAgreement::onFinalReceipt: Failure verifying sender's opening number.\n");
    }
    
    // -----------------------------------------------------------------
    
    if ((lSenderClosingNumber > 0) &&
        theOriginator.VerifyIssuedNum(strServerID, lSenderClosingNumber)         
        ) // ---------------------------------------------------------------
    {
        // In this case, I'm passing NULL for pstrNote, since there is no note.
        // (Additional information would normally be stored in the note.) 
        
        if (false == this->DropFinalReceiptToInbox(GetSenderUserID(),
                                          GetSenderAcctID(),
                                          lNewTransactionNumber,
                                          lSenderClosingNumber, // The closing transaction number to put on the receipt.
                                          strOrigCronItem,
                                          NULL, 
                                          pstrAttachment))
            OTLog::Error("OTAgreement::onFinalReceipt: Failure dropping receipt into sender's inbox.\n");

        // This part below doesn't happen until theOriginator ACCEPTS the final receipt (when processing his inbox.)
        //
//      theOriginator.RemoveIssuedNum(strServerID, lSenderClosingNumber, true); //bSave=false
    }
    else
    {
        OTLog::Error("OTAgreement::onFinalReceipt: Failed verifying lSenderClosingNumber=theOrigCronItem.GetClosingTransactionNoAt(0)>0 &&  "
                     "theOriginator.VerifyTransactionNum(lSenderClosingNumber)\n");
    }
    // -----------------------------------------------------------------
    //
    if ((NULL != pRecipient) && (lRecipientOpeningNumber > 0) && 
        pRecipient->VerifyIssuedNum(strServerID, lRecipientOpeningNumber)
        )
    {
        // The Nym (server side) stores a list of all opening and closing cron #s.
        // So when the number is released from the Nym, we also take it off that list.
        //
        std::set<long> & theIDSet = pRecipient->GetSetOpenCronItems();
        theIDSet.erase(lRecipientOpeningNumber);
        
        // the RemoveIssued call means the original transaction# (to find this cron item on cron) is now CLOSED.
        // But the Transaction itself is still OPEN. How? Because the CLOSING number is still signed out.
        // The closing number is also USED, since the NotarizePaymentPlan or NotarizeMarketOffer call, but it
        // remains ISSUED, until the final receipt itself is accepted during a process inbox.
        //
        pRecipient->RemoveIssuedNum(*pServerNym, strServerID, lRecipientOpeningNumber, false); //bSave=false       
//      pRecipient->SaveSignedNymfile(*pServerNym); // Moved lower.
        // -----------------------------------------------------
        
        if (false == this->DropFinalReceiptToNymbox(GetRecipientUserID(),
                                                    lNewTransactionNumber,
                                                    strOrigCronItem,
                                                    NULL,
                                                    pstrAttachment,
                                                    pRecipient)) // NymboxHash is updated here in pRecipient.
        {
            OTLog::Error("OTAgreement::onFinalReceipt: Failure dropping recipient final receipt into nymbox.\n");
        }
        // -----------------------------------------------------

        // Saving both the Removed Issued Number, as well as the new NymboxHash.
        // NOTE: Todo: if the NymboxHash WAS updated (as it should have been) then
        // it was probably saved at that time. Below is therefore a redundant save.
        // Need to fix by making certain objects savable and dirty, and then let them
        // autosave before destruction, IF they are dirty.
        //
        pRecipient->SaveSignedNymfile(*pServerNym); 
    }
    else
    {
        OTLog::Error("OTAgreement::onFinalReceipt: Failed verifying "
                     "lRecipientClosingNumber=this->GetRecipientClosingTransactionNoAt(1)>0 &&  "
                     "pRecipient->VerifyTransactionNum(lRecipientClosingNumber) && VerifyIssuedNum(lRecipientOpeningNumber)\n");
    }
    
    // -----------------------------------------------------------------
    
    if ((NULL != pRecipient) && (lRecipientClosingNumber > 0) && 
        pRecipient->VerifyIssuedNum(strServerID, lRecipientClosingNumber)
        )
    {
        if (false == this->DropFinalReceiptToInbox(GetRecipientUserID(),
                                      GetRecipientAcctID(),
                                      lNewTransactionNumber,
                                      lRecipientClosingNumber, // The closing transaction number to put on the receipt.
                                      strOrigCronItem,
                                      NULL,
                                      pstrAttachment))
            OTLog::Error("OTAgreement::onFinalReceipt: Failure dropping receipt into recipient's inbox.\n");

        // This part below doesn't happen until pRecipient ACCEPTs the final receipt (when processing his inbox.)
        //
//      pRecipient->RemoveIssuedNum(strServerID, lRecipientClosingNumber, true); //bSave=false
    }
    else
    {
        OTLog::Error("OTAgreement::onFinalReceipt: Failed verifying "
                     "lRecipientClosingNumber=this->GetRecipientClosingTransactionNoAt(1)>0 &&  "
                     "pRecipient->VerifyTransactionNum(lRecipientClosingNumber) && VerifyIssuedNum(lRecipientOpeningNumber)\n");
    }
    
    // QUESTION: Won't there be Cron Items that have no asset account at all?
    // In which case, there'd be no need to drop a final receipt, but I don't think
    // that's the case, since you have to use a transaction number to get onto cron
    // in the first place.
    // -----------------------------------------------------------------
}