#include <algorithm>
#include <cfloat>
#include <vector>
#include <iostream>

#include "caffe/common.hpp"
#include "caffe/layer.hpp"
#include "caffe/syncedmem.hpp"
#include "caffe/util/math_functions.hpp"
#include "caffe/vision_layers.hpp"

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/highgui/highgui_c.h>
#include <opencv2/imgproc/imgproc.hpp>

namespace caffe {

using std::min;
using std::max;

template <typename Dtype>
void UpsamplingLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom,
      vector<Blob<Dtype>*>* top) {
  UpsamplingParameter upsample_param = this->layer_param_.upsampling_param();
  //CHECK(!upsample_param.has_size_h()) << "size_h is required.";
  //CHECK(!upsample_param.has_size_w()) << "size_w is required.";

  size_h_ = upsample_param.size_h();
  size_w_ = upsample_param.size_w();
  CHECK_GT(size_h_, 0) << "Height cannot be zero.";
  CHECK_GT(size_w_, 0) << "Width cannot be zero.";
}

template <typename Dtype>
void UpsamplingLayer<Dtype>::Reshape(const vector<Blob<Dtype>*>& bottom,
      vector<Blob<Dtype>*>* top) {
  channels_ = bottom[0]->channels();
  height_ = bottom[0]->height();
  width_ = bottom[0]->width();

  (*top)[0]->Reshape(bottom[0]->num(), channels_, size_h_,
      size_w_);
  if (top->size() > 1) {
    (*top)[1]->ReshapeLike(*(*top)[0]);
  }
}

// TODO(Yangqing): Is there a faster way to do pooling in the channel-first
// case?
template <typename Dtype>
void UpsamplingLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
      vector<Blob<Dtype>*>* top) {

  const Dtype* bottom_data = bottom[0]->cpu_data();
  Dtype* top_data = (*top)[0]->mutable_cpu_data();
  //LOG(INFO) << "bottom_data:" << bottom_data;
  //LOG(INFO) << "upsampling bottom_data[0]:" << bottom_data[0];
  const int top_count = (*top)[0]->count();
  cv::Mat low_img(height_, width_, CV_8UC1);
int M=(bottom[0]->count())/(bottom[0]->num());
//LOG(INFO) << "M=" << M << ", channels=" << channels_ << ", height=" << height_ << ", width=" << width_;
int Mtop=((*top)[0]->count())/((*top)[0]->num());
//LOG(INFO) << "Mtop=" << Mtop << ", channels=" << channels_ << ", size_h_=" << size_h_ << ", size_w_=" << size_w_;
int offset2;
  for (int i = 0; i < bottom[0]->num(); i++){
	  offset2 = 0;
  for (int c = 0; c < 1; ++c) {
  	for (int h = 0; h < low_img.rows; ++h) {
  		for (int w = 0; w < low_img.cols; ++w) {
  			low_img.at<uchar>(h, w) = bottom_data[i*M+offset2];
  			offset2++;
  		}
  	}
  }
  cv::Mat resize_img(size_h_, size_w_, CV_8UC1);
  cv::resize(low_img, resize_img, cv::Size(size_h_, size_w_));
  //cv::imshow("gt_test", resize_img);
  //cv::waitKey(1000);
  offset2 = 0;
  for (int c = 0; c < 1; ++c) {
    	for (int h = 0; h < resize_img.rows; ++h) {
    		for (int w = 0; w < resize_img.cols; ++w) {
    			top_data[i*Mtop+offset2] = resize_img.at<uchar>(h, w);
    			offset2++;
    		}
    	}
    }
  }
}

template <typename Dtype>
void UpsamplingLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
      const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {
  //if (!propagate_down[0]) {
    return;
  //}
  //const Dtype* top_diff = top[0]->cpu_diff();
  //Dtype* bottom_diff = (*bottom)[0]->mutable_cpu_diff();
  // Different pooling methods. We explicitly do the switch outside the for
  // loop to save time, although this results in more codes.
  //caffe_set((*bottom)[0]->count(), Dtype(0), bottom_diff);
  //remaining realized...
}


#ifdef CPU_ONLY
STUB_GPU(UpsamplingLayer);
#endif

INSTANTIATE_CLASS(UpsamplingLayer);


}  // namespace caffe
