contract KTfactory is ownable, KTaccess {

  using safemath for uint256;

  uint256 public maxId;

  uint256 public initial_supply;

  uint256 public curr_number;

  event NewKT(string note, uint256 gene, uint256 level, uint256 tokenId);
  event UpdateNote(string newNote, uint256 tokenId);
  event PauseToken(uint256 tokenId);
  event UnpauseToken(uint256 tokenId);

  struct KT {
    string officialNote;
    string personalNote;
    bool paused;
    uint256 gene;
    uint256 level;
    uint256 id;
  }

  mapping (uint256 => KT) public KTs;

  mapping (uint => address) public KTToOwner;
  mapping (address => uint) ownerKTCount;

  modifier onlyOwnerOf(uint token_id) {
    require(msg.sender == KTToOwner[token_id]);
    _;
  }

  modifier whenNotFrozen(uint token_id) {
    require(KTs[token_id].paused == false);
    _;
  }

  modifier withinTotal() {
    require(curr_number<= initial_supply);
    _;
  }

  modifier hasKT(uint token_id) {
    require(KTs[token_id].id != 0);
    _;
  }
    
    /**
     * @dev The constructor. Sets the initial supply and some other global variables.
     * That's right, Krypital will only issue 2100 tokens in total. It also means the total number of KTs will not exceed this number!
     */
  constructor() public {
    initial_supply = 2100;
    maxId=0;
    curr_number=0;
  }

    /**
     * @dev The creator of KTs. Only done by Krypital.
     * @param oNote - the official, special note left only by Krypital!
     */
  function _createKT(string oNote) public onlyOLevel withinTotal {
    uint thisId = maxId + 1;
    string pNote;
    uint256 thisGene = uint256(keccak256(oNote));
    
    KT memory thisKT = KT({
        officialNote: oNote, 
        personalNote: pNote, 
        paused: false, 
        gene: thisGene, 
        level: 1, 
        id: thisId
    });
    
    KTs[thisId] = thisKT;
    maxId = maxId + 1;
    curr_number = curr_number + 1;
    KTToOwner[thisId] = msg.sender;
    ownerKTCount[msg.sender]++;
    emit NewKT(oNote, thisGene, 1, thisId);
  }
    
    /**
     * @dev This method is for editing your personal note!
     * @param note - the note you want the old one to be replaced by
     * @param token_id - just token id
     */
  function _editPersonalNote(string note, uint token_id) public onlyOwnerOf(token_id) hasKT(token_id){
    KT storage currKT = KTs[token_id];
    currKT.personalNote = note;
    emit UpdateNote(note, token_id);
  }
    
    /**
     * @dev Pauses a token, done by Krypital
     * When a token is paused by Krypital, the owner of the token can still update the personal note but the ownership cannot be transferred.
     * @param token_id - just token id
     */
  function pauseToken(uint token_id) public onlyOLevel hasKT(token_id){
    KT storage currKT = KTs[token_id];
    currKT.paused = true;
    emit PauseToken(token_id);
  }
  
  /**
   * @dev Unpauses a token, done by Krypital
   * @param token_id - just token id
   */
  function unpauseToken(uint token_id) public onlyOLevel hasKT(token_id){
    KT storage currKT = KTs[token_id];
    currKT.paused = false;
    emit UnpauseToken(token_id);
  }

}
/**
 * @title KTfactory
 * @author Yihan -- CyberMiles
 * @dev This main contract for creating KTs.
 * 
 * A KT, which is the token issued by Krypital, has the following properties: 
 * an officail note that can be created only by the contract owner;
 * a personal note that can be modified by the current owner of the token;
 * a bool value indicating if the token is currently frozen by Krypital;
 * a gene which is a hashed value that changes when mutate (merge or decompose). This is for some future interesting apps :D 
 * level, namely, the level of the token. Apparently higher is better :D
 * id, the key used to map to the associated KT.
 * 
 */
function _editPersonalNote(string note, uint token_id) public onlyOwnerOf(token_id) hasKT(token_id){
  KT storage currKT = KTs[token_id];
  currKT.personalNote = note;
  emit UpdateNote(note, token_id);
}

/**
 * @dev This method is for editing your personal note!
 * @param note - the note you want the old one to be replaced by
 * @param token_id - just token id
 */