//-------------------------------------------------------//
//----  SetUp       -------------------------------------//
//-------------------------------------------------------//
void SetUp( long int** table, // polyphase merge table
	    int order,
	    int nruns,
	    int runsize,
	    Device* devices[], Device* sources[], Device*& dest )
{
  int i;
  long int* initial_dist;  // initial distribution
  long int* dummy_list;    // distribution of dummies

  initial_dist = new long int [order+1];
  dummy_list = new long int [order+1];
  for (i = 0; i < order; i++)
    dummy_list[i] = 0;

  // distribute dummies evenly EXCEPT TO LAST DEVICE
  distribute( table, initial_dist, dummy_list );

  // save initial distribution of existing runs
  for (i = 0; i < order; i++)
    initial_dist[i] = table[dist][i] - dummy_list[i];

  // setting up the devices
  // loading runs and dummies onto devices
  // the destination device:
  devices[order] = new Device( nruns ); // maximum size; empty
  for (i=0; i < order; i++)
    devices[i] = new Device ( initial_dist[i], dummy_list[i], runsize );
  dest = devices[order];       // last one is destination
  for (i=0; i < order; i++)    // the rest are sources
    sources[i] = devices[i];

  delete [] initial_dist;
  delete [] dummy_list;

} // end SetUp

//-------------------------------------------------------//
//----  do_round    -------------------------------------//
//-------------------------------------------------------//
void do_round( Device* sources[], Device* dest, 
	       int order, 
	       long int rps,       // records per seek
	       long int& totseeks, 
	       long int& whos_empty,
	       bool& done )
{
  // collect 1 run from each device to merge to destination

  int i;
  long int newrun = 0;
  long int thisrun = 0;
  long int seeks;
  long int setseeks;

  setseeks = 0; // seeks for this set
  for (i=0; i < order; i++)
    {
      // make sure it's available
      if (sources[i]->IsAvailable())
	{
	  thisrun = sources[i]->Gives(); // grab the run

	  if (sources[i]->IsEmpty()) // is this device empty now?
	    {
	      done = true;
	      whos_empty = i;
	    }
	  newrun += thisrun; // 'merge' it
	  seeks = thisrun / rps; // count the seeks for this run
	  setseeks += seeks;
	}

    }// end for

  // 'write' the new run to the destination
  dest->Gets(newrun);
  totseeks += setseeks; // add the seeks for the set just finished

} // end do_round

//-------------------------------------------------------//
//----  polyphase   -------------------------------------//
//-------------------------------------------------------//
void polyphase ( Device* sources[], Device*& dest, int order, int memsize )
{
  // does N-way merge each time (phase) where N is the order of the merge
  // For each phase:
  //   collect 1 run from each source into 1 new run
  //   when one source goes empty this phase is done
  //   put the new run into dest
  //
  // After each phase:
  //   switch dest and the source that went empty
  //   check 1 other source: if it's empty too, we're done
  //     we'll check source[0] unless that's the one that went empty
  //       in which case we can check source[1]
  //
  
  long int setseeks;                   // seeks per set
  long int totseeks, grandtotal;       // seeks per phase; merge
  long int recs_per_seek;              // how many records we get for one seek
  long int whos_empty;                 // remembers which source went empty

  bool     done, alldone;              // flags for phase, merge

  Device*  t;                          // for switching

  int      i;

  recs_per_seek = memsize / order;
  grandtotal = 0;
  alldone = false;

  while (!alldone)
    {
      totseeks = 0; // for this phase
      done = false;
      whos_empty = 0;
      
      while (!(done))
	{

	  // collect 1 run from each device
	  do_round( sources, dest, order, recs_per_seek, 
		    totseeks, whos_empty, done);

	} // while !done

      grandtotal += totseeks;

      // switch empty source and dest
      t = dest;
      dest = sources[whos_empty];
      sources[whos_empty] = t;

      // check another source to see if >1 empty
      // if >1 empty; all MUST be empty so we're done
      if (whos_empty != 0)
	{
	  if (sources[0]->IsEmpty())
	    alldone = true;
	}
      else
	{
	  if (sources[1]->IsEmpty())
	    alldone = true;
	}
    } // end while !done

  cout << "Total seeks for Polyphase Merge: "
       << grandtotal << endl << endl;

} // end polyphase

