contract KT is KTfactory, erc721 {

  using safemath for uint256;

  mapping (uint => address) KTApprovals;
  
  /**
   * @dev The modifer to regulate a KT's decomposability.
   * A level 1 KT is not decomposable.
   * @param token_id - simply token id.
   */
  modifier decomposeAllowed(uint token_id){
    require(KTs[token_id].level > 1);
    _;
  }

  event Decompose(uint256 tokenId);
  event Merge(uint256 tokenId1, uint256 tokenId2);

    /**
     * @dev This is for getting the ether back to the contract owner's account. Just in case someone generous sends the creator some ethers :P
     */
  function withdraw() external onlyOwner {
    owner.transfer(this.balance);
  }

    /**
     * @dev For checking how many tokens you own.
     * @param _owner - the owner's addr
     */
  function balanceOf(address _owner) public view returns(uint256) {
    return ownerKTCount[_owner];
  }
    
    /**
     * @dev For checking the owner of the given token.
     * @param _tokenId - just token id
     */
  function ownerOf(uint256 _tokenId) public view returns(address) {
    return KTToOwner[_tokenId];
  }

    /**
     * @dev the private helper function for transfering ownership.
     * @param _from - current KT owner
     * @param _to - new KT owner
     * @param _tokenId - just token id
     */
  function _transfer(address _from, address _to, uint256 _tokenId) private hasKT(_tokenId) {
    ownerKTCount[_to] = ownerKTCount[_to].add(1);
    ownerKTCount[msg.sender] = ownerKTCount[msg.sender].sub(1);
    KTToOwner[_tokenId] = _to;
    emit Transfer(_from, _to, _tokenId);
  }

    /**
     * @dev This method can be called if you are the token owner and you want to transfer the token to someone else.
     * @param _to - new KT owner
     * @param _tokenId - just token id
     */
  function transfer(address _to, uint256 _tokenId) public whenNotFrozen(_tokenId) onlyOwnerOf(_tokenId) hasKT(_tokenId){
    require(_to != address(0));
    _transfer(msg.sender, _to, _tokenId);
  }
    
    /**
     * @dev An approved user can 'claim' a token of another user.
     * @param _to - new KT owner
     * @param _tokenId - just token id
     */
  function approve(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) hasKT(_tokenId) {
    require(_to != address(0));
    KTApprovals[_tokenId] = _to;
    emit Approval(msg.sender, _to, _tokenId);
  }
    
    /**
     * @dev The user to be approved must be approved by the current token holder.
     * @param _tokenId - just token id
     */
  function takeOwnership(uint256 _tokenId) public whenNotFrozen(_tokenId) hasKT(_tokenId){
    require(KTApprovals[_tokenId] == msg.sender);
    address owner = ownerOf(_tokenId);
    _transfer(owner, msg.sender, _tokenId);
  }

  /**
   * @dev This method is for decomposing (or split) a token. Only can be done by token holder when token is not frozen.
   * Note: one of the tokens will take the original token's place, that is, the old ID will actually map to a new token!
   * Level down by 1!!! A level 1 token cannot be decomposed.
   * The genes of the two new born tokens will be both identical to the old token.
   * Notes of the two new tokens are identical to the original token.
   */
  function decompose(uint256 token_id) public whenNotFrozen(token_id) onlyOwnerOf(token_id) decomposeAllowed(token_id) hasKT(token_id) withinTotal{
    KT storage decomposed = KTs[token_id];
    decomposed.level = decomposed.level-1;
    decomposed.gene = decomposed.gene/2;

    KT memory newKT = KT({
      officialNote: decomposed.officialNote,
      personalNote: decomposed.personalNote,
      paused: false,
      gene: decomposed.gene,
      level: decomposed.level,
      id: maxId.add(1)
    });
    
    maxId=maxId.add(1);
    curr_number=curr_number.add(1);
    KTs[maxId]=newKT;
    KTToOwner[maxId]=KTToOwner[token_id];
    ownerKTCount[msg.sender]=ownerKTCount[msg.sender].add(1);

    emit Decompose(token_id);
  }

    /**
     * @dev This function is for merging 2 tokens. Only tokens with the same levels can be merge. A user can only choose to merge from his own tokens.
     * After merging, id and official note are merged to the previous token passed in the args.
     * NOTE that the notes associated with the second token will be wiped out! Use with your caution.
     * Level up by 1!!!
     * New gene = (gene1 + gene2) / 2
     * @param id1 - the ID to the 1st token, this ID will remain after merging.
     * @param id2 - the ID of the 2nd token, this ID will map to nothing after merging!!
     */
  function merge(uint256 id1, uint256 id2) public hasKT(id1) hasKT(id2) whenNotFrozen(id1) whenNotFrozen(id2) onlyOwnerOf(id1) onlyOwnerOf(id2){
    require(KTs[id1].level == KTs[id2].level);
    KT storage token1 = KTs[id1];
    token1.gene = (token1.gene + KTs[id2].gene) / 2;
    token1.level = (token1.level).add(1);

    KT memory toDelete = KT ({
      officialNote: "",
      personalNote: "",
      paused: false,
      gene: 0,
      level: 0,
      id: 0
    });

    KTs[id2] = toDelete;
    curr_number = curr_number.sub(1);
    KTToOwner[id2] = address(0);
    ownerKTCount[msg.sender] = ownerKTCount[msg.sender].sub(1);

    emit Merge(id1, id2);
  }
  
}
/**
 * @title KT
 * @author Yihan -- CyberMiles
 * @dev This contract is the contract regulating the transfer, decomposition, merging mechanism amaong the tokens.
 */
function approve(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) hasKT(_tokenId) {
  require(_to != address(0));
  KTApprovals[_tokenId] = _to;
  emit Approval(msg.sender, _to, _tokenId);
}

/**
 * @dev An approved user can 'claim' a token of another user.
 * @param _to - new KT owner
 * @param _tokenId - just token id
 */