"use strict"
var __createBinding =
  (this && this.__createBinding) ||
  (Object.create
    ? function (o, m, k, k2) {
        if (k2 === undefined) k2 = k
        Object.defineProperty(o, k2, {
          enumerable: true,
          get: function () {
            return m[k]
          }
        })
      }
    : function (o, m, k, k2) {
        if (k2 === undefined) k2 = k
        o[k2] = m[k]
      })
var __setModuleDefault =
  (this && this.__setModuleDefault) ||
  (Object.create
    ? function (o, v) {
        Object.defineProperty(o, "default", { enumerable: true, value: v })
      }
    : function (o, v) {
        o["default"] = v
      })
var __importStar =
  (this && this.__importStar) ||
  function (mod) {
    if (mod && mod.__esModule) return mod
    var result = {}
    if (mod != null)
      for (var k in mod)
        if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k))
          __createBinding(result, mod, k)
    __setModuleDefault(result, mod)
    return result
  }
Object.defineProperty(exports, "__esModule", { value: true })
exports.concrete =
  exports.DerivedAll =
  exports.Derived =
  exports.Atomic =
  exports.TypeId =
    void 0
// tracing: off
const Tp = __importStar(require("../Collections/Immutable/Tuple"))
const E = __importStar(require("../Either"))
const Function_1 = require("../Function")
const atomic = __importStar(require("./atomic"))
const T = __importStar(require("./effect"))
exports.TypeId = Symbol()
class Atomic {
  constructor(value) {
    this.value = value
    this._tag = "Atomic"
    this._typeId = exports.TypeId
    this.fold = this.fold.bind(this)
    this.foldAll = this.foldAll.bind(this)
    this.set = this.set.bind(this)
  }
  fold(_ea, _eb, ca, bd) {
    return new Derived((f) =>
      f(
        this,
        (s) => bd(s),
        (c) => ca(c)
      )
    )
  }
  foldAll(_ea, _eb, _ec, ca, bd) {
    return new DerivedAll((f) =>
      f(
        this,
        (s) => bd(s),
        (c) => (s) => ca(c)(s)
      )
    )
  }
  get get() {
    return T.succeedWith(() => this.value.get)
  }
  set(a) {
    return T.succeedWith(() => {
      this.value.set(a)
    })
  }
}
exports.Atomic = Atomic
class Derived {
  constructor(use) {
    this.use = use
    this._tag = "Derived"
    this._typeId = exports.TypeId
    this.fold = this.fold.bind(this)
    this.foldAll = this.foldAll.bind(this)
    this.set = this.set.bind(this)
  }
  fold(ea, eb, ca, bd) {
    return this.use(
      (value, getEither, setEither) =>
        new Derived((f) =>
          f(
            value,
            (s) => E.fold_(getEither(s), (e) => E.left(eb(e)), bd),
            (c) =>
              E.chain_(ca(c), (a) =>
                E.fold_(setEither(a), (e) => E.left(ea(e)), E.right)
              )
          )
        )
    )
  }
  foldAll(ea, eb, ec, ca, _bd) {
    return this.use(
      (value, getEither, setEither) =>
        new DerivedAll((f) =>
          f(
            value,
            (s) => E.fold_(getEither(s), (e) => E.left(eb(e)), E.right),
            (c) => (s) =>
              E.chain_(
                E.fold_(getEither(s), (e) => E.left(ec(e)), ca(c)),
                (a) => E.fold_(setEither(a), (e) => E.left(ea(e)), E.right)
              )
          )
        )
    )
  }
  get get() {
    return this.use((value, getEither) =>
      T.chain_(value.get, (s) => E.fold_(getEither(s), T.fail, T.succeed))
    )
  }
  set(a) {
    return this.use((value, _, setEither) => E.fold_(setEither(a), T.fail, value.set))
  }
}
exports.Derived = Derived
class DerivedAll {
  constructor(use) {
    this.use = use
    this._tag = "DerivedAll"
    this._typeId = exports.TypeId
    this.fold = this.fold.bind(this)
    this.foldAll = this.foldAll.bind(this)
    this.set = this.set.bind(this)
  }
  fold(ea, eb, ca, bd) {
    return this.use(
      (value, getEither, setEither) =>
        new DerivedAll((f) =>
          f(
            value,
            (s) => E.fold_(getEither(s), (e) => E.left(eb(e)), bd),
            (c) => (s) =>
              E.chain_(ca(c), (a) =>
                E.fold_(setEither(a)(s), (e) => E.left(ea(e)), E.right)
              )
          )
        )
    )
  }
  foldAll(ea, eb, ec, ca, bd) {
    return this.use(
      (value, getEither, setEither) =>
        new DerivedAll((f) =>
          f(
            value,
            (s) => E.fold_(getEither(s), (e) => E.left(eb(e)), bd),
            (c) => (s) =>
              E.chain_(
                E.fold_(getEither(s), (e) => E.left(ec(e)), ca(c)),
                (a) => E.fold_(setEither(a)(s), (e) => E.left(ea(e)), E.right)
              )
          )
        )
    )
  }
  get get() {
    return this.use((value, getEither) =>
      T.chain_(value.get, (a) => E.fold_(getEither(a), T.fail, T.succeed))
    )
  }
  set(a) {
    return this.use((value, _, setEither) =>
      T.absolve(
        atomic.modify(value, (s) =>
          E.fold_(
            setEither(a)(s),
            (e) => Tp.tuple(E.leftW(e), s),
            (s) => Tp.tuple(E.right(undefined), s)
          )
        )
      )
    )
  }
}
exports.DerivedAll = DerivedAll
/**
 * Cast to a sealed union in case of ERef (where it make sense)
 *
 * @optimize identity
 */
function concrete(self) {
  return self
}
exports.concrete = concrete
//# sourceMappingURL=XRef.js.map
