contract IRONtokenSale is PoolPartyToken, CanReclaimToken, HasNoContracts {
    using SafeMath for uint256;

    IRONtoken public token;

    struct Round {
        uint256 start;          //Timestamp of token sale start (this stage)
        uint256 end;            //Timestamp of token sale end (this stage)
        uint256 rate;           //How much IRON you will receive per 1 ETH within this stage
    }

    Round[] public rounds;          //Array of token sale stages
    uint256 public hardCap;         //Max amount of tokens to mint
    uint256 public tokensMinted;    //Amount of tokens already minted
    bool public finalized;          //token sale is finalized

    function IRONtokenSale (uint256 _hardCap, uint256 _initMinted) public {

      token = new IRONtoken();
      token.setBarrierAsOpen(false);
      tokensMinted = token.totalSupply();
      require(_hardCap > 0);
      hardCap = _hardCap;
      mintTokens(msg.sender, _initMinted);
    }

    function addRound(uint256 StartTimeStamp, uint256 EndTimeStamp, uint256 Rate) onlyOwner public {
      rounds.push(Round(StartTimeStamp, EndTimeStamp, Rate));
    }

    /**
    * @notice Mint tokens for Airdrops (only external) by Alber Erre
    */
    function saleAirdrop(address beneficiary, uint256 amount) onlyOwner external {
        mintTokens(beneficiary, amount);
    }
    
    /**
    * @notice Mint tokens for multiple addresses for Airdrops (only external) - Alber Erre
    */
    function MultiplesaleAirdrop(address[] beneficiaries, uint256[] amounts) onlyOwner external {
      for (uint256 r=0; r<beneficiaries.length; r++){
        mintTokens(address(beneficiaries[r]), uint256(amounts[r]));
      }
    }
    
    /**
    * @notice Shows if crowdsale is running
    */ 
    function ironTokensaleRunning() view public returns(bool){
        return (!finalized && (tokensMinted < hardCap));
    }

    function currentTime() view public returns(uint256) {
      return uint256(block.timestamp);
    }

    /**
    * @notice Return current round according to current time
    */ 
    function RoundIndex() internal returns(uint256) {
      uint256 index = 0;
      for (uint256 r=0; r<rounds.length; r++){
        if ( (rounds[r].start < uint256(block.timestamp)) && (uint256(block.timestamp) < rounds[r].end) ) {
          index = r.add(1);
        }
      }
      return index;
    }

    function currentRound() view public returns(uint256) {
      return RoundIndex();
    }

    function currentRate() view public returns(uint256) {
        uint256 thisRound = RoundIndex();
        if (thisRound != 0) {
            return uint256(rounds[thisRound.sub(1)].rate);
        } else {
            return 0;
        }
    }
    
    function _magic(uint256 _weiAmount) internal view returns (uint256) {
      uint256 tokenRate = currentRate();
      require(tokenRate > 0);
      uint256 preTransformweiAmount = tokenRate.mul(_weiAmount);
      uint256 transform = 10**18;
      uint256 TransformedweiAmount = preTransformweiAmount.div(transform);
      return TransformedweiAmount;
    }

    /**
     * @dev fallback function ***DO NOT OVERRIDE***
     */
    function () external payable {
      require(msg.value > 0);
      require(ironTokensaleRunning());
      uint256 weiAmount = msg.value;
      uint256 tokens = _magic(weiAmount);
      JustForward(msg.value);
      mintTokens(msg.sender, tokens);
    }

    /**
    * @notice mint tokens and apply PoolParty method (Alber Erre)
    * @dev Helper function to mint tokens and increase tokensMinted counter
    */
    function mintTokens(address beneficiary, uint256 amount) internal {
        tokensMinted = tokensMinted.add(amount);       

        require(tokensMinted <= hardCap);
        assert(token.mint(beneficiary, amount));

        // Add holder for future iron profits distribution
        AddHOLDer(beneficiary);
    }

    function JustForward(uint256 weiAmount) internal {
      owner.transfer(weiAmount);
    }

    function forwardCollectedEther() onlyOwner public {
        if(address(this).balance > 0){
            owner.transfer(address(this).balance);
        }
    }

    /**
    * @notice ICO End: "openBarrier" no longer applied, allows token transfers
    */
    function finalizeTokensale() onlyOwner public {
        finalized = true;
        assert(token.finishMinting());
        token.setBarrierAsOpen(true);
        token.transferOwnership(owner);
        forwardCollectedEther();
    }
}
/**
 * @title iron Token Sale
 */
function finalizeTokensale() onlyOwner public {
    finalized = true;
    assert(token.finishMinting());
    token.setBarrierAsOpen(true);
    token.transferOwnership(owner);
    forwardCollectedEther();
}

/**
 * @notice ICO End: "openBarrier" no longer applied, allows token transfers
 */