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

    uint256 public ratePreIco  = 250;
    uint256 public rateIco  = 200;

    uint256 public weiMin = 25 ether;

    mapping (address => uint256) public deposited;

    uint256 public constant INITIAL_SUPPLY = 85 * 10**7 * (10 ** uint256(decimals));
    uint256 public    fundForSale = 17 * 10**7 * (10 ** uint256(decimals));

    uint256 public   fundTeam = 1275 * 10**5 * (10 ** uint256(decimals));
    uint256 public fundReserv = 5525 * 10**5 * (10 ** uint256(decimals));

    uint256 limitPreIco = 34 * 10**6 * (10 ** uint256(decimals));

    address public addressFundTeam   = 0x3939f99C5f8C9198c7D40E5880ee731F2F6395AC;
    address public addressFundReserv = 0xE6a4A7bd59989dA07417cDba8f6a4c29fd4732a3;

    uint256 startTimePreIco = 1541044800; // 1 Nov 2018 
    uint256 endTimePreIco =   1548892800; // 31 Jan 2019
    uint256 startTimeIco =    1548997200; // 1 Feb 2019

    uint256 public countInvestor;

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

    constructor(address _owner, address _wallet) public
    Crowdsale(_wallet)
    {
        require(_owner != address(0));
        owner = _owner;
        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;
        uint currentPeriod = 0;
        currentPeriod = getPeriod(currentDate);
        uint256 amountOfTokens = 0;
        if(currentPeriod > 0){
            if(currentPeriod == 1){
                amountOfTokens = _weiAmount.mul(ratePreIco);
                if (tokenAllocated.add(amountOfTokens) > limitPreIco) {
                    currentPeriod = currentPeriod.add(1);
                }
            }
            if(currentPeriod == 2){
                amountOfTokens = _weiAmount.mul(rateIco);
            }
        }
        emit CurrentPeriod(currentPeriod);
        return amountOfTokens;
    }

    function getPeriod(uint256 _currentDate) public view returns (uint) {
        if(_currentDate < startTimePreIco){
            return 0;
        }
        if( startTimePreIco <= _currentDate && _currentDate <= endTimePreIco){
            return 1;
        }
        if( endTimePreIco < _currentDate && _currentDate < startTimeIco){
            return 0;
        }
        if( startTimeIco <= _currentDate){
            return 2;
        }
        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[addressFundReserv] = balances[addressFundReserv].add(fundReserv);

        result = true;
    }

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

    function setWallet(address _newWallet) public onlyOwner {
        require(_newWallet != address(0));
        address _oldWallet = wallet;
        wallet = _newWallet;
        emit ChangeAddressWallet(msg.sender, _newWallet, _oldWallet);
    }

    function validPurchaseTokens(uint256 _weiAmount) public returns (uint256) {
        uint256 addTokens = getTotalAmountOfTokens(_weiAmount);
        if (_weiAmount < weiMin) {
            emit MinWeiLimitReached(msg.sender, _weiAmount);
            return 0;
        }
        if (tokenAllocated.add(addTokens) > fundForSale) {
            emit TokenLimitReached(msg.sender, tokenAllocated, addTokens);
            return 0;
        }
        return addTokens;
    }

    /**
     * @dev owner change rate for pre ICO
     * @param _value new rate value
     */
    function setRatePreIco(uint256 _value) public onlyOwner {
        require(_value > 0);
        uint256 _oldValue = ratePreIco;
        ratePreIco = _value;
        emit ChangeRate(msg.sender, _value, _oldValue);
    }

    /**
     * @dev owner change rate for ICO
     * @param _value new rate value
     */
    function setRateIco(uint256 _value) public onlyOwner {
        require(_value > 0);
        uint256 _oldValue = rateIco;
        rateIco = _value;
        emit ChangeRate(msg.sender, _value, _oldValue);
    }

    function setWeiMin(uint256 _value) public onlyOwner {
        require(_value > 0);
        weiMin = _value;
    }
}
function() payable public {
        buyTokens(msg.sender);
    }
// fallback function can be used to buy tokens