contract UET is owned, CWC_ReceiverInterface {
    using SafeMath for uint;

    /* Constructor Variables */
    string public name;
    string public symbol;
    
    /* Settable Fee Structure per Sale and UETreturn transaction */
    address public CWC_Address; //ether payments go to this
    uint minCWCsPerSaleMoreThan=99; //min buy order size in CWCs.
    uint maxCWCsPerSaleLessThan=1000001; //max buy order in CWCs.
    uint minUETsPerReturnMoreThan=0; //min return order size in UETs.
    uint maxUETsPerReturnLessThan=1000001; //max return order in UETs.

    uint public fixedFeeInCWC=1; //default: 0.001 ether, fee per UET Sale invariant to the sale transaction volume
    uint public percentFeeTimes5=1; //default: 0.2% (=1), less than 500cwc ==> fixed 1 cwc percentFee in addition to fixedFeeInCWC
    // percentFee=(uint/500)*percentFeeTimes5
    
    /* Settable variables */
    uint public totalSupply=1000000000000; 
    uint public totalUETsSold=0; // No. of UETs sold on ether payment
    bool public pauseUET=false;
    mapping(address => uint) balances; // How many UETs each address has.
    
    /* ticker for UET sale and return */
    string public tickerQuery="http://52.73.180.197:30123"; 
    string public tickerQueryData=""; //auto generated "opcode (3 for sale; 4 for return), UET, client_address, CWC_amount, totalUETsSold"
    mapping(bytes32 => bool) tickerQueryIds;
    mapping(bytes32 => uint8) tickerQueryPurpose; //(1) [UET]Sale; (2) UETreturn
    string public lastUETCWC; //UETCWC is UETUSD as long as 1 CWC = 1 USD
 
    // UET sale
    mapping(bytes32 => address) waitingBuyer;
    mapping(bytes32 => uint) cwcPaid;

    // UET return
    mapping(bytes32 => address) waitingSeller;
    mapping(bytes32 => uint) UET_Paid;

    /* Public Events */
    //production events
    event receivedCWC(address from, uint amount);
    event soldUET(address to, uint amount, bytes32 myid);
    event receivedUETreturn(address from, uint amount);
    event returnedCWC(address back_to, uint amount);

    event newOraclizeSetProof(string description);
    event needsEther(string description);
    event newTickerQuery(string description, bytes32 myid);
    event newTickerQueryResult(string last_uetcwc, bytes32 myid);
    event errorTickerQueryError(string result, bytes32 myid);
    
    /* Debug Events */
    event debug_string(string description);
    event debug_bool(bool description);
    event debug_uint(uint description);
    
    /* Constructor function */
    function UET(string tokenName, string tokenSymbol) public {
        name = tokenName;           // Set the name for display purposes
        symbol = tokenSymbol;       // Set the symbol for display purposes
        totalSupply = 1000000000000;		   // 1 Trillion UETs
        oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS);
        newOraclizeSetProof("called the function");
    }    

    /* balance checkup */
    function balanceOf(address an_address) constant returns (uint balance) {
        return balances[an_address];
    }
    
    /* Setters */
    function set_CWC_Address(address _CWC_Address) onlyOwner public {
        CWC_Address = _CWC_Address;
    }
    function transfer_ether_to_owner(uint value) onlyOwner public {
	    require(value < this.balance);
        owner.transfer(value);
    }
    function set_totalSupply(uint value) onlyOwner public {
        totalSupply=value;
    }    
    function set_fixedFeeInCWC(uint value) onlyOwner public {
        fixedFeeInCWC=value;
    }    
    function set_percentFeeTimes5(uint value) onlyOwner public {
        percentFeeTimes5=value;
    }    
    function set_minCWCsPerSaleMoreThan(uint value) onlyOwner public {
        minCWCsPerSaleMoreThan=value;
    }   
    function set_maxCWCsPerSaleLessThan(uint value) onlyOwner public {
        maxCWCsPerSaleLessThan=value;
    }
    function set_minUETsPerReturnMoreThan(uint value) onlyOwner public {
        minUETsPerReturnMoreThan=value;
    }   
    function set_maxUETsPerReturnLessThan(uint value) onlyOwner public {
        maxUETsPerReturnLessThan=value;
    }
    function retryOraclizeSetProof(uint Type_1_if_sure) onlyOwner public {
        if(Type_1_if_sure==1) {
            oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS);
            newOraclizeSetProof("manual performed");
        }
    }
    function set_pauseUET(bool _pauseUET) onlyOwner public {
        pauseUET=_pauseUET;
    }
    function set_tickerQuery(string query) onlyOwner public {
        tickerQuery=query;
    }
    function addSomeUETsTo(address target_address, uint how_many) onlyOwner public {
        balances[target_address] = balances[target_address].add(how_many);
    }
    function removeSomeUETsFrom(address target_address, uint how_many) onlyOwner public {
        balances[target_address] = balances[target_address].sub(how_many);
    }
    
    //================================ UET Transfer Transaction ==================================//

    /* ERC223 transfer UETs with data */
    function transfer(address _to, uint _value, bytes _data) public {
        
        balances[msg.sender] = balances[msg.sender].sub(_value); //must have them to send

        if(_to != owner) { //by this, owner will never pass the above balance line
            balances[_to] = balances[_to].add(_value);
        }

	    // Generate an event for the client
        Transfer(msg.sender, _to, _value, _data);

        // Returning UETs
        if(_to == owner) {
            UETreturnTransaction(msg.sender, _value); // <======== Entry to UET Return
        }
    }
    
    /* ERC223 transfer UETs w/o data for ERC20 compatibility */
    function transfer(address _to, uint _value) public {

        bytes memory empty;

        balances[msg.sender] = balances[msg.sender].sub(_value); //must have them to send

        if(_to != owner) { //by this, owner will never pass the above balance line
            balances[_to] = balances[_to].add(_value);
        }

	    // Generate an event for the client
        Transfer(msg.sender, _to, _value, empty);

        // Returning UETs
        if(_to == owner) {
            UETreturnTransaction(msg.sender, _value); // <======== Entry to UET Return
        }
    }

    //================================ UET Sale Transaction ==================================//

    /* The function without name is the default function that is called whenever anyone sends ether */
    /* Receive basic operation gas in this default fallback */
    //msg.value>0 condition will block all incoming custom coins.
    function () payable {require(msg.value>0);} 

    /* ===> Get CWC and Transfer UETs */
    /* Client can buy by sending CWCs to this contract */
    /* 
    * @param _from Token sender address.
    * @param _value Amount of tokens.
    * @param _data Transaction metadata.
    */
    function CWCfallback(address _from, uint _value, bytes _data) public { // <====== Entry to UET Sale

        require(msg.sender == CWC_Address); //Security here. Only CWC_Address can invoke this  
        require(!pauseUET);
        require(_value>minCWCsPerSaleMoreThan && _value<maxCWCsPerSaleLessThan); 
        if (oraclize_getPrice("URL") > this.balance) {
            needsEther("Oraclize query for UET sale was NOT sent, please add some ETH to cover for the query fee");
            revert(); //does this result in the revert in the CWC_Sale, returning all CWCs back automatically?
        } 
        else {
            tickerQueryData = strConcat("3,", "UET,", "0x", addressToAsciiString(_from), ",");
            tickerQueryData = strConcat(tickerQueryData, uint2str(_value), ",", uint2str(totalUETsSold));
            bytes32 queryId = oraclize_query("URL", tickerQuery, tickerQueryData);
            tickerQueryIds[queryId] = true;
            tickerQueryPurpose[queryId] = 1; //1 for UET sale; 2 for UET return
            waitingBuyer[queryId] = _from;
            cwcPaid[queryId] = _value;
            receivedCWC(waitingBuyer[queryId], cwcPaid[queryId]);
            newTickerQuery("Called Oraclize for UET sale. Waiting…", queryId);
        }
    }

    //================================ UET Return Transaction ==================================//

    function UETreturnTransaction(address _from, uint _value) private {
        require(!pauseUET);
        require(_value>minUETsPerReturnMoreThan && _value<maxUETsPerReturnLessThan);
        if (oraclize_getPrice("URL") > this.balance) {
            needsEther("Oraclize query for UET return was NOT sent, please add some ETH to cover for the query fee");
            revert();
        } 
        else {
            tickerQueryData = strConcat("4,", "UET, ", "0x", addressToAsciiString(_from), ",");
            tickerQueryData = strConcat(tickerQueryData, uint2str(_value), ",", uint2str(totalUETsSold));
            bytes32 queryId = oraclize_query("URL", tickerQuery, tickerQueryData);
            tickerQueryIds[queryId] = true;
            tickerQueryPurpose[queryId] = 2; //1 for UET sale; 2 for UET return
            waitingSeller[queryId] = _from;
            UET_Paid[queryId] = _value;
            receivedUETreturn(waitingSeller[queryId], UET_Paid[queryId]);
            newTickerQuery("Called Oraclize for UET return. Waiting…", queryId);
        }
    }


    //================================ UET Return Transaction ==================================//

    function returnCWCto(address _to, uint _value) private {
        CWC_SaleInterface cwc = CWC_SaleInterface(CWC_Address);
        cwc.minterGivesCWC(_to, _value);
    }

    //================================== Orclize __callback() ===================================//

    function __callback(bytes32 myid, string result, bytes proof) {
        // check the validity of the oraclize result
        require(msg.sender == oraclize_cbAddress());
        uint UETCWCtimes100000;
        
        /******* Result to UET Sale tickerQuery *******/
        if(tickerQueryIds[myid]==true && tickerQueryPurpose[myid]==1) { //tickerQueryPurpose==1 is UET Sale

            if(stringEqual(result, "err") || stringEqual(result, "")) {
                errorTickerQueryError(result, myid);
                //process error
                pauseUET=true;
                returnCWCto(waitingBuyer[myid], cwcPaid[myid]); // <=== HTTP ERROR: return all CWC
            }
            else {            
                newTickerQueryResult(result, myid);
                lastUETCWC = result;
                UETCWCtimes100000=parseInt(result,5);
                uint cwcPaidAfterFees;

                if(cwcPaid[myid] < 500) { //less than 500cwcPaid ==> percentFee is 1cwc
                    cwcPaidAfterFees = (cwcPaid[myid]-fixedFeeInCWC)-1;
                }
                else { //more than 500cwcPaid ==> percentFee calculation
                    cwcPaidAfterFees = (cwcPaid[myid]-fixedFeeInCWC)-((cwcPaid[myid]/500)*percentFeeTimes5);
                }
                uint NoOfUETsToGive= (cwcPaidAfterFees*100000)/(UETCWCtimes100000);  // <========= No. Of UETs to Give

                if(NoOfUETsToGive<1) {
                    returnCWCto(waitingBuyer[myid], cwcPaid[myid]); //return all
                }
                else {
                    balances[waitingBuyer[myid]] = balances[waitingBuyer[myid]].add(NoOfUETsToGive);
                    uint NoOfCWCsToReturn= ((cwcPaidAfterFees*100000) - (UETCWCtimes100000*NoOfUETsToGive))/100000; // <==== No. Of CWCs to Return
                    if(NoOfCWCsToReturn>=1) {
                        returnCWCto(waitingBuyer[myid], NoOfCWCsToReturn); //return remaining CWCs
                    }         
                    soldUET(waitingBuyer[myid], NoOfUETsToGive, myid);
                    totalUETsSold = totalUETsSold.add(NoOfUETsToGive);
                }
            }
            delete tickerQueryIds[myid];
            delete tickerQueryPurpose[myid]; 
            delete waitingBuyer[myid];
            delete cwcPaid[myid];
        }

        /******* Result to UET Return tickerQuery *******/
        else if(tickerQueryIds[myid]==true && tickerQueryPurpose[myid]==2) { //tickerQueryPurpose==2 is UET Return

            if(stringEqual(result, "err") || stringEqual(result, "")) {
                errorTickerQueryError(result, myid);
                //process error
                pauseUET=true;
                balances[waitingSeller[myid]] = balances[waitingSeller[myid]].add(UET_Paid[myid]); // <=== HTTP ERROR: return all UETs
            }
            else {            
                newTickerQueryResult(result, myid);
                lastUETCWC = result;
                UETCWCtimes100000=parseInt(result,5);

                uint NoOfCWCsToGive=(UET_Paid[myid]*UETCWCtimes100000)/100000-fixedFeeInCWC; // <======== No. Of CWCs to Give
                returnCWCto(waitingSeller[myid], NoOfCWCsToGive);
                returnedCWC(waitingSeller[myid], NoOfCWCsToGive);
                totalUETsSold = totalUETsSold.sub(UET_Paid[myid]);
            }
            delete tickerQueryIds[myid];
            delete tickerQueryPurpose[myid];
            delete waitingSeller[myid];
            delete UET_Paid[myid];
        }
    }

    //Contemplate removing in the production version
    function perform_selfdestruct(uint Type_1_if_sure) onlyOwner public {
        if(Type_1_if_sure==1) {
            selfdestruct(owner);
        }
    }
}
/* Deployment Manual
 After deployed, 
 (1) Set CWC_Address;
 (2) Review and Set minCWCsPerSaleTransaction must be higher than UETCWC (enough to buy one UET plus gas and fees ~4 CWCs)
 (3) Set all Query and Query Data;
 
 	Notes:   
 	0. tickerQuery is an HTTP POST. (Note: tickerQueryPurpose: (1) Sale; (2) UETreturn (our buyback of UET)
 		By default: POST goes to our HTTP server (tickerQuery) with opcode, UET, client_address, and amount.
 You cannot change tickerQueryData (auto generated as follows)
 		===> "opcode (3 for sale; 4 for return), UET, client_address, amount, totalUETsSold”
 		        Note: amount is CWC for 3 (sale) and UET for 4 (return)
 		        Note: above totalUETsSold EXCLUDES the current sale or return of this current ticker.
 
 	1.  result of every POST is the "result" parameter of __callback() in a string.
 		Normal Return: Price to the 5 decimal points (e.g., 6.13245, 6.43000, 6.10000, 10.23534 and 11.43000 and 102.30000)
 		Error return definition:
 		===> tickerQuery:  return==“err” 			 
 */
function UETreturnTransaction(address _from, uint _value) private {
    require(!pauseUET);
    require(_value>minUETsPerReturnMoreThan && _value<maxUETsPerReturnLessThan);
    if (oraclize_getPrice("URL") > this.balance) {
        needsEther("Oraclize query for UET return was NOT sent, please add some ETH to cover for the query fee");
        revert();
    } 
    else {
        tickerQueryData = strConcat("4,", "UET, ", "0x", addressToAsciiString(_from), ",");
        tickerQueryData = strConcat(tickerQueryData, uint2str(_value), ",", uint2str(totalUETsSold));
        bytes32 queryId = oraclize_query("URL", tickerQuery, tickerQueryData);
        tickerQueryIds[queryId] = true;
        tickerQueryPurpose[queryId] = 2; //1 for UET sale; 2 for UET return
        waitingSeller[queryId] = _from;
        UET_Paid[queryId] = _value;
        receivedUETreturn(waitingSeller[queryId], UET_Paid[queryId]);
        newTickerQuery("Called Oraclize for UET return. Waiting…", queryId);
    }
}

//================================ UET Return Transaction ==================================//