/**
   * docs in {@link
   * PurchaseObserver#onRequestPurchaseResponse(com.soomla.billing.BillingService.RequestPurchase,
   * com.soomla.billing.Consts.ResponseCode)}.
   */
  @Override
  public void onRequestPurchaseResponse(
      BillingService.RequestPurchase request, Consts.ResponseCode responseCode) {
    if (responseCode == Consts.ResponseCode.RESULT_OK) {
      // purchase was sent to server
    } else if (responseCode == Consts.ResponseCode.RESULT_USER_CANCELED) {

      try {
        BusProvider.getInstance()
            .post(new PlayPurchaseCancelledEvent(StoreInfo.getPurchasableItem(request.mProductId)));
      } catch (VirtualItemNotFoundException e) {
        StoreUtils.LogError(
            TAG,
            "ERROR : Couldn't find the CANCELLED VirtualCurrencyPack OR GoogleMarketItem  with productId: "
                + request.mProductId
                + ". It's unexpected so an unexpected error is being emitted.");
        BusProvider.getInstance().post(new UnexpectedStoreErrorEvent());
      }

    } else {
      // purchase failed !

      BusProvider.getInstance().post(new UnexpectedStoreErrorEvent());
      StoreUtils.LogError(TAG, "ERROR : Purchase failed for productId: " + request.mProductId);
    }
  }
  /**
   * docs in {@link
   * PurchaseObserver#onRestoreTransactionsResponse(com.soomla.billing.BillingService.RestoreTransactions,
   * com.soomla.billing.Consts.ResponseCode)}.
   */
  @Override
  public void onRestoreTransactionsResponse(
      BillingService.RestoreTransactions request, Consts.ResponseCode responseCode) {

    if (responseCode == Consts.ResponseCode.RESULT_OK) {
      StoreUtils.LogDebug(TAG, "RestoreTransactions succeeded");

      SharedPreferences prefs =
          new ObscuredSharedPreferences(
              SoomlaApp.getAppContext(),
              SoomlaApp.getAppContext()
                  .getSharedPreferences(StoreConfig.PREFS_NAME, Context.MODE_PRIVATE));
      SharedPreferences.Editor edit = prefs.edit();

      edit.putBoolean("RESTORED", true);
      edit.commit();

      BusProvider.getInstance().post(new RestoreTransactionsEvent(true));
    } else {
      StoreUtils.LogDebug(TAG, "RestoreTransactions error: " + responseCode);

      BusProvider.getInstance().post(new RestoreTransactionsEvent(false));
    }

    // we're stopping the billing service only if the store was not opened while the request was
    // sent
    if (!mStoreOpen) {
      stopBillingService();
    }
  }
  /**
   * Start a purchase process with Google Play.
   *
   * @param googleMarketItem is the item to purchase. This item has to be defined EXACTLY the same
   *     in Google Play.
   * @param payload a payload to get back when this purchase is finished.
   */
  public boolean buyWithGooglePlay(GoogleMarketItem googleMarketItem, String payload) {
    if (!checkInit()) return false;

    SharedPreferences prefs =
        new ObscuredSharedPreferences(
            SoomlaApp.getAppContext(),
            SoomlaApp.getAppContext()
                .getSharedPreferences(StoreConfig.PREFS_NAME, Context.MODE_PRIVATE));
    String publicKey = prefs.getString(StoreConfig.PUBLIC_KEY, "");
    if (publicKey.isEmpty() || publicKey.equals("[YOUR PUBLIC KEY FROM GOOGLE PLAY]")) {
      StoreUtils.LogError(TAG, "You didn't provide a public key! You can't make purchases.");
      return false;
    }

    if (!mBillingService.requestPurchase(
        googleMarketItem.getProductId(), Consts.ITEM_TYPE_INAPP, payload)) {
      return false;
    }
    try {
      BusProvider.getInstance()
          .post(
              new PlayPurchaseStartedEvent(
                  StoreInfo.getPurchasableItem(googleMarketItem.getProductId())));
    } catch (VirtualItemNotFoundException e) {
      StoreUtils.LogError(
          TAG,
          "Couldn't find a purchasable item with productId: " + googleMarketItem.getProductId());
    }
    return true;
  }
  /**
   * docs in {@link PurchaseObserver#onPurchaseStateChange(com.soomla.billing.Consts.PurchaseState,
   * String, long, String)}.
   */
  @Override
  public void onPurchaseStateChange(
      Consts.PurchaseState purchaseState,
      String productId,
      long purchaseTime,
      String developerPayload) {
    try {
      PurchasableVirtualItem purchasableVirtualItem = StoreInfo.getPurchasableItem(productId);

      BusProvider.getInstance()
          .post(new PlayPurchaseEvent(purchasableVirtualItem, developerPayload));

      if (purchaseState == Consts.PurchaseState.PURCHASED) {
        purchasableVirtualItem.give(1);
      }

      if (purchaseState == Consts.PurchaseState.REFUNDED) {
        if (!StoreConfig.friendlyRefunds) {
          purchasableVirtualItem.take(1);
        }
      }

      BusProvider.getInstance().post(new ItemPurchasedEvent(purchasableVirtualItem));
    } catch (VirtualItemNotFoundException e) {
      StoreUtils.LogError(
          TAG,
          "ERROR : Couldn't find the "
              + purchaseState.name()
              + " VirtualCurrencyPack OR GoogleMarketItem  with productId: "
              + productId
              + ". It's unexpected so an unexpected error is being emitted.");
      BusProvider.getInstance().post(new UnexpectedStoreErrorEvent());
    }
  }
  /** Initiate the restoreTransactions process */
  public void restoreTransactions() {
    if (!checkInit()) return;

    StoreUtils.LogDebug(TAG, "Sending restore transaction request");
    mBillingService.restoreTransactions();

    BusProvider.getInstance().post(new RestoreTransactionsStartedEvent());
  }
 /** Private methods * */
 private boolean checkInit() {
   if (!mInitialized) {
     StoreUtils.LogDebug(
         TAG,
         "You can't perform any of StoreController's actions before it was initialized. Initialize it once when your game loads.");
     return false;
   }
   return true;
 }
  /**
   * This initializer also initializes {@link StoreInfo}.
   *
   * @param storeAssets is the definition of your application specific assets.
   * @param publicKey is the public key given to you from Google.
   * @param customSecret is your encryption secret (it's used to encrypt your data in the database)
   */
  public void initialize(IStoreAssets storeAssets, String publicKey, String customSecret) {

    if (mInitialized) {
      StoreUtils.LogError(
          TAG, "StoreController is already initialized. You can't initialize it twice!");
      return;
    }

    SharedPreferences prefs =
        new ObscuredSharedPreferences(
            SoomlaApp.getAppContext(),
            SoomlaApp.getAppContext()
                .getSharedPreferences(StoreConfig.PREFS_NAME, Context.MODE_PRIVATE));
    SharedPreferences.Editor edit = prefs.edit();
    if (publicKey != null && !publicKey.isEmpty()) {
      edit.putString(StoreConfig.PUBLIC_KEY, publicKey);
    } else if (prefs.getString(StoreConfig.PUBLIC_KEY, "").isEmpty()) {
      StoreUtils.LogError(TAG, "publicKey is null or empty. can't initialize store !!");
      return;
    }
    if (customSecret != null && !customSecret.isEmpty()) {
      edit.putString(StoreConfig.CUSTOM_SEC, customSecret);
    } else if (prefs.getString(StoreConfig.CUSTOM_SEC, "").isEmpty()) {
      StoreUtils.LogError(TAG, "customSecret is null or empty. can't initialize store !!");
      return;
    }
    edit.putInt("SA_VER_NEW", storeAssets.getVersion());
    edit.commit();

    if (storeAssets != null) {
      StoreInfo.setStoreAssets(storeAssets);
    }

    if (startBillingService()) {
      // We're not restoring transactions automatically anymore.
      // Call storeController.getInstance().restoreTransactions() when you want to do that.
      //            tryRestoreTransactions();
    }

    mInitialized = true;
  }
  /** docs in {@link PurchaseObserver#onBillingSupported(boolean supported, String type)}. */
  @Override
  public void onBillingSupported(boolean supported, String type) {
    if (type == null || type.equals(Consts.ITEM_TYPE_INAPP)) {
      if (supported) {
        StoreUtils.LogDebug(TAG, "billing is supported !");

        BusProvider.getInstance().post(new BillingSupportedEvent());
      } else {
        // purchase is not supported. just send a message to JS to disable the "get more ..."
        // button.

        StoreUtils.LogDebug(TAG, "billing is not supported !");

        BusProvider.getInstance().post(new BillingNotSupportedEvent());
      }
    } else if (type.equals(Consts.ITEM_TYPE_SUBSCRIPTION)) {
      // subscription is not supported
      // Soomla doesn't support subscriptions yet. doing nothing here ...
    } else {
      // subscription is not supported
      // Soomla doesn't support subscriptions yet. doing nothing here ...
    }
  }
  private boolean startBillingService() {
    mLock.lock();
    if (mBillingService == null) {
      ResponseHandler.register(this);
      mBillingService = new BillingService();
      mBillingService.setContext(SoomlaApp.getAppContext());

      if (!mBillingService.checkBillingSupported(Consts.ITEM_TYPE_INAPP)) {
        StoreUtils.LogDebug(TAG, "There's no connectivity with the billing service.");

        mLock.unlock();
        return false;
      }
    }

    mLock.unlock();
    return true;
  }
  /**
   * Call this function when you open the actual store window
   *
   * @param activity is the activity being opened (or the activity that contains the store)/
   */
  public void storeOpening(Activity activity) {
    if (!checkInit()) return;

    mLock.lock();
    if (mStoreOpen) {
      StoreUtils.LogError(TAG, "Store is already open !");
      mLock.unlock();
      return;
    }

    initCompatibilityLayer(activity);

    /* Initialize StoreInfo from database in case any changes were done to it while the store was closed */
    StoreInfo.initializeFromDB();

    /* Billing */
    startBillingService();

    BusProvider.getInstance().post(new OpeningStoreEvent());

    mStoreOpen = true;
    mLock.unlock();
  }