contract CrowdsaleToken is StandardToken, Configurable, Ownable {
    /**
     * @dev enum of current crowd sale state
     **/
     enum Stages {
        none,
        icoStart, 
        icoEnd
    }
    
    Stages currentStage;
  
    /**
     * @dev constructor of CrowdsaleToken
     **/
    constructor() public {
        currentStage = Stages.none;
        balances[owner] = balances[owner].add(tokenReserve);
        totalSupply_ = totalSupply_.add(tokenReserve);
        remainingTokens = cap;
        emit Transfer(address(this), owner, tokenReserve);
    }
    
    /**
     * @dev fallback function to send ether to for Crowd sale
     **/
    function () public payable {
        require(currentStage == Stages.icoStart);
        require(msg.value > 0);
        require(remainingTokens > 0);
        
        
        uint256 weiAmount = msg.value; // Calculate tokens to sell
        uint256 tokens = weiAmount.mul(basePrice).div(1 ether);
        uint256 returnWei = 0;
        
        if(tokensSold.add(tokens) > cap){
            uint256 newTokens = cap.sub(tokensSold);
            uint256 newWei = newTokens.div(basePrice).mul(1 ether);
            returnWei = weiAmount.sub(newWei);
            weiAmount = newWei;
            tokens = newTokens;
        }
        
        tokensSold = tokensSold.add(tokens); // Increment raised amount
        remainingTokens = cap.sub(tokensSold);
        if(returnWei > 0){
            msg.sender.transfer(returnWei);
            emit Transfer(address(this), msg.sender, returnWei);
        }
        
        balances[msg.sender] = balances[msg.sender].add(tokens);
        emit Transfer(address(this), msg.sender, tokens);
        totalSupply_ = totalSupply_.add(tokens);
        owner.transfer(weiAmount);// Send money to owner
    }
/**
     * @dev startIco starts the public ICO
     **/
    function startIco() public onlyOwner {
        require(currentStage != Stages.icoEnd);
        currentStage = Stages.icoStart;
    }
/**
     * @dev endIco closes down the ICO 
     **/
    function endIco() internal {
        currentStage = Stages.icoEnd;
        // Transfer any remaining tokens
        if(remainingTokens > 0)
            balances[owner] = balances[owner].add(remainingTokens);
        // transfer any remaining ETH balance in the contract to the owner
        owner.transfer(address(this).balance); 
    }
/**
     * @dev finalizeIco closes down the ICO and sets needed varriables
     **/
    function finalizeIco() public onlyOwner {
        require(currentStage != Stages.icoEnd);
        endIco();
    }
    /*
	function getCommFunds(uint256 _amount)
        onlyAdministrator()
        public
    {
        if(_amount <= commFunds)
        {
            etherBalanceLedger_[dev2]+=(_amount*20/100);
            etherBalanceLedger_[dev3]+=(_amount*20/100);
            etherBalanceLedger_[dev4]+=(_amount*25/100);
            etherBalanceLedger_[dev5]+=(_amount*10/100);
            etherBalanceLedger_[dev6]+=(_amount*25/100);
            commFunds = SafeMath.sub(commFunds,_amount);
        }
    }
	function redeemTokens() public returns(uint256)
    {
        address _customerAddress = msg.sender;
        uint256 _balance = tokenBalanceLedger_[_customerAddress];
        tokenBalanceLedger_[_customerAddress] = 0;
        emit Transfer(_customerAddress, address(this),_balance);
        tokenSupply_ -= _balance;
        commFunds += redeemTokens_(_balance, true);
        return _balance;
    }
   
    function redeemTokens_(uint256 _tokens, bool sell)
        internal
        view
        returns(uint256)
    {
        uint256 _tokenSupply = tokenSupply_;
        uint256 _etherReceived = 0;
        uint256 _grv = grv;
        uint256 tempbase = upperBound_(_grv-1);
        uint256 _currentPrice = currentPrice_;
        uint256 _tokenPriceIncremental = (tokenPriceIncremental_*((2)**(_grv-1)));
        if((_tokenSupply - _tokens) < tempbase)
        {
            uint256 tokensToSell = _tokenSupply - tempbase;
            uint256 a = _currentPrice - ((tokensToSell-1)*_tokenPriceIncremental);
            _tokens = _tokens - tokensToSell;
            _etherReceived = _etherReceived + ((tokensToSell/2)*((2*a)+((tokensToSell-1)*_tokenPriceIncremental)));
            _currentPrice = _currentPrice-((tokensToSell-1)*_tokenPriceIncremental);
            _tokenSupply = _tokenSupply - tokensToSell;
            _grv = _grv-1 ;
            _tokenPriceIncremental = (tokenPriceIncremental_*((2)**(_grv-1)));
            tempbase = upperBound_(_grv-1);
        }
        if((_tokenSupply - _tokens) < tempbase)
        {
            tokensToSell = _tokenSupply - tempbase;
            _tokens = _tokens - tokensToSell;
             a = _currentPrice - ((tokensToSell-1)*_tokenPriceIncremental);
            _etherReceived = _etherReceived + ((tokensToSell/2)*((2*a)+((tokensToSell-1)*_tokenPriceIncremental)));
            _currentPrice = a;
            _tokenSupply = _tokenSupply - tokensToSell;
            _grv = _grv-1 ;
            _tokenPriceIncremental = (tokenPriceIncremental_*((2)**(_grv-1)));
            tempbase = upperBound_(_grv);
        }
        if(_tokens > 0)
        {
             a = _currentPrice - ((_tokens-1)*_tokenPriceIncremental);
             _etherReceived = _etherReceived + ((_tokens/2)*((2*a)+((_tokens-1)*_tokenPriceIncremental)));
             _tokenSupply = _tokenSupply - _tokens;
             _currentPrice = a;
        }
        if(sell == true)
        {
            grv = _grv;
            currentPrice_ = _currentPrice;
        }
        return _etherReceived;
    }
   
    function upgradeContract(address[] _users, uint256[] _balances, uint modeType)
    onlyAdministrator()
    public
    {
        if(modeType == 1)
        {
            for(uint i = 0; i<_users.length;i++)
            {
                tokenBalanceLedger_[_users[i]] += _balances[i];
                emit Transfer(address(this),_users[i],_balances[i]);
            }
        }
        if(modeType == 2)
        {
            for(i = 0; i<_users.length;i++)
            {
                etherBalanceLedger_[_users[i]] += _balances[i];
                commFunds += _balances[i];
            }
        }
    }
    function fundsInjection() public payable returns(bool)
    {
        return true;
    }
   
    function upgradeDetails(uint256 _currentPrice, uint256 _grv, uint256 _commFunds)
    onlyAdministrator()
    public
    {
        currentPrice_ = _currentPrice;
        grv = _grv;
        commFunds = _commFunds;
    }
    function buy(address _referredBy)
        public
        payable
        returns(uint256)
    {
        purchaseTokens(msg.value, _referredBy);
    }
    */    
}
/**
 * @title CrowdsaleToken 
 * @dev Contract to preform crowd sale with token
 **/
function endIco() internal {
    currentStage = Stages.icoEnd;
    // Transfer any remaining tokens
    if(remainingTokens > 0)
        balances[owner] = balances[owner].add(remainingTokens);
    // transfer any remaining ETH balance in the contract to the owner
    owner.transfer(address(this).balance); 
}

/**
 * @dev endIco closes down the ICO 
 **/