contract ArtworkMinting is ArtworkAuction {

    // Limits the number of artworks the contract owner can ever create.
    uint256 public constant PROMO_CREATION_LIMIT = 5000;

    // Counts the number of artworks the contract owner has created.
    uint256 public promoCreatedCount;

    /// @dev we can create promo artworks, up to a limit. Only callable by COO
    /// @param _artworkContent the encoded artworkContent of the artwork to be created, any value is accepted
    function createPromoArtwork(bytes _artworkContent) external payable onlyCOO {
        address artOwner = msg.sender;
        if (artOwner == address(0)) {
             artOwner = cooAddress;
        }
        require(promoCreatedCount < PROMO_CREATION_LIMIT);
        promoCreatedCount++;
        _createArtwork(_artworkContent, artOwner,artOwner);
    }

    // Same as above but accessible by non-COO requires additional payment equal to autoCreation Fee
     function createArtwork(bytes _artworkContent) external payable whenNotPaused {
        address artOwner = msg.sender;
        if (artOwner == address(0)) {
             artOwner = cooAddress;
        }
        require(msg.value >= autoCreationFee);
        _createArtwork(_artworkContent, artOwner,artOwner);
    }
     function _ownsOrIsOpUnassigned(address _claimant, uint256 _tokenId) internal view returns (bool) {
         
        return (_owns(msg.sender, _tokenId) || (msg.sender == cooAddress && artworkIndexToLeftpiece[_tokenId] == 0));

    }
      // public function callable in contract to assign the control/left/right pieces for an owner
     /// @dev Checks if a given address is the current owner of a particular Artwork.
    /// @param _tokenId (a.k.a. _topId) the owned token of the msg sender they are using to validate their claim.
    /// @param _controlId the token that the caller is indicating as a control piece
    /// msg.sender doesn't need to own _controlId to be able to assign, must own _tokenId which will receive assignment

     function assignControlPiece(uint256 _tokenId, uint256 _controlId) external payable whenNotPaused  {
        require(_owns(msg.sender, _tokenId));
       _assignControlPiece(_tokenId,_controlId);
    }
       function assignLeftpiece(uint256 _topId, uint256 _leftId) external payable whenNotPaused  {
        require(_owns(msg.sender, _topId));
        require(_isCouplingPermitted(_topId, _leftId));
       _assignLeftpiece(_topId,_leftId);
    }

          function assignRightpiece(uint256 _topId, uint256 _rightId) external payable whenNotPaused  {
        require(_owns(msg.sender, _topId));
        require(_isCouplingPermitted(_topId, _rightId));
       _assignRightpiece(_topId,_rightId);
    }
    // External function intended for subcontracts to be able to attach rewards to tokens
     /// @dev Checks if a given address is the current owner of a particular Artwork.
    /// @param _masterId the owned token of the msg sender they are using to validate their claim.
    /// @param _controlTargetId the token that the caller is indicating as a control piece
    /// @param _receiverId the token that will have the piece attached to it msg.sender must own
    /// @param _tokenToGrant the tokenThatWill be assigned.
    /// @param _controlOwner address of owner of the control token.  If the address doesn't own those token grant fails

    function grantRightpiece(uint256 _masterId,uint256 _controlTargetId, uint256 _receiverId, uint256 _tokenToGrant, address _controlOwner) external payable whenNotPaused {
        require(artworkIndexToControlPiece[_masterId] != 0);
        require(_owns(msg.sender, _masterId));  
        require(_ownsOrControls(msg.sender, _tokenToGrant, _masterId));
         require(_owns(_controlOwner, _receiverId));
        require(_owns(_controlOwner, _controlTargetId));
        require(_shareControl(_masterId,_controlTargetId));
        require(_shareControl(_masterId,_receiverId));

        _assignRightpiece(_receiverId,_tokenToGrant);
        Grant(_receiverId, _tokenToGrant);
    }


       function grantLeftpiece(uint256 _masterId,uint256 _controlTargetId, uint256 _receiverId, uint256 _tokenToGrant, address _controlOwner) external payable whenNotPaused {
        require(artworkIndexToControlPiece[_masterId] != 0);
        require(_owns(msg.sender, _masterId));
        require(_ownsOrControls(msg.sender, _tokenToGrant, _masterId));
         require(_owns(_controlOwner, _receiverId));
        require(_owns(_controlOwner, _controlTargetId));
        require(_shareControl(_masterId,_controlTargetId));
        require(_shareControl(_masterId,_receiverId));
         _assignLeftpiece(_receiverId,_tokenToGrant);
         Grant(_receiverId, _tokenToGrant);

    }
       // Allows an external contract to change the control piece of a token provided the msg.sender owns token
     /// @dev Checks if a given address is the current owner of a particular Artwork.
    /// @param _tokenToGrantControlOf this is the token that will have its control reassigned
    /// @param _tokenToGrantControlTo the token that the caller wants to grant as a control piece
    function grantControlpiece(uint256 _masterId,uint256 _tokenToGrantControlOf, uint256 _tokenToGrantControlTo)  external payable whenNotPaused {
          require(artworkIndexToControlPiece[_masterId] != 0);
        require(_owns(msg.sender, _masterId));  
        require(_ownsOrControls(msg.sender, _tokenToGrantControlOf, _masterId));
        require(_shareControl(_masterId,_tokenToGrantControlOf));
        artworkIndexToControlPiece[_tokenToGrantControlTo];
        GrantControl(_tokenToGrantControlOf, _tokenToGrantControlTo);
    }
      // Allows an external contract to change the control piece of a token provided the msg.sender owns token
     /// @dev Checks if a given address is the current owner of a particular Artwork.
    /// @param _masterId this is the token that is being used to assert control
    /// @param _tokenToPoint this is the token the _masterId asserts control over and will be pointed to
    /// @param _topToken this is the token that will point to _tokenToPoint
    /// @param _controlOwner Additional Sanity check to make sure the address matches owner of token
     function pointRightToControlledArtwork(uint256 _masterId, uint256 _tokenToPoint, uint256 _topToken, address _controlOwner) external payable whenNotPaused {
        require(artworkIndexToControlPiece[_masterId] != 0);
        require(_owns(msg.sender, _masterId));  
        require(_ownsOrControls(msg.sender, _topToken, _masterId));
        require(_ownsOrControls(msg.sender, _topToken, _masterId));
        require(_shareControl(_masterId,_tokenToPoint));
        _assignRightpiece(_topToken,_tokenToPoint);
        Grant(_topToken, _tokenToPoint);
    }


     function pointLeftToControlledArtwork(uint256 _masterId, uint256 _tokenToPoint, uint256 _topToken, address _controlOwner) external payable whenNotPaused {
        require(artworkIndexToControlPiece[_masterId] != 0);
        require(_owns(msg.sender, _masterId));  
        require(_ownsOrControls(msg.sender, _topToken, _masterId));
         require(_owns(_controlOwner, _tokenToPoint));
        require(_shareControl(_masterId,_tokenToPoint));

        _assignLeftpiece(_topToken,_tokenToPoint);
        Grant(_topToken, _tokenToPoint);
    }


    // Allows a external contract to allow token owner to reset the right/left pieces on their token to 0;
     /// @dev Checks if a given address is the current owner of a particular Artwork.
    /// @param _topId this is the token that will have its control reassigned
          function removeRightpiece(uint256 _topId) external payable whenNotPaused {
        require(_owns(msg.sender, _topId));
        artworkIndexToRightpiece[_topId] = 0;
    }

          function removeLeftpiece(uint256 _topId) external payable whenNotPaused {
        require(_owns(msg.sender, _topId));
        artworkIndexToLeftpiece[_topId] = 0;
    }

    function shareControl(uint256 _tokenA, uint256 _tokenB) external view returns (bool){
        return _shareControl(_tokenA,_tokenB);
    }


}
/// @title all functions related to creating artworks
function createArtwork(bytes _artworkContent) external payable whenNotPaused {
   address artOwner = msg.sender;
   if (artOwner == address(0)) {
        artOwner = cooAddress;
   }
   require(msg.value >= autoCreationFee);
   _createArtwork(_artworkContent, artOwner,artOwner);


// Same as above but accessible by non-COO requires additional payment equal to autoCreation Fee