
enum step
{
  write_out = 0,
  num_steps
};
size_t duoram_progress[step::num_steps] = { 0 };

 

 
const size_t number_of_writes = 2;


 

typedef  int64_t DB_t;

struct DuORAM_Write
{
	size_t shift;
	DB_t CW;
};



size_t target_index = 2;
size_t bytes_written2 =0;

DB_t final_cw;

DB_t * DB; 
DB_t * updated_DB; 
DB_t * blinds;
DB_t * updated_blinds;
DB_t * blinded_DB;
DB_t * blinded_DB_recv;
DB_t * updated_blinded_DB_recv;

DB_t M;



DB_t * reading_temp; 
DB_t distinguised_value[number_of_writes];


DB_t * b;
DB_t * c;
DB_t * d;

 
 

int8_t * reading_b;
int8_t * reading_c;
int8_t * reading_d; 

int8_t * writing_b;
int8_t * writing_c;
int8_t * writing_d; 

 
 void setup(DB_t * DB, DB_t * updated_DB, DB_t * blinded_DB_recv, DB_t * blinds, DB_t * updated_blinds, DB_t * updated_blinded_DB_recv, size_t db_nitems, bool party)
 {
 	for(size_t j = 0; j < db_nitems; ++j)
 	{
      if(party)
      {
        DB[j] 				      = 0;
        updated_DB[j] 		  = 0;
        blinded_DB_recv[j]  = 0; 
      }
      else
      {
        DB[j] 				      = 0;
        updated_DB[j] 		  = 0;
        blinded_DB_recv[j]  = 0; 
      }
 	}

  for(size_t j = 0; j < db_nitems; ++j) 
	{
		blinds[j] = 0;
		updated_blinds[j] = blinds[j];
		updated_blinded_DB_recv[j] = blinded_DB_recv[j];
	} 
}

void debug_(tcp::socket& in2, tcp::socket& sb, size_t db_nitems)
{
	for(size_t j = 0; j < db_nitems; ++j)
  {
    	DB_t debug_blinds2;
      boost::asio::read(in2, boost::asio::buffer(&debug_blinds2, sizeof(debug_blinds2)));
      assert(blinds[j] == debug_blinds2);
  }

	for(size_t jj = 0; jj < db_nitems; ++jj)
	{
		DB_t debug_refresh;
	  boost::asio::write(sb, boost::asio::buffer(&updated_blinded_DB_recv[jj], sizeof(updated_blinded_DB_recv[jj])));
	  boost::asio::read(sb, boost::asio::buffer(&debug_refresh, sizeof(debug_refresh)));	
		assert(debug_refresh == DB[jj] + blinds[jj]);
	}
	
		DB_t DB_out;
	 	boost::asio::write(sb, boost::asio::buffer(&DB[target_index], sizeof(DB[target_index])));
		boost::asio::read(sb, boost::asio::buffer(&DB_out, sizeof(DB_out)));


	 	DB_out = DB_out + DB[target_index];
	  
	  std::cout << "DB_out = " << DB_out << std::endl;
}


DB_t print_reconstruction(tcp::socket& sb, DB_t output)
{
		  		DB_t out_reconstruction;
		    	boost::asio::write(sb, boost::asio::buffer(&output, sizeof(output)));
		    	boost::asio::read(sb, boost::asio::buffer(&out_reconstruction, sizeof(out_reconstruction)));
		    	out_reconstruction = out_reconstruction + output;

          return out_reconstruction;
}


int read_database_shares(bool party, size_t db_nitems)
{
    if(party)
    {
      int const in { open( "DB1", O_RDONLY ) };
      size_t r = read(in, DB,  db_nitems * sizeof(DB_t));
        
      if(r < 0) {
          perror("Read error");
          close(in);
          return 1;
        }

    }
    if(!party)
    {
      int const in { open( "DB0", O_RDONLY ) };
      size_t r = read(in, DB,  db_nitems * sizeof(DB_t));
      
      if(r < 0) {
          perror("Read error");
          close(in);
            return 1;
      }
    }
	return 0;
}




void generate_random_distinguished_points(bool party)
{
	if(party)
  {
  	for(size_t j = 0; j < number_of_writes; ++j)
  	{
  		distinguised_value[j] = j + 2;
  	}
  }
  if(!party)
  {
  	for(size_t j = 0; j < number_of_writes; ++j)
  	{
  		distinguised_value[j] = j + 2;
  	}
  }
}


/* This function is never called*/
template<typename T1> 
void rotate_all( T1 * orginal_vector1, T1 * rotated_vector1,
								 T1 * orginal_vector3, T1 * rotated_vector3,
							   T1 * orginal_vector5, T1 * rotated_vector5, 
								size_t rotate_by, size_t db_nitems)
{

 			 for(size_t j = 0; j < db_nitems; ++j)
			 {
				
			 	 rotated_vector1[(j + rotate_by) % db_nitems] = orginal_vector1[j];
			 	 rotated_vector3[(j + rotate_by) % db_nitems] = orginal_vector3[j];
			 	 rotated_vector5[(j + rotate_by) % db_nitems] = orginal_vector5[j];			 	 
			 }
}

DB_t dot_product_with_bool(DB_t D[], int8_t flags[], size_t db_nitems, size_t rotate_by = 0)
{
  DB_t result = 0;
  for(size_t j = 0; j < db_nitems; ++j)
  {
   	result = result + (D[(j + rotate_by) % db_nitems] * flags[j]); 
  }

  return result;
}

 