/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef IORAP_BINDER_AUTO_PARCELABLE_H_
#define IORAP_BINDER_AUTO_PARCELABLE_H_

#include "binder/Parcelable.h"
#include "binder/Parcel.h"
#include "binder/Status.h"

#include "common/introspection.h"

namespace iorap {
namespace binder {

//
// Implements the android::Parcelable interface (readFromParcel, writeToParcel)
// automatically by using compile-time introspection on T.
//
// Requires that 'T' implements introspection by using the IORAP_INTROSPECT_ADAPT_STRUCT macro.
//
template <typename T>
struct AutoParcelable : public ::android::Parcelable {
 private:
  using Status = android::binder::Status;
  using Parcel = android::Parcel;
  using Parcelable = android::Parcelable;
  using status_t = android::status_t;

 public:
  // Write every (introspected) field to the parcel by automatically inferring the correct
  // write method to invoke on the parcel from the member type.
  status_t writeToParcel(Parcel* parcel) const override {
    if (parcel == nullptr) {
      return ::android::UNEXPECTED_NULL;
    }

    status_t result = android::NO_ERROR;
    ::iorap::introspect::for_each_member_field_value(*Self(), [&](auto&& value) {
      if (result == android::NO_ERROR) {
        result = writeAnyToParcel(/*inout*/parcel, value);
      }
    });

    return result;
  }

  // Read every (introspected) field to the parcel by automatically inferring the correct
  // read method to invoke on the parcel from the member type.
  //
  // Resilient to partial read failures: A return code other than NO_ERROR means that
  // the current value is left unmodified.
  status_t readFromParcel(const Parcel* parcel) override {
    if (parcel == nullptr) {
      return ::android::UNEXPECTED_NULL;
    }

    T tmp{*Self()};

    // Unpack all the parcelable data into a temporary copy.
    // Parceling could fail halfway through, in which case
    // the original object is unaffected.

    status_t result = android::NO_ERROR;
    ::iorap::introspect::for_each_member_field_set_value(tmp, [&](auto field_type) {
      // type<?> field_type

      using ValueT = typename decltype(field_type)::type;

      if (result == android::NO_ERROR) {
        auto&& [res, read_value] = readAnyFromParcel<ValueT>(/*inout*/parcel);
        result = res;
        return ::iorap::introspect::aliasing_forward<ValueT>(read_value);
      } else {
        // TODO: nice-to-have fold over members to early-out on failure.
        return ValueT{};
      }
    });

    if (result != android::NO_ERROR) {
      return result;
    }

    // Success! Now we can copy all the data in a single step.
    *Self() = std::move(tmp);

    // TODO: nice-to-have some kind of invariants-checking after reading the parcel data.

    return ::android::NO_ERROR;
  }

 private:
#define AUTO_PARCELABLE_BINDER_MAPPING(FN) \
FN(Byte,int8_t)\
FN(Int32,int32_t)\
FN(Uint32,uint32_t)\
FN(Int64,int64_t)\
FN(Uint64,uint64_t)\
FN(Float,float)\
FN(Double,double)\
FN(Bool,bool)\
FN(CString,const char*)\
FN(String16,const String16&)\
FN(String16,const std::unique_ptr<String16>&)\
FN(StrongBinder,const sp<IBinder>&)\

  template <typename F>
  static status_t writeAnyToParcel(Parcel* parcel, const F& value) {
    using namespace android;  // NOLINT

    // 'F' is the original type of the field here, so it's safe to use it undecayed.
    // However, to make matching easier we almost always want to match against the decayed type.
    using D = std::decay_t<F>;  // [const] [volatile] X[&][&] -> X

    if constexpr (std::is_base_of_v<Parcelable, D>) {
      return value.writeToParcel(parcel);
    } else if constexpr (std::is_enum_v<D>) {
      return writeAnyToParcel(parcel, static_cast<std::underlying_type_t<F>>(value));
#define AUTO_PARCELABLE_WRITE_TO_PARCEL(fn_name, type_name) \
    } else if constexpr (std::is_same_v<D, std::decay_t<type_name>>) { \
      return parcel->write ## fn_name (value);
AUTO_PARCELABLE_BINDER_MAPPING(AUTO_PARCELABLE_WRITE_TO_PARCEL)
    } else if constexpr (std::is_same_v<D, std::string>) {
      return parcel->writeUtf8AsUtf16(value);
    } else {
      STATIC_FAIL(D, "Unsupported type: Add more manual type conversions above^^^");
    }

#undef AUTO_PARCELABLE_WRITE_TO_PARCEL
  }

  template <typename F>
  static auto readAnyFromParcel(const Parcel* parcel) {
    // returns pair(status_t, ~F~)
    using namespace android;

    // Since 'F' is almost always an lvalue reference (due to F=decltype(auto&&),
    // we should lose the references, and also any consts.
    using D = std::decay_t<F>;

    D value;
    status_t result;

    if constexpr (std::is_base_of_v<Parcelable, D>) {
      status_t result = value.readFromParcel(/*in*/parcel);
    } else if constexpr (std::is_enum_v<D>) {
      auto&& [res, val] = readAnyFromParcel<std::underlying_type_t<D>>(parcel);
      result = res;
      value = static_cast<D>(val);
#define AUTO_PARCELABLE_READ_FROM_PARCEL(fn_name, type_name) \
    } else if constexpr (std::is_same_v<D, std::decay_t<type_name>>) { \
      result = parcel->read ## fn_name (/*out*/&value);
AUTO_PARCELABLE_BINDER_MAPPING(AUTO_PARCELABLE_READ_FROM_PARCEL)
    } else if constexpr (std::is_same_v<D, std::string>) {
      result = parcel->readUtf8FromUtf16(/*out*/&value);
    } else {
      STATIC_FAIL(D, "Unsupported type: Add more manual type conversions above^^^");
    }
#undef AUTO_PARCELABLE_READ_FROM_PARCEL

    return std::make_pair(result, std::move(value));
  }

  T* Self() {
    return static_cast<T*>(this);
  }
  const T* Self() const {
    return static_cast<const T*>(this);
  }
};

}  // namespace binder
}  // namespace iorap

#endif  // IORAP_BINDER_AUTO_PARCELABLE_H_
