contract ReferralCircle is Reward, Utils, Pausable {
    
    // Interface link
    ParentInterface public parentInterface;
    
    // Limit of manual synchronization repeats
    uint8 public syncLimit = 5;
    
    // Pet counter
    uint64 public lastPetId = 100;
    
    // Manual sync enabled
    bool public petSyncEnabled = true;
    
    // Setting default parent interface    
    constructor() public {
        parentInterface = ParentInterface(0x115f56742474f108AD3470DDD857C31a3f626c3C);
    }

    // Disable manual synchronization
    function disablePetSync() external onlyOwner {
        petSyncEnabled = false;
    }

    // Enable manual synchronization
    function enablePetSync() external onlyOwner {
        petSyncEnabled = true;
    }
    
    // Make synchronization, available for any sender
    function sync() external whenNotPaused {
        
        // Checking synchronization status
        require(petSyncEnabled);
        
        // Get supply of pets from parent contract
        uint64 petSupply = uint64(parentInterface.totalSupply());
        require(petSupply > lastPetId);

        // Synchronize pets        
        for(uint8 i=0; i < syncLimit; i++)
        {
            lastPetId++;
            
            if(lastPetId > petSupply)
            {
                lastPetId = petSupply;
                break;
            }
            
            addPet(lastPetId);
        }
    }
    
    // Change synchronization limit by owner
    function setSyncLimit(uint8 _limit) external onlyOwner {
        syncLimit = _limit;
    }

    // Function of manual add pet    
    function addPet(uint64 _id) internal {
        (uint64 birthTime, uint256 genes, uint64 breedTimeout, uint16 quality, address owner) = parentInterface.getPet(_id);
        
        uint16 gradeQuality = quality;

        // For first pets - bonus quality in grade calculating
        if(_id < 244)
			gradeQuality = quality - 13777;
			
		// Calculating seats in circle
        uint8 petGrade = getGradeByQuailty(gradeQuality);
        uint8 petSeats = seatsByGrade(petGrade);
        
        // Adding pet into circle
        addPetIntoCircle(_id, petSeats);
        
        // Save reward for each referral level
        applyReward(_id, quality);
    }
    
    // Function for automatic add pet
    function automaticPetAdd(uint256 _price, uint16 _quality, uint64 _id) external {
        require(!petSyncEnabled);
        require(msg.sender == address(parentInterface));
        
        lastPetId = _id;
        
        // Calculating seats in circle
        uint8 petGrade = getGradeByQuailty(_quality);
        uint8 petSeats = seatsByGrade(petGrade);
        
        // Adding pet into circle
        addPetIntoCircle(_id, petSeats);
        
        // Save reward for each referral level
        applyRewardByAmount(_id, _price);
    }
    
    // Function for withdraw reward by pet owner
    function withdrawReward(uint64 _petId) external whenNotPaused {
        
        // Get pet information
        PetInfo memory petInfo = petsInfo[_petId];
        
        // Get owner of pet from pet contract and check it
         (uint64 birthTime, uint256 genes, uint64 breedTimeout, uint16 quality, address petOwner) = parentInterface.getPet(_petId);
        require(petOwner == msg.sender);

        // Transfer reward
        msg.sender.transfer(petInfo.amount);
        
        // Change reward amount in pet information
        petInfo.amount = 0;
        petsInfo[_petId] = petInfo;
    }
    
    // Emergency reward sending by admin
    function sendRewardByAdmin(uint64 _petId) external onlyOwner whenNotPaused {
        
        // Get pet information
        PetInfo memory petInfo = petsInfo[_petId];
        
        // Get owner of pet from pet contract and check it
        (uint64 birthTime, uint256 genes, uint64 breedTimeout, uint16 quality, address petOwner) = parentInterface.getPet(_petId);

        // Transfer reward
        petOwner.transfer(petInfo.amount);
        
        // Change reward amount in pet information
        petInfo.amount = 0;
        petsInfo[_petId] = petInfo;
    }
        
    // Change parent contract
    function setParentAddress(address _address) public whenPaused onlyOwner
    {
        parentInterface = ParentInterface(_address);
    }

    // Just refill    
    function () public payable {}
    
    // Withdraw balance by owner
    function withdrawBalance(uint256 summ) external onlyOwner {
        owner.transfer(summ);
    }
}
// Launch it
function setParentAddress(address _address) public whenPaused onlyOwner
{
    parentInterface = ParentInterface(_address);
}

// Change parent contract