// 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 ConsRandPairLayer<Dtype>::LayerSetUp(
  const vector<Blob<Dtype>*>& bottom, vector<Blob<Dtype>*>* top) {
	;
}

template <typename Dtype>
void ConsRandPairLayer<Dtype>::Reshape(const vector<Blob<Dtype>*>& bottom,
      vector<Blob<Dtype>*>* top) {
    int maxlabel=-1;
    int minlabel=100000;
    const Dtype* label=bottom[0]->cpu_data();//default: 1~maxlabel
    //ConsNNPairParameter cons_nn_pair_param = this->layer_param_.cons_nn_pair_param_();
    NNpos=this->layer_param_.cons_rand_pair_param().positive();
    NNneg=this->layer_param_.cons_rand_pair_param().negative();
    pospairnum=NNpos;
    negpairnum=NNneg;
    //LOG(INFO) << "pos:" << pospairnum << ", neg:" << negpairnum;
    (*top)[0]->Reshape(pospairnum+negpairnum, 1, 1, 1);//data1
    (*top)[1]->Reshape(pospairnum+negpairnum, 1, 1, 1);//data2
    (*top)[2]->Reshape(pospairnum+negpairnum, 1, 1, 1);//pair label:pos(1),neg(0)
}

template <typename Dtype>
void ConsRandPairLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
    vector<Blob<Dtype>*>* top) {
	srand((unsigned)time(0));
	  const int num=bottom[0]->num();
		Dtype* pairlabel=(*top)[2]->mutable_cpu_data();
		int dim=bottom[0]->count()/bottom[0]->num();
		Dtype* data1idxarray=(*top)[0]->mutable_cpu_data();
		Dtype* data2idxarray=(*top)[1]->mutable_cpu_data();
		const int npos=NNpos;
		const int nneg=NNneg;
		const Dtype* bottom_label=bottom[0]->cpu_data();//default: 1~maxlabel
		const int count = bottom[0]->count();
		int *pairarray = new int [num*num];
	    int pairpos=0;
	    int pairneg=0;
	    for (int i=0;i<num*num;i++) {
	    	int pair1=int(i/num);
	    	int pair2=i%num;
	    	if (pair1==pair2) {
	    		pairarray[i]=2;
	    		continue;
	    	}
	    	if (bottom_label[pair1]==bottom_label[pair2]) {
	    		pairarray[i]=1;
	    		pairpos++;
	    	} else {
	    		pairarray[i]=0;
	    		pairneg++;
	    	}
	    }
	    const int posnum=pairpos;
	    const int negnum=pairneg;
	    int *posrandarray = new int [posnum];
	    int *negrandarray = new int [negnum];
	    //random array
	    pairpos=0;pairneg=0;
	    for (int i=0;i<num*num;i++) {
	    	if (pairarray[i]==1) {
	    		posrandarray[pairpos]=i;
	    		pairpos++;
	    	}
	    	if (pairarray[i]==0) {
	    		negrandarray[pairneg]=i;
	    		pairneg++;
	    	}
	    }
	    //LOG(INFO) << pairpos << "," << pairneg;
	    for (int i=0;i<NNpos;i++) {
	    	int j=rand()%(posnum-i)+i;
	    	int temp=posrandarray[i];
	    	posrandarray[i]=posrandarray[j];
	    	posrandarray[j]=temp;
	    }
	    CHECK_LT(NNpos,posnum) << "NNpos<posnum";
	    CHECK_LT(NNneg,negnum) << "NNneg<negnum";
	    for (int i=0;i<NNneg;i++) {
	    	int j=rand()%(negnum-i)+i;
	    	int temp=negrandarray[i];
	    	negrandarray[i]=negrandarray[j];
	    	negrandarray[j]=temp;
	    }
	    for (int i=0;i<NNpos;i++) {
	    	data1idxarray[i]=int(posrandarray[i]/num);
	    	data2idxarray[i]=posrandarray[i]%num;
	    	pairlabel[i]=1;
	    }
	    for (int i=0;i<NNneg;i++) {
	    	data1idxarray[NNpos+i]=int(negrandarray[i]/num);
	    	data2idxarray[NNpos+i]=negrandarray[i]%num;
	    	pairlabel[NNpos+i]=0;
	    }
	    //LOG(INFO) << pairidx1 << "," << pairidx2;
	    //CHECK_EQ(pairidx,pospairnum+negpairnum);
	    delete pairarray;
	    delete posrandarray;
	    delete negrandarray;
}


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

INSTANTIATE_CLASS(ConsRandPairLayer);

}  // namespace caffe
