#include "framework/operators/rpn_proposal_ssd.h"
namespace anakin {
namespace ops {
#ifdef USE_CUDA
template<>
void RPNProposalSSD<NV,  Precision::FP32>::operator()(
    OpContext<NV>& ctx,
    const std::vector<Tensor4dPtr<NV> >& ins,
    std::vector<Tensor4dPtr<NV> >& outs) {
    auto* impl = static_cast<RPNProposalSSDHelper<NV,  Precision::FP32>*>(this->_helper);
    auto& param = static_cast<RPNProposalSSDHelper<NV,  Precision::FP32>*>
                  (this->_helper)->_param_rpn_prop_ssd;
    impl->_funcs_rpn_prop_ssd(ins, outs, param, ctx);
}
#endif
#ifdef USE_ARM_PLACE
template<>
void RPNProposalSSD<ARM,  Precision::FP32>::operator()(
    OpContext<ARM>& ctx,
    const std::vector<Tensor4dPtr<ARM> >& ins,
    std::vector<Tensor4dPtr<ARM> >& outs) {
    auto* impl = static_cast<RPNProposalSSDHelper<ARM,  Precision::FP32>*>(this->_helper);
    auto& param = static_cast<RPNProposalSSDHelper<ARM,  Precision::FP32>*>
                  (this->_helper)->_param_rpn_prop_ssd;
    impl->_funcs_rpn_prop_ssd(ins, outs, param, ctx);
}
#endif
/// TODO ... specialization other type of operator
/// set helper
template<typename Ttype, Precision Ptype>
RPNProposalSSDHelper<Ttype, Ptype>::~RPNProposalSSDHelper() {
}
template<typename Ttype, Precision Ptype>
Status RPNProposalSSDHelper<Ttype, Ptype>::InitParam() {
    LOG(WARNING) << "Parsing RPNProposalSSD op parameter.";
    // get nms_param
    auto need_nms = GET_PARAMETER(bool, need_nms);
    auto overlap_ratio = GET_PARAMETER(PTuple<float>, overlap_ratio);
    auto top_n = GET_PARAMETER(PTuple<int>, top_n);
    auto add_score = GET_PARAMETER(bool, add_score);
    auto max_candidate_n = GET_PARAMETER(PTuple<int>, max_candidate_n);
    auto use_soft_nms = GET_PARAMETER(PTuple<bool>, use_soft_nms);
    auto nms_among_classes = GET_PARAMETER(bool, nms_among_classes);
    auto voting = GET_PARAMETER(PTuple<bool>, voting);
    auto vote_iou = GET_PARAMETER(PTuple<float>, vote_iou);
    auto nms_gpu_max_n_per_time = GET_PARAMETER(int, nms_gpu_max_n_per_time);
    // get detect_output_ssd
    auto threshold = GET_PARAMETER(PTuple<float>, threshold);
    auto channel_per_scale = GET_PARAMETER(int, channel_per_scale);
    auto class_name_list = GET_PARAMETER(std::string, class_name_list);
    auto num_class = GET_PARAMETER(int, num_class);
    auto refine_out_of_map_bbox = GET_PARAMETER(bool, refine_out_of_map_bbox);
    auto class_indexes = GET_PARAMETER(PTuple<int>, class_indexes);
    auto heat_map_a = GET_PARAMETER(PTuple<float>, heat_map_a);
    auto heat_map_b = GET_PARAMETER(PTuple<float>, heat_map_b);
    auto threshold_objectness = GET_PARAMETER(float, threshold_objectness);
    auto proposal_min_sqrt_area = GET_PARAMETER(PTuple<float>, proposal_min_sqrt_area);
    auto proposal_max_sqrt_area = GET_PARAMETER(PTuple<float>, proposal_max_sqrt_area);
    auto bg_as_one_of_softmax = GET_PARAMETER(bool, bg_as_one_of_softmax);
    auto use_target_type_rcnn = GET_PARAMETER(bool, use_target_type_rcnn);
    auto im_width = GET_PARAMETER(float, im_width);
    auto im_height = GET_PARAMETER(float, im_height);
    auto rpn_proposal_output_score = GET_PARAMETER(bool, rpn_proposal_output_score);
    auto regress_agnostic = GET_PARAMETER(bool, regress_agnostic);
    auto allow_border = GET_PARAMETER(float, allow_border);
    auto allow_border_ratio = GET_PARAMETER(float, allow_border_ratio);
    auto bbox_size_add_one = GET_PARAMETER(bool, bbox_size_add_one);
    auto read_width_scale = GET_PARAMETER(float, read_width_scale);
    auto read_height_scale = GET_PARAMETER(float, read_height_scale);
    auto read_height_offset = GET_PARAMETER(float, read_height_offset);
    auto min_size_h = GET_PARAMETER(float, min_size_h);
    auto min_size_w = GET_PARAMETER(float, min_size_w);
    auto min_size_mode = GET_PARAMETER(std::string, min_size_mode);
    // get gen_anchor_param
    auto base_size = GET_PARAMETER(float, base_size);
    auto ratios = GET_PARAMETER(PTuple<float>, ratios);
    auto scales = GET_PARAMETER(PTuple<float>, scales);
    auto anchor_width = GET_PARAMETER(PTuple<float>, anchor_width);
    auto anchor_height = GET_PARAMETER(PTuple<float>, anchor_height);
    auto anchor_x1 = GET_PARAMETER(PTuple<float>, anchor_x1);
    auto anchor_y1 = GET_PARAMETER(PTuple<float>, anchor_y1);
    auto anchor_x2 = GET_PARAMETER(PTuple<float>, anchor_x2);
    auto anchor_y2 = GET_PARAMETER(PTuple<float>, anchor_y2);
    auto zero_anchor_center = GET_PARAMETER(bool, zero_anchor_center);
    // get kpts_param
    //    auto kpts_exist_bottom_idx = GET_PARAMETER(int, kpts_exist_bottom_idx);
    //    auto kpts_reg_bottom_idx = GET_PARAMETER(int, kpts_reg_bottom_idx);
    //    auto kpts_reg_as_classify = GET_PARAMETER(bool, kpts_reg_as_classify);
    //    auto kpts_classify_width = GET_PARAMETER(int, kpts_classify_width);
    //    auto kpts_classify_height = GET_PARAMETER(int, kpts_classify_height);
    //    auto kpts_reg_norm_idx_st = GET_PARAMETER(int, kpts_reg_norm_idx_st);
    //    auto kpts_st_for_each_class = GET_PARAMETER(PTuple<int>, kpts_st_for_each_class);
    //    auto kpts_ed_for_each_class = GET_PARAMETER(PTuple<int>, kpts_ed_for_each_class);
    //    auto kpts_classify_pad_ratio = GET_PARAMETER(float, kpts_classify_pad_ratio);
    // get atrs_param
    //    auto atrs_reg_bottom_idx = GET_PARAMETER(int, atrs_reg_bottom_idx);
    //    auto atrs_reg_norm_idx_st = GET_PARAMETER(int, atrs_reg_norm_idx_st);
    //    auto atrs_norm_type = GET_PARAMETER(std::string, atrs_norm_type);
    // get ftrs_bottom_idx
    //    auto ftrs_bottom_idx = GET_PARAMETER(int, ftrs_bottom_idx);
    // get spmp_param
    //    auto spmp_bottom_idx = GET_PARAMETER(int, spmp_bottom_idx);
    //    auto spmp_class_aware = GET_PARAMETER(PTuple<bool>, spmp_class_aware);
    //    auto spmp_label_width = GET_PARAMETER(PTuple<int>, spmp_label_width);
    //    auto spmp_label_height = GET_PARAMETER(PTuple<int>, spmp_label_height);
    //    auto spmp_pad_ratio = GET_PARAMETER(PTuple<float>, spmp_pad_ratio);
    // get cam3d_param
    //    auto cam3d_bottom_idx = GET_PARAMETER(int, cam3d_bottom_idx);
    // get bbox_reg_param
    auto bbox_mean = GET_PARAMETER(PTuple<float>, bbox_mean);
    auto bbox_std = GET_PARAMETER(PTuple<float>, bbox_std);
    saber::NMSSSDParam<Ttype> nms_param(
            overlap_ratio.vector(),
            top_n.vector(),
            max_candidate_n.vector(),
            use_soft_nms.vector(),
            voting.vector(),
            vote_iou.vector(),
            need_nms,
            add_score,
            nms_among_classes,
            nms_gpu_max_n_per_time);
    saber::GenerateAnchorParam<Ttype> gen_anchor_param(
                ratios.vector(),
                scales.vector(),
                anchor_width.vector(),
                anchor_height.vector(),
                anchor_x1.vector(),
                anchor_y1.vector(),
                anchor_x2.vector(),
                anchor_y2.vector(),
                base_size,
                zero_anchor_center
            );
    //TODO!!!!!! enum
    saber::DetectionOutputSSD_MIN_SIZE_MODE min_size_mode_in;

    if (min_size_mode == "HEIGHT_AND_WIDTH") {
        min_size_mode_in = DetectionOutputSSD_HEIGHT_AND_WIDTH;
    } else {
        min_size_mode_in = DetectionOutputSSD_HEIGHT_OR_WIDTH;
    }

    saber::DetectionOutputSSDParam<Ttype> detection_output_ssd_param(
                threshold.vector(),
                class_indexes.vector(),
                heat_map_a.vector(),
                heat_map_b.vector(),
                proposal_min_sqrt_area.vector(),
                proposal_max_sqrt_area.vector(),
                refine_out_of_map_bbox,
                channel_per_scale,
                class_name_list,
                num_class,
                threshold_objectness,
                bg_as_one_of_softmax,
                use_target_type_rcnn,
                im_width,
                im_height,
                rpn_proposal_output_score,
                regress_agnostic,
                allow_border,
                allow_border_ratio,
                bbox_size_add_one,
                read_width_scale,
                read_height_scale,
                read_height_offset,
                min_size_h,
                min_size_w,
                min_size_mode_in
            );
    detection_output_ssd_param.nms_param = nms_param;
    detection_output_ssd_param.nms_param.has_param = true;
    detection_output_ssd_param.gen_anchor_param = gen_anchor_param;
    detection_output_ssd_param.gen_anchor_param.has_param = true;
    saber::BBoxRegParam<Ttype> bbox_reg_param(bbox_mean.vector(), bbox_std.vector());
    bbox_reg_param.has_param = true;
    saber::ProposalParam<Ttype> proposal_param(bbox_reg_param,
            detection_output_ssd_param);
    _param_rpn_prop_ssd = proposal_param;
    return Status::OK();
}
template<typename Ttype, Precision Ptype>
Status RPNProposalSSDHelper<Ttype, Ptype>::Init(OpContext<Ttype>& ctx,
        const std::vector<Tensor4dPtr<Ttype> >& ins,
        std::vector<Tensor4dPtr<Ttype> >& outs) {
    _funcs_rpn_prop_ssd.init(ins, outs, _param_rpn_prop_ssd, SPECIFY, SABER_IMPL, ctx);
    return Status::OK();
}
template<typename Ttype, Precision Ptype>
Status RPNProposalSSDHelper<Ttype, Ptype>::InferShape(const
        std::vector<Tensor4dPtr<Ttype> >& ins,
        std::vector<Tensor4dPtr<Ttype> >& outs) {
    _funcs_rpn_prop_ssd.compute_output_shape(ins, outs, _param_rpn_prop_ssd);
    return Status::OK();
}
#ifdef USE_CUDA
template class RPNProposalSSDHelper<NV,  Precision::FP32>;
template class RPNProposalSSDHelper<NV,  Precision::FP16>;
template class RPNProposalSSDHelper<NV,  Precision::INT8>;
#endif
#ifdef USE_ARM_PLACE
template class RPNProposalSSDHelper<ARM,  Precision::FP32>;
template class RPNProposalSSDHelper<ARM,  Precision::FP16>;
template class RPNProposalSSDHelper<ARM,  Precision::INT8>;
#endif
// register helper
#ifdef USE_CUDA
ANAKIN_REGISTER_OP_HELPER(RPNProposalSSD, RPNProposalSSDHelper, NV,  Precision::FP32);
#endif
#ifdef USE_ARM_PLACE
ANAKIN_REGISTER_OP_HELPER(RPNProposalSSD, RPNProposalSSDHelper, ARM,  Precision::FP32);
#endif
//! register op
ANAKIN_REGISTER_OP(RPNProposalSSD)
.Doc("RPNProposalSSD operator")
#ifdef USE_CUDA
.__alias__<NV,  Precision::FP32>("rpn_proposal_ssd")
#endif
#ifdef USE_ARM_PLACE
.__alias__<ARM,  Precision::FP32>("rpn_proposal_ssd")
#endif
.num_in(1)
.num_out(1)
.Args<bool>("need_nms", "need_nms of nms_param")
.Args<PTuple<float>>("overlap_ratio", "overlap_ratio of nms_param")
.Args<PTuple<int>>("top_n", "top_n of nms_param")
.Args<bool>("add_score", "add_score of nms_param")
.Args<PTuple<int>>("max_candidate_n", "max_candidate_n of nms_param")
.Args<PTuple<bool>>("use_soft_nms", "use_soft_nms of nms_param")
.Args<bool>("nms_among_classes", "nms_among_classes of nms_param")
.Args<PTuple<bool>>("voting", "voting of nms_param")
.Args<PTuple<float>>("vote_iou", "vote_iou of nms_param")
.Args<int>("nms_gpu_max_n_per_time", "nms_gpu_max_n_per_time of nms_param")
.Args<PTuple<float>>("threshold", "threshold of detect_output_ssd ")
.Args<int>("channel_per_scale", "channel_per_scale of detect_output_ssd ")
.Args<std::string>("class_name_list", "class_name_list of detect_output_ssd ")
.Args<int>("num_class", "num_class of detect_output_ssd ")
.Args<bool>("refine_out_of_map_bbox", "refine_out_of_map_bbox of detect_output_ssd ")
.Args<PTuple<int>>("class_indexes", "class_indexes of detect_output_ssd ")
.Args<PTuple<float>>("heat_map_a", "heat_map_a of detect_output_ssd ")
.Args<PTuple<float>>("heat_map_b", "heat_map_b of detect_output_ssd ")
.Args<float>("threshold_objectness", "threshold_objectness of detect_output_ssd ")
.Args<PTuple<float>>("proposal_min_sqrt_area", "proposal_min_sqrt_area of detect_output_ssd ")
.Args<PTuple<float>>("proposal_max_sqrt_area", "proposal_max_sqrt_area of detect_output_ssd ")
.Args<bool>("bg_as_one_of_softmax", "bg_as_one_of_softmax of detect_output_ssd ")
.Args<bool>("use_target_type_rcnn", "use_target_type_rcnn of detect_output_ssd ")
.Args<float>("im_width", "im_width of detect_output_ssd ")
.Args<float>("im_height", "im_height of detect_output_ssd ")
.Args<bool>("rpn_proposal_output_score", "rpn_proposal_output_score of detect_output_ssd ")
.Args<bool>("regress_agnostic", "regress_agnostic of detect_output_ssd ")
.Args<float>("allow_border", "allow_border of detect_output_ssd ")
.Args<float>("allow_border_ratio", "allow_border_ratio of detect_output_ssd ")
.Args<bool>("bbox_size_add_one", "bbox_size_add_one of detect_output_ssd ")
.Args<float>("read_width_scale", "read_width_scale of detect_output_ssd ")
.Args<float>("read_height_scale", "read_height_scale of detect_output_ssd ")
.Args<float>("read_height_offset", "read_height_offset of detect_output_ssd ")
.Args<float>("min_size_h", "min_size_h of detect_output_ssd ")
.Args<float>("min_size_w", "min_size_w of detect_output_ssd ")
.Args<std::string>("min_size_mode", "min_size_mode of detect_output_ssd")
.Args<float>("base_size", "base_size of gen_anchor_param")
.Args<PTuple<float>>("ratios", "ratios of gen_anchor_param")
.Args<PTuple<float>>("scales", "scales of gen_anchor_param ")
.Args<PTuple<float>>("anchor_width", "anchor_width of gen_anchor_param ")
.Args<PTuple<float>>("anchor_height", "anchor_height of gen_anchor_param ")
.Args<PTuple<float>>("anchor_x1", "anchor_x1 of gen_anchor_param ")
.Args<PTuple<float>>("anchor_y1", "anchor_y1 of gen_anchor_param ")
.Args<PTuple<float>>("anchor_x2", "anchor_x2 of gen_anchor_param ")
.Args<PTuple<float>>("anchor_y2", "anchor_y2 of gen_anchor_param ")
.Args<bool>("zero_anchor_center", "zero_anchor_center of gen_anchor_param ")
.Args<int>("kpts_exist_bottom_idx", "kpts_exist_bottom_idx of kpts_param ")
.Args<int>("kpts_reg_bottom_idx", "kpts_reg_bottom_idx of kpts_param ")
.Args<bool>("kpts_reg_as_classify", "kpts_reg_as_classify of kpts_param ")
.Args<int>("kpts_classify_width", "kpts_classify_width of kpts_param ")
.Args<int>("kpts_classify_height", "kpts_classify_height of kpts_param ")
.Args<int>("kpts_reg_norm_idx_st", "kpts_reg_norm_idx_st of kpts_param ")
.Args<PTuple<int>>("kpts_st_for_each_class", "kpts_st_for_each_class of kpts_param ")
.Args<PTuple<int>>("kpts_ed_for_each_class", "kpts_ed_for_each_class of kpts_param ")
.Args<float>("kpts_classify_pad_ratio", "kpts_classify_pad_ratio of kpts_param ")
.Args<int>("atrs_reg_bottom_idx", "atrs_reg_bottom_idx of atrs_param")
.Args<int>("atrs_reg_norm_idx_st", "atrs_reg_norm_idx_st of atrs_param")
.Args<PTuple<std::string>>("atrs_norm_type", "atrs_norm_type of atrs_param")
.Args<int>("ftrs_bottom_idx", "ftrs_bottom_idx of ftrs_param")
.Args<int>("spmp_bottom_idx", "spmp_bottom_idx of spmp_param ")
.Args<PTuple<bool>>("spmp_class_aware", "spmp_class_aware of spmp_param ")
.Args<PTuple<int>>("spmp_label_width", "spmp_label_width of spmp_param ")
.Args<PTuple<int>>("spmp_label_height", "spmp_label_height of spmp_param ")
.Args<PTuple<float>>("spmp_pad_ratio", "spmp_pad_ratio of spmp_param ")
.Args<int>("cam3d_bottom_idx", "cam3d_bottom_idx of cam3d_param")
.Args<PTuple<float>>("bbox_mean", "bbox_mean of bbox_reg_param")
.Args<PTuple<float>>("bbox_std", "bbox_std of bbox_reg_param");
} /* namespace ops */
} /* namespace anakin */
