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

    /**
    * Price: 1 ETH = 206 token
    * https://www.coingecko.com/en/coins/ethereum
    * October, 20, 2018
    */
    uint256 public rate  = 206;

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


    uint256 public constant INITIAL_SUPPLY = 35 * 10**6 * (10 ** uint256(decimals));

    uint256 startTimePreIco = 1539993600; // Sat, 20 Oct 2018 00:00:00 GMT
    uint256 endTimePreIco =   1546300799; // Mon, 31 Dec 2018 23:59:59 GMT

    uint256 startTimeIco = 1546300800; // Tue, 01 Jan 2019 00:00:00 GMT
    uint256 endTimeIco   = 1554076799; // Sun, 31 Mar 2019 23:59:59 GMT

    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 Finalized();

    constructor(address _owner) public
    Crowdsale(_owner)
    {
        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 = 1540425600; // (25 Oct 2018) // 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(currentPeriod >= 2){
                amountOfTokens += _weiAmount.mul(rate);
            }
        }
        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( startTimeIco <= _currentDate && _currentDate <= endTimeIco){
            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(INITIAL_SUPPLY);
        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;
        }
        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 startTimePreIco
     * @param _value new time value
     */
    function setStartTimePreIco(uint256 _value) external onlyOwner {
        require(_value > 0);
        uint256 _oldValue = startTimePreIco;
        startTimePreIco = _value;
        emit ChangeTime(msg.sender, _value, _oldValue);
    }


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

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

    /**
     * @dev owner change time for endTimeIco
     * @param _value new time value
     */
    function setEndTimeIco(uint256 _value) external onlyOwner {
        require(_value > 0);
        uint256 _oldValue = endTimeIco;
        endTimeIco = _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);
    }

    /**
     * @dev owner completes contract
     */
    function finalize() public onlyOwner returns (bool result) {
        result = false;
        transfersEnabled = false;
        finishMinting();
        emit Finalized();
        result = true;
    }

}
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 burn Token.
 * @param _value amount of burnt tokens
 */