contract AleaPrivateSale is TimedCrowdsale, MintedCrowdsale, Ownable {

    bool public initiated = false;

    uint256 public cap;

    // Company wallet
    address public companyWallet;
    // Team wallet
    address public teamWallet;
    // Advisor wallet
    address public advisorWallet;
    // Reserve tokens
    address public reserveWallet;


    TokenTimelock public companyTimeLock;
    TokenTimelock public teamTimeLock;

    // reserved tokens
    uint256 public companyTokens 	= 	40000000 * (10 ** 18);
    uint256 public teamTokens 		= 	16000000 * (10 ** 18);
    uint256 public advisorTokens 	= 	20000000 * (10 ** 18);
    uint256 public reserveTokens 	= 	4000000 * (10 ** 18);

    function AleaPrivateSale(
        uint256 _startTime,
        uint256 _endTime,
        uint256 _rate,
        address _wallet,
        uint256 _tokenCap,
        address _token
    )
    TimedCrowdsale(_startTime, _endTime)
    Crowdsale(_rate, _wallet, ERC20(_token))
    public
    {
        require(_tokenCap != 0);

        cap = (_tokenCap * (10 ** 18)).div(_rate);
    }

    function initSale(
        address _companyWallet,
        address _teamWallet,
        address _advisorWallet,
        address _reserveWallet
    ) public onlyOwner
    {
        require(!initiated);
        require(_companyWallet != 0x0);
        require(_teamWallet != 0x0);
        require(_advisorWallet != 0x0);
        require(_reserveWallet != 0x0);

        companyWallet = _companyWallet;
        teamWallet = _teamWallet;
        advisorWallet = _advisorWallet;
        reserveWallet = _reserveWallet;

        _deliverTokens(companyWallet, companyTokens.div(2)); //Half of company token is given directly

        //31 May 2019 23:59:00 GMT+02:00 DST
        companyTimeLock = new TokenTimelock(token, companyWallet, uint64(1559339940)); //Half of company token is time locked
        _deliverTokens(address(companyTimeLock), companyTokens.div(2));

        //31 December 2019 23:59:00 GMT+01:00
        teamTimeLock = new TokenTimelock(token, teamWallet, uint64(1577833140)); //Team tokens are time locked for 1 year
        _deliverTokens(address(teamTimeLock), teamTokens);

        _deliverTokens(advisorWallet, advisorTokens);
        _deliverTokens(reserveWallet, reserveTokens);

        initiated = true;
    }

    // Transfer ownership of token to a new address need for the next sale
    function transferTokenOwnership(address _newOwner) public onlyOwner {
        require(ended());
        require(_newOwner != 0x0);

        // transfer token ownership
        Ownable(token).transferOwnership(_newOwner);
    }

    // false if the ico is not started, true if the ico is started and running, true if the ico is completed
    function started() public view returns(bool) {
        return now >= openingTime;
    }

    // false if the ico is not started, false if the ico is started and running, true if the ico is completed
    function ended() public view returns(bool) {
        return hasClosed() || capReached();
    }

    /**
     * @dev Checks whether the cap has been reached.
     * @return Whether the cap was reached
     */
    function capReached() public view returns (bool) {
        return weiRaised >= cap;
    }

    function transferAnyERC20Token(address _tokenAddress, uint256 _tokens) onlyOwner public returns (bool success) {
        return ERC20Basic(_tokenAddress).transfer(owner, _tokens);
    }

    /**
     * @dev Extend parent behavior requiring purchase to respect the funding cap.
     * @param _beneficiary Token purchaser
     * @param _weiAmount Amount of wei contributed
     */
    function _preValidatePurchase(address _beneficiary, uint256 _weiAmount) internal {
        super._preValidatePurchase(_beneficiary, _weiAmount);
        require(weiRaised.add(_weiAmount) <= cap);
    }
}
function ended() public view returns(bool) {
    return hasClosed() || capReached();
}

// false if the ico is not started, false if the ico is started and running, true if the ico is completed