from backend import *
from basement import *
from kittyaccesscontrol import *

from kittyminting import KittyMinting
# @title CryptoKitties: Collectible, breedable, and oh-so-adorable cats on the Ethereum blockchain.
# @author Axiom Zen (https://www.axiomzen.co)
# @dev The main CryptoKitties contract, keeps track of kittens so they don't wander around and get lost.
class KittyCore(KittyMinting):

    # This is the main CryptoKitties contract. In order to keep our code seperated into logical sections,
    # we've broken it up in two ways. First, we have several seperately-instantiated sibling contracts
    # that handle auctions and our super-top-secret genetic combination algorithm. The auctions are
    # seperate since their logic is somewhat complex and there's always a risk of subtle bugs. By keeping
    # them in their own contracts, we can upgrade them without disrupting the main contract that tracks
    # kitty ownership. The genetic combination algorithm is kept seperate so we can open-source all of
    # the rest of our code without making it _too_ easy for folks to figure out how the genetics work.
    # Don't worry, I'm sure someone will reverse engineer it soon enough!
    #
    # Secondly, we break the core contract into multiple files using inheritence, one for each major
    # facet of functionality of CK. This allows us to keep related code bundled together while still
    # avoiding a single giant file with everything in it. The breakdown is as follows:
    #
    #      - KittyBase: This is where we define the most fundamental code shared throughout the core
    #             functionality. This includes our main data storage, constants and data types, plus
    #             internal functions for managing these items.
    #
    #      - KittyAccessControl: This contract manages the various addresses and constraints for operations
    #             that can be executed only by specific roles. Namely CEO, CFO and COO.
    #
    #      - KittyOwnership: This provides the methods required for basic non-fungible token
    #             transactions, following the draft ERC-721 spec (https:#github.com/ethereum/EIPs/issues/721).
    #
    #      - KittyBreeding: This file contains the methods necessary to breed cats together, including
    #             keeping track of siring offers, and relies on an external genetic combination contract.
    #
    #      - KittyAuctions: Here we have the public methods for auctioning or bidding on cats or siring
    #             services. The actual auction functionality is handled in two sibling contracts (one
    #             for sales and one for siring), while auction creation and bidding is mostly mediated
    #             through this facet of the core contract.
    #
    #      - KittyMinting: This final facet contains the functionality we use for creating new gen0 cats.
    #             We can make up to 5000 "promo" cats that can be given away (especially important when
    #             the community is new), and all others can only be created and then immediately put up
    #             for auction via an algorithmically determined starting price. Regardless of how they
    #             are created, there is a hard limit of 50k gen0 cats. After that, it's all up to the
    #             community to breed, breed, breed!

    # Set in case the core contract is broken and an upgrade is required

    # @notice Creates the main CryptoKitties smart contract instance.
    def __init__(self):
        super(KittyCore, self).__init__()

        self.newContractAddress = address(0)

        # Starts paused.
        self.paused = True

        # the creator of the contract is the initial CEO
        self.ceoAddress = self._loadAddress('ceoAddress')

        # the creator of the contract is also the initial COO
        self.cooAddress = self._loadAddress('ceoAddress')

    def onCreate(self):
        self.paused = True
        # the creator of the contract is the initial CEO
        self.ceoAddress = msg.sender
        # the creator of the contract is also the initial COO
        self.cooAddress = msg.sender
        # start with the mythical kitten 0 - so we don't have generation-0 parent issues
        self._createKitty(0, 0, 0, uint256(-1), address(0))

    
    # @dev Used to mark the smart contract as upgraded, in case there is a serious
    #  breaking bug. This method does nothing but keep track of the new contract and
    #  emit a message indicating that the new address is set. It's up to clients of this
    #  contract to update to the new contract address in that case. (This contract will
    #  be paused indefinitely if such an upgrade takes place.)
    # @param _v2Address new address
    @onlyCEO
    @whenPaused
    def setNewAddress(self, _v2Address: address):
        # See README.md for updgrade plan
        self.newContractAddress = _v2Address
        self.ContractUpgrade(_v2Address)

    # @notice No tipping!
    # @dev Reject all Ether from being sent here, unless it's from one of the
    #  two auction contracts. (Hopefully, we can prevent user accidents.)
    #FIXME
    def __call__(self): # external payable {
        require(msg.sender == address(self.saleAuction) or msg.sender == address(self.siringAuction) )

    # @notice Returns all the relevant information about a specific kitty.
    # @param _id The ID of the kitty of interest.
    def getKitty(self, _id: uint256):
        kit = self.kitties[_id]
        # if this variable is 0 then it's not gestating
        isGestating = (kit.siringWithId != 0)
        isReady = (kit.cooldownEndBlock <= block.number)
        cooldownIndex = uint256(kit.cooldownIndex)
        nextActionAt = uint256(kit.cooldownEndBlock)
        siringWithId = uint256(kit.siringWithId)
        birthTime = uint256(kit.birthTime)
        matronId = uint256(kit.matronId)
        sireId = uint256(kit.sireId)
        generation = uint256(kit.generation)
        genes = kit.genes

        return (
            isGestating,
            isReady,
            cooldownIndex,
            nextActionAt,
            siringWithId,
            birthTime,
            matronId,
            sireId,
            generation,
            genes)

    # @dev Override unpause so it requires all external contract addresses
    #  to be set before contract can be unpaused. Also, we can't have
    #  newContractAddress set either, because then the contract was upgraded.
    # @notice This is public rather than external so we can call super.unpause
    #  without using an expensive CALL.
    @onlyCEO
    @whenPaused
    def unpause(self):
        require(self.saleAuction != address(0))
        require(self.siringAuction != address(0))
        require(self.geneScience != address(0))
        require(self.newContractAddress == address(0))
        # Actually unpause the contract.
        super(KittyCore, self).unpause()

    # @dev Allows the CFO to capture the balance available to the contract.
    @onlyCFO
    def withdrawBalance(self):
        balance = this.balance
        # Subtract all the currently pregnant kittens we have, plus 1 of margin.
        subtractFees = (self.pregnantKitties + 1) * self.autoBirthFee

        if balance > subtractFees:
            self._cfoAddress.send(balance - subtractFees)
