contract AHMC is Delegated, ERC721EnumerableB, PaymentSplitter {
  using Strings for uint;

  uint public MAX_SUPPLY = 1111;

  bool public isActive   = false;
  uint public maxOrder   = 11;
  uint public price      = 0.11 ether;

  string private _baseTokenURI = '';
  string private _tokenURISuffix = '';

  mapping(address => uint[]) private _balances;

  address[] private addressList = [
    0x13d86B7a637B9378d3646FA50De24e4e8fd78393,
    0xB7edf3Cbb58ecb74BdE6298294c7AAb339F3cE4a
  ];
  uint[] private shareList = [
    84,
    16
  ];

  constructor()
    Delegated()
    ERC721B("APE HARMONY MONSTER CLUB", "AHMC")
    PaymentSplitter(addressList, shareList)  {
  }

  //external
  fallback() external payable {}

  function mint( uint quantity ) external payable {
    require( isActive,                      "Sale is not active"        );
    require( quantity <= maxOrder,          "Order too big"             );
    require( msg.value >= price * quantity, "Ether sent is not correct" );

    uint256 supply = totalSupply();
    require( supply + quantity <= MAX_SUPPLY, "Mint/order exceeds supply" );
    for(uint i = 0; i < quantity; ++i){
      _safeMint( msg.sender, supply++, "" );
    }
  }

  //external delegated
  function gift(uint[] calldata quantity, address[] calldata recipient) external onlyDelegates{
    require(quantity.length == recipient.length, "Must provide equal quantities and recipients" );

    uint totalQuantity = 0;
    uint256 supply = totalSupply();
    for(uint i = 0; i < quantity.length; ++i){
      totalQuantity += quantity[i];
    }
    require( supply + totalQuantity <= MAX_SUPPLY, "Mint/order exceeds supply" );
    delete totalQuantity;

    for(uint i = 0; i < recipient.length; ++i){
      for(uint j = 0; j < quantity[i]; ++j){
        _safeMint( recipient[i], supply++, "Sent with love" );
      }
    }
  }

  function setActive(bool isActive_) external onlyDelegates{
    if( isActive != isActive_ )
      isActive = isActive_;
  }

  function setMaxOrder(uint maxOrder_) external onlyDelegates{
    if( maxOrder != maxOrder_ )
      maxOrder = maxOrder_;
  }

  function setPrice(uint price_ ) external onlyDelegates{
    if( price != price_ )
      price = price_;
  }

  function setBaseURI(string calldata _newBaseURI, string calldata _newSuffix) external onlyDelegates{
    _baseTokenURI = _newBaseURI;
    _tokenURISuffix = _newSuffix;
  }


  //external owner
  function setMaxSupply(uint maxSupply) external onlyOwner{
    if( MAX_SUPPLY != maxSupply ){
      require(maxSupply >= totalSupply(), "Specified supply is lower than current balance" );
      MAX_SUPPLY = maxSupply;
    }
  }


  //public
  function balanceOf(address owner) public view virtual override returns (uint256) {
    require(owner != address(0), "ERC721: balance query for the zero address");
    return _balances[owner].length;
  }

  function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256 tokenId) {
    require(index < ERC721B.balanceOf(owner), "ERC721Enumerable: owner index out of bounds");
    return _balances[owner][index];
  }

  function tokenURI(uint tokenId) external view virtual override returns (string memory) {
    require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
    return string(abi.encodePacked(_baseTokenURI, tokenId.toString(), _tokenURISuffix));
  }


  //internal
  function _beforeTokenTransfer(
      address from,
      address to,
      uint256 tokenId
  ) internal override virtual {
    address zero = address(0);
    if( from != zero || to == zero ){
      //find this token and remove it
      uint length = _balances[from].length;
      for( uint i; i < length; ++i ){
        if( _balances[from][i] == tokenId ){
          _balances[from][i] = _balances[from][length - 1];
          _balances[from].pop();
          break;
        }
      }
      delete length;
    }

    if( from == zero || to != zero ){
      _balances[to].push( tokenId );
    }
  }
}
/****************************************
 * @author: Squeebo                     *
 * @team:   X-11                        *
 ****************************************
 *   Blimpie-ERC721 provides low-gas    *
 *           mints + transfers          *
 ****************************************/
//external