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

template <typename Dtype>
void ConsRandTripletLayer<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_();
    NNtriplet=this->layer_param_.cons_rand_triplet_param().triplet_number();
    //NNneg=this->layer_param_.cons_rand_pair_param().negative();
    //pospairnum=NNpos;
    //negpairnum=NNneg;
    //LOG(INFO) << "pos:" << pospairnum << ", neg:" << negpairnum;
    (*top)[0]->Reshape(NNtriplet, 1, 1, 1);//data1
    (*top)[1]->Reshape(NNtriplet, 1, 1, 1);//data2
    (*top)[2]->Reshape(NNtriplet, 1, 1, 1);//data3
}

template <typename Dtype>
void ConsRandTripletLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
    vector<Blob<Dtype>*>* top) {
	srand((unsigned)time(0));
	  const int num=bottom[0]->num();
		int dim=bottom[0]->count()/bottom[0]->num();
		Dtype* data1idxarray=(*top)[0]->mutable_cpu_data();
		Dtype* data2idxarray=(*top)[1]->mutable_cpu_data();
		Dtype* data3idxarray=(*top)[2]->mutable_cpu_data();
		const int ntri=NNtriplet;
		const Dtype* bottom_label=bottom[0]->cpu_data();//default: 1~maxlabel
		const int count = bottom[0]->count();
		//int pairarray[num*num*num];
		int *pairarray=new int[num*num*num];
	    int trinum=0;
	    for (int i=0;i<num*num*num;i++) {
	    	int pair1=int(i/(num*num));
	    	int res1=i-pair1*num*num;
	    	int pair2=int(res1/num);
	    	//int res2=res1-pair2*num;
	    	int pair3=i%num;
	    	if ((pair1==pair2)||(pair2==pair3)||(pair1==pair3)) {
	    		pairarray[i]=2;
	    		continue;
	    	}
	    	if ((bottom_label[pair1]==bottom_label[pair2])&&(bottom_label[pair1]!=bottom_label[pair3])) {
	    		pairarray[i]=1;
	    		trinum++;
	    	} else {
	    		pairarray[i]=0;
	    	}
	    }
	    const int tripletnum=trinum;
	    //int randarray[tripletnum];
	    int *randarray=new int [tripletnum];
	    //random array
	    trinum=0;
	    for (int i=0;i<num*num*num;i++) {
	    	if (pairarray[i]==1) {
	    		randarray[trinum]=i;
	    		trinum++;
	    	}
	    }
	    for (int i=0;i<NNtriplet;i++) {
	    	int j=rand()%(tripletnum-i)+i;
	    	int temp=randarray[i];
	    	randarray[i]=randarray[j];
	    	randarray[j]=temp;
	    }
	    for (int i=0;i<NNtriplet;i++) {
	    	data1idxarray[i]=int(randarray[i]/(num*num));
	    	int res1=randarray[i]-data1idxarray[i]*num*num;
	    	data2idxarray[i]=int(res1/num);
	    	data3idxarray[i]=randarray[i]%num;
	    }
	    //LOG(INFO) << pairidx1 << "," << pairidx2;
	    //CHECK_EQ(pairidx,pospairnum+negpairnum);
	    delete pairarray;
	    delete randarray;
}


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

INSTANTIATE_CLASS(ConsRandTripletLayer);

}  // namespace caffe
