contract Token is AdditionalToken, PausableToken {

    using SafeMath for uint256;
    
    string public  name;
    string public symbol;
    uint256 public decimals;

    mapping(address => bool) public singleLockFinished;
    
    struct lockToken {
        uint256 amount;
        uint256 validity;
    }

    mapping(address => lockToken[]) public locked;
    
    
    event Lock(
        address indexed _of,
        uint256 _amount,
        uint256 _validity
    );
    
    function () payable public  {
        revert();
    }
    
    constructor (string _symbol, string _name, uint256 _decimals, uint256 _initSupply, 
                    uint256 _maxProportion, uint256 _lockedYears) AdditionalToken(_maxProportion, _lockedYears) public {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;
        totalSupply = totalSupply.add(_initSupply * (10 ** decimals));
        balances[address(this)] = totalSupply;
    }

    /**
     * @dev Lock the special address 
     *
     * @param _time The array of released timestamp 
     * @param _amountWithoutDecimal The array of amount of released tokens
     * NOTICE: the amount in this function not include decimals. 
     */
    
    function lock(address _address, uint256[] _time, uint256[] _amountWithoutDecimal) onlyAdminer public returns(bool) {
        require(!singleLockFinished[_address]);
        require(_time.length == _amountWithoutDecimal.length);
        if(locked[_address].length != 0) {
            locked[_address].length = 0;
        }
        uint256 len = _time.length;
        uint256 totalAmount = 0;
        uint256 i = 0;
        for(i = 0; i<len; i++) {
            totalAmount = totalAmount.add(_amountWithoutDecimal[i]*(10 ** decimals));
        }
        require(balances[_address] >= totalAmount);
        for(i = 0; i < len; i++) {
            locked[_address].push(lockToken(_amountWithoutDecimal[i]*(10 ** decimals), block.timestamp.add(_time[i])));
            emit Lock(_address, _amountWithoutDecimal[i]*(10 ** decimals), block.timestamp.add(_time[i]));
        }
        return true;
    }
    
    function finishSingleLock(address _address) onlyAdminer public {
        singleLockFinished[_address] = true;
    }
    
    /**
     * @dev Returns tokens locked for a specified address for a
     *      specified purpose at a specified time
     *
     * @param _of The address whose tokens are locked
     * @param _time The timestamp to query the lock tokens for
     */
    function tokensLocked(address _of, uint256 _time)
        public
        view
        returns (uint256 amount)
    {
        for(uint256 i = 0;i < locked[_of].length;i++)
        {
            if(locked[_of][i].validity>_time)
                amount += locked[_of][i].amount;
        }
    }

    /**
     * @dev Returns tokens available for transfer for a specified address
     * @param _of The address to query the the lock tokens of
     */
    function transferableBalanceOf(address _of)
        public
        view
        returns (uint256 amount)
    {
        uint256 lockedAmount = 0;
        lockedAmount += tokensLocked(_of, block.timestamp);
        amount = balances[_of].sub(lockedAmount);
    }
    
    function transfer(address _to, uint256 _value) public  returns (bool) {
        require(_value <= transferableBalanceOf(msg.sender));
        return super.transfer(_to, _value);
    }

    function transferFrom(address _from, address _to, uint256 _value) public  returns (bool) {
        require(_value <= transferableBalanceOf(_from));
        return super.transferFrom(_from, _to, _value);
    }
    
    function transferAnyERC20Token(address tokenAddress, uint tokens) public onlyAdminer returns (bool success) {
        return ERC20(tokenAddress).transfer(owner, tokens);
    }
}
/**
 * @title Token contract for VEEC
 */
function tokensLocked(address _of, uint256 _time)
    public
    view
    returns (uint256 amount)
{
    for(uint256 i = 0;i < locked[_of].length;i++)
    {
        if(locked[_of][i].validity>_time)
            amount += locked[_of][i].amount;
    }
}

/**
 * @dev Returns tokens locked for a specified address for a
 *      specified purpose at a specified time
 *
 * @param _of The address whose tokens are locked
 * @param _time The timestamp to query the lock tokens for
 */