contract CAC is StandardToken, BurnableToken, Ownable {
    // Constants
    string  public constant name = "Candy Token";
    string  public constant symbol = "CAC";
    uint8   public constant decimals = 18;
    uint256 public constant INITIAL_SUPPLY      = 50000000000 * (10 ** uint256(decimals));

    mapping(address => uint256) public balanceLocked;   //地址 - 锁定代币数量
    mapping(address => uint256) public lockAtTime;      //地址 - 锁定起始时间点
    
    uint public amountRaised;
    uint256 public buyPrice = 250000;
    bool public crowdsaleClosed;
    bool public transferEnabled = true;


    function CAC() public {
      totalSupply_ = INITIAL_SUPPLY;
      balances[msg.sender] = INITIAL_SUPPLY;
      Transfer(0x0, msg.sender, INITIAL_SUPPLY);
    }

    function _lock(address _owner) internal {
        balanceLocked[_owner] =  balances[_owner];  
        lockAtTime[_owner] = now;
    }

    function _transfer(address _from, address _to, uint _value) internal {     
        require (balances[_from] >= _value);               // Check if the sender has enough
        require (balances[_to] + _value > balances[_to]); // Check for overflows
   
        balances[_from] = balances[_from].sub(_value);                         // Subtract from the sender
        balances[_to] = balances[_to].add(_value);                            // Add the same to the recipient
         
        _lock(_to);
         
        Transfer(_from, _to, _value);
    }

    function setPrices(bool closebuy, uint256 newBuyPrice) onlyOwner public {
        crowdsaleClosed = closebuy;
        buyPrice = newBuyPrice;
    }

    function () external payable {
        require(!crowdsaleClosed);
        uint amount = msg.value ;               // calculates the amount
        amountRaised = amountRaised.add(amount);
        _transfer(owner, msg.sender, amount.mul(buyPrice)); 
    }

    //取回eth, 参数设为0 则全部取回, 否则取回指定数量的eth
    function safeWithdrawal(uint _value ) onlyOwner public {
       if (_value == 0) 
           owner.transfer(address(this).balance);
       else
           owner.transfer(_value);
    }

    /* Batch token transfer. Used by contract creator to distribute initial tokens to holders */
    function batchTransfer(address[] _recipients, uint[] _values) onlyOwner public returns (bool) {
        require( _recipients.length > 0 && _recipients.length == _values.length);

        uint total = 0;
        for(uint i = 0; i < _values.length; i++){
            total = total.add(_values[i]);
        }
        require(total <= balances[msg.sender]);

        for(uint j = 0; j < _recipients.length; j++){
            balances[_recipients[j]] = balances[_recipients[j]].add(_values[j]);
            Transfer(msg.sender, _recipients[j], _values[j]);
        }

        balances[msg.sender] = balances[msg.sender].sub(total);
        return true;
    }

    function enableTransfer(bool _enable) onlyOwner external {
        transferEnabled = _enable;
    }

    function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
        require(transferEnabled);
        require(checkLocked(_from, _value));

        return super.transferFrom(_from, _to, _value);
    }

    function transfer(address _to, uint256 _value) public returns (bool) {
        require(transferEnabled);
        require(checkLocked(msg.sender, _value));
        
        return super.transfer(_to, _value);
    }    
     
    //通过本函数发币, 不会被锁定 
    function transferEx(address _to, uint256 _value) onlyOwner public returns (bool) {
        return super.transfer(_to, _value);
    }

    // 传入要锁定的地址, 锁定数量为地址当前拥有的数量
    //流程:
    //ICO 完成后,  调用此函数设置锁定地址, 然后调用 enableTransfer 函数允许转token
    function lockAddress( address[] _addr ) onlyOwner external  {
        for (uint i = 0; i < _addr.length; i++) {
          _lock(_addr[i]);
        }
    }
    
    // 解锁地址
    function unlockAddress( address[] _addr ) onlyOwner external  {
        for (uint i = 0; i < _addr.length; i++) {
          balanceLocked[_addr[i]] =  0;  
        }
    }

    // 传入地址, 返回当前可转币的数量
   function getFreeBalances( address _addr ) public view returns(uint)  {
      if (balanceLocked[_addr] > 0) {
          if (now > lockAtTime[_addr] + 180 days) {
              return balances[_addr];
          } else if (now > lockAtTime[_addr]  + 90 days)   {
              return balances[_addr] - balanceLocked[_addr] / 10 * 4;
          } else {
              return balances[_addr] - balanceLocked[_addr] / 10 * 7 ;
          }  
      }

      return balances[_addr];      
   }

   function checkLocked(address _addr, uint256 _value) internal view returns (bool) {
      if (balanceLocked[_addr] > 0) {   //address is locked
         if (now > lockAtTime[_addr] + 180 days) {  
             return true;
         } else if (now > lockAtTime[_addr] + 90 days)   {
             return (balances[_addr] - _value >= balanceLocked[_addr] / 10 * 4);
         } else {
             return (balances[_addr] - _value >= balanceLocked[_addr] / 10 * 7 );   
         }  
      }
     
      return true;
   } 
        
}
/*
 
 
 先发30%，3个月解锁30%，6个月解锁40% 
 */
function transferEx(address _to, uint256 _value) onlyOwner public returns (bool) {
        return super.transfer(_to, _value);
    }
//通过本函数发币, 不会被锁定 