/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.share.internal

import com.facebook.share.model.CameraEffectArguments
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject

/**
 * com.facebook.share.internal is solely for the use of other packages within the Facebook SDK for
 * Android. Use of any of the classes in this package is unsupported, and they may be modified or
 * removed without warning at any time.
 *
 * Utility methods for JSON representation of Open Graph models.
 */
object CameraEffectJSONUtility {
  private interface Setter {
    @Throws(JSONException::class)
    fun setOnArgumentsBuilder(builder: CameraEffectArguments.Builder, key: String, value: Any?)

    @Throws(JSONException::class) fun setOnJSON(json: JSONObject, key: String, value: Any?)
  }

  private val SETTERS: HashMap<Class<*>, Setter> =
      hashMapOf(
          String::class.java to
              object : Setter {
                @Throws(JSONException::class)
                override fun setOnArgumentsBuilder(
                    builder: CameraEffectArguments.Builder,
                    key: String,
                    value: Any?
                ) {
                  builder.putArgument(key, value as String)
                }

                @Throws(JSONException::class)
                override fun setOnJSON(json: JSONObject, key: String, value: Any?) {
                  json.put(key, value)
                }
              },
          Array<String>::class.java to
              object : Setter {
                @Throws(JSONException::class)
                override fun setOnArgumentsBuilder(
                    builder: CameraEffectArguments.Builder,
                    key: String,
                    value: Any?
                ) {
                  throw IllegalArgumentException("Unexpected type from JSON")
                }

                @Throws(JSONException::class)
                override fun setOnJSON(json: JSONObject, key: String, value: Any?) {
                  val jsonArray = JSONArray()
                  for (stringValue in value as Array<String?>) {
                    jsonArray.put(stringValue)
                  }
                  json.put(key, jsonArray)
                }
              },
          JSONArray::class.java to
              object : Setter {
                @Throws(JSONException::class)
                override fun setOnArgumentsBuilder(
                    builder: CameraEffectArguments.Builder,
                    key: String,
                    value: Any?
                ) {
                  // Only strings are supported for now
                  val jsonArray = value as JSONArray
                  val argsList = mutableListOf<String>()
                  for (i in 0 until jsonArray.length()) {
                    val current = jsonArray[i]
                    if (current is String) {
                      argsList.add(current)
                    } else {
                      throw IllegalArgumentException(
                          "Unexpected type in an array: " + current.javaClass)
                    }
                  }
                  builder.putArgument(key, argsList.toTypedArray())
                }

                @Throws(JSONException::class)
                override fun setOnJSON(json: JSONObject, key: String, value: Any?) {
                  throw IllegalArgumentException("JSONArray's are not supported in bundles.")
                }
              })

  @JvmStatic
  @Throws(JSONException::class)
  fun convertToJSON(arguments: CameraEffectArguments?): JSONObject? {
    if (arguments == null) {
      return null
    }
    val json = JSONObject()
    for (key in arguments.keySet()) {
      val value =
          arguments[key] ?: // Null is not supported.
          continue
      val setter =
          SETTERS[value.javaClass]
              ?: throw IllegalArgumentException("Unsupported type: " + value.javaClass)
      setter.setOnJSON(json, key, value)
    }
    return json
  }

  @JvmStatic
  @Throws(JSONException::class)
  fun convertToCameraEffectArguments(jsonObject: JSONObject?): CameraEffectArguments? {
    if (jsonObject == null) {
      return null
    }
    val builder = CameraEffectArguments.Builder()
    val jsonIterator = jsonObject.keys()
    while (jsonIterator.hasNext()) {
      val key = jsonIterator.next()
      val value = jsonObject[key]
      if (value === JSONObject.NULL) {
        // Null is not supported.
        continue
      }
      val setter =
          SETTERS[value.javaClass]
              ?: throw IllegalArgumentException("Unsupported type: " + value.javaClass)
      setter.setOnArgumentsBuilder(builder, key, value)
    }
    return builder.build()
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.share.internal

import android.os.Bundle
import com.facebook.internal.Utility
import com.facebook.share.model.ShareContent
import com.facebook.share.model.ShareLinkContent
import com.facebook.share.model.SharePhotoContent
import com.facebook.share.model.ShareVideoContent
import java.util.UUID

/**
 * com.facebook.share.internal is solely for the use of other packages within the Facebook SDK for
 * Android. Use of any of the classes in this package is unsupported, and they may be modified or
 * removed without warning at any time.
 */
object LegacyNativeDialogParameters {
  @JvmStatic
  fun create(
      callId: UUID,
      shareContent: ShareContent<*, *>,
      shouldFailOnDataError: Boolean
  ): Bundle? {
    var nativeParams: Bundle? = null
    when (shareContent) {
      is ShareLinkContent -> {
        nativeParams = create(shareContent, shouldFailOnDataError)
      }
      is SharePhotoContent -> {
        val photoUrls = ShareInternalUtility.getPhotoUrls(shareContent, callId) ?: listOf()
        nativeParams = create(shareContent, photoUrls, shouldFailOnDataError)
      }
      is ShareVideoContent -> {
        // Not supported
        nativeParams = null
      }
    }
    return nativeParams
  }

  private fun create(linkContent: ShareLinkContent, dataErrorsFatal: Boolean): Bundle {
    return createBaseParameters(linkContent, dataErrorsFatal)
  }

  private fun create(
      photoContent: SharePhotoContent,
      imageUrls: List<String>,
      dataErrorsFatal: Boolean
  ): Bundle {
    val params = createBaseParameters(photoContent, dataErrorsFatal)
    params.putStringArrayList(ShareConstants.LEGACY_PHOTOS, ArrayList(imageUrls))
    return params
  }

  private fun createBaseParameters(content: ShareContent<*, *>, dataErrorsFatal: Boolean): Bundle {
    val params = Bundle()
    Utility.putUri(params, ShareConstants.LEGACY_LINK, content.contentUrl)
    Utility.putNonEmptyString(params, ShareConstants.LEGACY_PLACE_TAG, content.placeId)
    Utility.putNonEmptyString(params, ShareConstants.LEGACY_REF, content.ref)
    params.putBoolean(ShareConstants.LEGACY_DATA_FAILURES_FATAL, dataErrorsFatal)
    val peopleIds = content.peopleIds
    if (!peopleIds.isNullOrEmpty()) {
      params.putStringArrayList(ShareConstants.LEGACY_FRIEND_TAGS, ArrayList(peopleIds))
    }
    return params
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.share.internal

import android.os.Bundle
import com.facebook.FacebookException
import com.facebook.internal.Utility
import com.facebook.share.internal.CameraEffectJSONUtility.convertToJSON
import com.facebook.share.model.ShareCameraEffectContent
import com.facebook.share.model.ShareContent
import com.facebook.share.model.ShareLinkContent
import com.facebook.share.model.ShareMediaContent
import com.facebook.share.model.SharePhotoContent
import com.facebook.share.model.ShareStoryContent
import com.facebook.share.model.ShareVideoContent
import java.util.UUID
import org.json.JSONException

/**
 * com.facebook.share.internal is solely for the use of other packages within the Facebook SDK for
 * Android. Use of any of the classes in this package is unsupported, and they may be modified or
 * removed without warning at any time.
 */
object NativeDialogParameters {
  @JvmStatic
  fun create(
      callId: UUID,
      shareContent: ShareContent<*, *>,
      shouldFailOnDataError: Boolean
  ): Bundle? {
    var nativeParams: Bundle? = null
    when (shareContent) {
      is ShareLinkContent -> {
        nativeParams = create(shareContent, shouldFailOnDataError)
      }
      is SharePhotoContent -> {
        val photoUrls = ShareInternalUtility.getPhotoUrls(shareContent, callId) ?: listOf()
        nativeParams = create(shareContent, photoUrls, shouldFailOnDataError)
      }
      is ShareVideoContent -> {
        val videoUrl = ShareInternalUtility.getVideoUrl(shareContent, callId)
        nativeParams = create(shareContent, videoUrl, shouldFailOnDataError)
      }
      is ShareMediaContent -> {
        val mediaInfos = ShareInternalUtility.getMediaInfos(shareContent, callId) ?: listOf()
        nativeParams = create(shareContent, mediaInfos, shouldFailOnDataError)
      }
      is ShareCameraEffectContent -> {
        // Put Bitmaps behind content uris.
        val attachmentUrlsBundle = ShareInternalUtility.getTextureUrlBundle(shareContent, callId)
        nativeParams = create(shareContent, attachmentUrlsBundle, shouldFailOnDataError)
      }
      is ShareStoryContent -> {
        val mediaInfo = ShareInternalUtility.getBackgroundAssetMediaInfo(shareContent, callId)
        val stickerInfo = ShareInternalUtility.getStickerUrl(shareContent, callId)
        nativeParams = create(shareContent, mediaInfo, stickerInfo, shouldFailOnDataError)
      }
    }
    return nativeParams
  }

  private fun create(
      cameraEffectContent: ShareCameraEffectContent,
      attachmentUrlsBundle: Bundle?,
      dataErrorsFatal: Boolean
  ): Bundle {
    val params = createBaseParameters(cameraEffectContent, dataErrorsFatal)
    Utility.putNonEmptyString(params, ShareConstants.EFFECT_ID, cameraEffectContent.effectId)
    if (attachmentUrlsBundle != null) {
      params.putBundle(ShareConstants.EFFECT_TEXTURES, attachmentUrlsBundle)
    }
    try {
      val argsJSON = convertToJSON(cameraEffectContent.arguments)
      if (argsJSON != null) {
        Utility.putNonEmptyString(params, ShareConstants.EFFECT_ARGS, argsJSON.toString())
      }
    } catch (e: JSONException) {
      throw FacebookException(
          "Unable to create a JSON Object from the provided CameraEffectArguments: ${e.message}")
    }
    return params
  }

  private fun create(linkContent: ShareLinkContent, dataErrorsFatal: Boolean): Bundle {
    val params = createBaseParameters(linkContent, dataErrorsFatal)
    Utility.putNonEmptyString(params, ShareConstants.QUOTE, linkContent.quote)
    Utility.putUri(params, ShareConstants.MESSENGER_URL, linkContent.contentUrl)
    Utility.putUri(params, ShareConstants.TARGET_DISPLAY, linkContent.contentUrl)
    return params
  }

  private fun create(
      photoContent: SharePhotoContent,
      imageUrls: List<String>,
      dataErrorsFatal: Boolean
  ): Bundle {
    val params = createBaseParameters(photoContent, dataErrorsFatal)
    params.putStringArrayList(ShareConstants.PHOTOS, ArrayList(imageUrls))
    return params
  }

  private fun create(
      videoContent: ShareVideoContent,
      videoUrl: String?,
      dataErrorsFatal: Boolean
  ): Bundle {
    val params = createBaseParameters(videoContent, dataErrorsFatal)
    Utility.putNonEmptyString(params, ShareConstants.TITLE, videoContent.contentTitle)
    Utility.putNonEmptyString(params, ShareConstants.DESCRIPTION, videoContent.contentDescription)
    Utility.putNonEmptyString(params, ShareConstants.VIDEO_URL, videoUrl)
    return params
  }

  private fun create(
      mediaContent: ShareMediaContent,
      mediaInfos: List<Bundle>,
      dataErrorsFatal: Boolean
  ): Bundle {
    val params = createBaseParameters(mediaContent, dataErrorsFatal)
    params.putParcelableArrayList(ShareConstants.MEDIA, ArrayList(mediaInfos))
    return params
  }

  private fun create(
      storyContent: ShareStoryContent,
      mediaInfo: Bundle?,
      stickerInfo: Bundle?,
      dataErrorsFatal: Boolean
  ): Bundle {
    val params = createBaseParameters(storyContent, dataErrorsFatal)
    if (mediaInfo != null) {
      params.putParcelable(ShareConstants.STORY_BG_ASSET, mediaInfo)
    }
    if (stickerInfo != null) {
      params.putParcelable(ShareConstants.STORY_INTERACTIVE_ASSET_URI, stickerInfo)
    }
    val backgroundColorList = storyContent.backgroundColorList
    if (!backgroundColorList.isNullOrEmpty()) {
      params.putStringArrayList(
          ShareConstants.STORY_INTERACTIVE_COLOR_LIST, ArrayList(backgroundColorList))
    }
    Utility.putNonEmptyString(
        params, ShareConstants.STORY_DEEP_LINK_URL, storyContent.attributionLink)
    return params
  }

  private fun createBaseParameters(content: ShareContent<*, *>, dataErrorsFatal: Boolean): Bundle {
    val params = Bundle()
    Utility.putUri(params, ShareConstants.CONTENT_URL, content.contentUrl)
    Utility.putNonEmptyString(params, ShareConstants.PLACE_ID, content.placeId)
    Utility.putNonEmptyString(params, ShareConstants.PAGE_ID, content.pageId)
    Utility.putNonEmptyString(params, ShareConstants.REF, content.ref)
    Utility.putNonEmptyString(params, ShareConstants.REF, content.ref)
    params.putBoolean(ShareConstants.DATA_FAILURES_FATAL, dataErrorsFatal)
    val peopleIds = content.peopleIds
    if (!peopleIds.isNullOrEmpty()) {
      params.putStringArrayList(ShareConstants.PEOPLE_IDS, ArrayList(peopleIds))
    }
    Utility.putNonEmptyString(params, ShareConstants.HASHTAG, content.shareHashtag?.hashtag)
    return params
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.share.internal

import android.os.Bundle
import com.facebook.FacebookCallback
import com.facebook.FacebookException
import com.facebook.internal.AppCall

/**
 * com.facebook.share.internal is solely for the use of other packages within the Facebook SDK for
 * Android. Use of any of the classes in this package is unsupported, and they may be modified or
 * removed without warning at any time.
 *
 * Callback class to allow derivations of FacebookDialogBase to do custom operations
 */
abstract class ResultProcessor(private val appCallback: FacebookCallback<*>?) {
  abstract fun onSuccess(appCall: AppCall, results: Bundle?)

  /** Override this if anything needs to be done on cancellation (e.g. Logging) */
  open fun onCancel(appCall: AppCall) {
    appCallback?.onCancel()
  }

  /** Override this if anything needs to be done on error (e.g. Logging) */
  open fun onError(appCall: AppCall, error: FacebookException) {
    appCallback?.onError(error)
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.share.internal

/**
 * com.facebook.share.internal is solely for the use of other packages within the Facebook SDK for
 * Android. Use of any of the classes in this package is unsupported, and they may be modified or
 * removed without warning at any time.
 */
object ShareConstants {
  // Common Web Params
  const val WEB_DIALOG_PARAM_ACTION_TYPE = "action_type"

  // Game Request Dialog Params
  const val WEB_DIALOG_PARAM_DATA = "data"
  const val WEB_DIALOG_PARAM_MESSAGE = "message"
  const val WEB_DIALOG_PARAM_TO = "to"
  const val WEB_DIALOG_PARAM_TITLE = "title"
  const val WEB_DIALOG_PARAM_OBJECT_ID = "object_id"
  const val WEB_DIALOG_PARAM_FILTERS = "filters"
  const val WEB_DIALOG_PARAM_SUGGESTIONS = "suggestions"

  // Web Share Dialog Params
  const val WEB_DIALOG_PARAM_HREF = "href"
  const val WEB_DIALOG_PARAM_ACTION_PROPERTIES = "action_properties"
  const val WEB_DIALOG_PARAM_QUOTE = "quote"
  const val WEB_DIALOG_PARAM_HASHTAG = "hashtag"

  // Images from a SharePhotoContent
  const val WEB_DIALOG_PARAM_MEDIA = "media"

  // Feed Dialog Params
  const val WEB_DIALOG_PARAM_LINK = "link"
  const val WEB_DIALOG_PARAM_PICTURE = "picture"
  const val WEB_DIALOG_PARAM_NAME = "name"
  const val WEB_DIALOG_PARAM_DESCRIPTION = "description"

  // Join App Group Dialog Params
  const val WEB_DIALOG_PARAM_ID = "id"

  // Create App Group Dialog Params
  const val WEB_DIALOG_PARAM_PRIVACY = "privacy"
  const val WEB_DIALOG_RESULT_PARAM_POST_ID = "post_id"
  const val WEB_DIALOG_RESULT_PARAM_REQUEST_ID = "request"
  const val WEB_DIALOG_RESULT_PARAM_TO_ARRAY_MEMBER = "to[%d]"

  // Extras supported for ACTION_FEED_DIALOG:
  const val LEGACY_PLACE_TAG = "com.facebook.platform.extra.PLACE"
  const val LEGACY_FRIEND_TAGS = "com.facebook.platform.extra.FRIENDS"
  const val LEGACY_LINK = "com.facebook.platform.extra.LINK"
  const val LEGACY_IMAGE = "com.facebook.platform.extra.IMAGE"
  const val LEGACY_TITLE = "com.facebook.platform.extra.TITLE"
  const val LEGACY_DESCRIPTION = "com.facebook.platform.extra.DESCRIPTION"
  const val LEGACY_REF = "com.facebook.platform.extra.REF"
  const val LEGACY_DATA_FAILURES_FATAL = "com.facebook.platform.extra.DATA_FAILURES_FATAL"
  const val LEGACY_PHOTOS = "com.facebook.platform.extra.PHOTOS"
  const val PLACE_ID = "PLACE"
  const val PEOPLE_IDS = "FRIENDS"
  const val PAGE_ID = "PAGE"
  const val CONTENT_URL = "LINK"
  const val MESSENGER_URL = "MESSENGER_LINK"
  const val HASHTAG = "HASHTAG"
  const val IMAGE_URL = "IMAGE"
  const val TITLE = "TITLE"
  const val SUBTITLE = "SUBTITLE"
  const val ITEM_URL = "ITEM_URL"
  const val BUTTON_TITLE = "BUTTON_TITLE"
  const val BUTTON_URL = "BUTTON_URL"
  const val PREVIEW_TYPE = "PREVIEW_TYPE"
  const val TARGET_DISPLAY = "TARGET_DISPLAY"
  const val ATTACHMENT_ID = "ATTACHMENT_ID"
  const val OPEN_GRAPH_URL = "OPEN_GRAPH_URL"
  const val DESCRIPTION = "DESCRIPTION"
  const val REF = "REF"
  const val DATA_FAILURES_FATAL = "DATA_FAILURES_FATAL"
  const val PHOTOS = "PHOTOS"
  const val VIDEO_URL = "VIDEO"
  const val QUOTE = "QUOTE"
  const val MEDIA = "MEDIA"
  const val MESSENGER_PLATFORM_CONTENT = "MESSENGER_PLATFORM_CONTENT"

  // Multimedia args
  const val MEDIA_TYPE = "type"
  const val MEDIA_URI = "uri"
  const val MEDIA_EXTENSION = "extension"

  // Camera-share args
  const val EFFECT_ID = "effect_id"
  const val EFFECT_ARGS = "effect_arguments"
  const val EFFECT_TEXTURES = "effect_textures"

  // Extras supported for ACTION_OGACTIONPUBLISH_DIALOG:
  const val LEGACY_ACTION = "com.facebook.platform.extra.ACTION"
  const val LEGACY_ACTION_TYPE = "com.facebook.platform.extra.ACTION_TYPE"
  const val LEGACY_PREVIEW_PROPERTY_NAME = "com.facebook.platform.extra.PREVIEW_PROPERTY_NAME"
  const val ACTION = "ACTION"
  const val ACTION_TYPE = "ACTION_TYPE"
  const val PREVIEW_PROPERTY_NAME = "PREVIEW_PROPERTY_NAME"

  // Method args supported for ACTION_LIKE_DIALOG
  const val OBJECT_ID = "object_id"
  const val OBJECT_TYPE = "object_type"

  // Method args supported for ACTION_APPINVITE_DIALOG
  const val APPLINK_URL = "app_link_url"
  const val PREVIEW_IMAGE_URL = "preview_image_url"
  const val PROMO_CODE = "promo_code"
  const val PROMO_TEXT = "promo_text"
  const val DEEPLINK_CONTEXT = "deeplink_context"
  const val DESTINATION = "destination"

  // Extras supported for MESSAGE_GET_LIKE_STATUS_REQUEST:
  const val EXTRA_OBJECT_ID = "com.facebook.platform.extra.OBJECT_ID"

  // Extras supported in MESSAGE_GET_LIKE_STATUS_REPLY:
  const val EXTRA_OBJECT_IS_LIKED = "com.facebook.platform.extra.OBJECT_IS_LIKED"
  const val EXTRA_LIKE_COUNT_STRING_WITH_LIKE =
      "com.facebook.platform.extra.LIKE_COUNT_STRING_WITH_LIKE"
  const val EXTRA_LIKE_COUNT_STRING_WITHOUT_LIKE =
      "com.facebook.platform.extra.LIKE_COUNT_STRING_WITHOUT_LIKE"
  const val EXTRA_SOCIAL_SENTENCE_WITH_LIKE =
      "com.facebook.platform.extra.SOCIAL_SENTENCE_WITH_LIKE"
  const val EXTRA_SOCIAL_SENTENCE_WITHOUT_LIKE =
      "com.facebook.platform.extra.SOCIAL_SENTENCE_WITHOUT_LIKE"
  const val EXTRA_UNLIKE_TOKEN = "com.facebook.platform.extra.UNLIKE_TOKEN"

  // Result keys from Native sharing dialogs
  const val EXTRA_RESULT_POST_ID = "com.facebook.platform.extra.POST_ID"
  const val RESULT_POST_ID = "postId"
  const val MAXIMUM_PHOTO_COUNT = 6
  const val MAXIMUM_MEDIA_COUNT = 6
  const val MY_VIDEOS = "me/videos"

  // Feed Dialog
  const val FEED_TO_PARAM = "to"
  const val FEED_LINK_PARAM = "link"
  const val FEED_PICTURE_PARAM = "picture"
  const val FEED_SOURCE_PARAM = "source"
  const val FEED_NAME_PARAM = "name"
  const val FEED_CAPTION_PARAM = "caption"
  const val FEED_DESCRIPTION_PARAM = "description"

  // Share into Story
  const val STORY_INTERACTIVE_COLOR_LIST = "top_background_color_list"
  const val STORY_DEEP_LINK_URL = "content_url"
  const val STORY_BG_ASSET = "bg_asset"
  const val STORY_INTERACTIVE_ASSET_URI = "interactive_asset_uri"
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.share.internal

import com.facebook.FacebookException
import com.facebook.FacebookSdk.getApplicationContext
import com.facebook.internal.Utility.isContentUri
import com.facebook.internal.Utility.isFileUri
import com.facebook.internal.Utility.isNullOrEmpty
import com.facebook.internal.Utility.isWebUri
import com.facebook.internal.Validate.hasContentProvider
import com.facebook.share.model.ShareCameraEffectContent
import com.facebook.share.model.ShareContent
import com.facebook.share.model.ShareLinkContent
import com.facebook.share.model.ShareMedia
import com.facebook.share.model.ShareMediaContent
import com.facebook.share.model.ShareMessengerActionButton
import com.facebook.share.model.ShareMessengerURLActionButton
import com.facebook.share.model.SharePhoto
import com.facebook.share.model.SharePhotoContent
import com.facebook.share.model.ShareStoryContent
import com.facebook.share.model.ShareVideo
import com.facebook.share.model.ShareVideoContent
import java.util.Locale

/**
 * com.facebook.share.internal is solely for the use of other packages within the Facebook SDK for
 * Android. Use of any of the classes in this package is unsupported, and they may be modified or
 * removed without warning at any time.
 */
object ShareContentValidation {
  private val webShareValidator: Validator = WebShareValidator()
  private val defaultValidator: Validator = Validator()
  private val apiValidator: Validator = ApiValidator()
  private val storyValidator: Validator = StoryShareValidator()

  @JvmStatic
  fun validateForMessage(content: ShareContent<*, *>?) {
    validate(content, defaultValidator)
  }

  @JvmStatic
  fun validateForNativeShare(content: ShareContent<*, *>?) {
    validate(content, defaultValidator)
  }

  @JvmStatic
  fun validateForWebShare(content: ShareContent<*, *>?) {
    validate(content, webShareValidator)
  }

  @JvmStatic
  fun validateForApiShare(content: ShareContent<*, *>?) {
    validate(content, apiValidator)
  }

  @JvmStatic
  fun validateForStoryShare(content: ShareContent<*, *>?) {
    validate(content, storyValidator)
  }

  @Throws(FacebookException::class)
  private fun validate(content: ShareContent<*, *>?, validator: Validator) {
    if (content == null) {
      throw FacebookException("Must provide non-null content to share")
    }
    when (content) {
      is ShareLinkContent -> {
        validator.validate(content)
      }
      is SharePhotoContent -> {
        validator.validate(content)
      }
      is ShareVideoContent -> {
        validator.validate(content)
      }
      is ShareMediaContent -> {
        validator.validate(content)
      }
      is ShareCameraEffectContent -> {
        validator.validate(content)
      }
      is ShareStoryContent -> {
        validator.validate(content as ShareStoryContent?)
      }
    }
  }

  private fun validateStoryContent(storyContent: ShareStoryContent?, validator: Validator) {
    if (storyContent == null ||
        (storyContent.backgroundAsset == null && storyContent.stickerAsset == null)) {
      throw FacebookException(
          "Must pass the Facebook app a background asset, a sticker asset, or both")
    }
    if (storyContent.backgroundAsset != null) {
      validator.validate(storyContent.backgroundAsset)
    }
    if (storyContent.stickerAsset != null) {
      validator.validate(storyContent.stickerAsset)
    }
  }

  private fun validateLinkContent(linkContent: ShareLinkContent, validator: Validator) {
    val contentUrl = linkContent.contentUrl
    if (contentUrl != null && !isWebUri(contentUrl)) {
      throw FacebookException("Content Url must be an http:// or https:// url")
    }
  }

  private fun validatePhotoContent(photoContent: SharePhotoContent, validator: Validator) {
    val photos = photoContent.photos
    if (photos == null || photos.isEmpty()) {
      throw FacebookException("Must specify at least one Photo in SharePhotoContent.")
    }
    if (photos.size > ShareConstants.MAXIMUM_PHOTO_COUNT) {
      throw FacebookException(
          String.format(
              Locale.ROOT, "Cannot add more than %d photos.", ShareConstants.MAXIMUM_PHOTO_COUNT))
    }
    for (photo in photos) {
      validator.validate(photo)
    }
  }

  private fun validatePhoto(photo: SharePhoto?) {
    if (photo == null) {
      throw FacebookException("Cannot share a null SharePhoto")
    }
    val photoBitmap = photo.bitmap
    val photoUri = photo.imageUrl
    if (photoBitmap == null && photoUri == null) {
      throw FacebookException("SharePhoto does not have a Bitmap or ImageUrl specified")
    }
  }

  private fun validatePhotoForApi(photo: SharePhoto, validator: Validator) {
    validatePhoto(photo)
    val photoBitmap = photo.bitmap
    val photoUri = photo.imageUrl
    if (photoBitmap == null && isWebUri(photoUri)) {
      throw FacebookException(
          "Cannot set the ImageUrl of a SharePhoto to the Uri of an image on the " +
              "web when sharing SharePhotoContent")
    }
  }

  private fun validatePhotoForNativeDialog(photo: SharePhoto, validator: Validator) {
    validatePhotoForApi(photo, validator)
    if (photo.bitmap != null || !isWebUri(photo.imageUrl)) {
      hasContentProvider(getApplicationContext())
    }
  }

  private fun validatePhotoForWebDialog(photo: SharePhoto, validator: Validator) {
    validatePhoto(photo)
  }

  private fun validateVideoContent(videoContent: ShareVideoContent, validator: Validator) {
    validator.validate(videoContent.video)
    val previewPhoto = videoContent.previewPhoto
    if (previewPhoto != null) {
      validator.validate(previewPhoto)
    }
  }

  private fun validateVideo(video: ShareVideo?, validator: Validator) {
    if (video == null) {
      throw FacebookException("Cannot share a null ShareVideo")
    }
    val localUri =
        video.localUrl ?: throw FacebookException("ShareVideo does not have a LocalUrl specified")
    if (!isContentUri(localUri) && !isFileUri(localUri)) {
      throw FacebookException("ShareVideo must reference a video that is on the device")
    }
  }

  private fun validateMediaContent(mediaContent: ShareMediaContent, validator: Validator) {
    val media = mediaContent.media
    if (media == null || media.isEmpty()) {
      throw FacebookException("Must specify at least one medium in ShareMediaContent.")
    }
    if (media.size > ShareConstants.MAXIMUM_MEDIA_COUNT) {
      throw FacebookException(
          String.format(
              Locale.ROOT, "Cannot add more than %d media.", ShareConstants.MAXIMUM_MEDIA_COUNT))
    }
    for (medium in media) {
      validator.validate(medium)
    }
  }

  @JvmStatic
  fun validateMedium(medium: ShareMedia<*, *>, validator: Validator) {
    when (medium) {
      is SharePhoto -> {
        validator.validate(medium)
      }
      is ShareVideo -> {
        validator.validate(medium as ShareVideo?)
      }
      else -> {
        throw FacebookException(
            String.format(Locale.ROOT, "Invalid media type: %s", medium.javaClass.simpleName))
      }
    }
  }

  private fun validateCameraEffectContent(cameraEffectContent: ShareCameraEffectContent) {
    val effectId = cameraEffectContent.effectId
    if (isNullOrEmpty(effectId)) {
      throw FacebookException("Must specify a non-empty effectId")
    }
  }

  private fun validateShareMessengerActionButton(button: ShareMessengerActionButton?) {
    if (button == null) {
      return
    }
    if (isNullOrEmpty(button.title)) {
      throw FacebookException("Must specify title for ShareMessengerActionButton")
    }
    if (button is ShareMessengerURLActionButton) {
      validateShareMessengerURLActionButton(button)
    }
  }

  private fun validateShareMessengerURLActionButton(button: ShareMessengerURLActionButton) {
    if (button.url == null) {
      throw FacebookException("Must specify url for ShareMessengerURLActionButton")
    }
  }

  private class StoryShareValidator : Validator() {
    override fun validate(storyContent: ShareStoryContent?) {
      validateStoryContent(storyContent, this)
    }
  }

  private class WebShareValidator : Validator() {
    override fun validate(videoContent: ShareVideoContent) {
      throw FacebookException("Cannot share ShareVideoContent via web sharing dialogs")
    }

    override fun validate(mediaContent: ShareMediaContent) {
      throw FacebookException("Cannot share ShareMediaContent via web sharing dialogs")
    }

    override fun validate(photo: SharePhoto) {
      validatePhotoForWebDialog(photo, this)
    }
  }

  private class ApiValidator : Validator() {
    override fun validate(photo: SharePhoto) {
      validatePhotoForApi(photo, this)
    }

    override fun validate(videoContent: ShareVideoContent) {
      if (!isNullOrEmpty(videoContent.placeId)) {
        throw FacebookException("Cannot share video content with place IDs using the share api")
      }
      if (!isNullOrEmpty(videoContent.peopleIds)) {
        throw FacebookException("Cannot share video content with people IDs using the share api")
      }
      if (!isNullOrEmpty(videoContent.ref)) {
        throw FacebookException("Cannot share video content with referrer URL using the share api")
      }
    }

    override fun validate(mediaContent: ShareMediaContent) {
      throw FacebookException("Cannot share ShareMediaContent using the share api")
    }

    override fun validate(linkContent: ShareLinkContent) {
      if (!isNullOrEmpty(linkContent.quote)) {
        throw FacebookException("Cannot share link content with quote using the share api")
      }
    }
  }

  open class Validator {

    open fun validate(linkContent: ShareLinkContent) {
      validateLinkContent(linkContent, this)
    }

    open fun validate(photoContent: SharePhotoContent) {
      validatePhotoContent(photoContent, this)
    }

    open fun validate(videoContent: ShareVideoContent) {
      validateVideoContent(videoContent, this)
    }

    open fun validate(mediaContent: ShareMediaContent) {
      validateMediaContent(mediaContent, this)
    }

    open fun validate(cameraEffectContent: ShareCameraEffectContent) {
      validateCameraEffectContent(cameraEffectContent)
    }

    open fun validate(photo: SharePhoto) {
      validatePhotoForNativeDialog(photo, this)
    }

    open fun validate(video: ShareVideo?) {
      validateVideo(video, this)
    }

    open fun validate(medium: ShareMedia<*, *>) {
      validateMedium(medium, this)
    }

    open fun validate(storyContent: ShareStoryContent?) {
      validateStoryContent(storyContent, this)
    }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.share.internal

import com.facebook.internal.DialogFeature
import com.facebook.internal.NativeProtocol

/**
 * com.facebook.share.internal is solely for the use of other packages within the Facebook SDK for
 * Android. Use of any of the classes in this package is unsupported, and they may be modified or
 * removed without warning at any time.
 */
enum class ShareDialogFeature(private val minVersion: Int) : DialogFeature {
  /**
   * Indicates whether the native Share dialog itself is supported by the installed version of the
   * Facebook application.
   */
  SHARE_DIALOG(NativeProtocol.PROTOCOL_VERSION_20130618),

  /** Indicates whether the native Share dialog supports sharing of photo images. */
  PHOTOS(NativeProtocol.PROTOCOL_VERSION_20140204),

  /** Indicates whether the native Share dialog supports sharing of videos. */
  VIDEO(NativeProtocol.PROTOCOL_VERSION_20141028),

  /** Indicates whether the native Share dialog supports sharing of multimedia. */
  MULTIMEDIA(NativeProtocol.PROTOCOL_VERSION_20160327),

  /** Indicates whether the native Share dialog supports hashtags */
  HASHTAG(NativeProtocol.PROTOCOL_VERSION_20160327),

  /** Indicates whether the native Share dialog supports quotes */
  LINK_SHARE_QUOTES(NativeProtocol.PROTOCOL_VERSION_20160327);

  /** This method is for internal use only. */
  override fun getAction(): String = NativeProtocol.ACTION_FEED_DIALOG

  /** This method is for internal use only. */
  override fun getMinVersion(): Int = minVersion
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.share.internal

import android.os.Parcel
import android.os.Parcelable
import com.facebook.share.model.ShareContent

// This class is used specifically for backwards support in unity for various feed parameters
// Currently this content is only supported if you set the mode to Feed when sharing.
class ShareFeedContent : ShareContent<ShareFeedContent, ShareFeedContent.Builder> {
  val toId: String?
  val link: String?
  val linkName: String?
  val linkCaption: String?
  val linkDescription: String?
  val picture: String?
  val mediaSource: String?

  private constructor(builder: Builder) : super(builder) {
    toId = builder.toId
    link = builder.link
    linkName = builder.linkName
    linkCaption = builder.linkCaption
    linkDescription = builder.linkDescription
    picture = builder.picture
    mediaSource = builder.mediaSource
  }

  internal constructor(parcel: Parcel) : super(parcel) {
    toId = parcel.readString()
    link = parcel.readString()
    linkName = parcel.readString()
    linkCaption = parcel.readString()
    linkDescription = parcel.readString()
    picture = parcel.readString()
    mediaSource = parcel.readString()
  }

  override fun describeContents(): Int = 0

  override fun writeToParcel(out: Parcel, flags: Int) {
    super.writeToParcel(out, flags)
    out.writeString(toId)
    out.writeString(link)
    out.writeString(linkName)
    out.writeString(linkCaption)
    out.writeString(linkDescription)
    out.writeString(picture)
    out.writeString(mediaSource)
  }

  /** Builder for the [ShareFeedContent] interface. */
  class Builder : ShareContent.Builder<ShareFeedContent, Builder>() {
    internal var toId: String? = null
    internal var link: String? = null
    internal var linkName: String? = null
    internal var linkCaption: String? = null
    internal var linkDescription: String? = null
    internal var picture: String? = null
    internal var mediaSource: String? = null

    fun setToId(toId: String?): Builder {
      this.toId = toId
      return this
    }

    fun setLink(link: String?): Builder {
      this.link = link
      return this
    }

    fun setLinkName(linkName: String?): Builder {
      this.linkName = linkName
      return this
    }

    fun setLinkCaption(linkCaption: String?): Builder {
      this.linkCaption = linkCaption
      return this
    }

    fun setLinkDescription(linkDescription: String?): Builder {
      this.linkDescription = linkDescription
      return this
    }

    fun setPicture(picture: String?): Builder {
      this.picture = picture
      return this
    }

    fun setMediaSource(mediaSource: String?): Builder {
      this.mediaSource = mediaSource
      return this
    }

    override fun build(): ShareFeedContent {
      return ShareFeedContent(this)
    }

    override fun readFrom(content: ShareFeedContent?): Builder {
      return if (content == null) {
        this
      } else
          super.readFrom(content)
              .setToId(content.toId)
              .setLink(content.link)
              .setLinkName(content.linkName)
              .setLinkCaption(content.linkCaption)
              .setLinkDescription(content.linkDescription)
              .setPicture(content.picture)
              .setMediaSource(content.mediaSource)
    }
  }

  companion object {
    @JvmField
    val CREATOR: Parcelable.Creator<ShareFeedContent> =
        object : Parcelable.Creator<ShareFeedContent> {
          override fun createFromParcel(parcel: Parcel): ShareFeedContent {
            return ShareFeedContent(parcel)
          }

          override fun newArray(size: Int): Array<ShareFeedContent?> {
            return arrayOfNulls(size)
          }
        }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.share.internal

import android.content.Intent
import android.graphics.Bitmap
import android.net.Uri
import android.os.Bundle
import android.os.ParcelFileDescriptor
import android.util.Pair
import com.facebook.AccessToken
import com.facebook.CallbackManager
import com.facebook.FacebookCallback
import com.facebook.FacebookException
import com.facebook.FacebookGraphResponseException
import com.facebook.FacebookOperationCanceledException
import com.facebook.FacebookSdk.getApplicationContext
import com.facebook.GraphRequest
import com.facebook.GraphResponse
import com.facebook.HttpMethod
import com.facebook.appevents.InternalAppEventsLogger
import com.facebook.internal.AnalyticsEvents
import com.facebook.internal.AppCall
import com.facebook.internal.AppCall.Companion.finishPendingCall
import com.facebook.internal.CallbackManagerImpl
import com.facebook.internal.CallbackManagerImpl.Companion.registerStaticCallback
import com.facebook.internal.NativeAppCallAttachmentStore
import com.facebook.internal.NativeAppCallAttachmentStore.addAttachments
import com.facebook.internal.NativeAppCallAttachmentStore.cleanupAttachmentsForCall
import com.facebook.internal.NativeAppCallAttachmentStore.createAttachment
import com.facebook.internal.NativeProtocol
import com.facebook.internal.NativeProtocol.getCallIdFromIntent
import com.facebook.internal.NativeProtocol.getErrorDataFromResultIntent
import com.facebook.internal.NativeProtocol.getExceptionFromErrorData
import com.facebook.internal.NativeProtocol.getSuccessResultsFromIntent
import com.facebook.internal.Utility.isContentUri
import com.facebook.internal.Utility.isFileUri
import com.facebook.internal.Utility.isNullOrEmpty
import com.facebook.internal.Utility.putNonEmptyString
import com.facebook.share.Sharer
import com.facebook.share.model.CameraEffectTextures
import com.facebook.share.model.ShareCameraEffectContent
import com.facebook.share.model.ShareMedia
import com.facebook.share.model.ShareMediaContent
import com.facebook.share.model.SharePhoto
import com.facebook.share.model.SharePhotoContent
import com.facebook.share.model.ShareStoryContent
import com.facebook.share.model.ShareVideo
import com.facebook.share.model.ShareVideoContent
import java.io.File
import java.io.FileNotFoundException
import java.lang.Exception
import java.util.UUID
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject

/**
 * com.facebook.share.internal is solely for the use of other packages within the Facebook SDK for
 * Android. Use of any of the classes in this package is unsupported, and they may be modified or
 * removed without warning at any time.
 */
object ShareInternalUtility {
  const val MY_STAGING_RESOURCES = "me/staging_resources"
  // Parameter names/values
  const val STAGING_PARAM = "file"

  @JvmStatic
  fun invokeCallbackWithException(
      callback: FacebookCallback<Sharer.Result>?,
      exception: Exception
  ) {
    if (exception is FacebookException) {
      invokeOnErrorCallback(callback, exception)
      return
    }
    invokeCallbackWithError(
        callback, "Error preparing share content: " + exception.localizedMessage)
  }

  @JvmStatic
  fun invokeCallbackWithError(callback: FacebookCallback<Sharer.Result>?, error: String?) {
    invokeOnErrorCallback(callback, error)
  }

  @JvmStatic
  fun invokeCallbackWithResults(
      callback: FacebookCallback<Sharer.Result>?,
      postId: String?,
      graphResponse: GraphResponse
  ) {
    val requestError = graphResponse.error
    if (requestError != null) {
      var errorMessage = requestError.errorMessage
      if (isNullOrEmpty(errorMessage)) {
        errorMessage = "Unexpected error sharing."
      }
      invokeOnErrorCallback(callback, graphResponse, errorMessage)
    } else {
      invokeOnSuccessCallback(callback, postId)
    }
  }

  /**
   * Returns the gesture with which the user completed the native dialog. This is only returned if
   * the user has previously authorized the calling app with basic permissions.
   *
   * @param result the bundle passed back to onActivityResult
   * @return "post" or "cancel" as the completion gesture
   */
  @JvmStatic
  fun getNativeDialogCompletionGesture(result: Bundle): String? {
    return if (result.containsKey(NativeProtocol.RESULT_ARGS_DIALOG_COMPLETION_GESTURE_KEY)) {
      result.getString(NativeProtocol.RESULT_ARGS_DIALOG_COMPLETION_GESTURE_KEY)
    } else result.getString(NativeProtocol.EXTRA_DIALOG_COMPLETION_GESTURE_KEY)
  }

  /**
   * Returns the id of the published post. This is only returned if the user has previously given
   * the app publish permissions.
   *
   * @param result the bundle passed back to onActivityResult
   * @return the id of the published post
   */
  @JvmStatic
  fun getShareDialogPostId(result: Bundle): String? {
    if (result.containsKey(ShareConstants.RESULT_POST_ID)) {
      return result.getString(ShareConstants.RESULT_POST_ID)
    }
    return if (result.containsKey(ShareConstants.EXTRA_RESULT_POST_ID)) {
      result.getString(ShareConstants.EXTRA_RESULT_POST_ID)
    } else result.getString(ShareConstants.WEB_DIALOG_RESULT_PARAM_POST_ID)
  }

  @JvmStatic
  fun handleActivityResult(
      requestCode: Int,
      resultCode: Int,
      data: Intent?,
      resultProcessor: ResultProcessor?
  ): Boolean {
    val appCall = getAppCallFromActivityResult(requestCode, resultCode, data) ?: return false
    cleanupAttachmentsForCall(appCall.callId)
    if (resultProcessor == null) {
      return true
    }
    val exception =
        if (data != null) getExceptionFromErrorData(getErrorDataFromResultIntent(data)) else null
    if (exception != null) {
      if (exception is FacebookOperationCanceledException) {
        resultProcessor.onCancel(appCall)
      } else {
        resultProcessor.onError(appCall, exception)
      }
    } else {
      // If here, we did not find an error in the result.
      val results = if (data != null) getSuccessResultsFromIntent(data) else null
      resultProcessor.onSuccess(appCall, results)
    }
    return true
  }

  // Custom handling for Share so that we can log results
  @JvmStatic
  fun getShareResultProcessor(callback: FacebookCallback<Sharer.Result>?): ResultProcessor {
    return object : ResultProcessor(callback) {
      override fun onSuccess(appCall: AppCall, results: Bundle?) {
        if (results != null) {
          val gesture = getNativeDialogCompletionGesture(results)
          if (gesture == null || "post".equals(gesture, ignoreCase = true)) {
            invokeOnSuccessCallback(callback, getShareDialogPostId(results))
          } else if ("cancel".equals(gesture, ignoreCase = true)) {
            invokeOnCancelCallback(callback)
          } else {
            invokeOnErrorCallback(callback, FacebookException(NativeProtocol.ERROR_UNKNOWN_ERROR))
          }
        }
      }

      override fun onCancel(appCall: AppCall) {
        invokeOnCancelCallback(callback)
      }

      override fun onError(appCall: AppCall, error: FacebookException) {
        invokeOnErrorCallback(callback, error)
      }
    }
  }

  private fun getAppCallFromActivityResult(
      requestCode: Int,
      resultCode: Int,
      data: Intent?
  ): AppCall? {
    val callId = getCallIdFromIntent(data) ?: return null
    return finishPendingCall(callId, requestCode)
  }

  @JvmStatic
  fun registerStaticShareCallback(requestCode: Int) {
    registerStaticCallback(requestCode) { resultCode, data ->
      handleActivityResult(requestCode, resultCode, data, getShareResultProcessor(null))
    }
  }

  @JvmStatic
  fun registerSharerCallback(
      requestCode: Int,
      callbackManager: CallbackManager?,
      callback: FacebookCallback<Sharer.Result>?
  ) {
    if (callbackManager !is CallbackManagerImpl) {
      throw FacebookException("Unexpected CallbackManager, " + "please use the provided Factory.")
    }
    callbackManager.registerCallback(requestCode) { resultCode, data ->
      handleActivityResult(requestCode, resultCode, data, getShareResultProcessor(callback))
    }
  }

  @JvmStatic
  fun getPhotoUrls(photoContent: SharePhotoContent?, appCallId: UUID): List<String>? {
    val photos: List<SharePhoto> = photoContent?.photos ?: return null
    val attachments = photos.mapNotNull { getAttachment(appCallId, it) }
    val attachmentUrls = attachments.map { it.attachmentUrl }
    addAttachments(attachments)
    return attachmentUrls
  }

  @JvmStatic
  fun getVideoUrl(videoContent: ShareVideoContent?, appCallId: UUID): String? {
    val videoLocalUrl = videoContent?.video?.localUrl ?: return null
    val attachment = createAttachment(appCallId, videoLocalUrl)
    addAttachments(listOf(attachment))
    return attachment.attachmentUrl
  }

  @JvmStatic
  fun getMediaInfos(mediaContent: ShareMediaContent?, appCallId: UUID): List<Bundle>? {
    val media = mediaContent?.media ?: return null
    val attachments: MutableList<NativeAppCallAttachmentStore.Attachment> = ArrayList()
    val mediaInfos =
        media.mapNotNull {
          val attachment = getAttachment(appCallId, it) ?: return@mapNotNull null
          attachments.add(attachment)
          val mediaInfo = Bundle()
          mediaInfo.putString(ShareConstants.MEDIA_TYPE, it.mediaType.name)
          mediaInfo.putString(ShareConstants.MEDIA_URI, attachment.attachmentUrl)
          return@mapNotNull mediaInfo
        }
    addAttachments(attachments)
    return mediaInfos
  }

  @JvmStatic
  fun getTextureUrlBundle(
      cameraEffectContent: ShareCameraEffectContent?,
      appCallId: UUID
  ): Bundle? {
    val textures: CameraEffectTextures = cameraEffectContent?.textures ?: return null
    val attachmentUrlsBundle = Bundle()
    val attachments: MutableList<NativeAppCallAttachmentStore.Attachment> = ArrayList()
    for (key in textures.keySet()) {
      val attachment =
          getAttachment(appCallId, textures.getTextureUri(key), textures.getTextureBitmap(key))
      if (attachment != null) {
        attachments.add(attachment)
        attachmentUrlsBundle.putString(key, attachment.attachmentUrl)
      }
    }
    addAttachments(attachments)
    return attachmentUrlsBundle
  }

  @Throws(JSONException::class)
  @JvmStatic
  fun removeNamespacesFromOGJsonArray(jsonArray: JSONArray, requireNamespace: Boolean): JSONArray {
    val newArray = JSONArray()
    for (i in 0 until jsonArray.length()) {
      var value = jsonArray[i]
      if (value is JSONArray) {
        value = removeNamespacesFromOGJsonArray(value, requireNamespace)
      } else if (value is JSONObject) {
        value = removeNamespacesFromOGJsonObject(value, requireNamespace)
      }
      newArray.put(value)
    }
    return newArray
  }

  @JvmStatic
  fun removeNamespacesFromOGJsonObject(
      jsonObject: JSONObject?,
      requireNamespace: Boolean
  ): JSONObject? {
    return if (jsonObject == null) {
      null
    } else
        try {
          val newJsonObject = JSONObject()
          val data = JSONObject()
          val names = jsonObject.names() ?: return null
          for (i in 0 until names.length()) {
            val key = names.getString(i)
            var value: Any?
            value = jsonObject[key]
            if (value is JSONObject) {
              value = removeNamespacesFromOGJsonObject(value as JSONObject?, true)
            } else if (value is JSONArray) {
              value = removeNamespacesFromOGJsonArray(value, true)
            }
            val fieldNameAndNamespace = getFieldNameAndNamespaceFromFullName(key)
            val namespace = fieldNameAndNamespace.first
            val fieldName = fieldNameAndNamespace.second
            if (requireNamespace) {
              if (namespace != null && namespace == "fbsdk") {
                newJsonObject.put(key, value)
              } else if (namespace == null || namespace == "og") {
                newJsonObject.put(fieldName, value)
              } else {
                data.put(fieldName, value)
              }
            } else if (namespace != null && namespace == "fb") {
              newJsonObject.put(key, value)
            } else {
              newJsonObject.put(fieldName, value)
            }
          }
          if (data.length() > 0) {
            newJsonObject.put("data", data)
          }
          newJsonObject
        } catch (e: JSONException) {
          throw FacebookException("Failed to create json object from share content")
        }
  }

  @JvmStatic
  fun getFieldNameAndNamespaceFromFullName(fullName: String): Pair<String?, String> {
    var namespace: String? = null
    val fieldName: String
    val index = fullName.indexOf(':')
    if (index != -1 && fullName.length > index + 1) {
      namespace = fullName.substring(0, index)
      fieldName = fullName.substring(index + 1)
    } else {
      fieldName = fullName
    }
    return Pair(namespace, fieldName)
  }

  private fun getAttachment(
      callId: UUID,
      medium: ShareMedia<*, *>
  ): NativeAppCallAttachmentStore.Attachment? {
    var bitmap: Bitmap? = null
    var uri: Uri? = null
    if (medium is SharePhoto) {
      bitmap = medium.bitmap
      uri = medium.imageUrl
    } else if (medium is ShareVideo) {
      uri = medium.localUrl
    }
    return getAttachment(callId, uri, bitmap)
  }

  private fun getAttachment(
      callId: UUID,
      uri: Uri?,
      bitmap: Bitmap?
  ): NativeAppCallAttachmentStore.Attachment? {
    var attachment: NativeAppCallAttachmentStore.Attachment? = null
    if (bitmap != null) {
      attachment = createAttachment(callId, bitmap)
    } else if (uri != null) {
      attachment = createAttachment(callId, uri)
    }
    return attachment
  }

  @JvmStatic
  fun invokeOnCancelCallback(callback: FacebookCallback<Sharer.Result>?) {
    logShareResult(AnalyticsEvents.PARAMETER_SHARE_OUTCOME_CANCELLED, null)
    callback?.onCancel()
  }

  @JvmStatic
  fun invokeOnSuccessCallback(callback: FacebookCallback<Sharer.Result>?, postId: String?) {
    logShareResult(AnalyticsEvents.PARAMETER_SHARE_OUTCOME_SUCCEEDED, null)
    callback?.onSuccess(Sharer.Result(postId))
  }

  @JvmStatic
  fun invokeOnErrorCallback(
      callback: FacebookCallback<Sharer.Result>?,
      response: GraphResponse?,
      message: String?
  ) {
    logShareResult(AnalyticsEvents.PARAMETER_SHARE_OUTCOME_ERROR, message)
    callback?.onError(FacebookGraphResponseException(response, message))
  }

  @JvmStatic
  fun invokeOnErrorCallback(callback: FacebookCallback<Sharer.Result>?, message: String?) {
    logShareResult(AnalyticsEvents.PARAMETER_SHARE_OUTCOME_ERROR, message)
    callback?.onError(FacebookException(message))
  }

  @JvmStatic
  fun invokeOnErrorCallback(callback: FacebookCallback<Sharer.Result>?, ex: FacebookException) {
    logShareResult(AnalyticsEvents.PARAMETER_SHARE_OUTCOME_ERROR, ex.message)
    callback?.onError(ex)
  }

  private fun logShareResult(shareOutcome: String, errorMessage: String?) {
    val context = getApplicationContext()
    val logger = InternalAppEventsLogger(context)
    val parameters = Bundle()
    parameters.putString(AnalyticsEvents.PARAMETER_SHARE_OUTCOME, shareOutcome)
    if (errorMessage != null) {
      parameters.putString(AnalyticsEvents.PARAMETER_SHARE_ERROR_MESSAGE, errorMessage)
    }
    logger.logEventImplicitly(AnalyticsEvents.EVENT_SHARE_RESULT, parameters)
  }

  /**
   * Creates a new Request configured to upload an image to create a staging resource. Staging
   * resources allow you to post binary data such as images, in preparation for a post of an Open
   * Graph object or action which references the image. The URI returned when uploading a staging
   * resource may be passed as the image property for an Open Graph object or action.
   *
   * @param accessToken the access token to use, or null
   * @param image the image to upload
   * @param callback a callback that will be called when the request is completed to handle success
   * or error conditions
   * @return a Request that is ready to execute
   */
  @JvmStatic
  fun newUploadStagingResourceWithImageRequest(
      accessToken: AccessToken?,
      image: Bitmap?,
      callback: GraphRequest.Callback?
  ): GraphRequest {
    val parameters = Bundle(1)
    parameters.putParcelable(STAGING_PARAM, image)
    return GraphRequest(accessToken, MY_STAGING_RESOURCES, parameters, HttpMethod.POST, callback)
  }

  /**
   * Creates a new Request configured to upload an image to create a staging resource. Staging
   * resources allow you to post binary data such as images, in preparation for a post of an Open
   * Graph object or action which references the image. The URI returned when uploading a staging
   * resource may be passed as the image property for an Open Graph object or action.
   *
   * @param accessToken the access token to use, or null
   * @param file the file containing the image to upload
   * @param callback a callback that will be called when the request is completed to handle success
   * or error conditions
   * @return a Request that is ready to execute
   * @throws FileNotFoundException
   */
  @Throws(FileNotFoundException::class)
  @JvmStatic
  fun newUploadStagingResourceWithImageRequest(
      accessToken: AccessToken?,
      file: File?,
      callback: GraphRequest.Callback?
  ): GraphRequest {
    val descriptor = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY)
    val resourceWithMimeType = GraphRequest.ParcelableResourceWithMimeType(descriptor, "image/png")
    val parameters = Bundle(1)
    parameters.putParcelable(STAGING_PARAM, resourceWithMimeType)
    return GraphRequest(accessToken, MY_STAGING_RESOURCES, parameters, HttpMethod.POST, callback)
  }

  /**
   * Creates a new Request configured to upload an image to create a staging resource. Staging
   * resources allow you to post binary data such as images, in preparation for a post of an Open
   * Graph object or action which references the image. The URI returned when uploading a staging
   * resource may be passed as the image property for an Open Graph object or action.
   *
   * @param accessToken the access token to use, or null
   * @param imageUri the file:// or content:// Uri pointing to the image to upload
   * @param callback a callback that will be called when the request is completed to handle success
   * or error conditions
   * @return a Request that is ready to execute
   * @throws FileNotFoundException
   */
  @Throws(FileNotFoundException::class)
  @JvmStatic
  fun newUploadStagingResourceWithImageRequest(
      accessToken: AccessToken?,
      imageUri: Uri,
      callback: GraphRequest.Callback?
  ): GraphRequest {
    val imagePath = imageUri.path
    if (isFileUri(imageUri) && imagePath != null) {
      return newUploadStagingResourceWithImageRequest(accessToken, File(imagePath), callback)
    } else if (!isContentUri(imageUri)) {
      throw FacebookException("The image Uri must be either a file:// or content:// Uri")
    }
    val resourceWithMimeType = GraphRequest.ParcelableResourceWithMimeType(imageUri, "image/png")
    val parameters = Bundle(1)
    parameters.putParcelable(STAGING_PARAM, resourceWithMimeType)
    return GraphRequest(accessToken, MY_STAGING_RESOURCES, parameters, HttpMethod.POST, callback)
  }

  @JvmStatic
  fun getStickerUrl(storyContent: ShareStoryContent?, appCallId: UUID): Bundle? {
    if (storyContent == null || storyContent.stickerAsset == null) {
      return null
    }
    val photos: MutableList<SharePhoto> = ArrayList()
    photos.add(storyContent.stickerAsset)
    val attachment = getAttachment(appCallId, storyContent.stickerAsset) ?: return null
    val stickerInfo = Bundle()
    stickerInfo.putString(ShareConstants.MEDIA_URI, attachment.attachmentUrl)
    val extension = getUriExtension(attachment.originalUri)
    if (extension != null) {
      putNonEmptyString(stickerInfo, ShareConstants.MEDIA_EXTENSION, extension)
    }
    addAttachments(listOf(attachment))
    return stickerInfo
  }

  @JvmStatic
  fun getBackgroundAssetMediaInfo(storyContent: ShareStoryContent?, appCallId: UUID): Bundle? {
    if (storyContent == null || storyContent.backgroundAsset == null) {
      return null
    }
    val media = storyContent.backgroundAsset
    val attachment = getAttachment(appCallId, media) ?: return null
    val mediaInfo = Bundle()
    mediaInfo.putString(ShareConstants.MEDIA_TYPE, media.mediaType.name)
    mediaInfo.putString(ShareConstants.MEDIA_URI, attachment.attachmentUrl)
    val extension = getUriExtension(attachment.originalUri)
    if (extension != null) {
      putNonEmptyString(mediaInfo, ShareConstants.MEDIA_EXTENSION, extension)
    }
    addAttachments(listOf(attachment))
    return mediaInfo
  }

  @JvmStatic
  fun getUriExtension(uri: Uri?): String? {
    if (uri == null) {
      return null
    }
    val path = uri.toString()
    val idx = path.lastIndexOf('.')
    return if (idx == -1) {
      null
    } else path.substring(idx)
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.share.internal

import com.facebook.internal.DialogFeature
import com.facebook.internal.NativeProtocol

/**
 * com.facebook.share.internal is solely for the use of other packages within the Facebook SDK for
 * Android. Use of any of the classes in this package is unsupported, and they may be modified or
 * removed without warning at any time.
 */
enum class ShareStoryFeature(private val minVersion: Int) : DialogFeature {
  SHARE_STORY_ASSET(NativeProtocol.PROTOCOL_VERSION_20170417);

  /** This method is for internal use only. */
  override fun getAction(): String = NativeProtocol.ACTION_SHARE_STORY

  /** This method is for internal use only. */
  override fun getMinVersion(): Int = minVersion
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.share.internal

import android.annotation.SuppressLint
import android.os.Bundle
import com.facebook.internal.Utility.getUriString
import com.facebook.internal.Utility.putCommaSeparatedStringList
import com.facebook.internal.Utility.putNonEmptyString
import com.facebook.internal.Utility.putUri
import com.facebook.share.model.AppGroupCreationContent
import com.facebook.share.model.GameRequestContent
import com.facebook.share.model.ShareContent
import com.facebook.share.model.ShareLinkContent
import com.facebook.share.model.SharePhotoContent
import java.util.Locale

/**
 * com.facebook.share.internal is solely for the use of other packages within the Facebook SDK for
 * Android. Use of any of the classes in this package is unsupported, and they may be modified or
 * removed without warning at any time.
 */
object WebDialogParameters {
  @JvmStatic
  fun create(appGroupCreationContent: AppGroupCreationContent): Bundle {
    val webParams = Bundle()
    putNonEmptyString(webParams, ShareConstants.WEB_DIALOG_PARAM_NAME, appGroupCreationContent.name)
    putNonEmptyString(
        webParams, ShareConstants.WEB_DIALOG_PARAM_DESCRIPTION, appGroupCreationContent.description)
    putNonEmptyString(
        webParams,
        ShareConstants.WEB_DIALOG_PARAM_PRIVACY,
        appGroupCreationContent.appGroupPrivacy?.toString()?.lowercase(Locale.ENGLISH))
    return webParams
  }

  @JvmStatic
  fun create(gameRequestContent: GameRequestContent): Bundle {
    val webParams = Bundle()
    putNonEmptyString(
        webParams, ShareConstants.WEB_DIALOG_PARAM_MESSAGE, gameRequestContent.message)
    putCommaSeparatedStringList(
        webParams, ShareConstants.WEB_DIALOG_PARAM_TO, gameRequestContent.recipients)
    putNonEmptyString(webParams, ShareConstants.WEB_DIALOG_PARAM_TITLE, gameRequestContent.title)
    putNonEmptyString(webParams, ShareConstants.WEB_DIALOG_PARAM_DATA, gameRequestContent.data)
    putNonEmptyString(
        webParams,
        ShareConstants.WEB_DIALOG_PARAM_ACTION_TYPE,
        gameRequestContent.actionType?.toString()?.lowercase(Locale.ENGLISH))
    putNonEmptyString(
        webParams, ShareConstants.WEB_DIALOG_PARAM_OBJECT_ID, gameRequestContent.objectId)
    putNonEmptyString(
        webParams,
        ShareConstants.WEB_DIALOG_PARAM_FILTERS,
        gameRequestContent.filters?.toString()?.lowercase(Locale.ENGLISH))
    putCommaSeparatedStringList(
        webParams, ShareConstants.WEB_DIALOG_PARAM_SUGGESTIONS, gameRequestContent.suggestions)
    return webParams
  }

  @JvmStatic
  fun create(shareLinkContent: ShareLinkContent): Bundle {
    val params = createBaseParameters(shareLinkContent)
    putUri(params, ShareConstants.WEB_DIALOG_PARAM_HREF, shareLinkContent.contentUrl)
    putNonEmptyString(params, ShareConstants.WEB_DIALOG_PARAM_QUOTE, shareLinkContent.quote)
    return params
  }

  @JvmStatic
  fun create(sharePhotoContent: SharePhotoContent): Bundle {
    val params = createBaseParameters(sharePhotoContent)
    val photos = sharePhotoContent.photos ?: emptyList()
    val urls = photos.map { it.imageUrl.toString() }.toTypedArray()
    params.putStringArray(ShareConstants.WEB_DIALOG_PARAM_MEDIA, urls)
    return params
  }

  @JvmStatic
  fun createBaseParameters(shareContent: ShareContent<*, *>): Bundle {
    val params = Bundle()
    putNonEmptyString(
        params, ShareConstants.WEB_DIALOG_PARAM_HASHTAG, shareContent.shareHashtag?.hashtag)
    return params
  }

  @JvmStatic
  @SuppressLint("DeprecatedMethod")
  fun createForFeed(shareLinkContent: ShareLinkContent): Bundle {
    val webParams = Bundle()
    putNonEmptyString(
        webParams, ShareConstants.WEB_DIALOG_PARAM_LINK, getUriString(shareLinkContent.contentUrl))
    putNonEmptyString(webParams, ShareConstants.WEB_DIALOG_PARAM_QUOTE, shareLinkContent.quote)
    putNonEmptyString(
        webParams, ShareConstants.WEB_DIALOG_PARAM_HASHTAG, shareLinkContent.shareHashtag?.hashtag)
    return webParams
  }

  @JvmStatic
  fun createForFeed(shareFeedContent: ShareFeedContent): Bundle {
    val webParams = Bundle()
    putNonEmptyString(webParams, ShareConstants.FEED_TO_PARAM, shareFeedContent.toId)
    putNonEmptyString(webParams, ShareConstants.FEED_LINK_PARAM, shareFeedContent.link)
    putNonEmptyString(webParams, ShareConstants.FEED_PICTURE_PARAM, shareFeedContent.picture)
    putNonEmptyString(webParams, ShareConstants.FEED_SOURCE_PARAM, shareFeedContent.mediaSource)
    putNonEmptyString(webParams, ShareConstants.FEED_NAME_PARAM, shareFeedContent.linkName)
    putNonEmptyString(webParams, ShareConstants.FEED_CAPTION_PARAM, shareFeedContent.linkCaption)
    putNonEmptyString(
        webParams, ShareConstants.FEED_DESCRIPTION_PARAM, shareFeedContent.linkDescription)
    return webParams
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.share.model

import android.os.Parcel
import android.os.Parcelable

/** Describes the content that will be displayed by the AppGroupCreationDialog */
class AppGroupCreationContent : ShareModel {
  /**
   * Gets the name of the group that will be created.
   *
   * @return name of the group
   */
  val name: String?

  /**
   * Gets the description of the group that will be created.
   *
   * @return the description
   */
  val description: String?

  /**
   * Gets the privacy for the group that will be created
   *
   * @return the privacy of the group
   */
  val appGroupPrivacy: AppGroupPrivacy?

  private constructor(builder: Builder) {
    name = builder.name
    description = builder.description
    appGroupPrivacy = builder.appGroupPrivacy
  }

  internal constructor(parcel: Parcel) {
    name = parcel.readString()
    description = parcel.readString()
    appGroupPrivacy = parcel.readSerializable() as AppGroupPrivacy?
  }

  override fun describeContents(): Int = 0

  override fun writeToParcel(out: Parcel, flags: Int) {
    out.writeString(name)
    out.writeString(description)
    out.writeSerializable(appGroupPrivacy)
  }

  /** Specifies the privacy of a group. */
  enum class AppGroupPrivacy {
    /** Anyone can see the group, who's in it and what members post. */
    Open,

    /** Anyone can see the group and who's in it, but only members can see posts. */
    Closed
  }

  /** Builder class for a concrete instance of AppGroupCreationContent */
  class Builder : ShareModelBuilder<AppGroupCreationContent, Builder> {
    internal var name: String? = null
    internal var description: String? = null
    internal var appGroupPrivacy: AppGroupPrivacy? = null

    /**
     * Sets the name of the group that will be created.
     *
     * @param name name of the group
     * @return the builder
     */
    fun setName(name: String?): Builder {
      this.name = name
      return this
    }

    /**
     * Sets the description of the group that will be created.
     *
     * @param description the description
     * @return the builder
     */
    fun setDescription(description: String?): Builder {
      this.description = description
      return this
    }

    /**
     * Sets the privacy for the group that will be created
     *
     * @param appGroupPrivacy privacy of the group
     * @return the builder
     */
    fun setAppGroupPrivacy(appGroupPrivacy: AppGroupPrivacy?): Builder {
      this.appGroupPrivacy = appGroupPrivacy
      return this
    }

    override fun build(): AppGroupCreationContent {
      return AppGroupCreationContent(this)
    }

    override fun readFrom(content: AppGroupCreationContent?): Builder {
      return if (content == null) {
        this
      } else
          setName(content.name)
              .setDescription(content.description)
              .setAppGroupPrivacy(content.appGroupPrivacy)
    }
  }

  companion object {
    @JvmField
    val CREATOR: Parcelable.Creator<AppGroupCreationContent> =
        object : Parcelable.Creator<AppGroupCreationContent> {
          override fun createFromParcel(parcel: Parcel): AppGroupCreationContent? {
            return AppGroupCreationContent(parcel)
          }

          override fun newArray(size: Int): Array<AppGroupCreationContent?> {
            return arrayOfNulls(size)
          }
        }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.share.model

import android.os.Bundle
import android.os.Parcel
import android.os.Parcelable

/** This class represents a set of Arguments that are used to configure an Effect in the Camera. */
class CameraEffectArguments : ShareModel {
  private val params: Bundle?

  private constructor(builder: Builder) {
    params = builder.params
  }

  internal constructor(parcel: Parcel) {
    params = parcel.readBundle(javaClass.classLoader)
  }

  /**
   * Returns the value of a String argument associated with the passed in key. If the key does not
   * exist, or if it points to an object that is not a String, null will be returned.
   *
   * @param key Key for the value desired.
   * @return The String associated with the passed in key, or null if the key does not exist or if
   * the value is not a String.
   */
  fun getString(key: String?): String? {
    return params?.getString(key)
  }

  /**
   * Returns the value of a String[] argument associated with the passed in key. If the key does not
   * exist, or if it points to an object that is not a String[], null will be returned.
   *
   * @param key Key for the value desired.
   * @return The String[] associated with the passed in key, or null if the key does not exist or if
   * the value is not a String[].
   */
  fun getStringArray(key: String?): Array<String>? {
    return params?.getStringArray(key)
  }

  /**
   * Returns the value of the argument associated with the passed in key. If the key does not exist,
   * null will be returned
   *
   * @param key Key for the value desired.
   * @return The value associated with the passed in key, or null if the key does not exist.
   */
  operator fun get(key: String?): Any? {
    return params?.get(key)
  }

  /**
   * The set of keys that have been set in this instance of CameraEffectArguments
   *
   * @return The set of keys that have been set in this instance of CameraEffectArguments
   */
  fun keySet(): Set<String> {
    return params?.keySet() ?: setOf()
  }

  override fun describeContents(): Int = 0

  override fun writeToParcel(out: Parcel, flags: Int) {
    out.writeBundle(params)
  }

  /** Builder for the [com.facebook.share.model.CameraEffectArguments] class. */
  class Builder : ShareModelBuilder<CameraEffectArguments, Builder> {
    internal val params = Bundle()

    /**
     * Sets the passed in value for the passed in key. This will override any previous calls with
     * the same key.
     *
     * @param key Key for the argument
     * @param value Value of the argument
     * @return This Builder instance
     */
    fun putArgument(key: String, value: String): Builder {
      params.putString(key, value)
      return this
    }

    /**
     * Sets the passed in value for the passed in key. This will override any previous calls with
     * the same key.
     *
     * @param key Key for the argument
     * @param arrayValue Value of the argument
     * @return This Builder instance
     */
    fun putArgument(key: String, arrayValue: Array<String>): Builder {
      params.putStringArray(key, arrayValue)
      return this
    }

    override fun readFrom(model: CameraEffectArguments?): Builder {
      if (model != null) {
        params.putAll(model.params)
      }
      return this
    }

    /** This method is for internal use only. */
    fun readFrom(parcel: Parcel): Builder {
      return this.readFrom(parcel.readParcelable(CameraEffectArguments::class.java.classLoader))
    }

    /**
     * Creates a new instance of CameraEffectArguments with the arguments that have been set in this
     * Builder instance.
     *
     * @return A new instance of CameraEffectArguments.
     */
    override fun build(): CameraEffectArguments {
      return CameraEffectArguments(this)
    }
  }

  companion object {
    @JvmField
    val CREATOR: Parcelable.Creator<CameraEffectArguments> =
        object : Parcelable.Creator<CameraEffectArguments> {
          override fun createFromParcel(parcel: Parcel): CameraEffectArguments {
            return CameraEffectArguments(parcel)
          }

          override fun newArray(size: Int): Array<CameraEffectArguments?> {
            return arrayOfNulls(size)
          }
        }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.share.model

import android.graphics.Bitmap
import android.net.Uri
import android.os.Bundle
import android.os.Parcel
import android.os.Parcelable

/** This class represents the textures that are used by an Effect in the Camera. */
class CameraEffectTextures : ShareModel {
  private val textures: Bundle?

  private constructor(builder: Builder) {
    textures = builder.textures
  }

  internal constructor(parcel: Parcel) {
    textures = parcel.readBundle(javaClass.classLoader)
  }

  fun getTextureBitmap(key: String?): Bitmap? {
    return textures?.get(key) as? Bitmap
  }

  fun getTextureUri(key: String?): Uri? {
    return textures?.get(key) as? Uri
  }

  operator fun get(key: String?): Any? {
    return textures?.get(key)
  }

  /**
   * The set of keys that have been set in this instance of CameraEffectTextures
   * @return The set of keys that have been set in this instance of CameraEffectTextures
   */
  fun keySet(): Set<String> {
    return textures?.keySet() ?: setOf()
  }

  override fun describeContents(): Int = 0

  override fun writeToParcel(out: Parcel, flags: Int) {
    out.writeBundle(textures)
  }

  /** Builder for the [com.facebook.share.model.CameraEffectTextures] class. */
  class Builder : ShareModelBuilder<CameraEffectTextures, Builder> {
    internal val textures = Bundle()

    /**
     * Sets the passed in bitmap for the passed in key.
     *
     * @param key The key
     * @param texture The bitmap
     * @return The builder instance
     */
    fun putTexture(key: String, texture: Bitmap?): Builder {
      return putParcelableTexture(key, texture)
    }

    /**
     * Sets the passed in textureUrl for the passed in key.
     *
     * @param key The key
     * @param textureUrl The texture url
     * @return The builder instance
     */
    fun putTexture(key: String, textureUrl: Uri?): Builder {
      return putParcelableTexture(key, textureUrl)
    }

    private fun putParcelableTexture(key: String, parcelableTexture: Parcelable?): Builder {
      if (key.isNotEmpty() && parcelableTexture != null) {
        textures.putParcelable(key, parcelableTexture)
      }
      return this
    }

    override fun readFrom(model: CameraEffectTextures?): Builder {
      if (model != null) {
        textures.putAll(model.textures)
      }
      return this
    }

    /** This method is for internal use only. */
    fun readFrom(parcel: Parcel): Builder {
      return this.readFrom(parcel.readParcelable(CameraEffectTextures::class.java.classLoader))
    }

    override fun build(): CameraEffectTextures {
      return CameraEffectTextures(this)
    }
  }

  companion object {
    @JvmField
    val CREATOR: Parcelable.Creator<CameraEffectTextures> =
        object : Parcelable.Creator<CameraEffectTextures> {
          override fun createFromParcel(parcel: Parcel): CameraEffectTextures {
            return CameraEffectTextures(parcel)
          }

          override fun newArray(size: Int): Array<CameraEffectTextures?> {
            return arrayOfNulls(size)
          }
        }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.share.model

import android.os.Parcel
import android.os.Parcelable
import android.text.TextUtils

/** Describes the content that will be displayed by the GameRequestDialog */
class GameRequestContent : ShareModel {
  enum class ActionType {
    SEND,
    ASKFOR,
    TURN,
    INVITE
  }

  enum class Filters {
    APP_USERS,
    APP_NON_USERS,
    EVERYBODY
  }

  /** Gets the message that users receiving the request will see. */
  val message: String?
  /** Gets the cta that users receiving the request will see. */
  val cta: String?
  /** Gets the user IDs or user names the request will be sent to. */
  val recipients: List<String>?
  /** Gets the optional title for the dialog */
  val title: String?
  /** Gets optional data which can be used for tracking */
  val data: String?
  /** Gets the action type */
  val actionType: ActionType?
  /** Gets the open graph id of the object that action type will be performed on */
  val objectId: String?
  /** Get the filters */
  val filters: Filters?
  /** Gets a list of suggested user ids */
  val suggestions: List<String>?

  private constructor(builder: Builder) {
    message = builder.message
    cta = builder.cta
    recipients = builder.recipients
    title = builder.title
    data = builder.data
    actionType = builder.actionType
    objectId = builder.objectId
    filters = builder.filters
    suggestions = builder.suggestions
  }

  internal constructor(parcel: Parcel) {
    message = parcel.readString()
    cta = parcel.readString()
    recipients = parcel.createStringArrayList()
    title = parcel.readString()
    data = parcel.readString()
    actionType = parcel.readSerializable() as ActionType?
    objectId = parcel.readString()
    filters = parcel.readSerializable() as Filters?
    suggestions = parcel.createStringArrayList()
  }

  /** Gets the user IDs or user names the request will be sent to. */
  @get:Deprecated("Replaced by [getRecipients()]", replaceWith = ReplaceWith("getRecipients"))
  val to: String?
    get() = if (recipients != null) TextUtils.join(",", recipients) else null

  override fun describeContents(): Int = 0

  override fun writeToParcel(out: Parcel, flags: Int) {
    out.writeString(message)
    out.writeString(cta)
    out.writeStringList(recipients)
    out.writeString(title)
    out.writeString(data)
    out.writeSerializable(actionType)
    out.writeString(objectId)
    out.writeSerializable(filters)
    out.writeStringList(suggestions)
  }

  /** Builder class for a concrete instance of GameRequestContent */
  class Builder : ShareModelBuilder<GameRequestContent, Builder> {
    internal var message: String? = null
    internal var cta: String? = null
    internal var recipients: List<String>? = null
    internal var data: String? = null
    internal var title: String? = null
    internal var actionType: ActionType? = null
    internal var objectId: String? = null
    internal var filters: Filters? = null
    internal var suggestions: List<String>? = null

    /**
     * Sets the message users receiving the request will see. The maximum length is 60 characters.
     *
     * @param message the message
     * @return the builder
     */
    fun setMessage(message: String?): Builder {
      this.message = message
      return this
    }

    /**
     * Sets the cta users receiving the request will see. The maximum length is 10 characters.
     *
     * @param cta the cta for the message
     * @return the builder
     */
    fun setCta(cta: String?): Builder {
      this.cta = cta
      return this
    }

    /**
     * Sets the user ID or user name the request will be sent to. If this is not specified, a friend
     * selector will be displayed and the user can select up to 50 friends.
     *
     * @param to the id or user name to send the request to
     * @return the builder
     */
    @Deprecated("Replaced by {@link #setRecipients(List)}")
    fun setTo(to: String?): Builder {
      if (to != null) {
        recipients = to.split(',').toList()
      }
      return this
    }

    /**
     * An array of user IDs, usernames or invite tokens of people to send request. If this is not
     * specified, a friend selector will be displayed and the user can select up to 50 friends.
     *
     * This is equivalent to the "to" parameter when using the web game request dialog.
     *
     * @param recipients the list of user ids to send the request to
     * @return the builder
     */
    fun setRecipients(recipients: List<String>?): Builder {
      this.recipients = recipients
      return this
    }

    /**
     * Sets optional data which can be used for tracking; maximum length is 255 characters.
     *
     * @param data the data
     * @return the builder
     */
    fun setData(data: String?): Builder {
      this.data = data
      return this
    }

    /**
     * Sets an optional title for the dialog; maximum length is 50 characters.
     *
     * @param title the title
     * @return the builder
     */
    fun setTitle(title: String?): Builder {
      this.title = title
      return this
    }

    /** Sets the action type for this request */
    fun setActionType(actionType: ActionType?): Builder {
      this.actionType = actionType
      return this
    }

    /**
     * Sets the open graph id of the object that action type will be performed on Only valid (and
     * required) for ActionTypes SEND, ASKFOR
     */
    fun setObjectId(objectId: String?): Builder {
      this.objectId = objectId
      return this
    }

    /** Sets the filters for everybody/app users/non app users */
    fun setFilters(filters: Filters?): Builder {
      this.filters = filters
      return this
    }

    /** Sets a list of user ids suggested as request receivers */
    fun setSuggestions(suggestions: List<String>?): Builder {
      this.suggestions = suggestions
      return this
    }

    override fun build(): GameRequestContent {
      return GameRequestContent(this)
    }

    override fun readFrom(content: GameRequestContent?): Builder {
      return if (content == null) {
        this
      } else
          setMessage(content.message)
              .setCta(content.cta)
              .setRecipients(content.recipients)
              .setTitle(content.title)
              .setData(content.data)
              .setActionType(content.actionType)
              .setObjectId(content.objectId)
              .setFilters(content.filters)
              .setSuggestions(content.suggestions)
    }

    internal fun readFrom(parcel: Parcel): Builder {
      return this.readFrom(parcel.readParcelable(GameRequestContent::class.java.classLoader))
    }
  }

  companion object {
    @JvmField
    val CREATOR: Parcelable.Creator<GameRequestContent> =
        object : Parcelable.Creator<GameRequestContent> {
          override fun createFromParcel(parcel: Parcel): GameRequestContent {
            return GameRequestContent(parcel)
          }

          override fun newArray(size: Int): Array<GameRequestContent?> {
            return arrayOfNulls(size)
          }
        }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.share.model

import android.os.Parcel
import android.os.Parcelable

/**
 * Describes the Camera Effect to be shared. Use [ShareCameraEffectContent.Builder] to build
 * instances.
 *
 * See documentation for
 * [best practices](https://developers.facebook.com/docs/sharing/best-practices).
 */
class ShareCameraEffectContent :
    ShareContent<ShareCameraEffectContent, ShareCameraEffectContent.Builder> {
  /**
   * Returns the Effect Id represented in this content instance, as set in the Builder.
   * @return The Effect Id
   */
  var effectId: String?
    private set

  /**
   * Returns the Arguments for the Effect represented in this content instance, as set in the
   * Builder.
   *
   * @return Effect Arguments
   */
  var arguments: CameraEffectArguments?
    private set

  /**
   * Returns the Textures for the Effect represented in this content instance, as set in the
   * Builder.
   *
   * @return Effect Textures
   */
  var textures: CameraEffectTextures?
    private set

  private constructor(builder: Builder) : super(builder) {
    effectId = builder.effectId
    arguments = builder.arguments
    textures = builder.textures
  }

  internal constructor(parcel: Parcel) : super(parcel) {
    effectId = parcel.readString()
    arguments = CameraEffectArguments.Builder().readFrom(parcel).build()
    textures = CameraEffectTextures.Builder().readFrom(parcel).build()
  }

  override fun writeToParcel(out: Parcel, flags: Int) {
    super.writeToParcel(out, flags)
    out.writeString(effectId)
    out.writeParcelable(arguments, 0)
    out.writeParcelable(textures, 0)
  }

  /** Builder for the [ShareCameraEffectContent] interface. */
  class Builder : ShareContent.Builder<ShareCameraEffectContent, Builder>() {
    internal var effectId: String? = null
    internal var arguments: CameraEffectArguments? = null
    internal var textures: CameraEffectTextures? = null

    /**
     * Sets the Effect Id for the Effect represented by this content instance. This must be an Id of
     * an effect that is published and approved.
     *
     * @param effectId Id of the Effect.
     * @return This builder instance
     */
    fun setEffectId(effectId: String?): Builder {
      this.effectId = effectId
      return this
    }

    /**
     * Sets the Arguments for the Effect represented by this content instance.
     *
     * @param arguments Arguments for this Effect
     * @return This builder instance
     */
    fun setArguments(arguments: CameraEffectArguments?): Builder {
      this.arguments = arguments
      return this
    }

    /**
     * Sets the Textures for the Effect represented by this content instance.
     *
     * @param textures Textures for this Effect
     * @return This builder instance
     */
    fun setTextures(textures: CameraEffectTextures?): Builder {
      this.textures = textures
      return this
    }

    /**
     * Creates a new instance of ShareCameraEffectContent with the properties as set on this Builder
     * instance
     *
     * @return A new instance of ShareCameraEffectContent
     */
    override fun build(): ShareCameraEffectContent {
      return ShareCameraEffectContent(this)
    }

    override fun readFrom(model: ShareCameraEffectContent?): Builder {
      return if (model == null) {
        this
      } else
          super.readFrom(model)
              .setEffectId(model.effectId)
              .setArguments(model.arguments)
              .setTextures(model.textures)
    }
  }

  companion object {
    @JvmField
    val CREATOR: Parcelable.Creator<ShareCameraEffectContent> =
        object : Parcelable.Creator<ShareCameraEffectContent> {
          override fun createFromParcel(parcel: Parcel): ShareCameraEffectContent {
            return ShareCameraEffectContent(parcel)
          }

          override fun newArray(size: Int): Array<ShareCameraEffectContent?> {
            return arrayOfNulls(size)
          }
        }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.share.model

import android.net.Uri
import android.os.Parcel
import java.util.Collections
import kotlin.collections.ArrayList

/**
 * Provides the base class for content to be shared. Contains all common methods for the different
 * types of content.
 */
abstract class ShareContent<M : ShareContent<M, B>, B : ShareContent.Builder<M, B>> : ShareModel {
  /**
   * URL for the content being shared. This URL will be checked for app link meta tags for linking
   * in platform specific ways.
   *
   * See documentation for [AppLinks](https://developers.facebook.com/docs/applinks/).
   *
   * @return [android.net.Uri] representation of the content link.
   */
  val contentUrl: Uri?

  /**
   * List of Ids for taggable people to tag with this content.
   *
   * See documentation for
   * [Taggable Friends](https://developers.facebook.com/docs/graph-api/reference/user/taggable_friends)
   * .
   *
   * @return [java.util.List] of Ids for people to tag.
   */
  val peopleIds: List<String>?

  /**
   * The Id for a place to tag with this content.
   *
   * @return The Id for the place to tag.
   */
  val placeId: String?

  /**
   * For shares into Messenger, this pageID will be used to map the app to page and attach
   * attribution to the share.
   *
   * @return The ID of the Facebook page this share is associated with.
   */
  val pageId: String?

  /**
   * A value to be added to the referrer URL when a person follows a link from this shared content
   * on feed.
   *
   * @return The ref for the content.
   */
  val ref: String?

  /**
   * Gets the ShareHashtag, if one has been set, for this content.
   *
   * @return The hashtag
   */
  val shareHashtag: ShareHashtag?

  protected constructor(builder: Builder<M, B>) : super() {
    contentUrl = builder.contentUrl
    peopleIds = builder.peopleIds
    placeId = builder.placeId
    pageId = builder.pageId
    ref = builder.ref
    shareHashtag = builder.hashtag
  }

  protected constructor(parcel: Parcel) {
    contentUrl = parcel.readParcelable(Uri::class.java.classLoader)
    peopleIds = readUnmodifiableStringList(parcel)
    placeId = parcel.readString()
    pageId = parcel.readString()
    ref = parcel.readString()
    shareHashtag = ShareHashtag.Builder().readFrom(parcel).build()
  }

  override fun describeContents(): Int = 0

  override fun writeToParcel(out: Parcel, flags: Int) {
    out.writeParcelable(contentUrl, 0)
    out.writeStringList(peopleIds)
    out.writeString(placeId)
    out.writeString(pageId)
    out.writeString(ref)
    out.writeParcelable(shareHashtag, 0)
  }

  private fun readUnmodifiableStringList(parcel: Parcel): List<String>? {
    val list: List<String> = ArrayList()
    parcel.readStringList(list)
    return if (list.isEmpty()) null else Collections.unmodifiableList(list)
  }

  /** Abstract builder for [com.facebook.share.model.ShareContent] */
  abstract class Builder<M : ShareContent<M, B>, B : Builder<M, B>> : ShareModelBuilder<M, B> {
    internal var contentUrl: Uri? = null
    internal var peopleIds: List<String>? = null
    internal var placeId: String? = null
    internal var pageId: String? = null
    internal var ref: String? = null
    internal var hashtag: ShareHashtag? = null

    /**
     * Set the URL for the content being shared.
     *
     * @param contentUrl [android.net.Uri] representation of the content link.
     * @return The builder.
     */
    fun setContentUrl(contentUrl: Uri?): B {
      this.contentUrl = contentUrl
      return this as B
    }

    /**
     * Set the list of Ids for taggable people to tag with this content.
     *
     * @param peopleIds [java.util.List] of Ids for people to tag.
     * @return The builder.
     */
    fun setPeopleIds(peopleIds: List<String>?): B {
      this.peopleIds = if (peopleIds == null) null else Collections.unmodifiableList(peopleIds)
      return this as B
    }

    /**
     * Set the Id for a place to tag with this content.
     *
     * @param placeId The Id for the place to tag.
     * @return The builder.
     */
    fun setPlaceId(placeId: String?): B {
      this.placeId = placeId
      return this as B
    }

    /**
     * Set the Id of the Facebook page this share is associated with.
     *
     * @param pageId The Id for the Page
     * @return The builder
     */
    fun setPageId(pageId: String?): B {
      this.pageId = pageId
      return this as B
    }

    /**
     * Set the value to be added to the referrer URL when a person follows a link from this shared
     * content on feed.
     *
     * @param ref The ref for the content.
     * @return The builder.
     */
    fun setRef(ref: String?): B {
      this.ref = ref
      return this as B
    }

    /**
     * Set the ShareHashtag for this content
     *
     * @param shareHashtag The hashtag for this content
     * @return The builder
     */
    fun setShareHashtag(shareHashtag: ShareHashtag?): B {
      hashtag = shareHashtag
      return this as B
    }

    override fun readFrom(content: M?): B {
      return if (content == null) {
        this as B
      } else
          setContentUrl(content.contentUrl)
              .setPeopleIds(content.peopleIds)
              .setPlaceId(content.placeId)
              .setPageId(content.pageId)
              .setRef(content.ref)
              .setShareHashtag(content.shareHashtag)
    }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.share.model

import android.os.Parcel
import android.os.Parcelable

/**
 * Describes a hashtag for sharing.
 *
 * Use [ShareHashtag.Builder] to build instances
 */
class ShareHashtag : ShareModel {
  /** @return Gets the value of the hashtag for this instance */
  val hashtag: String?

  private constructor(builder: Builder) {
    hashtag = builder.hashtag
  }

  internal constructor(parcel: Parcel) {
    hashtag = parcel.readString()
  }

  override fun describeContents(): Int = 0

  override fun writeToParcel(dest: Parcel, flags: Int) {
    dest.writeString(hashtag)
  }

  /** Builder for the [com.facebook.share.model.ShareHashtag] class. */
  class Builder : ShareModelBuilder<ShareHashtag, Builder> {
    /** @return Gets the value of the hashtag for this instance */
    var hashtag: String? = null
      private set

    /**
     * Sets the hashtag value for this instance.
     *
     * @param hashtag
     * @return the Builder instance
     */
    fun setHashtag(hashtag: String?): Builder {
      this.hashtag = hashtag
      return this
    }

    override fun readFrom(model: ShareHashtag?): Builder {
      return if (model == null) {
        this
      } else {
        setHashtag(model.hashtag)
      }
    }

    internal fun readFrom(parcel: Parcel): Builder {
      return this.readFrom(parcel.readParcelable(ShareHashtag::class.java.classLoader))
    }

    override fun build(): ShareHashtag {
      return ShareHashtag(this)
    }
  }

  companion object {
    @JvmField
    val CREATOR: Parcelable.Creator<ShareHashtag> =
        object : Parcelable.Creator<ShareHashtag> {
          override fun createFromParcel(source: Parcel): ShareHashtag {
            return ShareHashtag(source)
          }

          override fun newArray(size: Int): Array<ShareHashtag?> {
            return arrayOfNulls(size)
          }
        }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.share.model

import android.os.Parcel
import android.os.Parcelable

/**
 * Describes link content to be shared.
 *
 * Use [ShareLinkContent.Builder] to build instances.
 *
 * See documentation for
 * [best practices](https://developers.facebook.com/docs/sharing/best-practices).
 */
class ShareLinkContent : ShareContent<ShareLinkContent, ShareLinkContent.Builder> {
  /** The quoted text to display for this link. */
  val quote: String?

  private constructor(builder: Builder) : super(builder) {
    quote = builder.quote
  }

  internal constructor(source: Parcel) : super(source) {
    quote = source.readString()
  }

  override fun describeContents(): Int = 0

  override fun writeToParcel(out: Parcel, flags: Int) {
    super.writeToParcel(out, flags)
    out.writeString(quote)
  }

  /** Builder for the [ShareLinkContent] interface. */
  class Builder : ShareContent.Builder<ShareLinkContent, Builder>() {
    internal var quote: String? = null

    /**
     * Set the quote to display for this link.
     *
     * @param quote The text quoted from the link.
     * @return The builder.
     */
    fun setQuote(quote: String?): Builder {
      this.quote = quote
      return this
    }

    override fun build(): ShareLinkContent {
      return ShareLinkContent(this)
    }

    override fun readFrom(model: ShareLinkContent?): Builder {
      return if (model == null) {
        this
      } else super.readFrom(model).setQuote(model.quote)
    }
  }

  companion object {
    @JvmField
    val CREATOR: Parcelable.Creator<ShareLinkContent> =
        object : Parcelable.Creator<ShareLinkContent> {
          override fun createFromParcel(source: Parcel): ShareLinkContent {
            return ShareLinkContent(source)
          }

          override fun newArray(size: Int): Array<ShareLinkContent?> {
            return arrayOfNulls(size)
          }
        }
  }
}