contract MarketPlace is Pausable, MarketPlaceBase {

	// @dev Sanity check that allows us to ensure that we are pointing to the
    //  right auction in our setSaleMarketplaceAddress() call.
    bool public isMarketplace = true;
	
    /// @dev The ERC-165 interface signature for ERC-721.
    ///  Ref: https://github.com/ethereum/EIPs/issues/165
    ///  Ref: https://github.com/ethereum/EIPs/issues/721
    bytes4 constant InterfaceSignature_ERC721 = bytes4(0x9a20483d);

    /// @dev Constructor creates a reference to the NFT ownership contract
    ///  and verifies the owner cut is in the valid range.
    /// @param _nftAddress - address of a deployed contract implementing
    ///  the Nonfungible Interface.
    /// @param _cut - percent cut the owner takes on each sale, must be
    ///  between 0-10,000.
    function MarketPlace(address _nftAddress, uint256 _cut) public {
        require(_cut <= 10000);
        ownerCut = _cut;

        ERC721 candidateContract = ERC721(_nftAddress);
        //require(candidateContract.supportsInterface(InterfaceSignature_ERC721));
        nonFungibleContract = candidateContract;
    }
    function setNFTAddress(address _nftAddress, uint256 _cut) external onlyOwner {
        require(_cut <= 10000);
        ownerCut = _cut;
        ERC721 candidateContract = ERC721(_nftAddress);
        //require(candidateContract.supportsInterface(InterfaceSignature_ERC721));
        nonFungibleContract = candidateContract;
    }
    /// @dev Remove all Ether from the contract, which is the owner's cuts
    ///  as well as any Ether sent directly to the contract address.
    ///  Always transfers to the NFT contract, but can be called either by
    ///  the owner or the NFT contract.
    function withdrawBalance() external {
        address nftAddress = address(nonFungibleContract);

        require(
            msg.sender == owner ||
            msg.sender == nftAddress
        );
        // We are using this boolean method to make sure that even if one fails it will still work
        bool res = nftAddress.send(this.balance);
    }

    /// @dev Creates and begins a new sale.
    /// @param _tokenId - ID of token to sale, sender must be owner.
    /// @param _price - Price of item (in wei)
    /// @param _seller - Seller, if not the message sender
    function createSale(
        uint256 _tokenId,
        uint256 _price,
        address _seller
    )
        external
        whenNotPaused
    {
        // Sanity check that no inputs overflow how many bits we've allocated
        // to store them in the auction struct.
        require(_price == uint256(uint128(_price)));
        
        //require(_owns(msg.sender, _tokenId));
        //_escrow(msg.sender, _tokenId);
        
        require(msg.sender == address(nonFungibleContract));
        _escrow(_seller, _tokenId);
        
        Sale memory sale = Sale(
            _seller,
            uint128(_price),
            uint64(now)
        );
        _addSale(_tokenId, sale);
    }


    

    /// @dev Bids on a sale, completing the sale and transferring
    ///  ownership of the NFT if enough Ether is supplied.
    /// @param _tokenId - ID of token to bid on.
    function bid(uint256 _tokenId)
        external
        payable
        whenNotPaused
    {
        // _bid will throw if the bid or funds transfer fails
       _bid(_tokenId, msg.value); 
       _transfer(msg.sender, _tokenId);
      
    }

    /// @dev Bids on a sale, completing the sale and transferring
    ///  ownership of the NFT if enough Ether is supplied.
    /// @param _tokenId - ID of token to bid on.
    function bidReferral(uint256 _tokenId,uint256 _code)
        external
        payable
        whenNotPaused
    {
        // _bid will throw if the bid or funds transfer fails
        Affiliates storage affiliate = codeToAffiliate[_code];
        
        require(affiliate.affiliate_address!=0&&_code>0);
        _bidReferral(_tokenId, msg.value,affiliate);
        _transfer(msg.sender, _tokenId);

       
    }
    
    /// @dev Cancels an sale that hasn't been won yet.
    ///  Returns the NFT to original owner.
    /// @notice This is a state-modifying function that can
    ///  be called while the contract is paused.
    /// @param _tokenId - ID of token on sale
    function cancelSale(uint256 _tokenId)
        external
    {
        Sale storage sale = tokenIdToSale[_tokenId];
        require(_isOnSale(sale));
        address seller = sale.seller;
        require(msg.sender == seller);
        _cancelSale(_tokenId, seller);
    }

    /// @dev Cancels a sale when the contract is paused.
    ///  Only the owner may do this, and NFTs are returned to
    ///  the seller. This should only be used in emergencies.
    /// @param _tokenId - ID of the NFT on sale to cancel.
    function cancelSaleWhenPaused(uint256 _tokenId)
        whenPaused
        onlyOwner
        external
    {
        Sale storage sale = tokenIdToSale[_tokenId];
        require(_isOnSale(sale));
        _cancelSale(_tokenId, sale.seller);
    }

    /// @dev Returns sale info for an NFT on sale.
    /// @param _tokenId - ID of NFT on sale.
    function getSale(uint256 _tokenId)
        external
        view
        returns
    (
        address seller,
        uint256 price,
        uint256 startedAt
    ) {
        Sale storage sale = tokenIdToSale[_tokenId];
        require(_isOnSale(sale));
        return (
            sale.seller,
            sale.price,
            sale.startedAt
        );
    }

    /// @dev Returns the current price of a sale.
    /// @param _tokenId - ID of the token price we are checking.
    function getCurrentPrice(uint256 _tokenId)
        external
        view
        returns (uint256)
    {
        Sale storage sale = tokenIdToSale[_tokenId];
        require(_isOnSale(sale));
        return sale.price;
    }


    /// @dev Creates and begins a new sale.
    /// @param _code - ID of token to sale, sender must be owner.
    /// @param _commission - percentage of commission for affiliate
    /// @param _pricecut - percentage of sell price cut for buyer
    /// @param _affiliate_address - affiliate address 
    function createAffiliate(
        uint256 _code,
        uint64  _commission,
        uint64  _pricecut,
        address _affiliate_address
    )
        external
        onlyOwner
    {

        Affiliates memory affiliate = Affiliates(
            address(_affiliate_address),
            uint64(_commission),
            uint64(_pricecut)
        );
        _addAffiliate(_code, affiliate);
    }
    
    /// @dev Returns affiliate info for an affiliate code.
    /// @param _code - code for an affiliate.
    function getAffiliate(uint256 _code)
        external
        view
        onlyOwner
        returns
    (
         address affiliate_address,
         uint64 commission,
         uint64 pricecut
    ) {
        Affiliates storage affiliate = codeToAffiliate[_code];
        
        return (
            affiliate.affiliate_address,
            affiliate.commission,
            affiliate.pricecut
        );
    }
     /// @dev Removes affiliate.
    ///  Only the owner may do this
    /// @param _code - code for an affiliate.
    function removeAffiliate(uint256 _code)
        onlyOwner
        external
    {
        _removeAffiliate(_code); 
        
    }
}
/// @title MarketPlace for non-fungible tokens.
/// @notice We omit a fallback function to prevent accidental sends to this contract.
function getSale(uint256 _tokenId)
    external
    view
    returns
(
    address seller,
    uint256 price,
    uint256 startedAt
) {
    Sale storage sale = tokenIdToSale[_tokenId];
    require(_isOnSale(sale));
    return (
        sale.seller,
        sale.price,
        sale.startedAt
    );
}

/// @dev Returns sale info for an NFT on sale.
/// @param _tokenId - ID of NFT on sale.