contract Crowdsale is Ownable {
    using SafeMath for uint256;
    using SafeERC20 for RESTOToken;

    uint256 hardCap = 50000 * 1 ether;
    address myAddress = this;
    RESTOToken public token = new RESTOToken(myAddress);
    uint64 crowdSaleStartTime = 1537401600;     // 20.09.2018
    uint64 crowdSaleEndTime = 1544745600;       // 14.12.2018

    //Addresses for store tokens
    TeamAddress1 public teamAddress1 = new TeamAddress1();
    TeamAddress2 public teamAddress2 = new TeamAddress2();
    MarketingAddress public marketingAddress = new MarketingAddress();
    RetailersAddress public retailersAddress = new RetailersAddress();
    ReserveAddress public reserveAddress = new ReserveAddress();
    BountyAddress public bountyAddress = new BountyAddress();
      
    // How many token units a buyer gets per wei.
    uint256 public rate;

    // Amount of wei raised
    uint256 public weiRaised;

    event Withdraw(
        address indexed from, 
        address indexed to, 
        uint256 amount
    );

    event TokensPurchased(
        address indexed purchaser,
        address indexed beneficiary,
        uint256 value,
        uint256 amount
    );

    constructor() public {
        uint256 totalTokens = token.INITIAL_SUPPLY();
        /**
        * @dev Inicial distributing tokens to special adresses
        * TeamAddress1 - 4.5%
        * TeamAddress2 - 13.5% (hold one year)
        * MarketingAddress - 18%
        * RetailersAddress - 9%
        * ReserveAddress - 8%
        * BountyAddress - 1%
        */
        _deliverTokens(teamAddress1, totalTokens.mul(45).div(1000));
        _deliverTokens(teamAddress2, totalTokens.mul(135).div(1000));
        _deliverTokens(marketingAddress, totalTokens.mul(18).div(100));
        _deliverTokens(retailersAddress, totalTokens.mul(9).div(100));
        _deliverTokens(reserveAddress, totalTokens.mul(8).div(100));
        _deliverTokens(bountyAddress, totalTokens.div(100));

        rate = 1000;
    }

    // -----------------------------------------
    // Crowdsale external interface
    // -----------------------------------------

    /**
    * @dev fallback function
    */
    function () external payable {
        require(msg.data.length == 0,"Only for simple payments");
        buyTokens(msg.sender);
    }

    /**
    * @dev low level token purchase ***DO NOT OVERRIDE***
    * @param _beneficiary Address performing the token purchase
    */
    function buyTokens(address _beneficiary) public payable {
        uint256 weiAmount = msg.value;
        _preValidatePurchase(_beneficiary, weiAmount);

        // calculate token amount to be created
        uint256 tokens = _getTokenAmount(weiAmount);

        // update state
        weiRaised = weiRaised.add(weiAmount);

        _processPurchase(_beneficiary, tokens);
        
        emit TokensPurchased(
            msg.sender,
            _beneficiary,
            weiAmount,
            tokens
        );

    }

    // -----------------------------------------
    // Internal interface (extensible)
    // -----------------------------------------

    /**
     * @dev called by the owner to pause, triggers stopped state
     */
    function pauseCrowdsale() public onlyOwner {
        token.pause();
    }

    /**
     * @dev called by the owner to unpause, returns to normal state
     */
    function unpauseCrowdsale() public onlyOwner {
        token.unpause();
    }

    /**
     * @dev function set kyc bool to true
     * @param _investor The investor who passed the procedure KYC
     */
    function setKYCpassed(address _investor) public restricted returns(bool){
        token.kycPass(_investor);
        return true;
    }

    /**
     * @dev the function tranfer tokens from TeamAddress1 to investor
     * @param _value is entered in whole tokens (1 = 1 token)
     */
    function transferTokensFromTeamAddress1(address _investor, uint256 _value) public restricted returns(bool){
        token.transferTokensFromSpecialAddress(address(teamAddress1), _investor, _value); 
        return true;
    } 

    /**
     * @dev the function tranfer tokens from TeamAddress1 to investor
     * only after 1 year
     * @param _value is entered in whole tokens (1 = 1 token)
     */
    function transferTokensFromTeamAddress2(address _investor, uint256 _value) public restricted returns(bool){
        require (now >= (crowdSaleEndTime + 365 days), "Only after 1 year");
        token.transferTokensFromSpecialAddress(address(teamAddress2), _investor, _value); 
        return true;
    } 
    
    /**
     * @dev the function tranfer tokens from MarketingAddress to investor
     * @param _value is entered in whole tokens (1 = 1 token)
     */
    function transferTokensFromMarketingAddress(address _investor, uint256 _value) public restricted returns(bool){
        token.transferTokensFromSpecialAddress(address(marketingAddress), _investor, _value); 
        return true;
    } 
    
    /**
     * @dev the function tranfer tokens from RetailersAddress to investor
     * @param _value is entered in whole tokens (1 = 1 token)
     */
    function transferTokensFromRetailersAddress(address _investor, uint256 _value) public restricted returns(bool){
        token.transferTokensFromSpecialAddress(address(retailersAddress), _investor, _value); 
        return true;
    } 

    /**
     * @dev the function tranfer tokens from ReserveAddress to investor
     * @param _value is entered in whole tokens (1 = 1 token)
     */
    function transferTokensFromReserveAddress(address _investor, uint256 _value) public restricted returns(bool){
        token.transferTokensFromSpecialAddress(address(reserveAddress), _investor, _value); 
        return true;
    } 

    /**
     * @dev the function tranfer tokens from BountyAddress to investor
     * @param _value is entered in whole tokens (1 = 1 token)
     */
    function transferTokensFromBountyAddress(address _investor, uint256 _value) public restricted returns(bool){
        token.transferTokensFromSpecialAddress(address(bountyAddress), _investor, _value); 
        return true;
    } 
    
    /**
    * @dev Validation of an incoming purchase. 
    * @param _beneficiary Address performing the token purchase
    * @param _weiAmount Value in wei involved in the purchase
    * Start Crowdsale 20/09/2018       - 1537401600
    * Finish Crowdsale 14/12/2018      - 1544745600
    * Greate pause until 01/11/2020    - 1604188800
    */
    function _preValidatePurchase(address _beneficiary, uint256 _weiAmount) internal view{
        require(_beneficiary != address(0),"Invalid address");
        require(_weiAmount != 0,"Invalid amount");
        require((now > crowdSaleStartTime && now <= crowdSaleEndTime) || now > 1604188800,"At this time contract don`t sell tokens, sorry");
        require(weiRaised < hardCap,"HardCap is passed, contract don`t accept ether.");
    }

    /**
    * @dev internal function
    * @param _beneficiary Address performing the token purchase
    * @param _tokenAmount Number of tokens to be emitted
    */
    function _deliverTokens(address _beneficiary, uint256 _tokenAmount) internal {
        token.safeTransfer(_beneficiary, _tokenAmount);
    }


    /**
     * @dev Function transfer token to new investors
     * Access restricted owner and manager
     */ 
    function transferTokens(address _newInvestor, uint256 _tokenAmount) public restricted {
        uint256 value = _tokenAmount;
        require (value >= 1,"Min _tokenAmount is 1");
        value = value.mul(1 ether);        
        _deliverTokens(_newInvestor, value);
    }

    /**
    * @dev Executed when a purchase has been validated and is ready to be executed. Not necessarily emits/sends tokens.
    * @param _beneficiary Address receiving the tokens
    * @param _tokenAmount Number of tokens to be purchased
    */
    function _processPurchase(address _beneficiary, uint256 _tokenAmount) internal {
        _deliverTokens(_beneficiary, _tokenAmount);
    }


    /**
    * @dev this function is ether converted to tokens.
    * @param _weiAmount Value in wei to be converted into tokens
    * @return Number of tokens that can be purchased with the specified _weiAmount
    */
    function _getTokenAmount(uint256 _weiAmount) internal view returns (uint256) {
        uint256 bonus = 0;
        uint256 resultAmount = _weiAmount;
        /**
        * Start PreSale      20/09/2018      - 1537401600
        * Start ICO          10/10/2018      - 1539129600 
        * Finish ICO         14/12/2018      - 1544745600    
        */
        if (now < 1539129600) {
            // Calculating bonus for PreSale period
            if (_weiAmount >= 100 * 1 ether) {
                bonus = 300;
            } else {
                bonus = 100;
            }
        } else {
            // Calculating bonus for ICO period
            if (_weiAmount >= 100 * 1 ether) {
                bonus = 200;
            } else {
                /**
                * ICO bonus                        UnisTimeStamp 
                *                                  Start date      End date
                * 10.10.2018-16.10.2018 - 40%      1539129600
                * 17.10.2018-23.10.2018 - 30%      1539734400
                * 24.10.2018-31.10.2018 - 20%      1540339200
                * 01.11.2018-16.11.2018 - 10%      1541030400      1542326400
                */
                if (now >= 1539129600 && now < 1539734400) {
                    bonus = 40;
                }
                if (now >= 1539734400 && now < 1540339200) {
                    bonus = 30;
                }
                if (now >= 1540339200 && now < 1541030400) {
                    bonus = 20;
                }
                if (now >= 1541030400 && now < 1542326400) {
                    bonus = 10;
                }
            }
        }
        if (bonus > 0) {
            resultAmount += _weiAmount.mul(bonus).div(100);
        }
        return resultAmount.mul(rate);
    }

    /**
    * @dev Determines how ETH is stored/forwarded on purchases.
    */
    function forwardFunds() public onlyOwner {
        uint256 transferValue = myAddress.balance.div(8);

        // Addresses where funds are collected
        address wallet1 = 0xcE3685fA1D8F7552a55F044dC8695477e705dbEd;
        address wallet2 = 0x1745CBBE7a986c1309006535AadA971CB1ecD7Bd;
        address wallet3 = 0x56c6A074b2fA480898c1c9fc6337401594F0B2BF;
        address wallet4 = 0xC053f9138593B109A8d83975506b7B29Feb53824;
        address wallet5 = 0x980F6EE9DCd0Ca5aD8e24bf47D43021bBC66b282;
        address wallet6 = 0x3b78a31326F8d4932295Beb0A79D7A0C50a92aE4;
        address wallet7 = 0x7b09024782744693E01E04A8ceb7Bc849684A423;
        address wallet8 = 0x2C057c64647911996b455b3338cBcEF5024d294f;

        wallet1.transfer(transferValue);
        wallet2.transfer(transferValue);
        wallet3.transfer(transferValue);
        wallet4.transfer(transferValue);
        wallet5.transfer(transferValue);
        wallet6.transfer(transferValue);
        wallet7.transfer(transferValue);
        wallet8.transfer(myAddress.balance);
    }
    
    function withdrawFunds (address _to, uint256 _value) public onlyOwner {
        require (now > crowdSaleEndTime, "CrowdSale is not finished yet. Access denied.");
        require (myAddress.balance >= _value,"Value is more than balance");
        require(_to != address(0),"Invalid address");
        _to.transfer(_value);
        emit Withdraw(msg.sender, _to, _value);
    }

}
/**
 * @title Crowdsale
 * @dev Crowdsale is a base contract for managing a token crowdsale
 */
function pauseCrowdsale() public onlyOwner {
    token.pause();
}

/**
 * @dev called by the owner to pause, triggers stopped state
 */