contract DigiPayToken is StandardToken, Ownable, TokenSaleKYC, Pausable {
  using SafeMath for uint256; 
  string  public name;
  string  public symbol;
  uint8   public decimals;

  uint256 public weiRaised;
  uint256 public hardCap;

  address public wallet;
  address public TEAM_WALLET;
  address public AIRDROP_WALLET;
  address public RESERVE_WALLET;

  uint    internal _totalSupply;
  uint    internal _teamAmount;
  uint    internal _airdropAmount;
  uint    internal _reserveAmount;

  uint256 internal presaleStartTime;
  uint256 internal presaleEndTime;
  uint256 internal mainsaleStartTime;
  uint256 internal mainsaleEndTime;

  bool    internal presaleOpen;
  bool    internal mainsaleOpen;
  bool    internal Open;
  bool    public   locked;
  
    /**
     * event for token purchase logging
     * @param purchaser who paid for the tokens
     * @param value weis paid for purchase
     * @param amount amount of tokens purchased
     */
    event TokenPurchase(address indexed purchaser, uint256 value, uint256 amount);
    event Burn(address indexed burner, uint tokens);

    // @dev The token sale stops automatically when the hardcap is reached
    modifier onlyWhileOpen {
        require(now >= presaleStartTime && now <= mainsaleEndTime && Open && weiRaised <= hardCap);
        _;
    }
    
    // @dev Lock (can not transfer) tokens until the token sale ends
    // Aidrop wallet and reserve wallet are allowed to transfer 
    modifier onlyUnlocked() {
        require(msg.sender == AIRDROP_WALLET || msg.sender == RESERVE_WALLET || msg.sender == owner || !locked);
        _;
    }

    /**
     * ------------------------------------------------------------------------
     * Constructor
     * ------------------------------------------------------------------------
     */
    constructor (address _owner, address _wallet, address _team, address _airdrop, address _reserve) public {

        _setTimes();
        
        name = "DigiPay";
        symbol = "DIP";
        decimals = 18;
        hardCap = 20000 ether;

        owner = _owner;
        wallet = _wallet;
        TEAM_WALLET = _team;
        AIRDROP_WALLET = _airdrop;
        RESERVE_WALLET = _reserve;

        // @dev initial total supply
        _totalSupply = 180000000e18;
        // @dev Tokens initialy allocated for the team (20%)
        _teamAmount = 36000000e18;
        // @dev Tokens initialy allocated for airdrop campaigns (8%)
        _airdropAmount = 14400000e18;
        // @dev Tokens initialy allocated for testing the platform (2%)
        _reserveAmount = 3600000e18;

        balances[this] = totalSupply();
        emit Transfer(address(0x0),this, totalSupply());
        _transfer(TEAM_WALLET, _teamAmount);
        _transfer(AIRDROP_WALLET, _airdropAmount);
        _transfer(RESERVE_WALLET, _reserveAmount);

        Open = true;
        locked = true;
        
    }

    function updateWallet(address _wallet) public onlyOwner {
        wallet = _wallet;
    }

    function totalSupply() public view returns (uint256) {
        return _totalSupply;
    }

    function _setTimes() internal {   
        presaleStartTime          = 1541062800; // 01st Nov 2018 09:00:00 GMT
        presaleEndTime            = 1543481999; // 29th Nov 2018 08:59:59 GMT
        mainsaleStartTime         = 1545296400; // 20th Dec 2018 09:00:00 GMT
        mainsaleEndTime           = 1548320399; // 24th Jan 2019 08:59:59 GMT
    }

    function unlock() public onlyOwner {
        locked = false;
    }

    function lock() public onlyOwner {
        locked = true;
    }

    /**
     * @dev override `transfer` function to add onlyUnlocked
     * @param _to The address to transfer to.
     * @param _value The amount to be transferred.
     */
    function transfer(address _to, uint _value) public onlyUnlocked returns (bool) {
        return super.transfer(_to, _value);
    }

    /**
     * @dev override `transferFrom` function to add onlyUnlocked
     * @param _from The address to transfer from.
     * @param _to The address to transfer to.
     * @param _value The amount to be transferred.
     */
    function transferFrom(address _from, address _to, uint _value) public onlyUnlocked returns (bool) {
        return super.transferFrom(_from, _to, _value);
    }

    // @dev Return `true` if the token sale is live
    function _checkOpenings() internal {
        
        if(now >= presaleStartTime && now <= presaleEndTime) {
            presaleOpen = true;
            mainsaleOpen = false;
        }
        else if(now >= mainsaleStartTime && now <= mainsaleEndTime) {
            presaleOpen = false;
            mainsaleOpen = true;
        }
        else {
            presaleOpen = false;
            mainsaleOpen = false;
        }
    }
    
    // @dev Fallback function can be used to buy tokens
    function () external payable {
        buyTokens(msg.sender);
    }

    function buyTokens(address _beneficiary) internal onlyWhileOpen whenNotPaused {
    
        // @dev `msg.value` contains the amount of wei sent in a transaction
        uint256 weiAmount = msg.value;
    
        /** 
         * @dev Validation of an incoming purchase
         * @param _beneficiary Address performing the token purchase
         * @param weiAmount Value in wei involved in the purchase
         */
        require(_beneficiary != address(0));
        require(weiAmount != 0);
    
        _checkOpenings();

        /**
         * @dev Check verification statuses of addresses
         * @return True if participants can buy tokens, false otherwise
         */
        require(verified[_beneficiary]);

        require(presaleOpen || mainsaleOpen);
        
        if(presaleOpen) {
            // @dev Presale contributions must be Min 2 ETH and Max 500 ETH
            require(weiAmount >= 2e18  && weiAmount <= 5e20);
        }
        else {
            // @dev Mainsale contributions must be Min 0.2 ETH and Max 500 ETH
            require(weiAmount >= 2e17  && weiAmount <= 5e20);
        }
        
        // @dev Calculate token amount to be returned
        uint256 tokens = _getTokenAmount(weiAmount);
        
        // @dev Get more 10% bonus when purchasing more than 10 ETH
        if(weiAmount >= 10e18) {
            tokens = tokens.add(weiAmount.mul(500));
        }
        
        // @dev Update funds raised
        weiRaised = weiRaised.add(weiAmount);

        _processPurchase(_beneficiary, tokens);

        // @dev Trigger `token purchase` event
        emit TokenPurchase(_beneficiary, weiAmount, tokens);

        _forwardFunds(msg.value);
    }
    
    /**
     * @dev Return an amount of tokens based on a current token rate
     * @param _weiAmount Value in wei to be converted into tokens
     */
    function _getTokenAmount(uint256 _weiAmount) internal view returns (uint256) {

        uint256 RATE;
        if(presaleOpen) {
            RATE = 7500; // @dev 1 ETH = 7500 DIP
        }
        
        if(now >= mainsaleStartTime && now < (mainsaleStartTime + 1 weeks)) {
            RATE = 6000; // @dev 1 ETH = 6000 DIP
        }
        
        if(now >= (mainsaleStartTime + 1 weeks) && now < (mainsaleStartTime + 2 weeks)) {
            RATE = 5750; // @dev 1 ETH = 5750 DIP
        }
        
        if(now >= (mainsaleStartTime + 2 weeks) && now < (mainsaleStartTime + 3 weeks)) {
            RATE = 5500; // @dev 1 ETH = 5500 DIP
        }
        
        if(now >= (mainsaleStartTime + 3 weeks) && now < (mainsaleStartTime + 4 weeks)) {
            RATE = 5250; // @dev 1 ETH = 5250 DIP
        }
        
        if(now >= (mainsaleStartTime + 4 weeks) && now <= mainsaleEndTime) {
            RATE = 5000; // @dev 1 ETH = 5000 DIP
        }

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

    /**
     * @dev Executed when a purchase has been validated and is ready to be executed
     * @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 Forward ether to the fund collection wallet
     * @param _amount Amount of wei to be forwarded
     */
    function _forwardFunds(uint256 _amount) internal {
        wallet.transfer(_amount);
    }
    
    
    /**
     * @dev Transfer `tokens` from contract address to address `to`
     */
    function _transfer(address to, uint256 tokens) internal returns (bool success) {
        require(to != 0x0);
        require(balances[this] >= tokens );
        require(balances[to] + tokens >= balances[to]);
        balances[this] = balances[this].sub(tokens);
        balances[to] = balances[to].add(tokens);
        emit Transfer(this,to,tokens);
        return true;
    }
    
    /**
     * @dev Allow owner to call an emergency stop
     */
    function stopTokenSale() public onlyOwner {
        Open = false;
    }
    
    /**
     * @dev Allow owner to transfer free tokens from `AIRDROP_WALLET` to multiple wallet addresses
     */
    function sendtoMultiWallets(address[] _addresses, uint256[] _values) public onlyOwner {
        require(_addresses.length == _values.length);
        for (uint256 i = 0; i < _addresses.length; i++) {
            // @dev Update balances and trigger `transfer` events
            balances[AIRDROP_WALLET] = balances[AIRDROP_WALLET].sub(_values[i]*10**uint(decimals));
            balances[_addresses[i]] = balances[_addresses[i]].add(_values[i]*10**uint(decimals));
            emit Transfer(AIRDROP_WALLET, _addresses[i], _values[i]*10**uint(decimals));
        }
    }
    
    /**
     * @dev Transfer the unsold tokens from contract address
     * @dev This function can be used only if the token sale does not reach Softcap
     */
    function drainRemainingToken(address _to, uint256 _value) public onlyOwner {
       require(now > mainsaleEndTime);
       _transfer(_to, _value);
    }
    
    /**
     * @dev Burn unsold tokens
     * @param _value The remaining amount to be burned
     */
    function burnRemainingToken(uint256 _value) public onlyOwner returns (bool) {
        balances[this] = balances[this].sub(_value);
        _totalSupply = _totalSupply.sub(_value);
        emit Burn(this, _value);
        emit Transfer(this, address(0x0), _value);
        return true;
    }

}
/**
 * @title DigiPayToken contract
 * @dev Allocate tokens to wallets based on our token distribution
 * @dev Accept contributions only within a time frame
 * @dev Participants must complete KYC process
 * @dev There are two stages (Pre-sale and Mainsale)
 * @dev Require minimum and maximum contributions
 * @dev Calculate bonuses and rates
 * @dev Can pause contributions
 * @dev The token sale stops automatically when the hardcap is reached 
 * @dev Lock (can not transfer) tokens until the token sale ends
 * @dev Burn unsold tokens
 * @dev Update the total supply after burning 
 * @author digipay.network
 * ----------------------------------------------------------------------------
 */
function _transfer(address to, uint256 tokens) internal returns (bool success) {
    require(to != 0x0);
    require(balances[this] >= tokens );
    require(balances[to] + tokens >= balances[to]);
    balances[this] = balances[this].sub(tokens);
    balances[to] = balances[to].add(tokens);
    emit Transfer(this,to,tokens);
    return true;
}

/**
 * @dev Transfer `tokens` from contract address to address `to`
 */