contract EmpowCreateEosAccount {
    
    event CreateEosAccountEvent(string _name, string _activePublicKey, string _ownerPublicKey);
    
    struct AccountHistory {
        uint32 payment_type;
        string name;
        string activePublicKey;
        string ownerPublicKey;
        uint256 amount;
    }
    
    mapping (address => uint256) public countAccount;
    mapping (address => mapping (uint256 => AccountHistory)) public accountHistories;
    
    uint256 public PRICE = 144000000;
    uint256 public USDT_PRICE = 3000000;
    uint256 public NAME_LENGTH_LIMIT = 12;
    uint256 public PUBLIC_KEY_LENGTH_LIMIT = 53;
    address public owner;
    address public USDTAddress;
    
    modifier onlyOwner () {
        require(msg.sender == owner);
        _;
    }
    
    function EmpowCreateEosAccount ()
        public
    {
        owner = msg.sender;
    }
    
    function createEosAccount(string memory _name, string memory _activePublicKey, string memory _ownerPublicKey)
        public
        payable
        returns (bool)
    {
        // check name length
        require(getStringLength(_name) == NAME_LENGTH_LIMIT);
        // check public key
        require(getStringLength(_activePublicKey) == PUBLIC_KEY_LENGTH_LIMIT);
        require(getStringLength(_ownerPublicKey) == PUBLIC_KEY_LENGTH_LIMIT);
        // check price
        require(msg.value >= PRICE);
        
        // save history
        accountHistories[msg.sender][countAccount[msg.sender]].payment_type = 0; // 1 is USDT, 0 is ETH
        accountHistories[msg.sender][countAccount[msg.sender]].name = _name;
        accountHistories[msg.sender][countAccount[msg.sender]].activePublicKey = _activePublicKey;
        accountHistories[msg.sender][countAccount[msg.sender]].ownerPublicKey = _ownerPublicKey;
        accountHistories[msg.sender][countAccount[msg.sender]].amount = msg.value;
        countAccount[msg.sender]++;
        
        // emit event
        CreateEosAccountEvent(_name, _activePublicKey, _ownerPublicKey);
        return true;
    }
    
    function createEosAccountWithUSDT(string memory _name, string memory _activePublicKey, string memory _ownerPublicKey)
        public
        returns (bool)
    {
         // check name length
        require(getStringLength(_name) == NAME_LENGTH_LIMIT);
        // check public key
        require(getStringLength(_activePublicKey) == PUBLIC_KEY_LENGTH_LIMIT);
        require(getStringLength(_ownerPublicKey) == PUBLIC_KEY_LENGTH_LIMIT);
        // transfer USDT
        require(ERC20(USDTAddress).transferFrom(msg.sender, owner, USDT_PRICE));
        // save history
        accountHistories[msg.sender][countAccount[msg.sender]].payment_type = 1; // 1 is USDT, 0 is ETH
        accountHistories[msg.sender][countAccount[msg.sender]].name = _name;
        accountHistories[msg.sender][countAccount[msg.sender]].activePublicKey = _activePublicKey;
        accountHistories[msg.sender][countAccount[msg.sender]].ownerPublicKey = _ownerPublicKey;
        accountHistories[msg.sender][countAccount[msg.sender]].amount = USDT_PRICE;
        countAccount[msg.sender]++;
        
        // emit event
        CreateEosAccountEvent(_name, _activePublicKey, _ownerPublicKey);
        return true;
    }
    
    // OWNER FUNCTIONS
    
    function updateUSDTAddress (address _address) 
        public
        onlyOwner
        returns (bool)
    {
        USDTAddress = _address;
        return true;
    }
    
    function setPrice (uint256 _price, uint256 _usdtPrice)
        public
        onlyOwner
        returns (bool)
    {
        PRICE = _price;
        USDT_PRICE = _usdtPrice;
        return true;
    }
    
    function ownerWithdraw (uint256 _amount)
        public
        onlyOwner
        returns (bool)
    {
        owner.transfer(_amount);
        return true;
    }

    // HELPER FUNCTIONS
    function getStringLength (string memory _string)
        private
        returns (uint256)
    {
        bytes memory stringBytes = bytes(_string);
        return stringBytes.length;
    }
}
function getStringLength (string memory _string)
    private
    returns (uint256)
{
    bytes memory stringBytes = bytes(_string);
    return stringBytes.length;
}

// HELPER FUNCTIONS