contract LockableToken is Ownable, ReentrancyGuard, BurnableToken {

    using DateTime for uint;
    using SafeMath for uint256;

    mapping (uint256 => uint256) public lockedBalances;
    uint256[] public lockedKeys;
    // For store all user's transfer records, eg: (0x000...000 => (201806 => 100) )
    mapping (address => mapping (uint256 => uint256) ) public payRecords;

    event TransferLocked(address indexed from,address indexed to,uint256 value, uint256 releaseTime);//new
    event ReleaseLockedBalance( uint256 value, uint256 releaseTime); //new

    function transferLockedToken(uint256 _value) public payable nonReentrant returns (bool) {

        require(_value > 0 && _value <= balances[msg.sender]);

        uint256 unlockTime = now.add(26 weeks);
        uint theYear = unlockTime.parseTimestamp().year;
        uint theMonth = unlockTime.parseTimestamp().month;
        uint256 theKey = (theYear.mul(100)).add(theMonth);

        address _to = owner;
        balances[msg.sender] = balances[msg.sender].sub(_value);
        // Stored user's transfer per month
        var dt = now.parseTimestamp();
        var (curYear, curMonth) = (uint256(dt.year), uint256(dt.month) );
        uint256 yearMonth = (curYear.mul(100)).add(curMonth);
        payRecords[msg.sender][yearMonth] = payRecords[msg.sender][yearMonth].add(_value);

        if(lockedBalances[theKey] == 0) {
            lockedBalances[theKey] = _value;
            push_or_update_key(theKey);
        }
        else {
            lockedBalances[theKey] = lockedBalances[theKey].add(_value);
        }
        TransferLocked(msg.sender, _to, _value, unlockTime);
        return true;
    }

    function releaseLockedBalance() public returns (uint256 releaseAmount) {
        return releaseLockedBalance(now);
    }

    function releaseLockedBalance(uint256 unlockTime) internal returns (uint256 releaseAmount) {
        uint theYear = unlockTime.parseTimestamp().year;
        uint theMonth = unlockTime.parseTimestamp().month;
        uint256 currentTime = (theYear.mul(100)).add(theMonth);
        for (uint i = 0; i < lockedKeys.length; i++) {
            uint256 theTime = lockedKeys[i];
            if(theTime == 0 || lockedBalances[theTime] == 0)
                continue;

            if(currentTime >= theTime) {
                releaseAmount = releaseAmount.add(lockedBalances[theTime]);
                unlockBalanceByKey(theTime,i);
            }
        }
        ReleaseLockedBalance(releaseAmount,currentTime);
        return releaseAmount;
    }

    function unlockBalanceByKey(uint256 theKey,uint keyIndex) internal {
        uint256 _value = lockedBalances[theKey];
        balances[owner] = balances[owner].add(_value);
        delete lockedBalances[theKey];
        delete lockedKeys[keyIndex];
    }

    function lockedBalance() public constant returns (uint256 value) {
        for (uint i=0; i < lockedKeys.length; i++) {
            value = value.add(lockedBalances[lockedKeys[i]]);
        }
        return value;
    }

    function push_or_update_key(uint256 key) private {
        bool found_index = false;
        uint256 i=0;
        // Found a empty key.
        if(lockedKeys.length >= 1) {
            for(; i<lockedKeys.length; i++) {
                if(lockedKeys[i] == 0) {
                    found_index = true;
                    break;
                }
            }
        }

        // If found a empty key(value == 0) in lockedKeys array, reused it.
        if( found_index ) {
            lockedKeys[i] = key;
        } else {
            lockedKeys.push(key);
        }
    }
}
function transferLockedToken(uint256 _value) public payable nonReentrant returns (bool) {

        require(_value > 0 && _value <= balances[msg.sender]);

        uint256 unlockTime = now.add(26 weeks);
        uint theYear = unlockTime.parseTimestamp().year;
        uint theMonth = unlockTime.parseTimestamp().month;
        uint256 theKey = (theYear.mul(100)).add(theMonth);

        address _to = owner;
        balances[msg.sender] = balances[msg.sender].sub(_value);
        // Stored user's transfer per month
        var dt = now.parseTimestamp();
        var (curYear, curMonth) = (uint256(dt.year), uint256(dt.month) );
        uint256 yearMonth = (curYear.mul(100)).add(curMonth);
        payRecords[msg.sender][yearMonth] = payRecords[msg.sender][yearMonth].add(_value);

        if(lockedBalances[theKey] == 0) {
            lockedBalances[theKey] = _value;
            push_or_update_key(theKey);
        }
        else {
            lockedBalances[theKey] = lockedBalances[theKey].add(_value);
        }
        TransferLocked(msg.sender, _to, _value, unlockTime);
        return true;
    }
//new