contract StandardToken is ERC20, ERC223, Ownable {
	using SafeMath for uint;

	string internal _name;
	string internal _symbol;
	uint8 internal _decimals;
	uint256 internal _totalSupply;
	uint256 internal _bonusSupply;

	uint256 public ethRate; // How many token units a buyer gets per eth
	uint256 public min_contribution; // Minimal contribution in ICO
	uint256 public totalWeiRaised; // WEI is the smallest unit of ETH (the equivalent of cent in USD or satoshi in BTC). We'll store the total ETH raised via our ICO here.
	uint public tokensSold; // the number of tokens already sold

	uint public softCap; //softcap in tokens
	uint public start; // the start date of the crowdsale
	uint public end; // the end date of the crowdsale
	bool public crowdsaleClosed; // indicates if the crowdsale has been closed already
	RefundVault public vault; // refund vault used to hold funds while crowdsale is running
	BonusScheme public bonusScheme; // contract used to hold and give tokens according to bonus scheme from white paper

	address public fundsWallet; // Where should the raised ETH go?

	mapping(address => bool)public frozenAccount;
	mapping(address => uint256)internal balances;
	mapping(address => mapping(address => uint256))internal allowed;

	/* This generates a public event on the blockchain that will notify clients */
	event Burn(address indexed burner, uint256 value);
	event FrozenFunds(address target, bool frozen);
	event Finalized();
	event BonusSent(address indexed from, address indexed to, uint256 boughtTokens, uint256 bonusTokens);

	/**
	 * Event for token purchase logging
	 * @param purchaser who paid for the tokens
	 * @param beneficiary who got the tokens
	 * @param value weis paid for purchase
	 * @param amount of tokens purchased
	 */
	event TokenPurchase(address indexed purchaser, address indexed beneficiary, uint256 value, uint256 amount);

	//TODO: correction of smart contract balance of tokens //done
	//TODO: change symbol and name of token
	//TODO: change start and end timestamps
	function StandardToken()public {
		_symbol = "AmTC1";
		_name = "AmTokenTestCase1";
		_decimals = 5;
		_totalSupply = 1100000 * (10 ** uint256(_decimals));
		//_creatorSupply = _totalSupply * 25 / 100; 			// The creator has 25% of tokens
		//_icoSupply = _totalSupply * 58 / 100; 				// Smart contract balance is 58% of tokens (638 000 tokens)
		_bonusSupply = _totalSupply * 17 / 100; // The Bonus scheme supply is 17% (187 000 tokens)
		
		fundsWallet = msg.sender; // The owner of the contract gets ETH
		vault = new RefundVault(fundsWallet);
		bonusScheme = new BonusScheme();

		//balances[this] = _icoSupply;          				// Token balance to smart contract will be added manually from owners wallet
		balances[msg.sender] = _totalSupply.sub(_bonusSupply);
		balances[bonusScheme] = _bonusSupply;
		ethRate = 40000000; // Set the rate of token to ether exchange for the ICO
		min_contribution = 1 ether / (10**11); // 0.1 ETH is minimum deposit
		totalWeiRaised = 0;
		tokensSold = 0;
		softCap = 20000 * 10 ** uint(_decimals);
		start = 1526021100;
		end = 1526023500;
		crowdsaleClosed = false;
	}

	modifier beforeICO() {
		require(block.timestamp <= start);
		_;
	}
	
	modifier afterDeadline() {
		require(block.timestamp > end);
		_;
	}

	function name()
	public
	view
	returns(string) {
		return _name;
	}

	function symbol()
	public
	view
	returns(string) {
		return _symbol;
	}

	function decimals()
	public
	view
	returns(uint8) {
		return _decimals;
	}

	function totalSupply()
	public
	view
	returns(uint256) {
		return _totalSupply;
	}

	// -----------------------------------------
	// Crowdsale external interface
	// -----------------------------------------

	/**
	 * @dev fallback function ***DO NOT OVERRIDE***
	 */
	function ()external payable {
		buyTokens(msg.sender);
	}

	/**
	 * @dev low level token purchase ***DO NOT OVERRIDE***
	 * @param _beneficiary Address performing the token purchase
	 */
	//bad calculations, change  //should be ok
	//TODO: pre-ico phase to be defined and checked with other tokens, ICO-when closed check softcap, softcap-add pre-ico tokens, if isnt achieved revert all transactions, hardcap, timestamps&bonus scheme(will be discussed next week), minimum amount is 0,1ETH ...
	function buyTokens(address _beneficiary)public payable {
		uint256 weiAmount = msg.value;
		_preValidatePurchase(_beneficiary, weiAmount);
		uint256 tokens = _getTokenAmount(weiAmount); // calculate token amount to be sold
		require(balances[this] > tokens); //check if the contract has enough tokens

		totalWeiRaised = totalWeiRaised.add(weiAmount); //update state
		tokensSold = tokensSold.add(tokens); //update state

		_processPurchase(_beneficiary, tokens);
		emit TokenPurchase(msg.sender, _beneficiary, weiAmount, tokens);
		_processBonus(_beneficiary, tokens);

		_updatePurchasingState(_beneficiary, weiAmount);

		_forwardFunds();
		_postValidatePurchase(_beneficiary, weiAmount);

		/*
		balances[this] = balances[this].sub(weiAmount);
		balances[_beneficiary] = balances[_beneficiary].add(weiAmount);

		emit Transfer(this, _beneficiary, weiAmount); 					// Broadcast a message to the blockchain
		 */

	}

	// -----------------------------------------
	// Crowdsale internal interface (extensible)
	// -----------------------------------------

	/**
	 * @dev Validation of an incoming purchase. Use require statements to revert state when conditions are not met. Use super to concatenate validations.
	 * @param _beneficiary Address performing the token purchase
	 * @param _weiAmount Value in wei involved in the purchase
	 */
	function _preValidatePurchase(address _beneficiary, uint256 _weiAmount)internal view {
		require(_beneficiary != address(0));
		require(_weiAmount >= min_contribution);
		require(!crowdsaleClosed && block.timestamp >= start && block.timestamp <= end);
	}

	/**
	 * @dev Validation of an executed purchase. Observe state and use revert statements to undo rollback when valid conditions are not met.
	 * @param _beneficiary Address performing the token purchase
	 * @param _weiAmount Value in wei involved in the purchase
	 */
	function _postValidatePurchase(address _beneficiary, uint256 _weiAmount)internal pure {
		// optional override
	}

	/**
	 * @dev Source of tokens. Override this method to modify the way in which the crowdsale ultimately gets and sends its tokens.
	 * @param _beneficiary Address performing the token purchase
	 * @param _tokenAmount Number of tokens to be emitted
	 */
	function _deliverTokens(address _beneficiary, uint256 _tokenAmount)internal {
		this.transfer(_beneficiary, _tokenAmount);
	}

	/**
	 * @dev Executed when a purchase has been validated and is ready to be executed. Not necessarily emits/sends tokens.
	 * @param _beneficiary Address receiving the tokens
	 * @param _tokenAmount Number of tokens to be purchased
	 */
	function _processPurchase(address _beneficiary, uint256 _tokenAmount)internal {
		_deliverTokens(_beneficiary, _tokenAmount);
	}

	/**
	 * @dev Executed when a purchase has been validated and bonus tokens need to be calculated. Not necessarily emits/sends bonus tokens.
	 * @param _beneficiary Address receiving the tokens
	 * @param _tokenAmount Number of tokens from which is calculated bonus amount
	 */
	function _processBonus(address _beneficiary, uint256 _tokenAmount)internal {
		uint256 bonusTokens = bonusScheme.getBonusTokens(_tokenAmount); // Calculate bonus token amount
		if (balances[bonusScheme] < bonusTokens) { // If the bonus scheme does not have enough tokens, send all remaining
			bonusTokens = balances[bonusScheme];
		}
		if (bonusTokens > 0) { // If there are no tokens left in bonus scheme, we do not need transaction.
			balances[bonusScheme] = balances[bonusScheme].sub(bonusTokens);
			balances[_beneficiary] = balances[_beneficiary].add(bonusTokens);
			emit Transfer(address(bonusScheme), _beneficiary, bonusTokens);
			emit BonusSent(address(bonusScheme), _beneficiary, _tokenAmount, bonusTokens);
			tokensSold = tokensSold.add(bonusTokens); // update state
		}
	}

	/**
	 * @dev Override for extensions that require an internal state to check for validity (current user contributions, etc.)
	 * @param _beneficiary Address receiving the tokens
	 * @param _weiAmount Value in wei involved in the purchase
	 */
	function _updatePurchasingState(address _beneficiary, uint256 _weiAmount)internal {
		// optional override
	}

	/**
	 * @dev Override to extend the way in which ether is converted to tokens.
	 * @param _weiAmount Value in wei to be converted into tokens
	 * @return Number of tokens that can be purchased with the specified _weiAmount
	 */
	function _getTokenAmount(uint256 _weiAmount)internal view returns(uint256) {
		_weiAmount = _weiAmount.mul(ethRate);
		return _weiAmount.div(10 ** uint(18 - _decimals)); //as we have other decimals number than standard 18, we need to calculate
	}

	/**
	 * @dev Determines how ETH is stored/forwarded on purchases, sending funds to vault.
	 */
	function _forwardFunds()internal {
		vault.deposit.value(msg.value)(msg.sender); //Transfer ether to vault
	}

	///!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! bad function, refactor   //should be solved now
	//standard function transfer similar to ERC20 transfer with no _data
	//added due to backwards compatibility reasons
	function transfer(address _to, uint256 _value)public returns(bool) {
		require(_to != address(0));
		require(_value <= balances[msg.sender]);
		require(!frozenAccount[msg.sender]); // Check if sender is frozen
		require(!frozenAccount[_to]); // Check if recipient is frozen
		//require(!isContract(_to));
		balances[msg.sender] = balances[msg.sender].sub(_value);
		balances[_to] = balances[_to].add(_value);
		emit Transfer(msg.sender, _to, _value);
		return true;
	}

	function balanceOf(address _owner)public view returns(uint256 balance) {
		return balances[_owner];
	}

	//standard function transferFrom similar to ERC20 transferFrom with no _data
	//added due to backwards compatibility reasons
	function transferFrom(address _from, address _to, uint256 _value)public returns(bool) {
		require(_to != address(0));
		require(!frozenAccount[_from]); // Check if sender is frozen
		require(!frozenAccount[_to]); // Check if recipient is frozen
		require(_value <= balances[_from]);
		require(_value <= allowed[_from][msg.sender]);

		balances[_from] = balances[_from].sub(_value);
		balances[_to] = balances[_to].add(_value);
		allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
		emit Transfer(_from, _to, _value);
		return true;
	}

	function approve(address _spender, uint256 _value)public returns(bool) {
		allowed[msg.sender][_spender] = _value;
		emit Approval(msg.sender, _spender, _value);
		return true;
	}

	function allowance(address _owner, address _spender)public view returns(uint256) {
		return allowed[_owner][_spender];
	}

	function increaseApproval(address _spender, uint _addedValue)public returns(bool) {
		allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue);
		emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
		return true;
	}

	function decreaseApproval(address _spender, uint _subtractedValue)public returns(bool) {
		uint oldValue = allowed[msg.sender][_spender];
		if (_subtractedValue > oldValue) {
			allowed[msg.sender][_spender] = 0;
		} else {
			allowed[msg.sender][_spender] = SafeMath.sub(oldValue, _subtractedValue);
		}
		emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
		return true;
	}

	// Function that is called when a user or another contract wants to transfer funds .    ///add trasnfertocontractwithcustomfallback  //done
	function transfer(address _to, uint _value, bytes _data, string _custom_fallback)public returns(bool success) {
		require(!frozenAccount[msg.sender]); // Check if sender is frozen
		require(!frozenAccount[_to]); // Check if recipient is frozen
		if (isContract(_to)) {
			return transferToContractWithCustomFallback(_to, _value, _data, _custom_fallback);
		} else {
			return transferToAddress(_to, _value, _data);
		}
	}

	// Function that is called when a user or another contract wants to transfer funds .
	function transfer(address _to, uint _value, bytes _data)public returns(bool) {
		require(!frozenAccount[msg.sender]); // Check if sender is frozen
		require(!frozenAccount[_to]); // Check if recipient is frozen
		if (isContract(_to)) {
			return transferToContract(_to, _value, _data);
		} else {
			return transferToAddress(_to, _value, _data);
		}
		/*
		require(_to != address(0));
		require(_value > 0 && _value <= balances[msg.sender]);
		if(isContract(_to)) {
		ERC223ReceivingContract receiver = ERC223ReceivingContract(_to);
		receiver.tokenFallback(msg.sender, _value, _data);
		return true;
		}
		balances[msg.sender] = balances[msg.sender].sub(_value);
		balances[_to] = balances[_to].add(_value);
		emit Transfer(msg.sender, _to, _value, _data);
		 */
	}

	function isContract(address _addr)private view returns(bool is_contract) {
		uint length;
		assembly {
			//retrieve the size of the code on target address, this needs assembly
			length := extcodesize(_addr)
		}
		return (length > 0);
	}

	//function that is called when transaction target is an address
	function transferToAddress(address _to, uint _value, bytes _data)private returns(bool success) {
		require(balanceOf(msg.sender) > _value);
		balances[msg.sender] = balances[msg.sender].sub(_value);
		balances[_to] = balances[_to].add(_value);
		emit Transfer(msg.sender, _to, _value, _data);
		return true;
	}

	//function that is called when transaction target is a contract
	function transferToContract(address _to, uint _value, bytes _data)private returns(bool success) {
		require(balanceOf(msg.sender) > _value);
		balances[msg.sender] = balances[msg.sender].sub(_value);
		balances[_to] = balances[_to].add(_value);
		ERC223ReceivingContract receiver = ERC223ReceivingContract(_to);
		receiver.tokenFallback(msg.sender, _value, _data);
		emit Transfer(msg.sender, _to, _value, _data);
		return true;
	}

	//function that is called when transaction target is a contract with custom fallback
	function transferToContractWithCustomFallback(address _to, uint _value, bytes _data, string _custom_fallback)private returns(bool success) {
		require(balanceOf(msg.sender) > _value);
		balances[msg.sender] = balances[msg.sender].sub(_value);
		balances[_to] = balances[_to].add(_value);
		assert(_to.call.value(0)(bytes4(keccak256(_custom_fallback)), msg.sender, _value, _data));
		emit Transfer(msg.sender, _to, _value, _data);
		return true;
	}

	function setPreICOSoldAmount(uint256 _soldTokens, uint256 _raisedWei)onlyOwner beforeICO public {
		tokensSold = tokensSold.add(_soldTokens);
		totalWeiRaised = totalWeiRaised.add(_raisedWei);
	}
	
	/// @notice `freeze? Prevent | Allow` `target` from sending & receiving tokens
	/// @param target Address to be frozen
	/// @param freeze either to freeze it or not
	function freezeAccount(address target, bool freeze)onlyOwner public {
		frozenAccount[target] = freeze;
		emit FrozenFunds(target, freeze);
	}

	/**
	 * Destroy tokens
	 *
	 * Remove `_value` tokens from the system irreversibly
	 *
	 * @param _value the amount of money to burn
	 */
	function burn(uint256 _value)onlyOwner public returns(bool success) {
		require(balances[msg.sender] >= _value); // Check if the sender has enough
		balances[msg.sender] = balances[msg.sender].sub(_value); // Subtract from the sender
		_totalSupply = _totalSupply.sub(_value); // Updates totalSupply
		emit Burn(msg.sender, _value);
		emit Transfer(msg.sender, address(0), _value);
		return true;
	}

	/* NOT NEEDED as ethers are in vault
	//check the functionality
	// @notice Failsafe drain
	function withdrawEther()onlyOwner public returns(bool) {
	owner.transfer(address(this).balance);
	return true;
	}
	 */

	// @notice Failsafe transfer tokens for the team to given account
	function withdrawTokens()onlyOwner public returns(bool) {
		require(this.transfer(owner, balances[this]));
		uint256 bonusTokens = balances[address(bonusScheme)];
		balances[address(bonusScheme)] = 0;
		if (bonusTokens > 0) { // If there are no tokens left in bonus scheme, we do not need transaction.
			balances[owner] = balances[owner].add(bonusTokens);
			emit Transfer(address(bonusScheme), owner, bonusTokens);
		}
		return true;
	}

	/**
	 * @dev Allow the owner to transfer out any accidentally sent ERC20 tokens.
	 * @param _tokenAddress The address of the ERC20 contract.
	 * @param _amount The amount of tokens to be transferred.
	 */
	function transferAnyERC20Token(address _tokenAddress, uint256 _amount)onlyOwner public returns(bool success) {
		return ERC20(_tokenAddress).transfer(owner, _amount);
	}

	/**
	 * @dev Investors can claim refunds here if crowdsale is unsuccessful
	 */
	function claimRefund()public {
		require(crowdsaleClosed);
		require(!goalReached());

		vault.refund(msg.sender);
	}

	/**
	 * @dev Checks whether funding goal was reached.
	 * @return Whether funding goal was reached
	 */
	function goalReached()public view returns(bool) {
		return tokensSold >= softCap;
	}

	/**
	 * @dev vault finalization task, called when owner calls finalize()
	 */
	function finalization()internal {
		if (goalReached()) {
			vault.close();
		} else {
			vault.enableRefunds();
		}
	}

	/**
	 * @dev Must be called after crowdsale ends, to do some extra finalization
	 * work. Calls the contract's finalization function.
	 */
	function finalize()onlyOwner afterDeadline public {
		require(!crowdsaleClosed);

		finalization();
		emit Finalized();
		withdrawTokens();

		crowdsaleClosed = true;
	}

}
function _deliverTokens(address _beneficiary, uint256 _tokenAmount)internal {
	this.transfer(_beneficiary, _tokenAmount);
}

/**
 	 * @dev Source of tokens. Override this method to modify the way in which the crowdsale ultimately gets and sends its tokens.
 	 * @param _beneficiary Address performing the token purchase
 	 * @param _tokenAmount Number of tokens to be emitted
 	 */