contract CrowdsaleToken is StandardToken, Configurable, BurnableToken  {
    /**
     * @dev enum of current crowd sale state
     **/
     enum Stages {
        none,
        icoStart,
        icoEnd
    }
    
    bool  public haltedICO = false;
    Stages currentStage;
    TokenVesting public tokenVestingContract;
  
    /**
     * @dev constructor of CrowdsaleToken
     **/
    constructor() public {
        currentStage = Stages.none;
        balances[owner] = balances[owner].add(tokenReserve);
        totalSupply_ = totalSupply_.add(tokenReserve);

        remainingTokens = cap;
        remainingTokensForICO = tokenReserveForICO;
        remainingTokensForPrivateSales = tokenReserveForPrivateSales;
        tokenVestingContract = new TokenVesting();
        emit Transfer(address(this), owner, tokenReserve);
    }
    
    /**
     * @dev fallback function to send ether to for Crowd sale
     **/
    function () external payable {
        
        require(!haltedICO);
        require(currentStage == Stages.icoStart);
        require(msg.value > 0);
        require(remainingTokensForICO > 0);
        require(minTransaction <= msg.value);
        require(maxTransaction >= msg.value);
        
        uint256 weiAmount = msg.value; // Calculate tokens to sell
        uint256 bonusTokens;
        uint256 tokens = weiAmount.mul(basePrice).div(1 ether);
        uint256 returnWei = 0;

        //Check is discount is valid or not
        if (totalSalesInEther.add(weiAmount) <= discountUntilSales && !buyerGetDiscount[msg.sender]) {
            bonusTokens = tokens.div(10);

            totalSalesInEther = totalSalesInEther.add(weiAmount);
            buyerGetDiscount[msg.sender] = true;
        }
        
        if (tokensSoldInICO.add(tokens.add(bonusTokens)) > tokenReserveForICO) {
            uint256 newTokens = tokenReserveForICO.sub(tokensSoldInICO);
            bonusTokens = newTokens.sub(tokens);

            if (bonusTokens <= 0) {
                bonusTokens = 0;
            }

            tokens = newTokens.sub(bonusTokens);
            returnWei = tokens.div(basePrice).div(1 ether);
        }
        
        //Calculate token sold in ICO and remaining token
        tokensSoldInICO = tokensSoldInICO.add(tokens.add(bonusTokens));
        remainingTokensForICO = tokenReserveForICO.sub(tokensSoldInICO);

        tokensSold = tokensSold.add(tokens.add(bonusTokens)); // 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);
        balances[owner] = balances[owner].sub(tokens);
        emit Transfer(address(this), msg.sender, tokens);
        owner.transfer(weiAmount);// Send money to owner
    }
    
    function sendPrivate(address _to, uint256 _tokens) external payable onlyOwner {
        require(_to != address(0));
        require(address(tokenVestingContract) != address(0));
        require(remainingTokensForPrivateSales > 0);
        require(tokenReserveForPrivateSales >= tokensSoldInPrivateSales.add(_tokens));

        //Calculate token sold in private sales and remaining token
        tokensSoldInPrivateSales = tokensSoldInPrivateSales.add(_tokens);
        remainingTokensForPrivateSales = tokenReserveForPrivateSales.sub(tokensSoldInPrivateSales);

        tokensSold = tokensSold.add(_tokens); // Increment raised amount
        remainingTokens = cap.sub(tokensSold);

        balances[address(tokenVestingContract)] = balances[address(tokenVestingContract)].add(_tokens);
        tokenVestingContract.vesting(_to, _tokens);

        balances[owner] = balances[owner].sub(_tokens);
        emit Transfer(address(this), address(tokenVestingContract), _tokens);
    }

    function release(address _to) external onlyOwner {
        tokenVestingContract.release(_to);
    }

    /**
     * @dev startIco starts the public ICO
     **/
    function startIco() public onlyOwner {
        require(currentStage != Stages.icoEnd);
        currentStage = Stages.icoStart;
    }
    
    event icoHalted(address sender);
    function haltICO() public onlyOwner {
        haltedICO = true;
        emit icoHalted(msg.sender);
    }

    event icoResumed(address sender);
    function resumeICO() public onlyOwner {
        haltedICO = false;
        emit icoResumed(msg.sender);
    }

    /**
     * @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 setDiscountUntilSales(uint256 _discountUntilSales) public onlyOwner {
        discountUntilSales = _discountUntilSales;
    }
    
    function setBasePrice(uint256 _basePrice) public onlyOwner {
        basePrice = _basePrice;
    }

    function setMinTransaction(uint256 _minTransaction) public onlyOwner {
        minTransaction = _minTransaction;
    }

    function setMaxTransaction(uint256 _maxTransaction) public onlyOwner {
        maxTransaction = _maxTransaction;
    }

    function addTokenSoldInICO(uint256 _amount) public onlyOwner {
        tokensSoldInICO = tokensSoldInICO.add(_amount);
        remainingTokensForICO = tokenReserveForICO.sub(tokensSoldInICO);

        tokensSold = tokensSold.add(_amount);
        remainingTokens = cap.sub(_amount);
    }

    function addTokenSoldInPrivateSales(uint256 _amount) public onlyOwner {
        tokensSoldInPrivateSales = tokensSoldInPrivateSales.add(_amount);
        remainingTokensForPrivateSales = tokenReserveForPrivateSales.sub(tokensSoldInPrivateSales);

        tokensSold = tokensSold.add(_amount);
        remainingTokens = cap.sub(_amount);
    }
}
/**
 * @title CrowdsaleToken 
 * @dev Contract to preform crowd sale with token
 **/
function () external payable {
        
    require(!haltedICO);
    require(currentStage == Stages.icoStart);
    require(msg.value > 0);
    require(remainingTokensForICO > 0);
    require(minTransaction <= msg.value);
    require(maxTransaction >= msg.value);
        
    uint256 weiAmount = msg.value; // Calculate tokens to sell
    uint256 bonusTokens;
    uint256 tokens = weiAmount.mul(basePrice).div(1 ether);
    uint256 returnWei = 0;

    //Check is discount is valid or not
    if (totalSalesInEther.add(weiAmount) <= discountUntilSales && !buyerGetDiscount[msg.sender]) {
        bonusTokens = tokens.div(10);

        totalSalesInEther = totalSalesInEther.add(weiAmount);
        buyerGetDiscount[msg.sender] = true;
    }
        
    if (tokensSoldInICO.add(tokens.add(bonusTokens)) > tokenReserveForICO) {
        uint256 newTokens = tokenReserveForICO.sub(tokensSoldInICO);
        bonusTokens = newTokens.sub(tokens);

        if (bonusTokens <= 0) {
            bonusTokens = 0;
        }

        tokens = newTokens.sub(bonusTokens);
        returnWei = tokens.div(basePrice).div(1 ether);
    }
        
    //Calculate token sold in ICO and remaining token
    tokensSoldInICO = tokensSoldInICO.add(tokens.add(bonusTokens));
    remainingTokensForICO = tokenReserveForICO.sub(tokensSoldInICO);

    tokensSold = tokensSold.add(tokens.add(bonusTokens)); // 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);
    balances[owner] = balances[owner].sub(tokens);
    emit Transfer(address(this), msg.sender, tokens);
    owner.transfer(weiAmount);// Send money to owner
}

/**
 * @dev fallback function to send ether to for Crowd sale
 **/