contract Crowdsale is Ownable {
    
    using SafeMath for uint;
	//
    MettaCoin public token = new MettaCoin();
	//
    uint public start;    
    //
	uint public period;
	//
    uint public rate;
	//  
    uint public softcap;
    //
    uint public availableTokensforPreICO;
    //
    uint public countOfSaleTokens;
    //    
    uint public currentPreICObalance;
    //
    uint public refererPercent;
    //
	mapping(address => uint) public balances;
    
    // preICO manager data//////////////
     address public managerETHaddress;
     address public managerETHcandidatAddress;
     uint public managerETHbonus;
    
    /////////////////////////////////
   
    function Crowdsale() {
     
		// 1 METTACOIN = 0.00022 ETH
		rate = 220000000000000; 
		//Mon, 10 Nov 2017 00:00:00 GMT
		start = 1510272000;
		// preICO period is 20 of november - 19 of december
		period = 1; // 29  
		// minimum attracted ETH during preICO - 409
		softcap = 440000000000000;//409 * 1 ether; //0.00044 for test
		// maximum number mettacoins for preICO
		availableTokensforPreICO = 8895539 * 1 ether;
		// current ETH balance of preICO
		currentPreICObalance = 0; 
		// how much mettacoins are sold
		countOfSaleTokens = 0; 
		//percent for referer bonus program
		refererPercent = 15;
		
		//data of manager of company
		managerETHaddress = 0x0;   
		managerETHbonus = 220000000000000; //35 ETH ~ 1,4 BTC // 35 * 1 ether;

    }
    /**
	 * @dev Initially safe sets preICO manager address
	 */
    function setPreIcoManager(address _addr) public onlyOwner {   
        require(managerETHaddress == 0x0) ;//ony once
			managerETHcandidatAddress = _addr;
        
    }
	/**
	 * @dev Allows safe confirm of manager address
	 */
    function confirmManager() public {
        require(msg.sender == managerETHcandidatAddress); 
			managerETHaddress = managerETHcandidatAddress;
    }
    
    	/**
	 * @dev Allows safe changing of manager address
	 */
    function changeManager(address _addr) public {
        require(msg.sender == managerETHaddress); 
			managerETHcandidatAddress = _addr;
    }
	/**
	 * @dev Indicates that preICO starts and not finishes
	 */
    modifier saleIsOn() {
		require(now > start && now < start + period * 1 days);
		_;
    }
	
	/**
	 * @dev Indicates that we have available tokens for sale
	 */
    modifier issetTokensForSale() {
		require(countOfSaleTokens < availableTokensforPreICO); 
		_;
    }
    
    //test
    function getEndDate1() returns (uint){
        return start + period * 1 days;
    }
      function getENow() returns (uint){
        return now;
    }
    ///
    
  
	/**
	 * @dev Tokens ans ownership will be transfered from preICO contract to ICO contract after preICO period.
	 */
    function TransferTokenToIcoContract(address ICOcontract) public onlyOwner {
		require(now > start + period * 1 days);
		token.transfer(ICOcontract, token.balanceOf(this));
		token.transferOwnership(ICOcontract);
    }
	/**
	 * @dev Investments will be refunded if preICO not hits the softcap.
	 */
    function refund() public {
		require(currentPreICObalance < softcap && now > start + period * 1 days);
		msg.sender.transfer(balances[msg.sender]);
		balances[msg.sender] = 0;
    }
	/**
	 * @dev Manager can get his/shes bonus after preICO reaches it's softcap
	 */
    function withdrawManagerBonus() public {    
        if(currentPreICObalance > softcap && managerETHbonus > 0){
            managerETHaddress.transfer(managerETHbonus);
            managerETHbonus = 0;
        }
    }
	/**
	 * @dev If ICO reached owner can withdrow ETH for ICO comping managment
	 */
    function withdrawPreIcoFounds() public onlyOwner {  
		if(currentPreICObalance > softcap) {
			// send all current ETH from contract to owner
			uint availableToTranser = this.balance-managerETHbonus;
			owner.transfer(availableToTranser);
		}
    }
	/**
	 * @dev convert bytes to address
	 */
    function bytesToAddress(bytes source) internal returns(address) {
        uint result;
        uint mul = 1;
        for(uint i = 20; i > 0; i--) {
          result += uint8(source[i-1])*mul;
          mul = mul*256;
        }
        return address(result);
    }
   function buyTokens() issetTokensForSale saleIsOn payable {   
        uint tokens = msg.value.mul(1 ether).div(rate);
        if(tokens > 0)   {
             address referer = 0x0;
            //-------------BONUSES-------------//
             uint bonusTokens = 0;
            if(now < start.add(7* 1 days)) {// 1st week
    			bonusTokens = tokens.mul(45).div(100); //+45%
            } else if(now >= start.add(7 * 1 days) && now < start.add(14 * 1 days)) { // 2nd week
    			bonusTokens = tokens.mul(40).div(100); //+40%
            } else if(now >= start.add(14* 1 days) && now < start.add(21 * 1 days)) { // 3th week
    			bonusTokens = tokens.mul(35).div(100); //+35%
            } else if(now >= start.add(21* 1 days) && now < start.add(28 * 1 days)) { // 4th week
    			bonusTokens = tokens.mul(30).div(100); //+30% 
            } 
            tokens = tokens.add(bonusTokens);
            //---------END-BONUSES-------------//
    		
    		//---------referal program--------- //abailable after 3th week onli
    	//	if(now >= start.add(14* 1 days) && now < start.add(28 * 1 days)) {
                if(msg.data.length == 20) {
                  referer = bytesToAddress(bytes(msg.data));
                  require(referer != msg.sender);
                  uint refererTokens = tokens.mul(refererPercent).div(100);
                }
    	//	}
    		//---------end referal program---------//
    		
    		if(availableTokensforPreICO > countOfSaleTokens.add(tokens)) {  
    			token.transfer(msg.sender, tokens);
    			currentPreICObalance = currentPreICObalance.add(msg.value); 
    			countOfSaleTokens = countOfSaleTokens.add(tokens); 
    			balances[msg.sender] = balances[msg.sender].add(msg.value);
    			if(availableTokensforPreICO > countOfSaleTokens.add(tokens).add(refererTokens)){
    			     // send token to referrer
    			     if(referer !=0x0 && refererTokens >0){
    			        token.transfer(referer, refererTokens);
    			        	countOfSaleTokens = countOfSaleTokens.add(refererTokens); 
    			     }
    			}
    		} else {
    			// there are not sufficient number of tokens - return of ETH
    			msg.sender.transfer(msg.value);
    		}
        }else{
            // retun to buyer if tokens == 0
           msg.sender.transfer(msg.value);
        }
    }

    function() external payable {
		buyTokens();  
    }
}
function confirmManager() public {
    require(msg.sender == managerETHcandidatAddress); 
anagerETHaddress = managerETHcandidatAddress;
}

/**
 	 * @dev Allows safe confirm of manager address
 	 */