// Copyright 2014 BVLC and contributors.

#include <algorithm>
#include <cmath>
#include <cfloat>
#include <vector>
#include <cstdlib>
#include <ctime>

#include "caffe/layer.hpp"
#include "caffe/vision_layers.hpp"
#include "caffe/util/math_functions.hpp"
#include "caffe/util/io.hpp"
#include "caffe/filler.hpp"

using std::max;

namespace caffe {

template <typename Dtype>
void RandSelectLayer<Dtype>::LayerSetUp(
  const vector<Blob<Dtype>*>& bottom, vector<Blob<Dtype>*>* top) {
	batchsize=this->layer_param_.rand_select_param().batchsize();
}

template <typename Dtype>
void RandSelectLayer<Dtype>::Reshape(const vector<Blob<Dtype>*>& bottom,
      vector<Blob<Dtype>*>* top) {
	int channels = bottom[0]->channels();
	int height = bottom[0]->height();
	int width = bottom[0]->width();
	for (int i=0;i<bottom.size();i++) {
		(*top)[i]->Reshape(batchsize,channels,height,width);
	}
}

template <typename Dtype>
void RandSelectLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
    vector<Blob<Dtype>*>* top) {
	srand((unsigned)time(0));
	int num=bottom[0]->num();
	int *numarray = new int [num];
	int dim = bottom[0]->count()/bottom[0]->num();
	//LOG(INFO) << "********" << bottom[0]->num() << "," << bottom[0]->channels() << "," << bottom[0]->height() << "," << bottom[0]->width();
	for (int i=0;i<num;i++) {
		numarray[i]=i;
	}
	for (int i=0;i<batchsize;i++) {
		int j = rand()%(num-i)+i;
		int temp = numarray[i];
		numarray[i] = numarray[j];
		numarray[j] = temp;
	}
	for (int i=0;i<bottom.size();i++) {
		const Dtype* bottom_data = bottom[i]->cpu_data();
		Dtype* top_data = (*top)[i]->mutable_cpu_data();
		for (int j=0; j<batchsize; j++) {
			caffe_copy(dim, bottom_data+bottom[i]->offset(numarray[j]), top_data+(*top)[i]->offset(j));
		}
	}
	/*for (int j=0; j<4800; j++) {
		Dtype* top_data1 = (*top)[0]->mutable_cpu_data();
		Dtype* top_data2 = (*top)[1]->mutable_cpu_data();
		Dtype* top_data3 = (*top)[2]->mutable_cpu_data();
		Dtype* topp1=top_data1+(*top)[0]->offset(j);
		Dtype* topp2=top_data2+(*top)[1]->offset(j);
		Dtype* topp3=top_data3+(*top)[2]->offset(j);
		LOG(INFO) << topp1[0] << " " << topp2[0] << " " << topp3[0] << "," << numarray[j];
		Dtype* bottom_data1 = bottom[0]->mutable_cpu_data();
		Dtype* bottom_data2 = bottom[1]->mutable_cpu_data();
		Dtype* bottom_data3 = bottom[2]->mutable_cpu_data();
		LOG(INFO) << bottom_data1[j] << " " << bottom_data2[j] << " " << bottom_data3[j];
	}*/
	delete numarray;
}


#ifdef CPU_ONLY
STUB_GPU_FORWARD(RandSelectLayer, Forward);
#endif

INSTANTIATE_CLASS(RandSelectLayer);

}  // namespace caffe
