contract DepoToken is StandardToken, BurnableToken, Owned {
    string public constant name = "Depository Network Token";
    string public constant symbol = "DEPO";
    uint8 public constant decimals = 18;

    /// Maximum tokens to be allocated (3 billion DEPO)
    uint256 public constant HARD_CAP = 3000000000 * 10**uint256(decimals);

    /// This address is used to keep the tokens for sale
    address public saleTokensAddress;

    /// This address is used to keep the bounty and airdrop tokens
    address public bountyTokensAddress;

    /// This address is used to keep the reserve tokens
    address public reserveTokensAddress;

    /// This address will receive the team and founders tokens once they are unlocked
    address public teamTokensAddress;

    /// This address is used to keep the advisors tokens
    address public advisorsTokensAddress;

    /// This address will hold the locked team tokens
    TokenTimelock public teamTokensLock;

    /// the trading will open when this is set to true
    bool public saleClosed = false;

    /// Some addresses are whitelisted in order to be able to distribute bounty tokens before the trading is open
    mapping(address => bool) public whitelisted;

    /// Only allowed to execute before the token sale is closed
    modifier beforeEnd {
        require(!saleClosed);
        _;
    }

    constructor(address _teamTokensAddress, address _advisorsTokensAddress, address _reserveTokensAddress,
                address _saleTokensAddress, address _bountyTokensAddress) public {
        require(_teamTokensAddress != address(0));
        require(_advisorsTokensAddress != address(0));
        require(_reserveTokensAddress != address(0));
        require(_saleTokensAddress != address(0));
        require(_bountyTokensAddress != address(0));

        teamTokensAddress = _teamTokensAddress;
        advisorsTokensAddress = _advisorsTokensAddress;
        reserveTokensAddress = _reserveTokensAddress;
        saleTokensAddress = _saleTokensAddress;
        bountyTokensAddress = _bountyTokensAddress;

        whitelisted[saleTokensAddress] = true;
        whitelisted[bountyTokensAddress] = true;

        /// Maximum tokens to be allocated on the sale
        /// 1.5 billion DEPO
        uint256 saleTokens = 1500000000 * 10**uint256(decimals);
        totalSupply_ = saleTokens;
        balances[saleTokensAddress] = saleTokens;
        emit Transfer(address(0), saleTokensAddress, saleTokens);

        /// Bounty and airdrop tokens - 180 million DEPO
        uint256 bountyTokens = 180000000 * 10**uint256(decimals);
        totalSupply_ = totalSupply_.add(bountyTokens);
        balances[bountyTokensAddress] = bountyTokens;
        emit Transfer(address(0), bountyTokensAddress, bountyTokens);

        /// Reserve tokens - 780 million DEPO
        uint256 reserveTokens = 780000000 * 10**uint256(decimals);
        totalSupply_ = totalSupply_.add(reserveTokens);
        balances[reserveTokensAddress] = reserveTokens;
        emit Transfer(address(0), reserveTokensAddress, reserveTokens);

        /// Team tokens - 360 million DEPO
        uint256 teamTokens = 360000000 * 10**uint256(decimals);
        totalSupply_ = totalSupply_.add(teamTokens);
        teamTokensLock = new TokenTimelock(this, teamTokensAddress, uint64(now + 2 * 365 days));
        balances[address(teamTokensLock)] = teamTokens;
        emit Transfer(address(0), address(teamTokensLock), teamTokens);

        /// Advisors tokens - 180 million DEPO
        uint256 advisorsTokens = 180000000 * 10**uint256(decimals);
        totalSupply_ = totalSupply_.add(advisorsTokens);
        balances[advisorsTokensAddress] = advisorsTokens;
        emit Transfer(address(0), advisorsTokensAddress, advisorsTokens);

        require(totalSupply_ <= HARD_CAP);
    }

    /// @dev the trading will open when this is set to true
    function close() public onlyOwner beforeEnd {
        saleClosed = true;
    }

    /// @dev whitelist an address so it's able to transfer
    /// before the trading is opened
    function whitelist(address _address) external onlyOwner {
        whitelisted[_address] = true;
    }

    /// @dev Trading limited - requires the token sale to have closed
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
        if(!saleClosed) return false;
        return super.transferFrom(_from, _to, _value);
    }

    /// @dev Trading limited - requires the token sale to have closed
    function transfer(address _to, uint256 _value) public returns (bool) {
        if(!saleClosed && !whitelisted[msg.sender]) return false;
        return super.transfer(_to, _value);
    }
}
function whitelist(address _address) external onlyOwner {
    whitelisted[_address] = true;
}

/// @dev whitelist an address so it's able to transfer
/// before the trading is opened