contract TokenismWhitelist is Context, TokenismAdminWhitelist {
    using Roles for Roles.Role;
    Roles.Role private _userWhitelisteds;
    mapping(string=> bool) public symbolsDef;

    struct  whitelistInfo {
        bool valid;
        address wallet;
        bool kycVerified;
        bool accredationVerified;
        uint256 accredationExpiry;
        uint256 taxWithholding;
        string  userType;
        bool suspend;
    }
    mapping(address => whitelistInfo) public whitelistUsers;
    address[] public userList;

    // userTypes = Basic || Premium
    function addWhitelistedUser(address _wallet, bool _kycVerified, bool _accredationVerified, uint256 _accredationExpiry) public onlyManager {
        if(_accredationVerified)
            require(_accredationExpiry >= block.timestamp, "accredationExpiry: Accredation Expiry time is before current time");

        _userWhitelisteds.add(_wallet);
        whitelistInfo storage newUser = whitelistUsers[_wallet];

        newUser.valid = true;
        newUser.suspend = false;
        newUser.taxWithholding = 0;

        newUser.wallet = _wallet;
        newUser.kycVerified = _kycVerified;
        newUser.accredationExpiry = _accredationExpiry;
        newUser.accredationVerified = _accredationVerified;
        newUser.userType = "Basic";
        // maintain whitelist user list
        userList.push(_wallet);
    }

    function getWhitelistedUser(address _wallet) public view returns (address, bool, bool, uint256, uint256){
        whitelistInfo memory u = whitelistUsers[_wallet];
        return (u.wallet, u.kycVerified, u.accredationExpiry >= block.timestamp, u.accredationExpiry, u.taxWithholding);
    }

    function updateKycWhitelistedUser(address _wallet, bool _kycVerified) public onlyManager {
        whitelistInfo storage u = whitelistUsers[_wallet];
        u.kycVerified = _kycVerified;
    }

    function updateAccredationWhitelistedUser(address _wallet, uint256 _accredationExpiry) public onlyManager {
        require(_accredationExpiry >= block.timestamp, "accredationExpiry: Accredation Expiry time is before current time");

        whitelistInfo storage u = whitelistUsers[_wallet];
        u.accredationExpiry = _accredationExpiry;
    }

    function updateTaxWhitelistedUser(address _wallet, uint256 _taxWithholding) public onlyManager {
        whitelistInfo storage u = whitelistUsers[_wallet];
        u.taxWithholding = _taxWithholding;
    }

    function suspendUser(address _wallet) public onlyManager {
        whitelistInfo storage u = whitelistUsers[_wallet];
        u.suspend = true;
    }

    function activeUser(address _wallet) public onlyManager {
        whitelistInfo storage u = whitelistUsers[_wallet];
        u.suspend = false;
    }

    function updateUserType(address _wallet, string memory _userType) public onlyManager {
        require(
            StringUtils.equal(_userType , 'Basic') || StringUtils.equal(_userType , 'Premium')
        , "Please Enter Valid User Type");
        whitelistInfo storage u = whitelistUsers[_wallet];
        u.userType = _userType;
    }

// Check user status
    function isWhitelistedUser(address wallet) public view returns (uint) {
        whitelistInfo storage u = whitelistUsers[wallet];
    whitelistInfoManager memory m = whitelistManagers[wallet];

       /* Wallet is Super Admin */
      if(StringUtils.equal(admins[wallet], "superAdmin")) return 100;

       /* Wallet is Fee Admin */
        if(StringUtils.equal(admins[wallet], "fee"))   return 110;

         /* Wallet is Dev Admin */
        if(StringUtils.equal(admins[wallet], "dev"))   return 111;

         /* Wallet is Simple Admin */
        if(StringUtils.equal(admins[wallet], "admin")) return 112;

        /* Wallet is Manager Finance */
        if(StringUtils.equal(m.role, "finance"))     return 120;

         /* Wallet is Manager asset */
         if(StringUtils.equal(m.role, "assets"))  return 121;

           /* Wallet is Manager asset */
         if(StringUtils.equal(m.role, "signer"))  return 122;
         
        // /* Any type of Manager */
        // if(isWhitelistedManager(wallet)) return 200;

        /* Wallet is not Added */
        else if(!u.valid) return 404;

        /* If User is Suspendid */
        else if(u.suspend) return 401;

        /* Wallet KYC Expired */
        else if(!u.kycVerified) return 400;

        /* If Accredation check is false then Send 200 */
        else if(!accreditationCheck) return 200;

        /* Wallet AML Expired */
        else if(u.accredationExpiry <= block.timestamp)
            return 201;

        /* Wallet is Whitelisted */
        else return 200;
    }

    function removeWhitelistedUser(address _wallet) public onlyManager {
        _userWhitelisteds.remove(_wallet);
        whitelistInfo storage u = whitelistUsers[_wallet];
        u.valid = false;
    }

    /* Symbols Deployed Add to Contract */
    function addSymbols(string calldata _symbols)
        external
        // onlyManager
        returns(bool){
            if(symbolsDef[_symbols] == true)
                return false;
            else{
                symbolsDef[_symbols]=true;
                return true;
            }
        }
    // On destroy Symbol Removed
    function removeSymbols(string calldata _symbols)
        external
        // onlyManager
        returns(bool){
            if(symbolsDef[_symbols] == true)
            symbolsDef[_symbols] = false;
            return true;


        }

    function closeTokenismWhitelist() public {
      require(StringUtils.equal(admins[_msgSender()], "superAdmin"), "only superAdmin can destroy Contract");
    selfdestruct(msg.sender);
    } 


    function storedAllData()public view onlyAdmin returns(
        address[] memory _userList,
        bool[] memory _validity,
        bool[] memory _kycVery,
        bool[] memory _accredationVery,
        uint256[] memory _accredationExpir,
        uint256[] memory _taxWithHold,
        uint256[] memory _userTypes
        )
        {

            uint size = userList.length;

        bool[] memory validity = new bool[](size);
        bool[] memory kycVery = new bool[](size);
        bool[] memory accredationVery = new bool[](size);
        uint256[] memory accredationExpir = new uint256[](size);
        uint256[] memory taxWithHold = new uint256[](size);
        uint256[] memory userTypes = new uint256[](size);
            uint i;
            for(i=0; i<userList.length; i++){
                        if(whitelistUsers[userList[i]].valid){
                            validity[i]= true;
                        }
                        else{
                        validity[i]=false;   
                        }
                    if(whitelistUsers[userList[i]].kycVerified)
                    {
                    kycVery[i] = true;
                    }
                    else{
                    kycVery[i] = false;
                    }
                    if(whitelistUsers[userList[i]].accredationVerified)
                    {
                    accredationVery[i] = true;
                    }
                    else{
                    accredationVery[i] = false;
                    }
                    accredationExpir[i] = (whitelistUsers[userList[i]].accredationExpiry);
                    taxWithHold[i] = (whitelistUsers[userList[i]].taxWithholding);
                    if(StringUtils.equal(whitelistUsers[userList[i]].userType, "Basic")){
                        userTypes[i] = 20; 
                    }
                    else
                    userTypes[i] = 100;
            }
            return (userList,validity, kycVery,accredationVery, accredationExpir, taxWithHold,userTypes);
        }



    function userType(address _caller) public view returns(bool){
        if(StringUtils.equal(whitelistUsers[_caller].userType, "Premium"))
        return true;
        return false;
    }
}
function addWhitelistedUser(address _wallet, bool _kycVerified, bool _accredationVerified, uint256 _accredationExpiry) public onlyManager {
    if(_accredationVerified)
        require(_accredationExpiry >= block.timestamp, "accredationExpiry: Accredation Expiry time is before current time");

    _userWhitelisteds.add(_wallet);
    whitelistInfo storage newUser = whitelistUsers[_wallet];

    newUser.valid = true;
    newUser.suspend = false;
    newUser.taxWithholding = 0;

    newUser.wallet = _wallet;
    newUser.kycVerified = _kycVerified;
    newUser.accredationExpiry = _accredationExpiry;
    newUser.accredationVerified = _accredationVerified;
    newUser.userType = "Basic";
    // maintain whitelist user list
    userList.push(_wallet);
}

// userTypes = Basic || Premium