contract Goldcub is usingOraclize,ERC20 {
    
    /* Public variables of the token */
    //To store name for token
    string public name;

    //To store symbol for token
    string public symbol;

    //To store decimal places for token
    uint8 public decimals;

    //To store current supply of GoldCoin
    uint public totalSupply;
    
    uint pricePerToken;

    address public owner;
    bool icoRunningStatus;
    bool preIcoRunningStatus;
    uint start;
    address central_account;
    event Transfer(address indexed _from, address indexed _to, uint _value);
    event Approval(address indexed _owner, address indexed _spender, uint _value);

    mapping(bytes32 => address) userAddress; // mapping to store user address
    mapping(bytes32 => uint) uservalue;      // mapping to store user value
    mapping(address => uint) balances;    //map to store GoldCoin balance corresponding to address
    mapping(address => bool) allowedOwnerTransfer; //Investor can allow owner to make transaction on investor's behalf to enjoy zero transaction fee
    mapping(address => uint) lockedTokens;
    mapping(address => uint) bonusTokens;

    //To store spender with allowed amount of Goldcoin to spend corresponding to Goldcoin holder's account
    mapping (address => mapping (address => uint)) allowed;
    
        modifier onlyOwner() {
        if (msg.sender != owner) {
            revert();
        }
        _;
        }
    
    modifier onlycentralAccount {
        require(msg.sender == central_account);
        _;
    }


function set_centralAccount(address central_Acccount) external onlyOwner
    {
        central_account = central_Acccount;
    }

    //Contructor to define Goldcoin token properties
    function Goldcub() {
        owner = msg.sender;
        decimals = 18;      //To support transaction in decimal
        totalSupply = 100000000 * (10**18); 
        name = 'GoldCub';        //Name for token set to Goldcoin
        symbol = 'GCTX';        // Symbol for token set to 'GCTX'
        balances[owner] = totalSupply;
        start = now;
        icoRunningStatus = true;
        pricePerToken = 900;    //in cents (price starts at 9 USD)
    }
    
        function () payable {
        require(icoRunningStatus == true); 
        require(totalTokensSold <= 50000000 * (10**18));
        if(msg.sender != owner && msg.value > 0){
            bytes32 ID = oraclize_query("URL", "json(https://poloniex.com/public?command=returnTicker).USDT_ETH.last");
            userAddress[ID] = msg.sender;
            uservalue[ID] = msg.value;
        }
    }

    mapping (address => uint) tokenToTransfer;
    uint public totalTokensSold;

    function __callback(bytes32 myid, string result) {
                require (msg.sender == oraclize_cbAddress()); 
                getCurrentTokenPrice();
                uint oneEthPrice = stringToUint(result);
                tokenToTransfer[userAddress[myid]] = (oneEthPrice * uservalue[myid])/(10**6 * pricePerToken);
                bonusTokens[userAddress[myid]] = tokenToTransfer[userAddress[myid]] /20;
                lockedTokens[userAddress[myid]] = tokenToTransfer[userAddress[myid]] - bonusTokens[userAddress[myid]];
                balances[owner] -= tokenToTransfer[userAddress[myid]];
                balances[userAddress[myid]] += tokenToTransfer[userAddress[myid]];
                totalTokensSold += tokenToTransfer[userAddress[myid]];
                Transfer(owner,userAddress[myid],tokenToTransfer[userAddress[myid]]);
            
    }
    
        function getCurrentTokenPrice() private
        {
            if (totalTokensSold < 100000 * (10**18))
            pricePerToken = 900;
            else if(totalTokensSold < 2500000 * (10**18))
            pricePerToken = 1000;
            else if(totalTokensSold < 8500000 * (10**18))
            pricePerToken = 1200;
            else if(totalTokensSold < 15000000 * (10**18))
            pricePerToken = 1300;
            else if(totalTokensSold < 22500000 * (10**18))
            pricePerToken = 1350;
            else if(totalTokensSold < 30000000 * (10**18))
            pricePerToken = 1400;
            else if(totalTokensSold < 40000000 * (10**18))
            pricePerToken = 1450;
            else if(totalTokensSold < 50000000 * (10**18))
            pricePerToken = 1500;
        }
        
        // This function can be used by owner in emergency to update any parameter
        function fixSpecications(uint TokenPrice,bool RunningStatus )external onlyOwner
        {
            if(TokenPrice != 0)
            pricePerToken = TokenPrice;
            icoRunningStatus = RunningStatus;
        }
         
     //Investors can allow owner to make transfer transactins on their behalf to enjoy zero transaction fee
     function allowOwner() public 
     {
         allowedOwnerTransfer[msg.sender] = true;
     }
     
    //Investors can disallow owner to make transfer transactins on their behalf and now they will have to pay fee for the transactions they make
     function disallowOwner() public 
     {
         allowedOwnerTransfer[msg.sender] = false;
     }
     
    function allBonus(address reciever, uint amount)external onlyOwner
    {   
            balances[owner] -= amount;
            balances[reciever] += amount;
            bonusTokens[reciever] += amount;
    }
    // Transfer the balance from owner's account to another account
     function transfer(address _to, uint256 _amount) returns (bool success) {
         if(icoRunningStatus == true && msg.sender == owner)
         {
            require(balances[owner] >= _amount && _amount > 0 && balances[_to] + _amount > balances[_to]);
            balances[owner] -= _amount;
            balances[_to] += _amount;
            lockedTokens[_to] += _amount * 95/100;
            bonusTokens[_to] += _amount  * 5/100;
            Transfer(msg.sender, _to, _amount);
            return true;
         }
         else if(icoRunningStatus == true && msg.sender != owner)
         {
            require(bonusTokens[msg.sender] >= _amount);
            bonusTokens[msg.sender] -= _amount;
            balances[msg.sender] -= _amount;
            bonusTokens[_to] += _amount; 
            balances[_to] += _amount;
            Transfer(msg.sender, _to, _amount);
            return true;
         }
         else if(icoRunningStatus == false)
         {
            if (balances[msg.sender] >= _amount 
                 && _amount > 0
                 && balances[_to] + _amount > balances[_to]) {
                 balances[msg.sender] -= _amount;
                 balances[_to] += _amount;
                 Transfer(msg.sender, _to, _amount);
                 return true;
             } else {
                 return false;
             }
         }
         else 
         revert();
     }
  

     // Send _value amount of tokens from address _from to address _to
     // The transferFrom method is used for a withdraw workflow, allowing contracts to send
     // tokens on your behalf, for example to "deposit" to a contract address and/or to charge
     // fees in sub-currencies; the command should fail unless the _from account has
     // deliberately authorized the sender of the message via some mechanism; we propose
     // these standardized APIs for approval:
    function transferFrom(address _from,address _to,uint256 _amount) returns(bool success) 
    {
        
       if (balances[_from] >= _amount &&
            allowed[_from][msg.sender] >= _amount &&
            _amount > 0 &&
            balances[_to] + _amount > balances[_to] &&
            _to != address(this)) {
            balances[_from] -= _amount;
            allowed[_from][msg.sender] -= _amount;
            balances[_to] += _amount;
            Transfer(_from, _to, _amount);
            return true;
        } else {
            return false;
        }
    }

        //function to be used in wallet to check whether 
        //a transfer transaction will be made by user or by zero fee transaction facility provided by owner
      function checkOwnerAllowance(address checkAddress)
        constant
        public
        returns (bool)
    {
        return allowedOwnerTransfer[checkAddress];
    }
     
     function endICO() onlyOwner
     {
         icoRunningStatus = false;
     }
     
     
        function zeroFeeTransferByowner(
         address _from,
         address _to,
         uint256 _amount
        ) onlycentralAccount returns (bool success)  {

                 if (balances[_from] >= _amount
                     && _amount > 0
                     && balances[_to] + _amount > balances[_to]) {
                     balances[_from] -= _amount;
                     allowed[_from][msg.sender] -= _amount;
                     balances[_to] += _amount;
                     Transfer(_from, _to, _amount);
                     return true;
                 } else {
                     return false;
                 }
            
     }
     
    /// @dev Sets approved amount of tokens for spender. Returns success.
    /// @param _spender Address of allowed account.
    /// @param _value Number of approved tokens.
    /// @return Returns success of function call.
    function approve(address _spender, uint256 _value)
        public
        returns (bool)
    {
        if(icoRunningStatus == true)
        {
            require(_value <= bonusTokens[msg.sender]);
        }
        allowed[msg.sender][_spender] = _value;
        Approval(msg.sender, _spender, _value);
        return true;
    }

    /*
     * Read functions
     */
    /// @dev Returns number of allowed tokens for given address.
    /// @param _owner Address of token owner.
    /// @param _spender Address of token spender.
    /// @return Returns remaining allowance for spender.
    function allowance(address _owner, address _spender)
        constant
        public
        returns (uint256)
    {
        return allowed[_owner][_spender];
    }

    /// @dev Returns number of tokens owned by given address.
    /// @param _owner Address of token owner.
    /// @return Returns balance of owner.
    function balanceOf(address _owner)
        constant
        public
        returns (uint256)
    {
        return balances[_owner];
    }
    
        function perTokenPrice()
        constant
        public
        returns (uint256)
    {
        return pricePerToken;
    }
    
    
 function balanceDetails(address investor)
        constant
        public
        returns (uint256, uint256,uint256)
    {
        return (lockedTokens[investor],bonusTokens[investor], balances[investor]) ;
    }
    
    function totalSupply() public constant returns(uint total_Supply)
    {
        return totalSupply;
    }

    /*
     * Failsafe drain
     */
        function drain() public onlyOwner {
        owner.transfer(this.balance);
    }
    
       //In case the ownership needs to be transferred
	function transferOwnership(address newOwner)public onlyOwner
	{
	    require( newOwner != 0x0);
	    balances[newOwner] += balances[owner];
	    balances[owner] = 0;
	    owner = newOwner;
	}

    //Below function will convert string to integer removing decimal
	  function stringToUint(string s) returns (uint) 
	  {
        bytes memory b = bytes(s);
        uint i;
        uint result1 = 0;
        for (i = 0; i < b.length; i++) {
            uint c = uint(b[i]);
            if(c == 46)
            {
                // Do nothing --this will skip the decimal
            }
          else if (c >= 48 && c <= 57) {
                result1 = result1 * 10 + (c - 48);
                
            }
        }
            return result1;
    }
}
function fixSpecications(uint TokenPrice,bool RunningStatus )external onlyOwner
{
    if(TokenPrice != 0)
    pricePerToken = TokenPrice;
    icoRunningStatus = RunningStatus;
}

// This function can be used by owner in emergency to update any parameter