contract AuctionHouse is CardOwnership {
    
    event AuctionStarted(uint256 tokenId, uint128 startPrice, uint128 finalPrice, uint256 timestamp);
    event AuctionEnded(address winner, uint256 tokenId);
    struct Auction {
        address seller;
        uint128 startPrice;
        uint128 finalPrice;
        uint256 timestamp;
    }
    mapping (uint256 => Auction) public tokenIdToAuction;
	// max auction time for token is 7 days..
      
    function _isAuctionAble(uint256 _timestamp) internal view returns(bool)
    {
       return (_timestamp + constantTime >= now);
    }
  
    function createAuction(
        uint256 _tokenId,
        uint128 _startPrice,
        uint128 _finalPrice
    ) external cardOwner(_tokenId){
	    require(!_isAuctionAble(tokenIdToAuction[_tokenId].timestamp));
        // then approve for this
        approve( this, _tokenId);
         
        Auction memory auction = Auction(
            msg.sender,
            _startPrice,
            _finalPrice,
            now
        );
        
        tokenIdToAuction[_tokenId] = auction;
        AuctionStarted(_tokenId, _startPrice, _finalPrice, now);
    }
	
    function buyout(uint256 _tokenId) external payable {
        Auction storage auction = tokenIdToAuction[_tokenId];
        
        require(_isAuctionAble(auction.timestamp));
        
        uint256 price = _currentPrice(auction);
        
        require(msg.value >= price);
        
        address seller = tokenIdToAuction[_tokenId].seller;
        
        uint256 auctionCost = percentage(msg.value, auctionMarge); 
        
        _removeAuction(_tokenId);
        //send money to seller
         seller.transfer(msg.value - auctionCost);
         // do transfer token
        transferFrom(seller, msg.sender, _tokenId);
        AuctionEnded(msg.sender, _tokenId);

    }
    
    function _currentPrice(Auction storage _auction)
        internal
        view
        returns (uint256)
    {
        uint256 secondsPassed = 0;

        if (now > _auction.timestamp) {
            secondsPassed = now - _auction.timestamp;
        }

        return _computeCurrentPrice(
            _auction.startPrice,
            _auction.finalPrice,
            secondsPassed,
            constantTime
        );
    }
    function _computeCurrentPrice(
        uint256 _startingPrice,
        uint256 _endingPrice,
        uint256 _secondsPassed,
        uint32 _sevenDays
    )
        internal
        pure
        returns (uint256)
    {
    
        if (_secondsPassed >= _sevenDays) {
            return _endingPrice;
        } 
        else 
        {
            int256 totalPriceChange = int256(_endingPrice) - int256(_startingPrice);
            int256 currentPriceChange = totalPriceChange * int256(_secondsPassed) / int256(_sevenDays);
            int256 currentPrice = int256(_startingPrice) + currentPriceChange;

            return uint256(currentPrice);
        }
    }


	function cancelAuction(uint256 _tokenId)
        external cardOwner(_tokenId)
    {
        Auction storage auction = tokenIdToAuction[_tokenId];
        require(auction.timestamp > 0);
        require(msg.sender == auction.seller);
        
        _removeAuction(_tokenId);
        delete cardApprovals[_tokenId];
        AuctionEnded(address(0), _tokenId);
    }

    function _removeAuction(uint256 _tokenId) internal {
        delete tokenIdToAuction[_tokenId];
    }
    function getCurrentPrice(uint256 _tokenId)
        external
        view
        returns (uint256)
    {
        Auction storage auction = tokenIdToAuction[_tokenId];
        require(_isAuctionAble(auction.timestamp));
        return _currentPrice(auction);
    }


}
/**************************************
 * @title AuctionHouse
 * @dev provides simple auction of NFT tokens
 **************************************/
function _isAuctionAble(uint256 _timestamp) internal view returns(bool)
{
   return (_timestamp + constantTime >= now);
}

// max auction time for token is 7 days..