contract DutchAuction is NFTAuctionBase, EtherbotsPrivileges {

    // The ERC-165 interface signature for ERC-721.
    bytes4 constant InterfaceSignature_ERC721 = bytes4(0xda671b9b);
 
    function DutchAuction(address _nftAddress, uint256 _fee) public {
        require(_fee <= 10000);
        ownerCut = _fee;

        ERC721AllImplementations candidateContract = ERC721AllImplementations(_nftAddress);
        require(candidateContract.supportsInterface(InterfaceSignature_ERC721));
        nftContract = candidateContract;
    }

    // Remove all ether from the contract. This will be marketplace fees.
    // Transfers to the NFT contract. 
    // Can be called by owner or NFT contract.

    function withdrawBalance() external {
        address nftAddress = address(nftContract);

        require(msg.sender == owner || msg.sender == nftAddress);

        nftAddress.transfer(this.balance);
    }

    event PrintEvent(string, address, uint);

    // Creates an auction and lists it.
    function createAuction( uint256 _partId, uint256 _startPrice, uint256 _endPrice, uint256 _duration, address _seller ) external whenNotPaused {
        // Sanity check that no inputs overflow how many bits we've allocated
        // to store them in the auction struct.
        require(_startPrice == uint256(uint128(_startPrice)));
        require(_endPrice == uint256(uint128(_endPrice)));
        require(_duration == uint256(uint64(_duration)));
        require(_startPrice >= _endPrice);

        require(msg.sender == address(nftContract));
        _escrow(_seller, _partId);
        Auction memory auction = Auction(
            _seller,
            uint128(_startPrice),
            uint128(_endPrice),
            uint64(_duration),
            uint64(now) //seconds uint 
        );
        PrintEvent("Auction Start", 0x0, auction.start);
        _newAuction(_partId, auction);
    }


    // SCRAPYARD PRICING LOGIC

    uint8 constant LAST_CONSIDERED = 5;
    uint8 public scrapCounter = 0;
    uint[5] public lastScrapPrices;
    
    // Purchases an open auction
    // Will transfer ownership if successful.
    
    function purchase(uint256 _partId) external payable whenNotPaused {
        address seller = tokenIdToAuction[_partId].seller;

        // _purchase will throw if the purchase or funds transfer fails
        uint256 price = _purchase(_partId, msg.value);
        _transfer(msg.sender, _partId);
        
        // If the seller is the scrapyard, track price information.
        if (seller == address(nftContract)) {

            lastScrapPrices[scrapCounter] = price;
            if (scrapCounter == LAST_CONSIDERED - 1) {
                scrapCounter = 0;
            } else {
                scrapCounter++;
            }
        }
    }

    function averageScrapPrice() public view returns (uint) {
        uint sum = 0;
        for (uint8 i = 0; i < LAST_CONSIDERED; i++) {
            sum += lastScrapPrices[i];
        }
        return sum / LAST_CONSIDERED;
    }

    // Allows a user to cancel an auction before it's resolved.
    // Returns the part to the seller.

    function cancelAuction(uint256 _partId) external {
        Auction storage auction = tokenIdToAuction[_partId];
        require(_isActiveAuction(auction));
        address seller = auction.seller;
        require(msg.sender == seller);
        _cancelAuction(_partId, seller);
    }

    // returns the current price of the auction of a token with id _partId
    function getCurrentPrice(uint256 _partId) external view returns (uint256) {
        Auction storage auction = tokenIdToAuction[_partId];
        require(_isActiveAuction(auction));
        return _currentPrice(auction);
    }

    //  Returns the details of an auction from its _partId.
    function getAuction(uint256 _partId) external view returns ( address seller, uint256 startPrice, uint256 endPrice, uint256 duration, uint256 startedAt ) {
        Auction storage auction = tokenIdToAuction[_partId];
        require(_isActiveAuction(auction));
        return ( auction.seller, auction.startPrice, auction.endPrice, auction.duration, auction.start);
    }

    // Allows owner to cancel an auction.
    // ONLY able to be used when contract is paused,
    // in the case of emergencies.
    // Parts returned to seller as it's equivalent to them 
    // calling cancel.
    function cancelAuctionWhenPaused(uint256 _partId) whenPaused onlyOwner external {
        Auction storage auction = tokenIdToAuction[_partId];
        require(_isActiveAuction(auction));
        _cancelAuction(_partId, auction.seller);
    }
}
// Clock auction for NFTParts.
// Only timed when pricing is dynamic (i.e. startPrice != endPrice).
// Else, this becomes an infinite duration statically priced sale,
// resolving when succesfully purchase for or cancelled.
function getAuction(uint256 _partId) external view returns ( address seller, uint256 startPrice, uint256 endPrice, uint256 duration, uint256 startedAt ) {
    Auction storage auction = tokenIdToAuction[_partId];
    require(_isActiveAuction(auction));
    return ( auction.seller, auction.startPrice, auction.endPrice, auction.duration, auction.start);
}

//  Returns the details of an auction from its _partId.