contract SuperplayerEquipmentV001 is EquipGeneratorWhitelist,ERC721 ,ERC721Metadata("SuperPlayerEquipment","SPE") {

  using SafeMath for uint256;

  enum EquipmentPart {Weapon ,Head,Coat,Pants ,Shoes ,Bag}
  enum EquipmentRareness {Blue,Purple, Orange,Red }

  struct Equipment {
    string key; //using key to contains part and rareness format : rareness_part_name
//    EquipmentPart part;
 //   EquipmentRareness rareness;
    uint[] randomProperties;
    uint[] advancedProperties; //for equipment enhance
  }



  event Birth(address where,uint256 tokenId , string key,  uint[] randomProps);
  event GetAdvancedProperties(address where,uint256 tokenId,uint[] advancedProps);


  mapping (uint256 => uint256) private typeLimitsMap;
  mapping (uint256 => uint256) private typeCurrCntMap;

  uint256 TotalEquipNum; // for ERC721


  Equipment[] private equips;

  constructor() public{

  }

  function totalSupply() public view returns (uint) {
    return TotalEquipNum;
  }

  function addEquipmentGenerator(address addr, string memory category) onlyOwner public returns(bool success){
    return addAddressToWhitelist(addr,category);
  }

  function removeEquipmentGenerator(address addr) onlyOwner public returns(bool success){
    return removeAddressFromWhitelist(addr);
  }

  function setLimit(string memory key, uint256 limit) onlyOwner public {
    uint256 uintkey =  uint256(keccak256(abi.encodePacked(bytes(key))));
    //only can set once
    require( typeLimitsMap[uintkey] == uint256(0) ) ;
    typeLimitsMap[ uintkey ] = limit;
  }

  function setLimits(uint256[] memory uintkeys, uint256[] memory limits) onlyOwner public {
    require(uintkeys.length == limits.length);
    uint len = uintkeys.length;
    for (uint i = 0;i < len ; i++){
    //only can set once
      uint256 uintkey = uintkeys[i];
      if( typeLimitsMap[ uintkey]  == 0 ) {
        typeLimitsMap[ uintkey ] = limits[i];
      }
    }
  }



  function getLimit(string memory key)  public view returns(uint256 current, uint256 limit){
    uint256 uintkey = uint256(keccak256(abi.encodePacked(bytes(key))));
    current = typeCurrCntMap[uintkey];
    limit = typeLimitsMap[uintkey];
  }

  /*
   * This privilege should transfer to the community nodes ,but as the beginning,our team control it for game's quickly  iteration
   */
  function createEquip(address to, string memory key, uint[] memory randomProps) canGenerate public returns(uint256){
    uint256 uintkey =  uint256(keccak256(abi.encodePacked(bytes(key))));
    uint256 currentTypCnt = typeCurrCntMap[uintkey]; 

    // limit checkt
    require(currentTypCnt < typeLimitsMap[uintkey]) ;

    uint[] memory emptyProps = new uint[](0); 
    Equipment memory newEquip = Equipment({
      key : key,
      randomProperties : randomProps,
      advancedProperties : emptyProps
    });
    TotalEquipNum = TotalEquipNum.add(1);
    uint256 newEquipId = equips.push(newEquip).sub(1);
    emit Birth(msg.sender,newEquipId,key,randomProps);
    _mint(to,newEquipId);

    typeCurrCntMap[uintkey] =  currentTypCnt + 1;

    return newEquipId;
  }


  function accquireAdvancedProps(uint256 tokenId,uint[] memory advancedProps) canGenerate public  {
    require(tokenId < TotalEquipNum );
    require( _isApprovedOrOwner( msg.sender,tokenId));
    Equipment storage equip = equips[tokenId];
    equip.advancedProperties = advancedProps;
  }

  function getEquip(uint256 idx) public view returns(
    string memory key,
    uint[] memory randomProps,
    uint[] memory advancedProperties
  ){
      require(idx < TotalEquipNum);
      Equipment storage equip = equips[idx];
      key = equip.key;
      randomProps = equip.randomProperties;
      advancedProperties = equip.advancedProperties;
  }
}
function createEquip(address to, string memory key, uint[] memory randomProps) canGenerate public returns(uint256){
  uint256 uintkey =  uint256(keccak256(abi.encodePacked(bytes(key))));
  uint256 currentTypCnt = typeCurrCntMap[uintkey]; 

  // limit checkt
  require(currentTypCnt < typeLimitsMap[uintkey]) ;

  uint[] memory emptyProps = new uint[](0); 
  Equipment memory newEquip = Equipment({
    key : key,
    randomProperties : randomProps,
    advancedProperties : emptyProps
  });
  TotalEquipNum = TotalEquipNum.add(1);
  uint256 newEquipId = equips.push(newEquip).sub(1);
  emit Birth(msg.sender,newEquipId,key,randomProps);
  _mint(to,newEquipId);

  typeCurrCntMap[uintkey] =  currentTypCnt + 1;

  return newEquipId;
}

/*
 * This privilege should transfer to the community nodes ,but as the beginning,our team control it for game's quickly  iteration
 */