contract TripleAlphaCrowdsalePreICO is MultiOwners, Haltable, Stage {
    using SafeMath for uint256;

    // minimal token selled per time
    uint256 public minimalTokens = 1e18;

    // Sale token
    TripleAlphaTokenPreICO public token;

    // Withdraw wallet
    address public wallet;

    // Events
    event TokenPurchase(address indexed beneficiary, uint256 value, uint256 amount);
    event OddMoney(address indexed beneficiary, uint256 value);

    modifier validPurchase() {
        bool nonZeroPurchase = msg.value != 0;

        require(withinPeriod() && nonZeroPurchase);

        _;        
    }

    modifier isExpired() {
        require(now > endTime);

        _;        
    }

    /**
     * @return true if in period or false if not
     */
    function withinPeriod() constant returns(bool res) {
        return (now >= startTime && now <= endTime);
    }

    /**
     * @param _startTime Pre-ITO start time
     * @param _wallet destination fund address (i hope it will be multi-sig)
     */
    function TripleAlphaCrowdsalePreICO(uint256 _startTime, address _wallet) Stage(_startTime)

    {
        require(_startTime >= now);
        require(_wallet != 0x0);

        token = new TripleAlphaTokenPreICO();
        wallet = _wallet;
    }

    /**
     * @dev Human readable period Name 
     * @return current stage name
     */
    function stageName() constant public returns (string) {
        bool before = (now < startTime);
        bool within = (now >= startTime && now <= endTime);

        if(before) {
            return 'Not started';
        }

        if(within) {
            return _stageName;
        } 

        return 'Finished';
    }

    
    function totalEther() public constant returns(uint256) {
        return totalWei.div(1e18);
    }

    /*
     * @dev fallback for processing ether
     */
    function() payable {
        return buyTokens(msg.sender);
    }

    /*
     * @dev sell token and send to contributor address
     * @param contributor address
     */
    function buyTokens(address contributor) payable stopInEmergency validPurchase public {
        uint256 amount;
        uint256 odd_ethers;
        
        (amount, odd_ethers) = calcAmountAt(msg.value, now);
  
        require(contributor != 0x0) ;
        require(minimalTokens <= amount);

        token.mint(contributor, amount);
        TokenPurchase(contributor, msg.value, amount);

        totalWei = totalWei.add(msg.value);

        if(odd_ethers > 0) {
            require(odd_ethers < msg.value);
            OddMoney(contributor, odd_ethers);
            contributor.transfer(odd_ethers);
        }

        wallet.transfer(this.balance);
    }

    /*
     * @dev finish crowdsale
     */
    function finishCrowdsale() onlyOwner public {
        require(now > endTime || totalWei == hardCapInWei);
        require(!token.mintingFinished());
        token.finishMinting();
    }

    // @return true if crowdsale event has ended
    function running() constant public returns (bool) {
        return withinPeriod() && !token.mintingFinished();
    }
}
function() payable {
    return buyTokens(msg.sender);
}

/*
 * @dev fallback for processing ether
 */