/*
// Copyright (c) 2018 Intel Corporation
//
// 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.
*/

#include "apply_adam_inst.h"
#include "primitive_type_base.h"
#include "error_handler.h"
#include "json_object.h"
#include <string>
#include <memory>

namespace cldnn {
primitive_type_id apply_adam::type_id() {
    static primitive_type_base<apply_adam> instance;
    return &instance;
}

apply_adam_node::typed_program_node(const std::shared_ptr<apply_adam> prim, program_impl& prog) : parent(prim, prog) {
    can_share_buffer(false);  // apply adam's output initial val should be either 0 or use same buffer as mutable_data
                              // after it (no allocation needed)
}
layout apply_adam_inst::calc_output_layout(apply_adam_node const& node) {
    assert(static_cast<bool>(node.get_primitive()->output_data_type) == false &&
           "Output data type forcing is not supported for apply_adam_node!");
    return node.input().get_non_padded_output_layout();
}

std::string apply_adam_inst::to_string(apply_adam_node const& node) {
    auto desc = node.get_primitive();
    auto node_info = node.desc_to_json();
    auto& m = node.m();
    auto& v = node.v();
    auto& beta1_power = node.beta1_power();
    auto& beta2_power = node.beta2_power();

    std::stringstream primitive_description;

    json_composite apply_adam_info;
    apply_adam_info.add("m_id", m.id());
    apply_adam_info.add("v_id", v.id());
    apply_adam_info.add("beta1_power_id", beta1_power.id());
    apply_adam_info.add("beta2_power_id", beta2_power.id());
    apply_adam_info.add("lr", desc->lr);
    apply_adam_info.add("beta1", desc->beta1);
    apply_adam_info.add("beta2", desc->beta2);
    apply_adam_info.add("epsilon", desc->epsilon);

    node_info->add("apply adam info", apply_adam_info);
    node_info->dump(primitive_description);

    return primitive_description.str();
}

apply_adam_inst::typed_primitive_inst(network_impl& network, apply_adam_node const& node) : parent(network, node) {
    auto m_format = node.m().get_output_layout().format;
    auto v_format = node.v().get_output_layout().format;
    auto beta1_power_format = node.beta1_power().get_output_layout().format;
    auto beta2_power_format = node.beta2_power().get_output_layout().format;

    CLDNN_ERROR_NOT_PROPER_FORMAT(node.id(),
                                  "M format",
                                  m_format.value,
                                  "supported m formats",
                                  format::yxfb,
                                  format::bfyx);
    CLDNN_ERROR_NOT_PROPER_FORMAT(node.id(),
                                  "V format",
                                  v_format.value,
                                  "supported v formats",
                                  format::yxfb,
                                  format::bfyx);
    CLDNN_ERROR_NOT_PROPER_FORMAT(node.id(),
                                  "beta1_power format",
                                  beta1_power_format.value,
                                  "supported beta1_power formats",
                                  format::yxfb,
                                  format::bfyx);
    CLDNN_ERROR_NOT_PROPER_FORMAT(node.id(),
                                  "beta2_power format",
                                  beta2_power_format.value,
                                  "supported beta2_power formats",
                                  format::yxfb,
                                  format::bfyx);
}
}  // namespace cldnn
