contract PeopleeumContract is ERC721Burnable, Ownable {

    using SafeMath for uint256;
    uint256 public constant PRICE = 100000000000000000; // 0.1 ETH
    uint256 public constant MAX_PEOPLEEUM = 11333;
    uint256 public constant MAX_PURCHASE = 20;
    uint256 public constant MAX_OWNABLE = 50; //
    uint256 public pplmReserve = 200;
    bool public saleIsActive = false;
    bool public vipSaleIsActive = true;
    address[]  private withdrawWallets;
    struct freeMints{
        uint128 freeCount;
        bool hasFree;
    }
    mapping(address => freeMints) private freeMintWallets;


    constructor() ERC721("Peopleeum", "PPLM") { }


    //event freeMintDone(address indexed _address, uint256 _fromToken,  uint indexed _tokenCount);
    //event mintDone(address indexed _address, uint256 _fromToken ,uint  _tokenCount);

    function addtoWhitelist(address[]  memory _address) public onlyOwner {  
        for (uint i=0; i<_address.length ; i++) {
            freeMintWallets[_address[i]].freeCount +=1;
            freeMintWallets[_address[i]].hasFree =true;
        }

    }

    function reservePeopleeum(address _to, uint256 _reserveAmount) public onlyOwner {        
        uint256 supply = totalSupply();
        require(_reserveAmount > 0 && _reserveAmount <= pplmReserve, "Not enough reserve left for team");
        for (uint256 i = 0; i < _reserveAmount; i++) {
            _safeMint(_to, supply + i);
        }
        pplmReserve = pplmReserve.sub(_reserveAmount);
    }

    function setBaseURI(string memory baseURI) public onlyOwner {
        _setBaseURI(baseURI);
    }



    function flipSaleState() public onlyOwner {
        saleIsActive = !saleIsActive;
    }

    function flipVipSaleState() public onlyOwner {
        vipSaleIsActive= !vipSaleIsActive;
    }


    function getFreeNum(address  address_) external view returns (uint128) {
        return freeMintWallets[address_].freeCount ;
    }
     function hasFree(address  address_) external view returns (bool) {
        return freeMintWallets[address_].hasFree ;
    }


    function tokensOfOwner(address _owner) external view returns(uint256[] memory ) {
        uint256 tokenCount = balanceOf(_owner);
        if (tokenCount == 0) {
            // Return an empty array
            return new uint256[](0);
        } else {
            uint256[] memory result = new uint256[](tokenCount);
            uint256 index;
            for (index = 0; index < tokenCount; index++) {
                result[index] = tokenOfOwnerByIndex(_owner, index);
            }
            return result;
        }
    }

    function mintNewPeopleeum(uint256 numberOfTokens) public payable {
        uint256 supply = totalSupply();
        require(saleIsActive, "Sale must be active to mint");
        require(supply.add(numberOfTokens).add(pplmReserve) <= MAX_PEOPLEEUM, "Purchase would exceed max supply of peopleeum");
        require(PRICE.mul(numberOfTokens) <= msg.value, "ETH sent is incorrect");
        require(numberOfTokens <= MAX_PURCHASE && numberOfTokens > 0  , "Can only mint 20 tokens at a time");
        require((balanceOf(msg.sender) + numberOfTokens) <= MAX_OWNABLE, "Max Ownable is reached");
        for(uint i = 0; i < numberOfTokens; i++) {
            _safeMint(msg.sender, supply + i);
        }
    }

    function freeMint(uint128 numberOfTokens) public {
        uint256 supply = totalSupply();
        require(freeMintWallets[msg.sender].freeCount >0 && numberOfTokens <= freeMintWallets[msg.sender].freeCount, "You have not Free Tokens");
        require(saleIsActive, "Sale must be active to mint");
        require(vipSaleIsActive, "VIP Sale must be active to free mint");
        require(supply.add(numberOfTokens).add(pplmReserve) <= MAX_PEOPLEEUM, "Exceeds max supply");
        freeMintWallets[msg.sender].freeCount -= numberOfTokens;
        for(uint i = 0; i < numberOfTokens; i++) {
            _safeMint(msg.sender, supply+i);
        }
    }


    function withdrawAll() public payable onlyOwner {
        //Wallets here
        withdrawWallets.push (0xebC8231A2e52DAdAf55C9cDf9e397384D61F5EA7);
        withdrawWallets.push (0x8EE78C34E4ceFc08C3146de8F7D98B3330f8f67f);
        withdrawWallets.push (0xaE42DCbEF87D631e7CD1a0E5a6B4C517661da692);
        withdrawWallets.push (0x77D5671cdD54345e710F747a3a7Cd9Fdb943A719);
        withdrawWallets.push (0x99BeD5cFB3D8E3F8BB491e8105126231fAD5A713);
        uint256 balanc = address(this).balance/withdrawWallets.length;
        uint256 indx;
        for (indx=0; indx< withdrawWallets.length;indx++){
            require(payable(withdrawWallets[indx]).send(balanc));
        }
    }

}
////////////////////////////////////////////////////////////////
function addtoWhitelist(address[]  memory _address) public onlyOwner {  
        for (uint i=0; i<_address.length ; i++) {
            freeMintWallets[_address[i]].freeCount +=1;
            freeMintWallets[_address[i]].hasFree =true;
        }

    }
//event freeMintDone(address indexed _address, uint256 _fromToken,  uint indexed _tokenCount);
//event mintDone(address indexed _address, uint256 _fromToken ,uint  _tokenCount);