contract TrustShoreToken is ERC20, Ownable, Mintable, Pausable, Burnable, Lockable, Delegatable{
    string private _name = "TrustShore";
    string private _symbol = "TST";
    uint8 private _decimals = 18;

    constructor (uint256 cap) public Mintable(cap){
    }

    function name() public view returns (string memory) {
        return _name;
    }

    function symbol() public view returns (string memory) {
        return _symbol;
    }

    function decimals() public view returns (uint8) {
        return _decimals;
    }

    //Override Mintable
    function _mint(address account, uint256 value) internal {
        require(account != address(0), "Mintable: mint to the zero address.");
        require(totalSupply().add(value).add(totalLocked()) <= cap(), "Mintable: cap exceeded.");

        _totalSupply = _totalSupply.add(value);
        _balances[account] = _balances[account].add(value);
        emit Transfer(address(0), account, value);
    }

    function renounceMinter() public {
        require(msg.sender != owner, "Mintable: Owner cannot renounce. Transfer owner first.");
        super._removeMinter(msg.sender);
    }

    function addMinter(address minter) public onlyOwner{
        super._addMinter(minter);

    }

    function removeMinter(address minter) public onlyOwner{
        super._removeMinter(minter);
    }

    //Override Ownerble
    function transferOwnership(address newOwner) public{
        require(msg.sender == owner, "Ownable: only owner transfer ownership");
        addMinter(newOwner);
        addDelegator(newOwner);
        removeMinter(owner);
        removeDelegator(owner);
        super._transferOwnership(newOwner);
    }

    //Override Pausable
    function pause() public onlyOwner {
        require(!paused(), "Pausable: Already paused.");
        super._pause();
    }

    function unpause() public onlyOwner {
        require(paused(), "Pausable: Not paused.");
        super._unpause();
    }

    function transfer(address to, uint256 value) public returns (bool) {
        require(!paused(), "Pausable: token transfer is paused.");
        super._transfer(msg.sender, to, value);
        return true;
    }

    function transferFrom(address from, address to, uint256 value) public whenNotPaused returns (bool) {
        require(value > 0, "transferFrom: value is must be greater than zero.");
        require(balanceOf(from) >= value, "transferFrom: balance of from address is not enough");
        require(_allowances[from][msg.sender] >= value, "transferFrom: sender are not allowed to send.");

        return super.transferFrom(from, to, value);
    }

    function approve(address spender, uint256 value) public whenNotPaused returns (bool) {
        return super.approve(spender, value);
    }

    //Override Burnable
    function burn(address account, uint256 value) public onlyOwner {
        require(account != address(0), "Burnable: burn from the zero address");
        require(_balances[account] >= value, "Burnable: not enough tokens");
        _totalSupply = _totalSupply.sub(value);
        _balances[account] = _balances[account].sub(value);
        super._burn(account, value);
        emit Transfer(account, address(0), value);
    }

    //Apply SafeTransfer
    function safeTransfer(address to, uint256 value) public {
        require(!_isContract(to),"SafeTransfer: receiver is contract");
        transfer(to,value);
    }

    function safeTransferFrom(address from, address to, uint256 value) public {
        require(!_isContract(from),"SafeTransfer: sender is contract");
        require(!_isContract(to),"SafeTransfer: receiver is contract");
        transferFrom(from, to, value);
    }

    function safeApprove(address spender, uint256 value) public {
        require(value != 0, "SafeTransfer: approve from non-zero to non-zero allowance");
        require(!_isContract(spender),"SafeTransfer: spender is contract");
        approve(spender, value);
    }

    function _isContract(address _addr) private view returns (bool is_contract){
        uint length;
        assembly {
            length := extcodesize(_addr)
        }
        return (length>0);
    }

    //Override Lockable
    function mintLockedToken(address addr, uint256 tokens, uint256 _duration) public {
        require(msg.sender == owner, "Lockable: only owner can lock token ");
        require(_totalSupply.add(totalLocked()).add(tokens) <= cap(), "Lockable: locked tokens can not exceed total cap.");
        require(_lock_list[addr] == false, "Lockable: this address is already locked");

        uint256 releaseTime = block.timestamp.add(_duration.mul(1 minutes));

        //if(_lock_list[addr] == true) {
        //    _totalLocked.sub(_revocable[addr]);
        //}

        _lock_list_period[addr] = releaseTime;
        _lock_list[addr] = true;
        _revocable[addr] = tokens;
        _totalLocked = _totalLocked.add(tokens);

        emit Lock(addr, tokens, releaseTime);
    }

    function releaseLockedToken() public returns (bool) {
        require(_lock_list[msg.sender] == true);
        require(_revocable[msg.sender] > 0);

        uint256 releaseTime = _lock_list_period[msg.sender];
        uint256 currentTime = block.timestamp;

        if(currentTime > releaseTime) {
            uint256 tokens = _revocable[msg.sender];

            _lock_list_period[msg.sender] = 0;
            _lock_list[msg.sender] = false;
            _revocable[msg.sender] = 0;
            _totalSupply = _totalSupply.add(tokens);
            _balances[msg.sender] = _balances[msg.sender].add(tokens);
            return true;
        } else {
            return false;
        }
    }

    //Override Delegatable
    function setFeeRate(uint16 _rate) public{
        require(msg.sender == owner, "Delegatable: only owner change the fee rate");
        _setFeeRate(_rate);
    }

    function setFeeCollector(address _collector) public{
        require(msg.sender == owner, "Delegatable: only owner change the fee collector");
        _setFeeCollector(_collector);
    }

    function renounceDelegator() public {
        require(msg.sender != owner, "Delegatable : Owner cannot renounce. Transfer owner first.");
        super._removeDelegator(msg.sender);
    }

    function _delegatedTransfer(address _from, address _to, uint256 _value, uint256 _fee) internal returns(bool success){
        uint _amount = _value.add(_fee);

        if (balanceOf(_from) < _amount)
            return false;
        _balances[_from] = balanceOf(_from).sub(_amount);
        _balances[_to] = balanceOf(_to).add(_value);
        _balances[feeCollector()] = balanceOf(feeCollector()).add(_fee);
        emit Transfer(_from, _to, _value);
        emit Transfer(_from, feeCollector(), _fee);
        return true;
    }

    function addDelegator(address delegator) public onlyOwner{
        super._addDelegator(delegator);

    }

    function removeDelegator(address delegator) public onlyOwner{
        super._removeDelegator(delegator);
    }
}
function _mint(address account, uint256 value) internal {
    require(account != address(0), "Mintable: mint to the zero address.");
    require(totalSupply().add(value).add(totalLocked()) <= cap(), "Mintable: cap exceeded.");

    _totalSupply = _totalSupply.add(value);
    _balances[account] = _balances[account].add(value);
    emit Transfer(address(0), account, value);
}

//Override Mintable