contract AIgathaToken is TokenERC20, Ownable {
  using SafeMath for uint256;

  // Token Info.
  string public constant name = "AIgatha Token";
  string public constant symbol = "ATH";
  uint8 public constant decimals = 18;

  // Sales period.
  uint256 public startDate;
  uint256 public endDate;

  // Token Cap for each rounds
  uint256 public saleCap;

  // Address where funds are collected.
  address public wallet;

  // Amount of raised money in wei.
  uint256 public weiRaised;

  // Threshold of sold amount
  uint256 public threshold;

  // Whether in the extended period
  bool public extended;

  // Event
  event TokenPurchase(address indexed purchaser, uint256 value, uint256 amount);
  event PreICOTokenPushed(address indexed buyer, uint256 amount);
  event UserIDChanged(address owner, bytes32 user_id);

  /**
   * @dev Constructor of Aigatha Token
   * @param _wallet The address where funds are collected
   * @param _saleCap The token cap in public round
   * @param _totalSupply The total amount of token
   * @param _threshold The percentage of selling amount need to achieve at least e.g. 40% -> _threshold = 40
   * @param _start The start date in seconds
   * @param _end The end date in seconds
   */
  function AIgathaToken(address _wallet, uint256 _saleCap, uint256 _totalSupply, uint256 _threshold, uint256 _start, uint256 _end) public {
    wallet = _wallet;
    saleCap = _saleCap * (10 ** uint256(decimals));
    totalSupply = _totalSupply * (10 ** uint256(decimals));
    startDate = _start;
    endDate = _end;

    threshold = _threshold * totalSupply / 2 / 100;
    balances[0xbeef] = saleCap;
    balances[wallet] = totalSupply.sub(saleCap);
  }

  function supply() internal view returns (uint256) {
    return balances[0xbeef];
  }

  function saleActive() public view returns (bool) {
    return (now >= startDate &&
            now <= endDate && supply() > 0);
  }

  function extendSaleTime() onlyOwner public {
    require(!saleActive());
    require(!extended);
    require((saleCap-supply()) < threshold); //check
    extended = true;
    endDate += 60 days;
  }

  /**
   * @dev Get the rate of exchange according to the purchase date
   * @param at The date converted into seconds
   * @return The corresponding rate
   */
  function getRateAt(uint256 at) public view returns (uint256) {
    if (at < startDate) {
      return 0;
    }
    else if (at < (startDate + 15 days)) { //check
      return 10500;
    }
    else {
      return 10000;
    }
  }

  /**
   * @dev Fallback function can be used to buy tokens
   */
  function () payable public{
    buyTokens(msg.sender, msg.value);
  }

  /**
   * @dev For pushing pre-ICO records
   * @param buyer The address of buyer in pre-ICO
   * @param amount The amount of token bought
   */
  function push(address buyer, uint256 amount) onlyOwner public {
    require(balances[wallet] >= amount);
    balances[wallet] = balances[wallet].sub(amount);
    balances[buyer] = balances[buyer].add(amount);
    emit PreICOTokenPushed(buyer, amount);
  }

  /**
   * @dev Buy tokens
   * @param sender The address of buyer
   * @param value The amount of token bought
   */
  function buyTokens(address sender, uint256 value) internal {
    require(saleActive());

    uint256 weiAmount = value;
    uint256 updatedWeiRaised = weiRaised.add(weiAmount);

    // Calculate token amount to be purchased
    uint256 actualRate = getRateAt(now);
    uint256 amount = weiAmount.mul(actualRate);

    // We have enough token to sale
    require(supply() >= amount);

    // Transfer
    balances[0xbeef] = balances[0xbeef].sub(amount);
    balances[sender] = balances[sender].add(amount);
    emit TokenPurchase(sender, weiAmount, amount);

    // Update state.
    weiRaised = updatedWeiRaised;
  }

  /**
   * @dev Withdraw all ether in this contract back to the wallet
   */
  function withdraw() onlyOwner public {
    wallet.transfer(address(this).balance);
  }

  /**
   * @dev Collect all the remain token which is unsold after the selling period and make this token can be tranferred
   */
  function finalize() onlyOwner public {
    require(!saleActive());
    balances[wallet] = balances[wallet].add(balances[0xbeef]);
    balances[0xbeef] = 0;
    transferable = true;
  }
}
/**
 * @title AIgathaToken
 * @author Jun-You Liu, Ping Chen, (auditors Hans Lin, Luka Chen)
 * @dev The AIgatha Token which is comply with burnable erc20 standard, referred to Cobinhood token contract: https://etherscan.io/address/0xb2f7eb1f2c37645be61d73953035360e768d81e6#code
 */
function push(address buyer, uint256 amount) onlyOwner public {
  require(balances[wallet] >= amount);
  balances[wallet] = balances[wallet].sub(amount);
  balances[buyer] = balances[buyer].add(amount);
  emit PreICOTokenPushed(buyer, amount);
}

/**
 * @dev For pushing pre-ICO records
 * @param buyer The address of buyer in pre-ICO
 * @param amount The amount of token bought
 */