/** Like the strip action, closest will modify the current parm keeping info
  * for atoms in mask plus the closestWaters solvent molecules. Set up the
  * vector of MolDist objects, one for every solvent molecule in the original
  * parm file. Atom masks for each solvent molecule will be set up.
  */
Action_Closest::RetType Action_Closest::Setup(Topology const& topIn, CoordinateInfo const& cInfoIn)
{
  // If there are no solvent molecules this action is not valid.
  if (topIn.Nsolvent()==0) {
    mprintf("Warning: Parm %s does not contain solvent.\n",topIn.c_str());
    return Action_Closest::SKIP;
  }
  // If # solvent to keep >= solvent in this parm the action is not valid.
  if (closestWaters_ >= topIn.Nsolvent()) {
    mprintf("Warning: # solvent to keep (%i) >= # solvent molecules in '%s' (%i)\n",
            closestWaters_, topIn.c_str(), topIn.Nsolvent());
    return Action_Closest::SKIP;
  }
  image_.SetupImaging( cInfoIn.TrajBox().Type() );
  if (image_.ImagingEnabled())
    mprintf("\tDistances will be imaged.\n");
  else
    mprintf("\tImaging off.\n"); 
  // LOOP OVER MOLECULES
  // 1: Check that all solvent molecules contain same # atoms. Solvent 
  //    molecules must be identical for the command to work properly; 
  //    the prmtop strip occurs only once so the solvent params become fixed.
  // 2: Set up a mask for all solvent molecules.
  SolventMols_.clear();
  // NOTE: May not be necessary to init 'solvent'
  MolDist solvent;
  solvent.D = 0.0;
  solvent.mol = 0;
  SolventMols_.resize(topIn.Nsolvent(), solvent);
  std::vector<MolDist>::iterator mdist = SolventMols_.begin();
  // 3: Set up the soluteMask for all non-solvent molecules.
  int molnum = 1;
  int nclosest = 0;
  int NsolventAtoms = -1;
  for (Topology::mol_iterator Mol = topIn.MolStart();
                              Mol != topIn.MolEnd(); ++Mol)
  {
    if ( Mol->IsSolvent() ) {
      // Solvent, check for same # of atoms.
      if (NsolventAtoms == -1)
        NsolventAtoms = Mol->NumAtoms();
      else if ( NsolventAtoms != Mol->NumAtoms() ) {
        mprinterr("Error: Solvent molecules in '%s' are not of uniform size.\n"
                  "Error:   First solvent mol = %i atoms, solvent mol %i = %i atoms.\n",
                  topIn.c_str(), NsolventAtoms, molnum, (*Mol).NumAtoms());
        return Action_Closest::ERR;
      }
      // mol here is the output molecule number which is why it starts from 1.
      mdist->mol = molnum;
      // Solvent molecule mask
      mdist->mask.AddAtomRange( Mol->BeginAtom(), Mol->EndAtom() );
      // Atoms in the solvent molecule to actually calculate distances to.
      if (firstAtom_) {
        mdist->solventAtoms.assign(1, Mol->BeginAtom() );
      } else {
        mdist->solventAtoms.clear();
        mdist->solventAtoms.reserve( Mol->NumAtoms() );
        for (int svatom = Mol->BeginAtom(); svatom < Mol->EndAtom(); svatom++)
          mdist->solventAtoms.push_back( svatom );
      }
      if (debug_ > 0) {
        mprintf("DEBUG:\tSet up mol %i:", mdist->mol); // DEBUG
        mdist->mask.PrintMaskAtoms("solvent"); // DEBUG
        mprintf("\n"); // DEBUG
      }
      ++mdist;
    }
    ++molnum;
  }

  // Setup distance atom mask
  // NOTE: Should ensure that no solvent atoms are selected!
  if ( topIn.SetupIntegerMask(distanceMask_) ) return Action_Closest::ERR;
  if (distanceMask_.None()) {
    mprintf("Warning: Distance mask '%s' contains no atoms.\n",
            distanceMask_.MaskString());
    return Action_Closest::SKIP;
  }
  distanceMask_.MaskInfo();

  // Check the total number of solvent atoms to be kept.
  NsolventAtoms *= closestWaters_;
  mprintf("\tKeeping %i solvent atoms.\n",NsolventAtoms);
  if (NsolventAtoms < 1) {
    mprintf("Warning: # of solvent atoms to be kept is < 1.\n");
    return Action_Closest::SKIP;
  }
  NsolventMolecules_ = (int)SolventMols_.size();

  return Action_Closest::OK;
}
// Action_RandomizeIons::Setup()
Action::RetType Action_RandomizeIons::Setup(ActionSetup& setup) {
  n_solvent_ = setup.Top().Nsolvent();
  if (n_solvent_ < 1) {
    mprinterr("Error: This command only works if solvent information has been specified.\n");
    return Action::ERR;
  }

  // Set up ion mask
  if (setup.Top().SetupIntegerMask( ions_ )) return Action::ERR;
  if ( ions_.None() ) {
    mprintf("Warning: Ion mask '%s' has no atoms.\n", ions_.MaskString());
    return Action::SKIP;
  }
  mprintf("\tIon mask is '%s' (%i atoms)\n", ions_.MaskString(), ions_.Nselected());

  // Set up the around mask if necessary
  if (around_.MaskStringSet()) {
    if (setup.Top().SetupIntegerMask( around_ )) return Action::ERR;
    if ( around_.None() ) {
      mprintf("Warning: Around mask '%s' has no atoms.\n", around_.MaskString());
    } else {
      mprintf("\tAround mask is '%s' (%i atoms)\n", around_.MaskString(),
              around_.Nselected());
    }
  }

  // Check that each ion is only a single atom residue.
  // NOTE: Should this be a molecule check instead? If so can then get rid of ResSize 
  for (AtomMask::const_iterator ion = ions_.begin(); ion != ions_.end(); ++ion)
  {
    int res = setup.Top()[*ion].ResNum();
    if (debug_ > 0)
      mprintf("\tAtom %i is in residue %i which is %i atoms\n",
              *ion+1, res+1, setup.Top().Res( res ).NumAtoms() );
    if ( setup.Top().Res( res ).NumAtoms() > 1 ) {
      mprintf("Warning: randomizeions: Ion atom %i belongs to residue %i which\n",
              *ion + 1, res + 1);
      mprintf("Warning:                contains more than 1 atom (%i)!\n", 
              setup.Top().Res( res ).NumAtoms());
    }
  }

  // Check the solvent information to make sure that each solvent listed has the
  // same number of atoms in each molecule; otherwise a uniform trajectory is not
  // possible and therefore this command will be ignored.
  // Also save the start and end atom of each solvent molecule.
  int NsolventAtoms = -1;
  solventStart_.clear();
  solventEnd_.clear();
  solventStart_.reserve( n_solvent_ );
  solventEnd_.reserve( n_solvent_ );
  for (Topology::mol_iterator Mol = setup.Top().MolStart();
                              Mol != setup.Top().MolEnd(); ++Mol)
  {
    if ( Mol->IsSolvent() ) {
      if (NsolventAtoms == -1)
        NsolventAtoms = Mol->NumAtoms();
      else if ( NsolventAtoms != Mol->NumAtoms() ) {
        mprinterr("Error: Solvent molecules in %s are not of uniform size.\n",
                  setup.Top().c_str());
        mprinterr("Error:   First solvent mol = %i atoms, this solvent mol = %i atoms.\n",
                  NsolventAtoms, Mol->NumAtoms());
        return Action::ERR;
      }
      solventStart_.push_back( Mol->BeginAtom() );
      solventEnd_.push_back( Mol->EndAtom() );
    }
  }
  image_.SetupImaging( setup.CoordInfo().TrajBox().Type() );
  // Allocate solvent molecule mask
  solvent_.resize( n_solvent_ );

  return Action::OK;
}