contract RealityClashWeapon is ERC721Token, Operators {

  // mappings to store RealityClash Weapon Data
  mapping (uint => string) gameDataOf;
  mapping (uint => string) weaponDataOf;
  mapping (uint => string) ownerDataOf;

 
  event WeaponAdded(uint indexed weaponId, string gameData, string weaponData, string ownerData, string tokenURI);
  event WeaponUpdated(uint indexed weaponId, string gameData, string weaponData, string ownerData, string tokenURI);
  event WeaponOwnerUpdated (uint indexed  _weaponId, address indexed  _oldOwner, address indexed  _newOwner);

  constructor() public  ERC721Token('Reality Clash Weapon', 'RC GUN'){
  }

  /**
   * @dev Mints new tokens wih jsons on blockchain
   * Reverts if the sender is not operator with level 1
   * @param _id Id of weapon to be minted
   * @param _gameData represent game data of the weapon
   * @param _weaponData represents weapon data of the weapon
   * @param _ownerData represents owner data of the weapon
   */
  function mint(uint256 _id, string memory _gameData, string memory _weaponData, string memory _ownerData, address _to)
    public
    onlyLevel(1)
    whenNotPaused
  {
    super._mint(_to, _id);
    gameDataOf[_id] = _gameData;
    weaponDataOf[_id] = _weaponData;
    ownerDataOf[_id] = _ownerData;
    emit WeaponAdded(_id, _gameData, _weaponData, _ownerData, '');
  }

  /**
   * @dev Mints new tokens with tokenURI
   * Reverts if the sender is not operator with level 1
   * @param _id Id of weapon to be minted
   * @param _to represent address to which unique token is minted
   * @param _uri represents string URI to assign
   */
  function mintWithURI(uint256 _id, address _to, string memory _uri)
    public
    onlyLevel(1)
    whenNotPaused
  {
    super._mint(_to, _id);
    super._setTokenURI(_id, _uri);
    emit WeaponAdded(_id, '', '', '', _uri);
  }


  /**
   * @dev Transfer tokens (similar to ERC-20 transfer)
   * Reverts if the sender is not owner of the weapon or approved
   * @param _to address to which token is transferred
   * @param _tokenId Id of weapon being transferred
   */
  function transfer(address _to, uint256 _tokenId)
    public
    whenNotPaused
  {
    safeTransferFrom(msg.sender, _to, _tokenId);
  }

  /**
   * @dev Updates metaData of already minted tokens
   * Reverts if the sender is not operator with level 2 or above
   * @param _id Id of weapon whose data needs to be updated
   * @param _gameData represent game data of the weapon
   * @param _weaponData represents weapon data of the weapon
   * @param _ownerData represents owner data of the weapon
   */
  function updateMetaData(uint _id, string memory _gameData, string memory _weaponData, string memory _ownerData)
    public 
    onlyLevel(2)
    whenNotPaused
  {
    gameDataOf[_id] = _gameData;
    weaponDataOf[_id] = _weaponData;
    ownerDataOf[_id] = _ownerData;
  }

  /**
   * @dev Burn an existing weapon
   * @param _id Id of weapon to be burned
   */
  function burn(uint _id)
    public
    whenNotPaused
  {
   super._burn(msg.sender, _id);
  }


  /**
   * @dev Update game proprietary data
   * @param _id Id of weapon whose data needs to be updated
   * @param _gameData is new game data for weapon
   */
  function updateGameData (uint _id, string memory _gameData)
    public
    onlyLevel(2)
    whenNotPaused
    returns(bool)
  {
    gameDataOf[_id] = _gameData;
    emit WeaponUpdated(_id, _gameData, "", "", "");
    return true;
  }

  /**
   * @dev Update weapon sepcific data of weapon
   * @param _id Id of weapon whose data needs to be updated
   * @param _weaponData is new public data for weapon
   */
  function updateWeaponData (uint _id,  string memory _weaponData)
    public 
    onlyLevel(2)
    whenNotPaused
    returns(bool) 
  {
    weaponDataOf[_id] = _weaponData;
    emit WeaponUpdated(_id, "", _weaponData, "", "");
    return true;
  }

  /**
   * @dev Update owner proprietary data
   * @param _id Id of weapon whose data needs to be updated
   * @param _ownerData is new owner data for weapon
   */
  function updateOwnerData (uint _id, string memory _ownerData)
    public
    onlyLevel(2)
    whenNotPaused
    returns(bool)
  {
    ownerDataOf[_id] = _ownerData;
    emit WeaponUpdated(_id, "", "", _ownerData, "");
    return true;
  }

  /**
   * @dev Update token URI of weapon
   * @param _id Id of weapon whose data needs to be updated
   * @param _uri Url of weapon details
   */
  function updateURI (uint _id, string memory _uri)
    public
    onlyLevel(2)
    whenNotPaused
    returns(bool)
  {
    super._setTokenURI(_id, _uri);
    emit WeaponUpdated(_id, "", "", "", _uri);
    return true;
  }

  //////////////////////////////////////////
  // PUBLICLY ACCESSIBLE METHODS (CONSTANT)
  //////////////////////////////////////////

  /**
  * @return game data of weapon.
  */
  function getGameData (uint _id) public view returns(string memory _gameData) {
    return gameDataOf[_id];
  }

  /**
  * @return weapon data of weapon.
  */
  function getWeaponData (uint _id) public view returns(string memory _pubicData) {
    return weaponDataOf[_id];
  }

  /**
  * @return owner data of weapon.
  */
  function getOwnerData (uint _id) public view returns(string memory _ownerData) {
    return ownerDataOf[_id] ;
  }

  /**
  * @return all metaData data of weapon including game data, weapon data, owner data.
  */
  function getMetaData (uint _id) public view returns(string memory _gameData,string memory _pubicData,string memory _ownerData ) {
    return (gameDataOf[_id], weaponDataOf[_id], ownerDataOf[_id]);
  }
}
/**
 * @title RealityClashWeapon
 * @author Prashant Prabhakar Singh
 * This contract implements Reality Clash Weapons NFTs.
 */
function updateWeaponData (uint _id,  string memory _weaponData)
  public 
  onlyLevel(2)
  whenNotPaused
  returns(bool) 
{
  weaponDataOf[_id] = _weaponData;
  emit WeaponUpdated(_id, "", _weaponData, "", "");
  return true;
}

/**
 * @dev Update weapon sepcific data of weapon
 * @param _id Id of weapon whose data needs to be updated
 * @param _weaponData is new public data for weapon
 */