contract NewWiraTokenSale is Pausable {
   using SafeMath for uint256;

   TokenInterface public token;
   uint256 public totalWeiRaised;
   uint256 public tokensMinted;
   uint256 public contributors;

   bool public finalized = false;

   address public tokenWalletAddress;
   address payable tokenSaleWalletAddress;
   uint256 public constant TOKENSALE_CAP = 122500000 * 10 ** 18;
   uint256 public constant TOTAL_CAP = 408333334 * 10 ** 18;
   uint256 public constant TEAM_TOKENS = 285833334 * 10 ** 18; //TOTAL_CAP - TOKENSALE_CAP

   uint256 public conversionRateInCents = 15000; // 1ETH = 15000 cents by default - can be updated
   event TokenPurchase(address indexed purchaser, address indexed beneficiary, uint256 value, uint256 amount);
   event Finalized();

   constructor(
     address _tokenAddress,
     address _tokenSaleWalletAddress,
     address _tokenWalletAddress
   ) public {
      require(_tokenAddress != address(0));
      token = TokenInterface(_tokenAddress);
      tokensMinted = 26983068991913242797089;
      totalWeiRaised = 17172834754735456896;
      contributors = 20;

      tokenWalletAddress = _tokenWalletAddress;
      tokenSaleWalletAddress = address(uint160(_tokenSaleWalletAddress));
   }

   /**
    * High level token purchase function
    */
   function() external payable {
     buyTokens(msg.sender);
   }

   /**
    * Low level token purchase function
    * @param _beneficiary will receive the tokens.
    */
   function buyTokens(address _beneficiary) public payable whenNotPaused whenNotFinalized {
    require(_beneficiary != address(0));
    validatePurchase();

    uint256 current = now;
    uint256 tokens;

    totalWeiRaised = totalWeiRaised.add(msg.value);
    tokens = (msg.value * conversionRateInCents) / 20;
    contributors = contributors.add(1);
    tokensMinted = tokensMinted.add(tokens);

    /*
    *@info: msg.value can stay in Wei as long as decimals for the tokens are the same as Ethereum (18 decimals)
    */
    require(tokensMinted < TOKENSALE_CAP);

    token.mint(_beneficiary, tokens);
    emit TokenPurchase(msg.sender, _beneficiary, msg.value, tokens);
    forwardFunds();
   }

   function updateConversionRate(uint256 _conversionRateInCents) onlyOwner public {
       conversionRateInCents = _conversionRateInCents;
   }

   /**
   * Forwards funds to the tokensale wallet
   */
   function forwardFunds() internal {
       address(tokenSaleWalletAddress).transfer(msg.value);
   }

   function currentDate() public view returns (uint256) {
       return now;
   }

   /**
   * Validates the purchase (period, minimum amount, within cap)
   * @return {bool} valid
   */
   function validatePurchase() internal returns (bool) {
      bool nonZeroPurchase = msg.value != 0;
      require(nonZeroPurchase);
   }

   /**
   * Returns the total WIRA token supply
   * @return totalSupply {uint256} WIRA Token Total Supply
   */
   function totalSupply() public view returns (uint256) {
       return token.totalSupply();
   }

   /**
   * Returns token holder WIRA Token balance
   * @param _owner {address} Token holder address
   * @return balance {uint256} Corresponding token holder balance
   */
   function balanceOf(address _owner) public view returns (uint256) {
      return token.balanceOf(_owner);
   }

   /**
   * Change the WIRA Token controller
   * @param _newController {address} New WIRA Token controller
   */
   function changeController(address _newController) public onlyOwner {
      require(isContract(_newController));
      token.transferControl(_newController);
   }

   function finalize() public onlyOwner {
      require(paused);
      emit Finalized();

      uint256 remainingTokens = TOKENSALE_CAP - tokensMinted;
      token.mint(tokenWalletAddress, remainingTokens);
      finalized = true;
   }

   function enableTransfers() public onlyOwner {
     token.enableTransfers();
   }


   function isContract(address _addr) view internal returns(bool) {
     uint size;
     if (_addr == address(0))
       return false;
     assembly {
         size := extcodesize(_addr)
     }
     return size>0;
   }

   modifier whenNotFinalized() {
     require(!finalized);
     _;
   }

 }
/**
 * @title NewWiraTokenSale
 * Tokensale allows investors to make token purchases and assigns them tokens based
 
 * on a token per ETH rate. Funds collected are forwarded to a wallet as they arrive.
 */
function forwardFunds() internal {
    address(tokenSaleWalletAddress).transfer(msg.value);
}

/**
 * Forwards funds to the tokensale wallet
 */