contract PresaleMarket is PausableSimple {
    struct Auction {
        address seller;
        uint256 price;           // In wei, can be 0
    }

    ERC721 public artworkContract;
    mapping (uint256 => Auction) artworkIdToAuction;

    //      0 means everything goes to the seller
    //   1000 means 1%
    //   2500 means 2.5%
    //   4000 means 4%
    //  50000 means 50%
    // 100000 means everything goes to us
    uint256 public distributionCut = 2500;
    bool public constant isPresaleMarket = true;

    event AuctionCreated(uint256 _artworkId, uint256 _price);
    event AuctionConcluded(uint256 _artworkId, uint256 _price, address _buyer);
    event AuctionCancelled(uint256 _artworkId);

    // mapping(address => uint256[]) public auctionsRunByUser;
    // No need to have a dedicated variable
    // Can be found by
    //  iterate all artwork ids owned by this auction contract
    //    get the auction object from artworkIdToAuction
    //      get the seller property
    //        return artwork id
    // however it would be a lot better if our second layer keeps track of it
    function auctionsRunByUser(address _address) external view returns(uint256[]) {
        uint256 allArtworkCount = artworkContract.balanceOf(this);

        uint256 artworkCount = 0;
        uint256[] memory allArtworkIds = new uint256[](allArtworkCount);
        for(uint256 i = 0; i < allArtworkCount; i++) {
            uint256 artworkId = artworkContract.tokenOfOwnerByIndex(this, i);
            Auction storage auction = artworkIdToAuction[artworkId];
            if(auction.seller == _address) {
                allArtworkIds[artworkCount++] = artworkId;
            }
        }

        uint256[] memory result = new uint256[](artworkCount);
        for(i = 0; i < artworkCount; i++) {
            result[i] = allArtworkIds[i];
        }

        return result;
    }

    // constructor. rename this if you rename the contract
    function PresaleMarket(address _artworkContract) public {
        artworkContract = ERC721(_artworkContract);
    }

    function bid(uint256 _artworkId) external payable whenNotPaused {
        require(_isAuctionExist(_artworkId));
        Auction storage auction = artworkIdToAuction[_artworkId];
        require(auction.seller != msg.sender);
        uint256 price = auction.price;
        require(msg.value == price);

        address seller = auction.seller;
        delete artworkIdToAuction[_artworkId];

        if(price > 0) {
            uint256 myCut =  price * distributionCut / 100000;
            uint256 sellerCut = price - myCut;
            seller.transfer(sellerCut);
        }

        AuctionConcluded(_artworkId, price, msg.sender);
        artworkContract.transfer(msg.sender, _artworkId);
    }

    function getAuction(uint256 _artworkId) external view returns(address seller, uint256 price) {
        require(_isAuctionExist(_artworkId));
        Auction storage auction = artworkIdToAuction[_artworkId];
        return (auction.seller, auction.price);
    }

    function createAuction(uint256 _artworkId, uint256 _price, address _originalOwner) external whenNotPaused {
        require(msg.sender == address(artworkContract));

        // Will check to see if the seller owns the asset at the contract
        _takeOwnership(_originalOwner, _artworkId);

        Auction memory auction;

        auction.seller = _originalOwner;
        auction.price = _price;

        _createAuction(_artworkId, auction);
    }

    function _createAuction(uint256 _artworkId, Auction _auction) internal {
        artworkIdToAuction[_artworkId] = _auction;
        AuctionCreated(_artworkId, _auction.price);
    }

    function cancelAuction(uint256 _artworkId) external {
        require(_isAuctionExist(_artworkId));
        Auction storage auction = artworkIdToAuction[_artworkId];
        address seller = auction.seller;
        require(msg.sender == seller);
        _cancelAuction(_artworkId, seller);
    }

    function _cancelAuction(uint256 _artworkId, address _owner) internal {
        delete artworkIdToAuction[_artworkId];
        artworkContract.transfer(_owner, _artworkId);
        AuctionCancelled(_artworkId);
    }

    function withdraw() public onlyOwner {
        msg.sender.transfer(this.balance);
    }

    // only if there is a bug discovered and we need to migrate to a new market contract
    function cancelAuctionEmergency(uint256 _artworkId) external whenPaused onlyOwner {
        require(_isAuctionExist(_artworkId));
        Auction storage auction = artworkIdToAuction[_artworkId];
        _cancelAuction(_artworkId, auction.seller);
    }

    // simple methods

    function _isAuctionExist(uint256 _artworkId) internal view returns(bool) {
        return artworkIdToAuction[_artworkId].seller != address(0);
    }

    function _owns(address _address, uint256 _artworkId) internal view returns(bool) {
        return artworkContract.ownerOf(_artworkId) == _address;
    }

    function _takeOwnership(address _originalOwner, uint256 _artworkId) internal {
        artworkContract.transferFrom(_originalOwner, this, _artworkId);
    }
}
// heavily modified from https://github.com/dob/auctionhouse/blob/master/contracts/AuctionHouse.sol
// license: MIT
// original author: Doug Petkanics (petkanics@gmail.com) https://github.com/dob
function PresaleMarket(address _artworkContract) public {
    artworkContract = ERC721(_artworkContract);
}

// constructor. rename this if you rename the contract