//============================================================================
// Return the tag of the event (ie the anti-flavour of the produced 
// B meson). Flip the flavour of the event with probB probability
//============================================================================
void EvtIncoherentMixing::OtherB( EvtParticle * p ,
                                  double & t ,
                                  EvtId & otherb ,
                                  double probB ) 
{
  //if(p->getId() == B0 || p->getId() == B0B) 
  //added by liming Zhang
  enableFlip();
  if ( ( isB0Mixed( p ) ) || ( isBsMixed( p ) ) ) {
    p->getParent()->setLifetime() ;
    t = p->getParent()->getLifetime() ;
  }
  else {
    p->setLifetime() ;
    t = p->getLifetime() ;
  }

  if ( flipIsEnabled() ) {
    //std::cout << " liming << flipIsEnabled " << std::endl;
    // Flip the flavour of the particle with probability probB
    bool isFlipped = ( EvtRandom::Flat( 0. , 1. ) < probB ) ;
    
    if ( isFlipped ) {
      if ( ( isB0Mixed( p ) ) || ( isBsMixed( p ) ) ) {
        p->getParent()
          ->setId( EvtPDL::chargeConj( p->getParent()->getId() ) ) ;
        p->setId( EvtPDL::chargeConj( p->getId() ) ) ;
      }
      else {
        p->setId( EvtPDL::chargeConj( p->getId() ) ) ;
      }
    }
  }
  
  if ( ( isB0Mixed( p ) ) || ( isBsMixed( p ) ) ) {
    // if B has mixed, tag flavour is charge conjugate of parent of B-meson
    otherb = EvtPDL::chargeConj( p->getParent()->getId() ) ;
  }
  else {
    // else it is opposite flavour than this B hadron
    otherb = EvtPDL::chargeConj( p->getId() ) ;
  }

  return ;
}
//============================================================================
// Return the tag of the event (ie the anti-flavour of the produced 
// B meson). No flip
//============================================================================
void EvtIncoherentMixing::OtherB( EvtParticle * p ,
                                  double & t ,
                                  EvtId & otherb ) 
{
  if ( ( isB0Mixed( p ) ) || ( isBsMixed( p ) ) ) {
    p->getParent()->setLifetime() ;
    t = p->getParent()->getLifetime() ;
  }
  else {
    p->setLifetime() ;
    t = p->getLifetime() ;
  }
  
  if ( ( isB0Mixed( p ) ) || ( isBsMixed( p ) ) ) {
    // if B has mixed, tag flavour is charge conjugate of parent of B-meson
    otherb = EvtPDL::chargeConj( p->getParent()->getId() ) ;
  }
  else {
    // else it is opposite flavour than this B hadron
    otherb = EvtPDL::chargeConj( p->getId() ) ;
  }

  return ;
}
void EvtPVVCPLH::decay( EvtParticle *p){

  //added by Lange Jan4,2000
  static EvtId BS0=EvtPDL::getId("B_s0");
  static EvtId BSB=EvtPDL::getId("anti-B_s0");

  //This is only to get tag-ID
  //Mixing is not relevant
  //Lifetime is made correctly later
  //Tristan
  EvtId other_b;
  double t;

// To generate integrated CP asymmetry, EvtGen uses the "flipping".
// CP-asymmetry in this channel very small, since:
// deltaMs large ..and..
// CPV-phase small
  EvtCPUtil::getInstance()->OtherB(p,t,other_b);

  //Here we're gonna generate and set the "envelope" lifetime
  //So we take the longest living component (for positive deltaGamma: tauH)
  //The double exponent will be taken care of later, by the amplitudes
  //Tristan
  
  static double Gamma = EvtConst::c/(EvtPDL::getctau(BS0));
  static double deltaGamma = EvtCPUtil::getInstance()->getDeltaGamma(BS0);
  static double ctauLong = EvtConst::c/(Gamma-fabs(deltaGamma)/2);
  // if dG>0: tauLong=tauH(CP-odd) is then largest

  //This overrules the lifetimes made in OtherB
  t=-log(EvtRandom::Flat())*(ctauLong);//ctauLong has same dimensions as t
  if(isBsMixed(p)){
    p->getParent()->setLifetime(t);
  }else{
    p->setLifetime(t);
  }

  //These should be filled with the transversity amplitudes at t=0 //Tristan
  EvtComplex G0P,G1P,G1M;  
  G1P=EvtComplex(getArg(2)*cos(getArg(3)),getArg(2)*sin(getArg(3)));
  G0P=EvtComplex(getArg(4)*cos(getArg(5)),getArg(4)*sin(getArg(5)));
  G1M=EvtComplex(getArg(6)*cos(getArg(7)),getArg(6)*sin(getArg(7)));

  EvtComplex lambda_km=EvtComplex(cos(2*getArg(0)),sin(2*getArg(0)));//was een min in oude versie

  //deltaMs is no argument anymore
  //Tristan
  
  static double deltaMs = EvtCPUtil::getInstance()->getDeltaM(BS0);

  EvtComplex cG0P,cG1P,cG1M;

  double mt = exp(-std::max(0.,deltaGamma)*t/(2*EvtConst::c));
  double pt = exp(+std::min(0.,deltaGamma)*t/(2*EvtConst::c));

  EvtComplex gplus  = ( mt*EvtComplex(cos(deltaMs*t/(2*EvtConst::c)),sin( deltaMs*t/(2*EvtConst::c)))
		      +pt*EvtComplex(cos(deltaMs*t/(2*EvtConst::c)),sin(-deltaMs*t/(2*EvtConst::c))) )/2;
  EvtComplex gminus = ( mt*EvtComplex(cos(deltaMs*t/(2*EvtConst::c)),sin( deltaMs*t/(2*EvtConst::c)))
        	      -pt*EvtComplex(cos(deltaMs*t/(2*EvtConst::c)),sin(-deltaMs*t/(2*EvtConst::c))) )/2;;

  if (other_b==BSB){
    //These are the right equations for the transversity formalism
    //cGOP is de 0-component, CP-even, so lives shorter: mainly lifetime tauL
    //cG1P is the //-component, also CP-even, also mainly smaller exponent
    //cG1M is the transverse component, CP-odd, so has mainly longer lifetime tauH
    //Tristan
    cG0P = G0P*( gplus + lambda_km*gminus );
    cG1P = G1P*( gplus + lambda_km*gminus );
    cG1M = G1M*( gplus - lambda_km*gminus );
  } else if (other_b==BS0){
    //The equations for BsBar
    //Note the minus-sign difference
    //Tristan
    cG0P = G0P*( gplus + (1.0/lambda_km)*gminus );
    cG1P = G1P*( gplus + (1.0/lambda_km)*gminus );
    cG1M =-G1M*( gplus - (1.0/lambda_km)*gminus );

  } else{
    EvtGenReport(EVTGEN_ERROR,"EvtGen") << "other_b was not BSB or BS0!"<<std::endl;
    ::abort();
  }

  EvtComplex A0,AP,AM;
  //Converting the transversity amplitudes
  //to helicity amplitudes
  //(to plug them into SVVHelAmp)
  A0=cG0P;
  AP=(cG1P+cG1M)/sqrt(2.0);
  AM=(cG1P-cG1M)/sqrt(2.0);
  
  EvtSVVHelAmp::SVVHel(p,_amp2,getDaug(0),getDaug(1),AP,A0,AM);

  return ;
}
void EvtSSD_DirectCP::decay( EvtParticle *p) {

    bool flip = false ;
    EvtId daugs[2];

    // decide it is B or Bbar:
    if ( EvtRandom::Flat(0.,1.) < ( ( 1. - _acp ) / 2. ) ) {
        // it is a B
        if ( EvtPDL::getStdHep( getParentId() ) < 0 ) flip = true ;
    } else {
        // it is a Bbar
        if ( EvtPDL::getStdHep( getParentId() ) > 0 ) flip = true ;
    }

    if ( flip ) {
        if ( ( isB0Mixed( p ) ) || ( isBsMixed( p ) ) ) {
            p->getParent()
            ->setId( EvtPDL::chargeConj( p->getParent()->getId() ) ) ;
            p->setId( EvtPDL::chargeConj( p->getId() ) ) ;
        }
        else {
            p->setId( EvtPDL::chargeConj( p->getId() ) ) ;
        }
    }

    if (!flip) {
        daugs[0]=getDaug(0);
        daugs[1]=getDaug(1);
    }
    else {
        daugs[0]=EvtPDL::chargeConj(getDaug(0));
        daugs[1]=EvtPDL::chargeConj(getDaug(1));
    }

    EvtParticle *d;
    p->initializePhaseSpace(2, daugs);

    EvtVector4R p4_parent=p->getP4Restframe();
    double m_parent=p4_parent.mass();

    EvtSpinType::spintype d2type=EvtPDL::getSpinType(getDaug(1));

    EvtVector4R momv;
    EvtVector4R moms;

    if (d2type==EvtSpinType::SCALAR) {
        d2type=EvtPDL::getSpinType(getDaug(0));
        d= p->getDaug(0);
        momv = d->getP4();
        moms = p->getDaug(1)->getP4();
    }
    else {
        d= p->getDaug(1);
        momv = d->getP4();
        moms = p->getDaug(0)->getP4();
    }

    if (d2type==EvtSpinType::SCALAR) {
        vertex(1.);
    }

    if (d2type==EvtSpinType::VECTOR) {

        double norm=momv.mass()/(momv.d3mag()*p->mass());

        vertex(0,norm*p4_parent*(d->epsParent(0)));
        vertex(1,norm*p4_parent*(d->epsParent(1)));
        vertex(2,norm*p4_parent*(d->epsParent(2)));

    }

    if (d2type==EvtSpinType::TENSOR) {

        double norm=
            d->mass()*d->mass()/(m_parent*d->getP4().d3mag()*d->getP4().d3mag());


        vertex(0,norm*d->epsTensorParent(0).cont1(p4_parent)*p4_parent);
        vertex(1,norm*d->epsTensorParent(1).cont1(p4_parent)*p4_parent);
        vertex(2,norm*d->epsTensorParent(2).cont1(p4_parent)*p4_parent);
        vertex(3,norm*d->epsTensorParent(3).cont1(p4_parent)*p4_parent);
        vertex(4,norm*d->epsTensorParent(4).cont1(p4_parent)*p4_parent);
    }
}