contract ColorToken{

	mapping(address => uint256) public balances;
	mapping(address => uint256) public red;
	mapping(address => uint256) public green;
	mapping(address => uint256) public blue;

	uint public _totalSupply;

	mapping(address => mapping(address => uint)) approvals;

	event Transfer(
		address indexed from,
		address indexed to,
		uint256 amount,
		bytes data
	);
	
	function totalSupply() public view returns (uint256) {
        return _totalSupply;
    }

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

	function addColor(address addr, uint amount, uint _red, uint _green, uint _blue) internal {
		//adding color values to balance
		red[addr] += _red * amount;
		green[addr] += _green * amount;
		blue[addr] += _blue * amount;
	}


  	function RGB_Ratio() public view returns(uint,uint,uint){
  		return RGB_Ratio(msg.sender);
  	}

  	function RGB_Ratio(address addr) public view returns(uint,uint,uint){
  		//returns the color of one's tokens
  		uint weight = balances[addr];
  		if (weight == 0){
  			return (0,0,0);
  		}
  		return ( red[addr]/weight, green[addr]/weight, blue[addr]/weight);
  	}

  	function RGB_scale(address addr, uint numerator, uint denominator) internal view returns(uint,uint,uint){
		return (red[addr] * numerator / denominator, green[addr] * numerator / denominator, blue[addr] * numerator / denominator);
	}

	// Function that is called when a user or another contract wants to transfer funds.
	function transfer(address _to, uint _value, bytes memory _data) public virtual returns (bool) {
		if( isContract(_to) ){
			return transferToContract(_to, _value, _data);
		}else{
			return transferToAddress(_to, _value, _data);
		}
	}
	
	// Standard function transfer similar to ERC20 transfer with no _data.
	// Added due to backwards compatibility reasons .
	function transfer(address _to, uint _value) public virtual returns (bool) {
		//standard function transfer similar to ERC20 transfer with no _data
		//added due to backwards compatibility reasons
		bytes memory empty;
		if(isContract(_to)){
			return transferToContract(_to, _value, empty);
		}else{
			return transferToAddress(_to, _value, empty);
		}
	}


	//function that is called when transaction target is an address
	function transferToAddress(address _to, uint _value, bytes memory _data) private returns (bool) {
		moveTokens(msg.sender, _to, _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 memory _data) private returns (bool) {
		moveTokens(msg.sender, _to, _value);
		ERC223ReceivingContract receiver = ERC223ReceivingContract(_to);
		receiver.tokenFallback(msg.sender, _value, _data);
		emit Transfer(msg.sender, _to, _value, _data);
		return true;
	}

	function moveTokens(address _from, address _to, uint _amount) internal virtual{
		require( _amount <= balances[_from] );

		//mix colors
		(uint red_ratio, uint green_ratio, uint blue_ratio) = RGB_scale( _from, _amount, balances[_from] );
		red[_from] -= red_ratio;
		green[_from] -= green_ratio;
		blue[_from] -= blue_ratio;
		red[_to] += red_ratio;
		green[_to] += green_ratio;
		blue[_to] += blue_ratio;

		//update balances
		balances[_from] -= _amount;
		balances[_to] += _amount;
	}

    function allowance(address src, address guy) public view returns (uint) {
        return approvals[src][guy];
    }
  	
    function transferFrom(address src, address dst, uint amount) public returns (bool){
        address sender = msg.sender;
        require(approvals[src][sender] >=  amount);
        require(balances[src] >= amount);
        approvals[src][sender] -= amount;
        moveTokens(src,dst,amount);
        bytes memory empty;
        emit Transfer(sender, dst, amount, empty);
        return true;
    }

    event Approval(address indexed src, address indexed guy, uint amount);
    function approve(address guy, uint amount) public returns (bool) {
        address sender = msg.sender;
        approvals[sender][guy] = amount;

        emit Approval( sender, guy, amount );
        return true;
    }

    function isContract(address _addr) public view returns (bool is_contract) {
		uint length;
		assembly {
			//retrieve the size of the code on target address, this needs assembly
			length := extcodesize(_addr)
		}
		if(length>0) {
			return true;
		}else {
			return false;
		}
	}
}
/*
 ,/`.
 ,'/ __`.
 ,'_/__ _ _`.
 ,'__/__ _ _  _`.
 ,'_  /___ __ _ __ `.
 '-.._/___ _ __ __  __`.
 */
function transferToContract(address _to, uint _value, bytes memory _data) private returns (bool) {
	moveTokens(msg.sender, _to, _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