/*
    This file is part of TON Blockchain Library.
    TON Blockchain Library is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 2 of the License, or
    (at your option) any later version.
    TON Blockchain Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.
    You should have received a copy of the GNU Lesser General Public License
    along with TON Blockchain Library.  If not, see .
    Copyright 2020 Telegram Systems LLP
*/
#pragma once
#include "refcnt.hpp"
#include "td/actor/PromiseFuture.h"
namespace td {
template 
class BinaryPromiseMerger : public CntObject {
  Result first_;
  Result second_;
  Promise> promise_;
  std::atomic pending_;
 public:
  BinaryPromiseMerger(Promise> promise) : promise_(std::move(promise)), pending_(2) {
  }
  static std::pair, Promise> split(Promise> promise) {
    auto ref = make_ref(std::move(promise));
    auto& obj = ref.write();
    return std::make_pair(obj.left(), obj.right());
  }
 private:
  Promise left() {
    return [this, self = Ref(this)](Result res) {
      first_ = std::move(res);
      work();
    };
  }
  Promise right() {
    return [this, self = Ref(this)](Result res) {
      second_ = std::move(res);
      work();
    };
  }
  void work() {
    if (!--pending_) {
      if (first_.is_error()) {
        promise_.set_error(first_.move_as_error());
      } else if (second_.is_error()) {
        promise_.set_error(second_.move_as_error());
      } else {
        promise_.set_result(std::pair(first_.move_as_ok(), second_.move_as_ok()));
      }
    }
  }
};
template 
std::pair, Promise> split_promise(Promise> promise) {
  return BinaryPromiseMerger::split(std::move(promise));
}
}  // namespace td