contract SimpleBreedingFactory is Pausable {
    using SafeMath for uint256;

    KittyCoreInterface public kittyCore;
    uint256 public breederReward = 0.001 ether;
    uint256 public commission = 0 wei;
    uint256 public provisionFee;
    mapping (bytes32 => address) public breederToContract;

    event ContractCreated(address contractAddress, address breeder, address owner);
    event ContractRemoved(address contractAddress);

    constructor(address _kittyCoreAddress) Pausable(address(0)) public {
        provisionFee = commission + breederReward;
        kittyCore = KittyCoreInterface(_kittyCoreAddress);
        require(kittyCore.supportsInterface(0x9a20483d), "Invalid contract");
    }

    /**
     * Owner can adjust breeder reward
     * Factory contract does not use breeder reward directly, but sets it to Breeding contracts during contract creation
     * Existing contracts won't be affected by the change
     */
    function setBreederReward(uint256 _breederReward) external onlyOwner {
        require(_breederReward > 0, "Breeder reward must be greater than 0");
        breederReward = _breederReward;
        provisionFee = uint256(commission).add(breederReward);
    }

    /**
     * Owner can set flat fee for contract creation
     */
    function setCommission(uint256 _commission) external onlyOwner {
        commission = _commission;
        provisionFee = uint256(commission).add(breederReward);
    }

    /**
     * Just in case owner can change address of Kitty Core contract
     * Factory contract does not user Kitty Core directly, but sets it to Breeding contracts during contract creation
     * Existing contracts won't be affected by the change
     */
    function setKittyCore(address _kittyCore) external onlyOwner {
        kittyCore = KittyCoreInterface(_kittyCore);
        require(kittyCore.supportsInterface(0x9a20483d), "Invalid contract");
    }

    function () external payable {
        revert("Do not send funds to contract");
    }

    /**
     * Owner can withdraw funds from contracts, if any
     * Contract can only gets funds from contraction creation commission
     */
    function withdraw(uint256 amount) external onlyOwner {
        owner.transfer(amount);
    }

    /**
     * Create new breeding contract for breeder. This function should be called by user during breeder enrollment process.
     * Message value should be greater than breeder reward + commission. Value excess wil be transfered to created contract.
     * Breeder reward amount is transfered to breeder's address so it can start sending transactions
     * Comission amount stays in the contract
     * When contract is created, provisioning script can get address its address from breederToContract mapping
     */
    function createContract(address payable _breederAddress) external payable whenNotPaused {
        require(msg.value >= provisionFee, "Invalid value");

        // owner's address and breeder's address should uniquely identify contract
        // also we need to avoid situation when existing contract address is overwritten by enrolling breeder by same owner twice,
        // or enrolling same breeder by different owner
        bytes32 key = keccak256(abi.encodePacked(_breederAddress, msg.sender));
        require(breederToContract[key] == address(0), "Breeder already enrolled");

        //transfer value excess to new contract, owner can widthdraw later or use it for breeding
        uint256 excess = uint256(msg.value).sub(provisionFee);
        SimpleBreeding newContract = new SimpleBreeding(msg.sender, _breederAddress, address(kittyCore), breederReward);
        breederToContract[key] = address(newContract);
        if(excess > 0) {
            address(newContract).transfer(excess);
        }

        //transfer 1st breeder reward to breeder
        _breederAddress.transfer(breederReward);

        emit ContractCreated(address(newContract), _breederAddress, msg.sender);
    }

    /**
     * In most cases it does not make sense to delete contract's address. If needed it can be done by owner of factory contract.
     * This will not destroy breeding contract, just remove it address from the mapping, so user can deploy new contract for same breeder
     */
    function removeContract(address _breederAddress, address _ownerAddress) external onlyOwner {
        bytes32 key = keccak256(abi.encodePacked(_breederAddress, _ownerAddress));
        address contractAddress = breederToContract[key];
        require(contractAddress != address(0), "Breeder not enrolled");
        delete breederToContract[key];

        emit ContractRemoved(contractAddress);
    }
}
function createContract(address payable _breederAddress) external payable whenNotPaused {
    require(msg.value >= provisionFee, "Invalid value");

    // owner's address and breeder's address should uniquely identify contract
    // also we need to avoid situation when existing contract address is overwritten by enrolling breeder by same owner twice,
    // or enrolling same breeder by different owner
    bytes32 key = keccak256(abi.encodePacked(_breederAddress, msg.sender));
    require(breederToContract[key] == address(0), "Breeder already enrolled");

    //transfer value excess to new contract, owner can widthdraw later or use it for breeding
    uint256 excess = uint256(msg.value).sub(provisionFee);
    SimpleBreeding newContract = new SimpleBreeding(msg.sender, _breederAddress, address(kittyCore), breederReward);
    breederToContract[key] = address(newContract);
    if(excess > 0) {
        address(newContract).transfer(excess);
    }

    //transfer 1st breeder reward to breeder
    _breederAddress.transfer(breederReward);

    emit ContractCreated(address(newContract), _breederAddress, msg.sender);
}

/**
 * Create new breeding contract for breeder. This function should be called by user during breeder enrollment process.
 * Message value should be greater than breeder reward + commission. Value excess wil be transfered to created contract.
 * Breeder reward amount is transfered to breeder's address so it can start sending transactions
 * Comission amount stays in the contract
 * When contract is created, provisioning script can get address its address from breederToContract mapping
 */