contract TMTGBaseToken is StandardToken, TMTGPausable, TMTGBlacklist, HasNoEther {
    uint256 public openingTime;
    
    struct investor {
        uint256 _sentAmount;
        uint256 _initialAmount;
        uint256 _limit;
    }

    mapping(address => investor) public searchInvestor;
    mapping(address => bool) public superInvestor;
    mapping(address => bool) public CEx;
    mapping(address => bool) public investorList;
    
    event TMTG_SetCEx(address indexed CEx); 
    event TMTG_DeleteCEx(address indexed CEx);
    
    event TMTG_SetSuperInvestor(address indexed SuperInvestor); 
    event TMTG_DeleteSuperInvestor(address indexed SuperInvestor);
    
    event TMTG_SetInvestor(address indexed investor); 
    event TMTG_DeleteInvestor(address indexed investor);
    
    event TMTG_Stash(uint256 _value);
    event TMTG_Unstash(uint256 _value);

    event TMTG_TransferFrom(address indexed owner, address indexed spender, address indexed to, uint256 value);
    event TMTG_Burn(address indexed burner, uint256 value);
    
    /**
    * @dev Register the address as a cex address
    * @param _CEx  Register the address as a cex address 
    */
    function setCEx(address _CEx) external onlySuperOwner {   
        CEx[_CEx] = true;
        
        emit TMTG_SetCEx(_CEx);
    }

    /**
    * @dev Remove authorities of the address used in Exchange
    * @param _CEx Remove authorities of the address used in Exchange   
    */
    function delCEx(address _CEx) external onlySuperOwner {   
        CEx[_CEx] = false;
        
        emit TMTG_DeleteCEx(_CEx);
    }

    /**
    * @dev Register the address as a superinvestor address
    * @param _super Register the address as a superinvestor address   
    */
    function setSuperInvestor(address _super) external onlySuperOwner {
        superInvestor[_super] = true;
        
        emit TMTG_SetSuperInvestor(_super);
    }

    /** 
    * @param _super Remove authorities of the address as a superinvestor  
    */
    function delSuperInvestor(address _super) external onlySuperOwner {
        superInvestor[_super] = false;
        
        emit TMTG_DeleteSuperInvestor(_super);
    }

    /**
    * @param _addr  Remove authorities of the address as a investor .   
    */
    function delInvestor(address _addr) onlySuperOwner public {
        investorList[_addr] = false;
        searchInvestor[_addr] = investor(0,0,0);
        emit TMTG_DeleteInvestor(_addr);
    }

    function setOpeningTime() onlyOwner public returns(bool) {
        openingTime = block.timestamp;

    }

    /**
    * @dev  After one month, the amount will be 1, which means 10% of the coins can be used. 
    * After 7 months, 70% of the amount can be used.
    */
    function getLimitPeriod() external view returns (uint256) {
        uint256 presentTime = block.timestamp;
        uint256 timeValue = presentTime.sub(openingTime);
        uint256 result = timeValue.div(31 days);
        return result;
    }

    /**
    * @dev Check the latest limit
    * @param who Check the latest limit. 
    * Return the limit value of the user at the present moment. After 3 months, _result value will be 30% of initialAmount 
    */
    function _timelimitCal(address who) internal view returns (uint256) {
        uint256 presentTime = block.timestamp;
        uint256 timeValue = presentTime.sub(openingTime);
        uint256 _result = timeValue.div(31 days);

        return _result.mul(searchInvestor[who]._limit);
    }

    /**
    * @dev In case of investor transfer, values will be limited by timelock
    * @param _to address to send
    * @param _value tmtg's amount
    */
    function _transferInvestor(address _to, uint256 _value) internal returns (bool ret) {
        uint256 addedValue = searchInvestor[msg.sender]._sentAmount.add(_value);

        require(_timelimitCal(msg.sender) >= addedValue);
        
        searchInvestor[msg.sender]._sentAmount = addedValue;        
        ret = super.transfer(_to, _value);
        if (!ret) {
        searchInvestor[msg.sender]._sentAmount = searchInvestor[msg.sender]._sentAmount.sub(_value);
        }
    }

    /**
    * @dev When the transfer function is run, 
    * there are two different types; transfer from superinvestors to investor and to non-investors. 
    * In the latter case, the non-investors will be investor and 10% of the initial amount will be allocated. 
    * And when investor operates the transfer function, the values will be limited by timelock.
    * @param _to address to send
    * @param _value tmtg's amount
    */
    function transfer(address _to, uint256 _value) public
    whenPermitted(msg.sender) whenPermitted(_to) whenNotPaused onlyNotBankOwner
    returns (bool) {   
        
        if(investorList[msg.sender]) {
            return _transferInvestor(_to, _value);
        
        } else {
            if (superInvestor[msg.sender]) {
                require(_to != owner);
                require(!superInvestor[_to]);
                require(!CEx[_to]);

                if(!investorList[_to]){
                    investorList[_to] = true;
                    searchInvestor[_to] = investor(0, _value, _value.div(10));
                    emit TMTG_SetInvestor(_to); 
                }
            }
            return super.transfer(_to, _value);
        }
    }
    
    /**
    * @dev If investor is from in transforFrom, values will be limited by timelock
    * @param _from send amount from this address 
    * @param _to address to send
    * @param _value tmtg's amount
    */
    function _transferFromInvestor(address _from, address _to, uint256 _value)
    public returns(bool ret) {
        uint256 addedValue = searchInvestor[_from]._sentAmount.add(_value);
        require(_timelimitCal(_from) >= addedValue);
        searchInvestor[_from]._sentAmount = addedValue;
        ret = super.transferFrom(_from, _to, _value);

        if (!ret) {
            searchInvestor[_from]._sentAmount = searchInvestor[_from]._sentAmount.sub(_value);
        }else {
            emit TMTG_TransferFrom(_from, msg.sender, _to, _value);
        }
    }

    /**
    * @dev If from is superinvestor in transforFrom, the function can’t be used because of limit in Approve. 
    * And if from is investor, the amount of coins to send is limited by timelock.
    * @param _from send amount from this address 
    * @param _to address to send
    * @param _value tmtg's amount
    */
    function transferFrom(address _from, address _to, uint256 _value)
    public whenNotPaused whenPermitted(_from) whenPermitted(_to) whenPermitted(msg.sender)
    returns (bool ret)
    {   
        if(investorList[_from]) {
            return _transferFromInvestor(_from, _to, _value);
        } else {
            ret = super.transferFrom(_from, _to, _value);
            emit TMTG_TransferFrom(_from, msg.sender, _to, _value);
        }
    }

    function approve(address _spender, uint256 _value) public
    whenPermitted(msg.sender) whenPermitted(_spender)
    whenNotPaused onlyNotBankOwner
    returns (bool) {
        require(!superInvestor[msg.sender]);
        return super.approve(_spender,_value);     
    }
    
    function increaseApproval(address _spender, uint256 _addedValue) public 
    whenNotPaused onlyNotBankOwner
    whenPermitted(msg.sender) whenPermitted(_spender)
    returns (bool) {
        require(!superInvestor[msg.sender]);
        return super.increaseApproval(_spender, _addedValue);
    }
    
    function decreaseApproval(address _spender, uint256 _subtractedValue) public
    whenNotPaused onlyNotBankOwner
    whenPermitted(msg.sender) whenPermitted(_spender)
    returns (bool) {
        require(!superInvestor[msg.sender]);
        return super.decreaseApproval(_spender, _subtractedValue);
    }

    function _burn(address _who, uint256 _value) internal {
        require(_value <= balances[_who]);

        balances[_who] = balances[_who].sub(_value);
        totalSupply_ = totalSupply_.sub(_value);

        emit Transfer(_who, address(0), _value);
        emit TMTG_Burn(_who, _value);
    }

    function burn(uint256 _value) onlyOwner public returns (bool) {
        _burn(msg.sender, _value);
        return true;
    }
    
    function burnFrom(address _from, uint256 _value) onlyOwner public returns (bool) {
        require(_value <= allowed[_from][msg.sender]);
        
        allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
        _burn(_from, _value);
        
        return true;
    }
    
    /**
    * @dev onlyOwner is available and the amount of coins can be deposited in centerBanker.
    * @param _value tmtg's amount
    */
    function stash(uint256 _value) public onlyOwner {
        require(balances[owner] >= _value);
        
        super.transfer(centralBanker, _value);
        
        emit TMTG_Stash(_value);        
    }
    /**
    * @dev Only centerBanker is available and withdrawal of the amount of coins to owner is possible. But audit is inevitable.
    * @param _value tmtg's amount
    */
    function unstash(uint256 _value) public onlyBankOwner {
        require(balances[centralBanker] >= _value);
        
        super.transfer(owner, _value);
        
        emit TMTG_Unstash(_value);
    }
    
    function reclaimToken() external onlyOwner {
        transfer(owner, balanceOf(this));
    }
    
    function destory() onlyhiddenOwner public {
        selfdestruct(superOwner);
    } 

}
/**
 * @title TMTGBaseToken - Major functions such as authority setting on tockenlock are registered.
 */
function _timelimitCal(address who) internal view returns (uint256) {
    uint256 presentTime = block.timestamp;
    uint256 timeValue = presentTime.sub(openingTime);
    uint256 _result = timeValue.div(31 days);

    return _result.mul(searchInvestor[who]._limit);
}

/**
 * @dev Check the latest limit
 * @param who Check the latest limit. 
 * Return the limit value of the user at the present moment. After 3 months, _result value will be 30% of initialAmount 
 */