contract WSPXCrowdsale is Ownable, Crowdsale, MintableToken {
    using SafeMath for uint256;

    uint256 public rate  = 312500;

    mapping (address => uint256) public deposited;
    mapping (address => bool) internal isRefferer;

    uint256 public weiMinSale = 0.1 ether;

    uint256 public constant INITIAL_SUPPLY = 9 * 10**9 * (10 ** uint256(decimals));

    uint256 public fundForSale   = 6 * 10**9 * (10 ** uint256(decimals));
    uint256 public    fundTeam   = 1 * 10**9 * (10 ** uint256(decimals));
    uint256 public    fundBounty = 2 * 10**9 * (10 ** uint256(decimals));

    address public addressFundTeam   = 0xA2434A8F6457fe7CF29AEa841cf3D0B0FE3217c8;
    address public addressFundBounty = 0x8828c48DEc2764868aD3bBf7fE9e8aBE773E3064;

    // 1 Jan - 15 Jan
    uint256 startTimeIcoStage1 = 1546300800; // Tue, 01 Jan 2019 00:00:00 GMT
    uint256 endTimeIcoStage1 =   1547596799; // Tue, 15 Jan 2019 23:59:59 GMT

    // 16 Jan - 31 Jan
    uint256 startTimeIcoStage2 = 1547596800; // Wed, 16 Jan 2019 00:00:00 GMT
    uint256 endTimeIcoStage2   = 1548979199; // Thu, 31 Jan 2019 23:59:59 GMT

    // 1 Feb - 15 Feb
    uint256 startTimeIcoStage3 = 1548979200; // Fri, 01 Feb 2019 00:00:00 GMT
    uint256 endTimeIcoStage3   = 1554076799; // Fri, 15 Feb 2019 23:59:59 GMT

    uint256 limitStage1 =  2 * 10**9 * (10 ** uint256(decimals));
    uint256 limitStage2 =  4 * 10**9 * (10 ** uint256(decimals));
    uint256 limitStage3 =  6 * 10**9 * (10 ** uint256(decimals));

    uint256 public countInvestor;

    event TokenPurchase(address indexed beneficiary, uint256 value, uint256 amount);
    event TokenLimitReached(address indexed sender, uint256 tokenRaised, uint256 purchasedToken);
    event CurrentPeriod(uint period);
    event ChangeTime(address indexed owner, uint256 newValue, uint256 oldValue);
    event ChangeAddressWallet(address indexed owner, address indexed newAddress, address indexed oldAddress);
    event ChangeRate(address indexed owner, uint256 newValue, uint256 oldValue);
    event Burn(address indexed burner, uint256 value);
    event HardCapReached();


    constructor(address _owner, address _wallet) public
    Crowdsale(_wallet)
    {
        require(_owner != address(0));
        owner = _owner;
        //owner = msg.sender; // for test's
        transfersEnabled = true;
        mintingFinished = false;
        totalSupply = INITIAL_SUPPLY;
        bool resultMintForOwner = mintForFund(owner);
        require(resultMintForOwner);
    }

    // fallback function can be used to buy tokens
    function() payable public {
        buyTokens(msg.sender);
    }

    function buyTokens(address _investor) public payable returns (uint256){
        require(_investor != address(0));
        uint256 weiAmount = msg.value;
        uint256 tokens = validPurchaseTokens(weiAmount);
        if (tokens == 0) {revert();}
        weiRaised = weiRaised.add(weiAmount);
        tokenAllocated = tokenAllocated.add(tokens);
        mint(_investor, tokens, owner);

        emit TokenPurchase(_investor, weiAmount, tokens);
        if (deposited[_investor] == 0) {
            countInvestor = countInvestor.add(1);
        }
        deposit(_investor);
        wallet.transfer(weiAmount);
        return tokens;
    }

    function getTotalAmountOfTokens(uint256 _weiAmount) internal returns (uint256) {
        uint256 currentDate = now;
        //currentDate = 1547114400; // Thu, 10 Jan 2019 10:00:00 GMT // for test's
        uint currentPeriod = 0;
        currentPeriod = getPeriod(currentDate);
        uint256 amountOfTokens = 0;
        if(currentPeriod > 0){
            if(currentPeriod == 1){
                amountOfTokens = _weiAmount.mul(rate).mul(130).div(100);
                if (tokenAllocated.add(amountOfTokens) > limitStage1) {
                    currentPeriod = currentPeriod.add(1);
                    amountOfTokens = 0;
                }
            }
            if(currentPeriod == 2){
                amountOfTokens = _weiAmount.mul(rate).mul(120).div(100);
                if (tokenAllocated.add(amountOfTokens) > limitStage2) {
                    currentPeriod = currentPeriod.add(1);
                    amountOfTokens = 0;
                }
            }
            if(currentPeriod == 3){
                amountOfTokens = _weiAmount.mul(rate).mul(110).div(100);
                if (tokenAllocated.add(amountOfTokens) > limitStage3) {
                    currentPeriod = 0;
                    amountOfTokens = 0;
                }
            }
        }
        emit CurrentPeriod(currentPeriod);
        return amountOfTokens;
    }

    function getPeriod(uint256 _currentDate) public view returns (uint) {
        if(_currentDate < startTimeIcoStage1){
            return 0;
        }
        if( startTimeIcoStage1 <= _currentDate && _currentDate <= endTimeIcoStage1){
            return 1;
        }
        if( startTimeIcoStage2 <= _currentDate && _currentDate <= endTimeIcoStage2){
            return 2;
        }
        if( startTimeIcoStage3 <= _currentDate && _currentDate <= endTimeIcoStage3){
            return 3;
        }
        return 0;
    }

    function deposit(address investor) internal {
        deposited[investor] = deposited[investor].add(msg.value);
    }

    function mintForFund(address _walletOwner) internal returns (bool result) {
        result = false;
        require(_walletOwner != address(0));
        balances[_walletOwner] = balances[_walletOwner].add(fundForSale);
        balances[addressFundTeam] = balances[addressFundTeam].add(fundTeam);
        balances[addressFundBounty] = balances[addressFundBounty].add(fundBounty);
        result = true;
    }

    function getDeposited(address _investor) external view returns (uint256){
        return deposited[_investor];
    }

    function validPurchaseTokens(uint256 _weiAmount) public returns (uint256) {
        uint256 addTokens = getTotalAmountOfTokens(_weiAmount);
        if (tokenAllocated.add(addTokens) > balances[owner]) {
            emit TokenLimitReached(msg.sender, tokenAllocated, addTokens);
            return 0;
        }
        if (weiRaised.add(_weiAmount) > hardWeiCap) {
            emit HardCapReached();
            return 0;
        }
        if (_weiAmount < weiMinSale) {
            return 0;
        }

    return addTokens;
    }

    /**
     * @dev owner burn Token.
     * @param _value amount of burnt tokens
     */
    function ownerBurnToken(uint _value) public onlyOwner {
        require(_value > 0);
        require(_value <= balances[owner]);
        require(_value <= totalSupply);

        balances[owner] = balances[owner].sub(_value);
        totalSupply = totalSupply.sub(_value);
        emit Burn(msg.sender, _value);
    }

    /**
     * @dev owner change time for startTimeIcoStage1
     * @param _value new time value
     */
    function setStartTimeIcoStage1(uint256 _value) external onlyOwner {
        require(_value > 0);
        uint256 _oldValue = startTimeIcoStage1;
        startTimeIcoStage1 = _value;
        emit ChangeTime(msg.sender, _value, _oldValue);
    }

    /**
     * @dev owner change time for endTimeIcoStage1
     * @param _value new time value
     */
    function setEndTimeIcoStage1(uint256 _value) external onlyOwner {
        require(_value > 0);
        uint256 _oldValue = endTimeIcoStage1;
        endTimeIcoStage1 = _value;
        emit ChangeTime(msg.sender, _value, _oldValue);
    }

    /**
     * @dev owner change time for startTimeIcoStage2
     * @param _value new time value
     */
    function setStartTimeIcoStage2(uint256 _value) external onlyOwner {
        require(_value > 0);
        uint256 _oldValue = startTimeIcoStage2;
        startTimeIcoStage2 = _value;
        emit ChangeTime(msg.sender, _value, _oldValue);
    }


    /**
     * @dev owner change time for endTimeIcoStage2
     * @param _value new time value
     */
    function setEndTimeIcoStage2(uint256 _value) external onlyOwner {
        require(_value > 0);
        uint256 _oldValue = endTimeIcoStage2;
        endTimeIcoStage2 = _value;
        emit ChangeTime(msg.sender, _value, _oldValue);
    }

    /**
 * @dev owner change time for startTimeIcoStage3
 * @param _value new time value
 */
    function setStartTimeIcoStage3(uint256 _value) external onlyOwner {
        require(_value > 0);
        uint256 _oldValue = startTimeIcoStage3;
        startTimeIcoStage3 = _value;
        emit ChangeTime(msg.sender, _value, _oldValue);
    }


    /**
     * @dev owner change time for endTimeIcoStage3
     * @param _value new time value
     */
    function setEndTimeIcoStage3(uint256 _value) external onlyOwner {
        require(_value > 0);
        uint256 _oldValue = endTimeIcoStage3;
        endTimeIcoStage3 = _value;
        emit ChangeTime(msg.sender, _value, _oldValue);
    }

    /**
     * @dev owner change address of wallet for collecting ETH
     * @param _newWallet new address of wallet
     */
    function setWallet(address _newWallet) external onlyOwner {
        require(_newWallet != address(0));
        address _oldWallet = wallet;
        wallet = _newWallet;
        emit ChangeAddressWallet(msg.sender, _newWallet, _oldWallet);
    }

    /**
     * @dev owner change price of tokens
     * @param _newRate new price
     */
    function setRate(uint256 _newRate) external onlyOwner {
        require(_newRate > 0);
        uint256 _oldRate = rate;
        rate = _newRate;
        emit ChangeRate(msg.sender, _newRate, _oldRate);
    }
}
function setEndTimeIcoStage1(uint256 _value) external onlyOwner {
    require(_value > 0);
    uint256 _oldValue = endTimeIcoStage1;
    endTimeIcoStage1 = _value;
    emit ChangeTime(msg.sender, _value, _oldValue);
}

/**
 * @dev owner change time for endTimeIcoStage1
 * @param _value new time value
 */