#include "user3dsample.h"
#include "udata.h"
#include "ustring.h"
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "user3duobja.h"
#include "mpi.h"


UserSample::UserSample(bool bRegister) :
  User(ulCpCodeSAMPLE, bRegister),dx(0.1),dy(0.2),ix(1),iy(2),bx(true),by(false) {
  if (!bRegister) {
	  uobjaArray = new UobjA *[10];
    for (int i=0;i<10;i++)
			uobjaArray[i] = 0;
  }
}


UserSample::~UserSample(void) {
}


const char *UserSample::Name(void) const {
  return("sample");
}


const char **UserSample::FunctionNames(void) const {
  static const char *strKey[] = {
    "smp_f1", "smp_f2", "smp_f3", "smp_f4", "smp_f5", "smp_f6",
    "cpp_traverse_ball_100",
    "cpp_sendBalls_byMPI", "cpp_receiveBalls_byMPI",
     0
  };
  return(strKey);
}


const char **UserSample::PlotFunctionNames(void) const {
  static const char *strKey[] = {
    "smp_pf1", "smp_pf2", "smp_pf3",
     0
	};
  return(strKey);
}


const char **UserSample::IntVariableNames(void) const {
  static const char *strKey[] = {
    "smp_ix", 
    0
  };
  return(strKey);
}


const char **UserSample::DoubleVariableNames(void) const {
  static const char *strKey[] = {
    "smp_dx", 
    0
  };
  return(strKey);
}


const char **UserSample::BoolVariableNames(void) const {
  static const char *strKey[] = {
    "smp_bx", 
    0
  };
  return(strKey);
}


int UserSample::ReturnIntVariable(int iN) const {
  switch (iN) {
    case 0:  return ix;
		default: return 0;
  }
}


double UserSample::ReturnDoubleVariable(int iN) const {
  switch (iN) {
    case 0:  return dx;
    default: return 0.0;
  }
}


bool UserSample::ReturnBoolVariable(int iN) const {
  switch (iN) {
    case 0 : return bx;
    default: return 0;
  }
}

void UserSample::Execute(int iN) {
  switch (iN) {
    case 0:  Function1();   break;
    case 1:	 Function2();   break;
    case 2:	 Function3();   break;
    case 3:	 Function4();   break;
    case 4:  Function5();   break;
    case 5:  Function6();   break;
		case 6:  TraverseAllBallsContact_100(); break;
		case 7:  sendBalls();    break;
		case 8:  receiveBalls(); break;
    default:                 break;
  }
}


void UserSample::Function1(void) {
  // this function is labeled "smp_f1".
  Uball *bp = Udata::ball_head();
  while (bp) {
    char msg[256];
    sprintf(msg, "*** ball id = %i x = %10f y = %10f \n",
      Udata::b_id(bp), Udata::b_pos(bp).x,Udata::b_pos(bp).y);
    Udata::out(msg);
    bp = Udata::b_next(bp);
  }
}


void UserSample::Function2(void) {
  // this function is labeled "smp_f2".
  unsigned long bid = 2;
  Uball *bp = Udata::find_ball(bid);
	if (bp) {
    char msg1[255];
    sprintf(msg1, "*** Traversing contacts about ball with ID = %u \n", bid);
    Udata::out(msg1);
    Ucontact *cp = Udata::b_clist(bp);
    while (cp) {
      Uball *bp_other;
      if ((Uball *)Udata::c_gobj1(cp)==bp)
        bp_other = (Uball *)Udata::c_gobj2(cp);
      else
        bp_other = (Uball *)Udata::c_gobj1(cp);
      char msg2[255];
      sprintf(msg2, "***** adjacent ball has ID =  %u \n",
        Udata::b_id(bp_other));
      Udata::out(msg2);
      if ((Uball *)Udata::c_gobj1(cp)==bp)
        cp = Udata::c_go1clist(cp);
      else
        cp = Udata::c_go2clist(cp);
		}
  }
}


void UserSample::Function3(void) {
  // this function is labeled "smp_f3".
  int num = 500;
	Udata::Ucommand("gen id 1" + Udata::ToString(num) + "x 0 10 y 0 10 z 0 10 rad 0.1 0.2");
  Udata::Ucommand("prop dens 2000 kn 1e8 ks 1e8");
  Udata::Ucommand("pl add ball yellow");
  Udata::Ucommand("pl sh");
}


void UserSample::Function4(void) {
  // this function is labeled "smp_f4".
  for (int i=0;i<10;i++) {
    if(uobjaArray[i]) delete uobjaArray[i];
      uobjaArray[i] = new UobjA;
  }
  Uobj *up = Udata::uobj_head();
  while (up) {
    char msg[256];
    sprintf(msg, "*** uobj addres = %p\n",up);
    Udata::out(msg);
    up = Udata::u_next(up);
  }
}


void UserSample::Function5(void) {
  // this function is labeled "smp_f5".
  Udata::Ucommand("gen id 1 50 x 0 10 y 0 10 z 0 10 rad 0.1 0.2");
  Udata::Ucommand("set extra ball 3");
  Uball *bp = Udata::ball_head();
  while (bp) {
    char msg[255];
  	// set in b_extra
  	Udata::IntToUparam((int &)Udata::b_id(bp),Udata::b_extra(bp,1));
  	Udata::DoubleToUparam(Udata::b_rad(bp),Udata::b_extra(bp,2));
  	Udata::PointToUparam((void *)bp,Udata::b_extra(bp,3));
    // put from b_extra
  	int bid = Udata::UparamToInt(Udata::b_extra(bp,1));
  	double d = Udata::UparamToDouble(Udata::b_extra(bp,2));
    Uball *badd = (Uball *)Udata::UparamToPoint(Udata::b_extra(bp,3));
    sprintf(msg, "ball id = %u rad = %f address = %p\n",bid,d,badd);
    Udata::out(msg);
    bp = Udata::b_next(bp);
  }
}


void UserSample::Function6(void) {
  // this function is labeled "smp_f6".
  ix = Udata::UparamToInt(Udata::Fish("fishv"));
}


void UserSample::ExecutePlot(int iN, UcppPlotItem *upi) {
  switch (iN) {
    case 0:  PlotFunction1(upi);   break;
    case 1:	 PlotFunction2(upi);   break;
    case 2:	 PlotFunction3(upi);   break;
    default:                       break;
	}
}


void UserSample::PlotFunction1(UcppPlotItem *upi) {
	Udvect dvp(0.0,0.0,0.0);
	Udata::draw_circle(dvp,0.8,upi);
}


void UserSample::PlotFunction2(UcppPlotItem *upi) {
	Udvect dvp1(0.0,0.0,0.0);
	Udvect dvp2(1.0,1.0,1.0);
	Udata::set_line_width(1,upi);
	Udata::set_dash_pattern(1,upi);
	Udata::draw_line(dvp1,dvp2,upi);

	Udvect dvp3(1.5,0.0,1.5);
	Udvect dvp4(1.5,1.0,2.5);
	Udata::set_line_width(3,upi);
	Udata::set_dash_pattern(0,upi);
	Udata::move_to(dvp3,upi);
 	Udata::line_to(dvp4,upi);

	Udvect dvp5(-1.0,1.5,2.0);
	Udata::set_color(3,upi); 
	Udata::set_font(1.5,upi);
	Udata::draw_string(dvp5,"This is smp_pf2.",upi);
}


void UserSample::PlotFunction3(UcppPlotItem *upi) {
  Udvect dvp[3];
	dvp[0].Set(-1.0,0.0,3.0),
	dvp[1].Set(1.0,0.0,3.0);
	dvp[2].Set(0.0,1.0,3.0);
	Udata::fill_poly(dvp,3,upi);
}


void UserSample::AcceptIntVariable(int iN, int iV) {
  switch (iN) {
    case 0: ix = iV; break;
  }
}


void UserSample::AcceptDoubleVariable(int iN, double dV) {
  switch (iN) {
    case 0: dx = dV; break;
  }
}


void UserSample::AcceptBoolVariable(int iN, bool bV) {
  switch (iN) {
    case 0: bx = bV; break;
  }
}


void UserSample::write(Ufile &fi) const {
	Udata::Uwrite(fi,dx);
	Udata::Uwrite(fi,ix);
	Udata::Uwrite(fi,bx);
	for (int i=0;i<10;i++)
	  Udata::Uwrite(fi,uobjaArray[i]);
}

void UserSample::read(Ufile &fi) {
	Udata::Uread(fi,dx);
	Udata::Uread(fi,ix);
	Udata::Uread(fi,bx);
 	for (int i=0;i<10;i++)
    uobjaArray[i] = (UobjA *)Udata::Uread(fi,uobjaArray[i]);
}

void UserSample::TraverseAllBallsContact_100(void)
{
  // this function is labeled "cpp_traverse_ball_100".
  int count; 
	double xx,yy,zz,nforce;
	for (int i=0;i<100;i++) {
    Uball *bp = Udata::ball_head();
    while (bp) {
		  count = 0;
		  nforce=0.0;
		  xx = 0.0;
		  yy = 0.0;
		  zz = 0.0;
      Ucontact *cp = Udata::b_clist(bp);
      while (cp) {
		    nforce += Udata::c_nforce(cp);
 			  xx += Udata::c_pos(cp).x;
			  yy += Udata::c_pos(cp).y;
			  zz += Udata::c_pos(cp).z;
			  count ++;
			  if ((Uball *)Udata::c_gobj1(cp)==bp)
          cp = Udata::c_go1clist(cp);
        else
          cp = Udata::c_go2clist(cp);
		  }
		  if (count) {
        nforce /= (double)count;
			  xx /= (double)count;
		    yy /= (double)count;
			  zz /= (double)count;
		  }
  	  bp = Udata::b_next(bp);
		}
  }
}

struct bImage {
	Udvect pos;
	double rad;
};

void UserSample::sendBalls(void) 
{
  // this function is labeled "cpp_sendBalls_byMPI".
	int bcount=0;
	Uball *bp = Udata::ball_head();
	while (bp) {
		bcount++;
		bp = Udata::b_next(bp);
	}
	char msg[256];
	sprintf(msg, " number of balls = %i\n",bcount);
	Udata::out(msg);
  int numproc,thisproc;
	MPI_Comm_size(MPI_COMM_WORLD,&numproc);
	MPI_Comm_rank(MPI_COMM_WORLD,&thisproc);
	char mmsg[256];
	sprintf(mmsg, " numproc %i thisproc %i \n",numproc,thisproc);
	Udata::out(mmsg);
	int ret=0,slave=0;;
	int data=bcount;
	if (thisproc==0) slave=1;
	else slave=0;
	ret = MPI_Send(&data,1,MPI_INT,slave,0,MPI_COMM_WORLD);
	bImage bi;
	bp = Udata::ball_head();
	while (bp) {
		bi.pos = Udata::b_pos(bp);
		bi.rad = Udata::b_rad(bp);
		ret = MPI_Send(&bi,sizeof(bImage),MPI_BYTE,slave,0,MPI_COMM_WORLD);
		bp = Udata::b_next(bp);
	}
}

void UserSample::receiveBalls(void)
{
  // this function is labeled "cpp_receiveBalls_byMPI".
	int ret=0, nballs=0;
	MPI_Status stat;
	ret = MPI_Recv(&nballs,1,MPI_INT,MPI_ANY_SOURCE,MPI_ANY_TAG,MPI_COMM_WORLD,&stat);
	char msg[256];
	sprintf(msg, " number of balls = %i\n",nballs);
	Udata::out(msg);
	if (!nballs) return;
	bImage bi;
	double meanRad = 0.0;
	for (int i=0 ; i<nballs ; i++) {
		ret = MPI_Recv(&bi,sizeof(bImage),MPI_BYTE,
						MPI_ANY_SOURCE,MPI_ANY_TAG,MPI_COMM_WORLD,&stat);
		meanRad += bi.rad;
		sprintf(msg," ball id %i x %g y %g z %g rad %g\n",
			            i+1,bi.pos.x,bi.pos.y,bi.pos.z,bi.rad);
	  Udata::out(msg);
	}
	Udata::out(" all balls images received!\n");
	meanRad /= (double)nballs;
	sprintf(msg, " mean ball radius = %g\n",meanRad);
	Udata::out(msg);
}

void UserSample::assignUdmProperties(void) {
  // this function is labeled "catch_contact_cpp".
  Ucontact *cp = (Ucontact *)Udata::UparamToPoint(Udata::cc_arg(0));
  Udata::c_model(cp,"usercm1");
  Udata::c_prop(cp,"cm1_kn",1.0);
  Udata::c_prop(cp,"cm1_ks",1.0);
  Udata::c_prop(cp,"cm1_fric",0.1);
}
  
void UserSample::assignUdmProperties2(void) {
  // this function is labeled "catch_contact_cpp2".
  Ucontact *cp = (Ucontact *)Udata::UparamToPoint(Udata::cc_arg(0));
  Udata::c_model(cp,"usercm1");
  double kn, ks;
  Uball *bp = (Uball *)Udata::c_gobj1(cp);
  if (Udata::pointer_type(Udata::c_gobj2(cp))==100) {
    Uball *bp_other = (Uball *)Udata::c_gobj2(cp);
    kn = Udata::b_realmass(bp)
      /(Udata::b_realmass(bp)+Udata::b_realmass(bp_other));
    ks = Udata::b_realmass(bp_other)
      /(Udata::b_realmass(bp)+Udata::b_realmass(bp_other));
  } else {
    kn = 1.0;
    ks = 1.0;
  }
  Udata::c_prop(cp,"cm1_kn",kn);
  Udata::c_prop(cp,"cm1_ks",ks);
  Udata::c_prop(cp,"cm1_fric",0.1);
}



/* EoF */