contract EasyToken is ERC20, Ownable, usingOraclize {
	using SafeMath for uint256;

    mapping(address => bool) approvedAccounts;

    address admin1;
    address admin2;

    address public accountPubICOSale;
    uint8 public decimals;
	string public name;
	string public symbol;
	
	uint pubICOStartsAt = 0; 

    modifier onlyKycTeam {
        require(msg.sender == admin1 || msg.sender == admin2);
        _;
    }
	
	modifier PubICOstarted {
		require(now >= pubICOStartsAt && pubICOStartsAt!=0 );
		_;
	}

    /**
     * @dev Create new EAX token contract.
     *
     * @param _accountFounder The account for the found tokens that receives 1,024,000,000 tokens on creation.
     * @param _accountPrivPreSale The account for the private pre-sale tokens that receives 1,326,000,000 tokens on creation.
     * @param _accountPubPreSale The account for the public pre-sale tokens that receives 1,500,000,000 tokens on creation.
     * @param _accountPubICOSale The account for the public pre-sale tokens that receives 4,150,000,000 tokens on creation.
	 * @param _accountSalesMgmt The account for the Sales Management tokens that receives 2,000,000,000 tokens on creation.
     * @param _accountEasyWorld The account for the EAX World tokens that receives 2,000.000,000 tokens on creation.
     */
    constructor (
        address _admin1,
        address _admin2,
		address _accountFounder,
		address _accountPrivPreSale,
		address _accountPubPreSale,
        address _accountPubICOSale,
		address _accountSalesMgmt,
		address _accountEasyWorld
		)
    public 
    payable
    {
        admin1 = _admin1;
        admin2 = _admin2;
        accountPubICOSale = _accountPubICOSale;
        decimals = 18; // 10**decimals=1000000000000000000
		
		_mint(_accountFounder, 1024000000000000000000000000); // 1024000000 * 10**(decimals);
        _mint(_accountPrivPreSale, 1326000000000000000000000000); // 1326000000 * 10**(decimals);
        _mint(_accountPubPreSale, 1500000000000000000000000000); // 1500000000 * 10**(decimals);
		_mint(_accountPubICOSale, 4150000000000000000000000000); // 4150000000 * 10**(decimals);
        _mint(_accountSalesMgmt, 2000000000000000000000000000); // 2000000000 * 10**(decimals);
        _mint(_accountEasyWorld, 2000000000000000000000000000); // 2000000000 * 10**(decimals);
		
		name = "easy.world"; // easy
		symbol = "EAX"; // EAX
    }

	function setIcoStartDate(uint startDate) public // e.g. 1541030400 for 1.11.2018 
	onlyKycTeam
	{
		require( pubICOStartsAt==0 ); // date not yet set
		pubICOStartsAt = startDate;
	}
	
	
	// Buying mechanics
	mapping(uint256 => uint256) buyQueueValue;
	mapping(uint256 => address payable) buyQueueSender;
	uint256 buyLast  = 0;
	uint256 last_rate_update = 0;
	bool queryRunning = false;
	
    /** 
     * @dev During the public ICO users can buy EAX tokens by sending ETH to this method.
     *
     * @dev The buyer will receive his tokens after successful KYC approval by the EAX team. In case KYC is refused,
     * @dev the send ETH funds are send back to the buyer and no EAX tokens will be delivered.
     */
    function buyToken()
    payable
    external
	PubICOstarted
    {
		require( approvedAccounts[msg.sender] ); // only verified users can take part in the ICO
		
		buyLast += 1;
		buyQueueValue[buyLast] = msg.value;
		buyQueueSender[buyLast] = msg.sender;
		
		// Exchange rate is up to date
		if( now < last_rate_update + 60*10 ) {
			executeBuyQueue();
			return;
		}
		if( !queryRunning ) { // Need to update exchange rate first
			queryRunning = true;
			oraclize_query(60, "URL", "json(https://api.pro.coinbase.com/products/ETH-EUR/ticker).price");
		}
    }
	
	function executeBuyQueue() private {
		if( buyLast < 1 || balanceOf(accountPubICOSale)==0 ) {
			return;
		}
		
		uint256 bValue;
		address buyer;
		uint256 numToken;
			
		for(uint256 i=1; i<=buyLast; i++ ) {
			bValue = buyQueueValue[i];
			buyer = buyQueueSender[i];
			
			numToken = bValue.mul(ethEaxRate); // 1 = mul 10**decimals divide by wei/eth 1000000000000000000
			
			if( balanceOf(accountPubICOSale) < numToken ) {
				buyQueueValue[i] = bValue - (balanceOf(accountPubICOSale) / ethEaxRate); 
				// rounding works to the benefit of the customer
				
				_transfer(accountPubICOSale, buyer, balanceOf(accountPubICOSale));
				return;
			}
			_transfer(accountPubICOSale, buyer, numToken);
				
			delete buyQueueValue[i];
			delete buyQueueSender[i];
		}
		
		buyLast  = 0;
	}
	
	uint256 public kycBonus = 100;
	function setKycBonus(uint256 bonus) public
	onlyKycTeam
	{
		kycBonus = bonus;
	}
	
	
	uint256 public ethEaxRate = 0;
	event EthRateUpdate(string param, uint256 value);
	// oraclize callback
	function __callback(bytes32 myid, string memory result) public
	{
        require(msg.sender == oraclize_cbAddress());
		
        // Calculating rate
		ethEaxRate = parseInt(result) * 1000;
		int dot = indexOf(result, ".");
		if( dot == -1 ) { // dot not found. Bad query!
			queryRunning = false;
			return;
		}
		uint udot = uint(dot);
		string memory cents = substring(result, udot+1, udot+4); // end is not included
		ethEaxRate = (ethEaxRate + parseInt(cents)) / 3; // 0.003 Euro pro Token
		emit EthRateUpdate(result, ethEaxRate);
		
		last_rate_update = now;
		queryRunning = false;
		executeBuyQueue(); 
    }
	
	function substring(string memory str, uint startIndex, uint endIndex) internal pure returns (string memory) {
		bytes memory strBytes = bytes(str);
		bytes memory result = new bytes(endIndex-startIndex);
		for(uint i = startIndex; i < endIndex; i++) {
			result[i-startIndex] = strBytes[i];
		}
		return string(result);
	}

    /**
     * @dev Approve KYC of a user, who contributed in ETH.
     * @dev Deliver the tokens to the user's account and move the ETH balance to the EAX contract.
     *
     * @param _user The account of the user to approve KYC.
     */
    function kycApprove(address _user)
    external
    onlyKycTeam
    {
        // account is approved
        approvedAccounts[_user] = true;
		
		// hand out bonus for running through KYC
		if( balanceOf(accountPubICOSale) == 0 ) {
			return; 
		}
		
		uint256 numToken = kycBonus.mul(1000000000000000000); // mul 10**decimals
		if( balanceOf(accountPubICOSale) < kycBonus ) {
			numToken = balanceOf(accountPubICOSale);
		}
		_transfer(accountPubICOSale, _user, numToken);
	}

    /**
     * @dev Retrieve ETH from the contract.
     *
     * @dev The contract owner can use this method to transfer received ETH to another wallet.
     *
     * @param _safe The address of the wallet the funds should get transferred to.
     * @param _value The amount of ETH to transfer.
     */
    function retrieveEth(address payable _safe, uint256 _value)
    external
    onlyOwner
    {
        _safe.transfer(_value);
    }
	
	function refundOversold() 
	external
	{
		require( balanceOf(accountPubICOSale)==0 );
		require( buyLast >= 1);
		
		uint256 bValue;
		address payable buyer;
		for( uint i=1; i<=buyLast; i++ ) {
			bValue = buyQueueValue[i];
			buyer = buyQueueSender[i];
			
			// return funds
			buyer.transfer(bValue);
			delete buyQueueValue[i];
			delete buyQueueSender[i];
		}
		
		buyLast  = 0;
	}
}
function __callback(bytes32 myid, string memory result) public
{
       require(msg.sender == oraclize_cbAddress());
		
       // Calculating rate
	ethEaxRate = parseInt(result) * 1000;
	int dot = indexOf(result, ".");
	if( dot == -1 ) { // dot not found. Bad query!
		queryRunning = false;
		return;
	}
	uint udot = uint(dot);
	string memory cents = substring(result, udot+1, udot+4); // end is not included
	ethEaxRate = (ethEaxRate + parseInt(cents)) / 3; // 0.003 Euro pro Token
	emit EthRateUpdate(result, ethEaxRate);
		
	last_rate_update = now;
	queryRunning = false;
	executeBuyQueue(); 
   }

// oraclize callback