/*******************************************************************************************
* @Name         UpdateContactNumberBatch 
* @Author       FirstName LastName <author@email.com>
* @Date         09/20/2017
* @Group        Apex Batches
* @Description  This batch class updates a custom field in account with the number of contact  
*				under it
*******************************************************************************************/
/* MODIFICATION LOG
* Version          Developer          Date               Description
*-------------------------------------------------------------------------------------------
*  1.0              Firstname      09/20/2017          Initial Creation                                                      
*******************************************************************************************/
global class UpdateContactNumberBatch implements Database.Batchable<sObject> {
    /**************************************************************************************
    * @Description  This method gets all the accounts that needs to be processed and returns
    *               a QueryLocator
    * @Param		bc - BatchableContext
    * @Return       Database.QueryLocator - QueryLocator to the queried records 
    **************************************************************************************/ 
    global Database.QueryLocator start(Database.BatchableContext bc) {
        return Database.getQueryLocator([SELECT Id,Contact_Count__c FROM Account]);
    }

    /**************************************************************************************
    * @Description  This method executes aggregate query on contact object and updates
    *               corresponding account with number of contacts under it
    * @Param		bc - BatchableContext
    * @Param		accountList - Chunk of accounts that needs to be processed
    * @Return       NA
    **************************************************************************************/ 
    global void execute(Database.BatchableContext bc, List<Account> accountList){
        //Getting all Ids from list;
        Set<Id> allAccIdSet = new Map<Id, Account>(accountList).keyset();
        List<Account> accUpdateList = new List<Account>();
        //Aggregating contacts by accounts
        for(AggregateResult aggResult: [SELECT AccountId, Count(Id) 
                                            FROM Contact 
                                            WHERE AccountId =: accountList 
                                            GROUP BY AccountId]) {
            Account acc = new Account(Id = (Id)aggResult.get('AccountId'));
            acc.Contact_Count__c = (Integer)aggResult.get('expr0');        
            accUpdateList.add(acc);
            allAccIdSet.remove(acc.Id);                       
        }
        for(Id accId: allAccIdSet) {
            accUpdateList.add(new Account(Id = accId, Contact_Count__c = 0));
        }
        update accUpdateList;
    }  

    /**************************************************************************************
    * @Description  This method executes any post-processing operations
    * @Param		bc - BatchableContext
    * @Return       NA
    **************************************************************************************/
    global void finish(Database.BatchableContext bc){
        // execute any post-processing operations
    }    
}