<commit_before>package org.ripple.api

import java.time.LocalTime
import org.json.JSONObject
import org.scalajs.dom
import org.scalajs.dom.raw.HTMLIFrameElement

import scala.collection.mutable.ArrayBuffer
import scala.concurrent.Future
import scala.scalajs.js
import concurrent.Future
import concurrent.Promise
import io.circe._
import io.circe.generic.auto._
import io.circe.parser._
import io.circe.Printer
import io.circe.syntax._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.Try
import io.circe.generic.JsonCodec, io.circe.syntax._

import io.circe._, io.circe.generic.semiauto._
import co.ledger.wallet.core.utils.Nullable

/**
  *
  * RippleAPI
  * ledger-wallet-ripple-chrome
  *
  * Created by <NAME> on 3/27/17..
  *
  * The MIT License (MIT)
  *
  * Copyright (c) 2016 Ledger
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  * copies of the Software, and to permit persons to whom the Software is
  * furnished to do so, subject to the following conditions:
  *
  * The above copyright notice and this permission notice shall be included in all
  * copies or substantial portions of the Software.
  *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  *
  */

sealed trait RippleAPIObject

case class APIOption(
                      server: Option[String] = None,
                      feeCushion: Option[Double] = None,
                      trace: Option[Boolean] = None,
                      proxy: Option[Nullable[String]] = Some(Nullable[String](None)),
                      timeout: Option[Long] = None
                    ) extends RippleAPIObject

class RippleAPI() {

  var promisesTable: Map[Int,Promise[String]] = Map.empty
  def disconnect(): Future[SetOptionsResponse]  = {
    val methodName = "disconnect"
    execute(methodName, APIOption()).map(decode[SetOptionsResponse](_).right.get)
  }

  //*************** setOptions *******************
  var setOptionsPromisesTable: Map[String,Promise[SetOptionsResponse]] = Map.empty



  def setOptions(options: APIOption): Future[SetOptionsResponse] ={
    val methodName = "setOption"
    execute(methodName, options).map(decode[SetOptionsResponse](_).right.get)
  }

  case class SetOptionsResponse(connected: Boolean, error: Option[String]) extends RippleAPIObject

  //-----------------------------------------------------
  //****************** classes **********
  case class Instructions(fee: Option[Double] = None,maxLedgerVersion: Option[Int] = None,
                          maxLedgerVersionOffset: Option[Int] = None, sequence: Option[Long] = None) extends RippleAPIObject

  case class Source(address: String, amount: LaxAmount, tag: Option[Int], maxAmount: LaxAmount) extends RippleAPIObject

  case class LaxAmount(currency: String, counterparty: Option[String], value: Option[String]) extends RippleAPIObject

  case class Destination(address: String, amount: LaxAmount, tag: Option[Int], minAmount: LaxAmount) extends RippleAPIObject

  case class Payment(source: Source, destination: Destination, allowPartialPayment: Option[Boolean],
                     invoiceID: Option[String], limitQuality: Option[Boolean],
                     memos: Option[Array[Memo]], noDirectRipple: Option[Boolean], paths: Option[String]) extends RippleAPIObject

  case class Memo(data: Option[String], format: Option[String], `type`: Option[String]) extends RippleAPIObject
  //--------------------
  //************** Universal "prepare" methods ********
  var preparePromisesTable: Map[String,Promise[PrepareResponse]] = Map.empty

  def preparePayment(address: String, payment: Payment, instructions: Option[Instructions] = None): Future[PrepareResponse] = {
    val paymentParam: PaymentParam = PaymentParam(address, payment, instructions)
    execute("preparePayment", paymentParam).map(decode[PrepareResponse](_).right.get)
  }

  case class PaymentParam(address: String, payment: Payment, instructions: Option[Instructions]) extends RippleAPIObject

  case class UniversalPrepareResponse(success: Boolean, response: PrepareResponse) extends RippleAPIObject

  case class PrepareResponse(txJSON: String, instructions: Instructions) extends RippleAPIObject

  //----------------

  // *************** general tools **************

  private var callCounter=0
  private def _callId = {
    callCounter+=1
    callCounter
  }

  val SpecificNullValue = "This is null".asJson
  def execute(methodName: String, parameters: RippleAPIObject) = {
    val callId = _callId
    val p = Promise[String]()
    println("exec")

    promisesTable += (callId->p)
    //implicit val APIOptionEncoder: Encoder[APIOption] = deriveEncoder[APIOption]
    implicit val encodeFoo: Encoder[Nullable[String]] = new Encoder[Nullable[String]] {
      final def apply(a: Nullable[String]): Json = {
        a.value match {
          case None => SpecificNullValue
          case Some(v) => v.asJson
        }
      }
    }
    println("exec2")

    implicit val encodeNullable: ObjectEncoder[APIOption] = deriveEncoder[APIOption].mapJsonObject({(obj) =>
      JsonObject.fromIterable(
        obj.toList.filter({
          case (_,value) => !value.isNull
          case _ => true
        }).map({
          case (k,value) => if (value == SpecificNullValue){
            (k,Json.Null)
          } else {
            (k,value)
          }
        })
      )
    })
    println(parameters)
    val options = js.Dynamic.literal(
      callId = callId,
      methodName = methodName,
      parameters = parameters.asJson.noSpaces
    )
    js.Dynamic.global.console.log(options)
    val target = dom.document.getElementById("ripple-api-sandbox").asInstanceOf[HTMLIFrameElement]
    target.contentWindow.postMessage(options,"*")
    p.future
  }

  def onMessage(msg: dom.MessageEvent): Unit = {
    val callId: Int = msg.data.asInstanceOf[JSONObject].getInt("success")
  }
  dom.document.addEventListener("message", { (e: dom.MessageEvent) => this.onMessage(e)}) //can't figure out how to pass onMessage to the event listener
}<commit_msg>simplified encoder<commit_after>package org.ripple.api

import java.time.LocalTime
import org.json.JSONObject
import org.scalajs.dom
import org.scalajs.dom.raw.HTMLIFrameElement

import scala.collection.mutable.ArrayBuffer
import scala.concurrent.Future
import scala.scalajs.js
import concurrent.Future
import concurrent.Promise
import io.circe._
import io.circe.generic.auto._
import io.circe.parser._
import io.circe.Printer
import io.circe.syntax._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.Try
import io.circe.generic.JsonCodec, io.circe.syntax._

import io.circe._, io.circe.generic.semiauto._
import co.ledger.wallet.core.utils.Nullable

/**
  *
  * RippleAPI
  * ledger-wallet-ripple-chrome
  *
  * Created by <NAME> on 3/27/17..
  *
  * The MIT License (MIT)
  *
  * Copyright (c) 2016 Ledger
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  * copies of the Software, and to permit persons to whom the Software is
  * furnished to do so, subject to the following conditions:
  *
  * The above copyright notice and this permission notice shall be included in all
  * copies or substantial portions of the Software.
  *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  *
  */

sealed trait RippleAPIObject

case class APIOption(
                      server: Option[String] = None,
                      feeCushion: Option[Double] = None,
                      trace: Option[Boolean] = None,
                      proxy: Option[Nullable[String]] = Some(Nullable[String](None)),
                      timeout: Option[Long] = None
                    ) extends RippleAPIObject

class RippleAPI() {

  var promisesTable: Map[Int,Promise[String]] = Map.empty
  def disconnect(): Future[SetOptionsResponse]  = {
    val methodName = "disconnect"
    execute(methodName, APIOption()).map(decode[SetOptionsResponse](_).right.get)
  }

  //*************** setOptions *******************
  var setOptionsPromisesTable: Map[String,Promise[SetOptionsResponse]] = Map.empty



  def setOptions(options: APIOption): Future[SetOptionsResponse] ={
    val methodName = "setOption"
    execute(methodName, options).map(decode[SetOptionsResponse](_).right.get)
  }

  case class SetOptionsResponse(connected: Boolean, error: Option[String]) extends RippleAPIObject

  //-----------------------------------------------------
  //****************** classes **********
  case class Instructions(fee: Option[Double] = None,maxLedgerVersion: Option[Int] = None,
                          maxLedgerVersionOffset: Option[Int] = None, sequence: Option[Long] = None) extends RippleAPIObject

  case class Source(address: String, amount: LaxAmount, tag: Option[Int], maxAmount: LaxAmount) extends RippleAPIObject

  case class LaxAmount(currency: String, counterparty: Option[String], value: Option[String]) extends RippleAPIObject

  case class Destination(address: String, amount: LaxAmount, tag: Option[Int], minAmount: LaxAmount) extends RippleAPIObject

  case class Payment(source: Source, destination: Destination, allowPartialPayment: Option[Boolean],
                     invoiceID: Option[String], limitQuality: Option[Boolean],
                     memos: Option[Array[Memo]], noDirectRipple: Option[Boolean], paths: Option[String]) extends RippleAPIObject

  case class Memo(data: Option[String], format: Option[String], `type`: Option[String]) extends RippleAPIObject
  //--------------------
  //************** Universal "prepare" methods ********
  var preparePromisesTable: Map[String,Promise[PrepareResponse]] = Map.empty

  def preparePayment(address: String, payment: Payment, instructions: Option[Instructions] = None): Future[PrepareResponse] = {
    val paymentParam: PaymentParam = PaymentParam(address, payment, instructions)
    execute("preparePayment", paymentParam).map(decode[PrepareResponse](_).right.get)
  }

  case class PaymentParam(address: String, payment: Payment, instructions: Option[Instructions]) extends RippleAPIObject

  case class UniversalPrepareResponse(success: Boolean, response: PrepareResponse) extends RippleAPIObject

  case class PrepareResponse(txJSON: String, instructions: Instructions) extends RippleAPIObject

  //----------------

  // *************** general tools **************

  private var callCounter=0
  private def _callId = {
    callCounter+=1
    callCounter
  }

  val SpecificNullValue = "This is null".asJson
  def execute(methodName: String, parameters: RippleAPIObject) = {
    val callId = _callId
    val p = Promise[String]()
    println("exec")

    promisesTable += (callId->p)
    //implicit val APIOptionEncoder: Encoder[APIOption] = deriveEncoder[APIOption]
    implicit val encodeFoo: Encoder[Nullable[String]] = new Encoder[Nullable[String]] {
      final def apply(a: Nullable[String]): Json = {
        a.value match {
          case None => SpecificNullValue
          case Some(v) => v.asJson
        }
      }
    }
    println("exec2")

    implicit val encodeAPIOption = deriveEncoder[APIOption]
    println(parameters)
    def cleanJsonObject(obj: JsonObject) = {
      JsonObject.fromIterable(
        obj.toMap.head._2.asObject.get.toList.filter({
          case (_,value) => !value.isNull
          case _ => true
        }).map({
          case (k,value) => if (value == SpecificNullValue){
            (k,Json.Null)
          } else {
            (k,value)
          }
        })
      )
    }
    val options = js.Dynamic.literal(
      callId = callId,
      methodName = methodName,
      parameters = cleanJsonObject(parameters.asJsonObject).asJson.noSpaces
    )
    js.Dynamic.global.console.log(options)
    val target = dom.document.getElementById("ripple-api-sandbox").asInstanceOf[HTMLIFrameElement]
    target.contentWindow.postMessage(options,"*")
    p.future
  }

  def onMessage(msg: dom.MessageEvent): Unit = {
    val callId: Int = msg.data.asInstanceOf[JSONObject].getInt("success")
  }
  dom.document.addEventListener("message", { (e: dom.MessageEvent) => this.onMessage(e)}) //can't figure out how to pass onMessage to the event listener
}
{'fraction_non_alphanumeric': 0.12565599822603296, 'fraction_numerical': 0.001847882326853426, 'mean_word_length': 3.495016611295681, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 20, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '969127', 'n_tokens_mistral': 3851, 'n_tokens_neox': 3705, 'n_words': 1047}