contract CryptoFamousStorage is CryptoFamousOwnership {
  function CryptoFamousStorage() public {
      godAddress = msg.sender;
      managerAddress = msg.sender;
      bursarAddress = msg.sender;

      // avoid zero identifiers
      _createCard(0, 0, address(0), address(0));
  }

  function() external payable {
      // just let msg.value be added to this.balance
      FallbackEtherReceived(msg.sender, msg.value);
  }

  event FallbackEtherReceived(address from, uint256 value);

  /// @dev Only this address will be allowed to call functions marked with `requireAuthorizedLogicContract`
  address public authorizedLogicContractAddress;
  modifier requireAuthorizedLogicContract() {
      require(msg.sender == authorizedLogicContractAddress);
      _;
  }

  /// @dev mapping from Card ID to information about that card's last trade
  mapping (uint256 => SaleInfo) public cardIdToSaleInfo;

  /// @dev mapping from Card ID to the current value stashed away for a future claimer
  mapping (uint256 => uint256) public cardIdToStashedPayout;
  /// @dev total amount of stashed payouts
  uint256 public totalStashedPayouts;

  /// @dev if we fail to send any value to a Card's previous owner as part of the
  /// invite/steal transaction we'll hold it in this contract. This mapping records the amount
  /// owed to that "previous owner".
  mapping (address => uint256) public addressToFailedOldOwnerTransferAmount;
  /// @dev total amount of failed old owner transfers
  uint256 public totalFailedOldOwnerTransferAmounts;

  /// @dev mapping from Card ID to that card's current perk text
  mapping (uint256 => string) public cardIdToPerkText;

  function authorized_setCardPerkText(uint256 _cardId, string _perkText) external requireAuthorizedLogicContract {
    cardIdToPerkText[_cardId] = _perkText;
  }

  function setAuthorizedLogicContractAddress(address _newAuthorizedLogicContractAddress) external requireGod {
    authorizedLogicContractAddress = _newAuthorizedLogicContractAddress;
  }

  function authorized_changeOwnership(address _from, address _to, uint256 _cardId) external requireAuthorizedLogicContract {
    _changeOwnership(_from, _to, _cardId);
  }

  function authorized_createCard(uint256 _socialNetworkType, uint256 _socialId, address _owner, address _claimer) external requireAuthorizedLogicContract returns (uint256) {
    return _createCard(_socialNetworkType, _socialId, _owner, _claimer);
  }

  function authorized_updateSaleInfo(uint256 _cardId, uint256 _sentValue) external requireAuthorizedLogicContract {
    cardIdToSaleInfo[_cardId] = SaleInfo(uint128(now), uint128(_sentValue)); // solhint-disable-line not-rely-on-time
  }

  function authorized_updateCardClaimerAddress(uint256 _cardId, address _claimerAddress) external requireAuthorizedLogicContract {
    Card storage card = allCards[_cardId];
    if (card.claimer == address(0)) {
      _recordFirstClaimTimestamp(_cardId);
    }
    card.claimer = _claimerAddress;
    card.claimNonce += 1;
  }

  function authorized_updateCardReserved1(uint256 _cardId, uint8 _reserved) external requireAuthorizedLogicContract {
    uint8 _reserved8 = uint8(_reserved);
    require(_reserved == uint256(_reserved8));

    Card storage card = allCards[_cardId];
    card.reserved1 = _reserved8;
  }

  function authorized_triggerStashedPayoutTransfer(uint256 _cardId) external requireAuthorizedLogicContract {
    Card storage card = allCards[_cardId];
    address claimerAddress = card.claimer;

    require(claimerAddress != address(0));

    uint256 stashedPayout = cardIdToStashedPayout[_cardId];

    require(stashedPayout > 0);

    cardIdToStashedPayout[_cardId] = 0;
    totalStashedPayouts -= stashedPayout;

    claimerAddress.transfer(stashedPayout);
  }

  function authorized_recordStashedPayout(uint256 _cardId) external payable requireAuthorizedLogicContract {
      cardIdToStashedPayout[_cardId] += msg.value;
      totalStashedPayouts += msg.value;
  }

  function authorized_recordFailedOldOwnerTransfer(address _oldOwner) external payable requireAuthorizedLogicContract {
      addressToFailedOldOwnerTransferAmount[_oldOwner] += msg.value;
      totalFailedOldOwnerTransferAmounts += msg.value;
  }

  // solhint-disable-next-line no-empty-blocks
  function authorized_recordPlatformFee() external payable requireAuthorizedLogicContract {
      // just let msg.value be added to this.balance
  }

  /// @dev returns the current contract balance after subtracting the amounts stashed away for others
  function netContractBalance() public view returns (uint256 balance) {
    balance = this.balance - totalStashedPayouts - totalFailedOldOwnerTransferAmounts;
    return balance;
  }

  /// @dev the Bursar account can use this to withdraw the contract's net balance
  function bursarPayOutNetContractBalance(address _to) external requireBursar {
      uint256 payout = netContractBalance();

      if (_to == address(0)) {
          bursarAddress.transfer(payout);
      } else {
          _to.transfer(payout);
      }
  }

  /// @dev Any wallet owed value that's recorded under `addressToFailedOldOwnerTransferAmount`
  /// can use this function to withdraw that value.
  function withdrawFailedOldOwnerTransferAmount() external whenNotPaused {
      uint256 failedTransferAmount = addressToFailedOldOwnerTransferAmount[msg.sender];

      require(failedTransferAmount > 0);

      addressToFailedOldOwnerTransferAmount[msg.sender] = 0;
      totalFailedOldOwnerTransferAmounts -= failedTransferAmount;

      msg.sender.transfer(failedTransferAmount);
  }
}
function authorized_recordPlatformFee() external payable requireAuthorizedLogicContract {
    // just let msg.value be added to this.balance
}

// solhint-disable-next-line no-empty-blocks