//Simulation code for BouncingBall
//Generated by OpenModelica.

#include "modelica.h"

#include "assert.h"

#include "simulation_runtime.h"

#include "BouncingBall_functions.cpp"
extern "C" {

}

#define NHELP 6
#define NG 2//number of zero crossing
#define NX 3
#define NY 3
#define NP 2 // number of paramters
#define NO 0 // number of outputvar on topmodel
#define NI 0 // number of inputvar on topmodel
#define NR 7 // number of residuals for initialialization function
#define NEXT 0 // number of external objects
#define MAXORD 5



static DATA* localData = 0;
#define time localData->timeValue
char *model_name="BouncingBall";
char* state_names[3]={"$dummy", "h", "v"};
char* derivative_names[3]={"der($dummy)", "der(h)", "der(v)"};
char* algvars_names[3]={"flying", "impact", "v_new"};
char* input_names[1] = {""};
char* output_names[1] = {""};
char* param_names[2]={"e", "g"};

char* state_comments[3]={"",  "height of ball",  "velocity of ball"};
char* derivative_comments[3]={"",  "height of ball",  "velocity of ball"};
char* algvars_comments[3]={ "true, if ball is flying", "", ""};
char* input_comments[1] = {""};
char* output_comments[1] = {""};
char* param_comments[2]={ "coefficient of restitution",  "gravity acceleration"};

#define $g localData->parameters[1]
#define $e localData->parameters[0]
#define $v_new localData->algebraics[2]
#define $impact localData->algebraics[1]
#define $flying localData->algebraics[0]
#define $v localData->states[2]
#define $derivative$v localData->statesDerivatives[2]
#define $h localData->states[1]
#define $derivative$h localData->statesDerivatives[1]
#define $$dummy localData->states[0]
#define $derivative$$dummy localData->statesDerivatives[0]

char* getName( double* ptr)
{
  if( &$v_new == ptr ) return algvars_names[2];
  if( &$impact == ptr ) return algvars_names[1];
  if( &$flying == ptr ) return algvars_names[0];
  if( &$derivative$v == ptr ) return derivative_names[2];
  if( &$v == ptr ) return state_names[2];
  if( &$derivative$h == ptr ) return derivative_names[1];
  if( &$h == ptr ) return state_names[1];
  if( &$derivative$$dummy == ptr ) return derivative_names[0];
  if( &$$dummy == ptr ) return state_names[0];

  return "";
}
static char init_fixed[NX+NX+NY+NP]={1/*$dummy*/, 1/*h*/, 1/*v*/, 0/*default*/, 
0/*default*/, 0/*default*/, 0/*flying*/, 
0/*impact*/, 0/*v_new*/, 1/*e*/, 
1/*g*/};
char var_attr[NX+NY+NP]={/*$dummy:*/1+0, /*h:*/1+0, /*v:*/1+0, /*flying:*/8+16, 
/*impact:*/8+16, /*v_new:*/1+16, /*e:*/1+0, 
/*g:*/1+0};
#define DIVISION(a,b,c) ((b != 0) ? a / b : a / division_error(b,c))


int encounteredDivisionByZero = 0;
double division_error(double b,const char* division_str)
{
  if(!encounteredDivisionByZero){
    fprintf(stderr,"ERROR: Division by zero in partial equation: %s.\n",division_str);
    encounteredDivisionByZero = 1;
   }   return b;
}


void setLocalData(DATA* data)
{

   localData = data;
}

DATA* initializeDataStruc(DATA_FLAGS flags)
{


  DATA* returnData = (DATA*)malloc(sizeof(DATA));

  if(!returnData) //error check

    return 0;

  returnData->nStates = NX;

  returnData->nAlgebraic = NY;

  returnData->nParameters = NP;

  returnData->nInputVars = NI;

  returnData->nOutputVars = NO;

  returnData->nZeroCrossing = NG;

  returnData->nInitialResiduals = NR;

  returnData->nHelpVars = NHELP;

  if(flags & STATES && returnData->nStates){

    returnData->states = (double*) malloc(sizeof(double)*returnData->nStates);

  }else{

    returnData->states = 0;

  }

  if(flags & STATESDERIVATIVES && returnData->nStates){

    returnData->statesDerivatives = (double*) malloc(sizeof(double)*returnData->nStates);

  }else{

    returnData->statesDerivatives = 0;

  }

  if(flags & HELPVARS && returnData->nHelpVars){

    returnData->helpVars = (double*) malloc(sizeof(double)*returnData->nHelpVars);

  }else{

    returnData->helpVars = 0;

  }

  if(flags & ALGEBRAICS && returnData->nAlgebraic){

    returnData->algebraics = (double*) malloc(sizeof(double)*returnData->nAlgebraic);

  }else{

    returnData->algebraics = 0;

  }

  if(flags & PARAMETERS && returnData->nParameters){

    returnData->parameters = (double*) malloc(sizeof(double)*returnData->nParameters);

  }else{

    returnData->parameters = 0;

  }

  if(flags & OUTPUTVARS && returnData->nOutputVars){

    returnData->outputVars = (double*) malloc(sizeof(double)*returnData->nOutputVars);

  }else{

    returnData->outputVars = 0;

  }

  if(flags & INPUTVARS && returnData->nInputVars){

    returnData->inputVars = (double*) malloc(sizeof(double)*returnData->nInputVars);

  }else{

    returnData->inputVars = 0;

  }

  if(flags & INITIALRESIDUALS && returnData->nInitialResiduals){

    returnData->initialResiduals = (double*) malloc(sizeof(double)*returnData->nInitialResiduals);

  }else{

    returnData->initialResiduals = 0;

  }

  if(flags & INITFIXED){

    returnData->initFixed = init_fixed;

  }else{

    returnData->initFixed = 0;

  }

  /*   names   */

  if(flags & MODELNAME){

    returnData->modelName = model_name;

  }else{

    returnData->modelName = 0;

  }

  if(flags & STATESNAMES){

    returnData->statesNames = state_names;

  }else{

    returnData->statesNames = 0;

  }

  if(flags & STATESDERIVATIVESNAMES){

    returnData->stateDerivativesNames = derivative_names;

  }else{

    returnData->stateDerivativesNames = 0;

  }

  if(flags & ALGEBRAICSNAMES){

    returnData->algebraicsNames = algvars_names;

  }else{

    returnData->algebraicsNames = 0;

  }

  if(flags & PARAMETERSNAMES){

    returnData->parametersNames = param_names;

  }else{

    returnData->parametersNames = 0;

  }

  if(flags & INPUTNAMES){

    returnData->inputNames = input_names;

  }else{

    returnData->inputNames = 0;

  }

  if(flags & OUTPUTNAMES){

    returnData->outputNames = output_names;

  }else{

    returnData->outputNames = 0;

  }

  /*   comments  */

  if(flags & STATESCOMMENTS){

    returnData->statesComments = state_comments;

  }else{

    returnData->statesComments = 0;

  }

  if(flags & STATESDERIVATIVESCOMMENTS){

    returnData->stateDerivativesComments = derivative_comments;

  }else{

    returnData->stateDerivativesComments = 0;

  }

  if(flags & ALGEBRAICSCOMMENTS){

    returnData->algebraicsComments = algvars_comments;

  }else{

    returnData->algebraicsComments = 0;

  }

  if(flags & PARAMETERSCOMMENTS){

    returnData->parametersComments = param_comments;

  }else{

    returnData->parametersComments = 0;

  }

  if(flags & INPUTCOMMENTS){

    returnData->inputComments = input_comments;

  }else{

    returnData->inputComments = 0;

  }

  if(flags & OUTPUTCOMMENTS){

    returnData->outputComments = output_comments;

  }else{

    returnData->outputComments = 0;

  }

  if (flags & EXTERNALVARS) {

  returnData->extObjs = (void**)malloc(sizeof(void*)*NEXT);

  if (!returnData->extObjs) { 

     printf("error allocating external objects\n");

     exit(-2);

  }

  setLocalData(returnData); /* must be set since used by constructors*/


  }

  return returnData;

}

void deInitializeDataStruc(DATA* data, DATA_FLAGS flags)

{

  if(!data)

    return;

  if(flags & STATES && data->states){

    free(data->states);

    data->states = 0;

  }

  if(flags & STATESDERIVATIVES && data->statesDerivatives){

    free(data->statesDerivatives);

    data->statesDerivatives = 0;

  }

  if(flags & ALGEBRAICS && data->algebraics){

    free(data->algebraics);

    data->algebraics = 0;

  }

  if(flags & PARAMETERS && data->parameters){

    free(data->parameters);

    data->parameters = 0;

  }

  if(flags & OUTPUTVARS && data->inputVars){

    free(data->inputVars);

    data->inputVars = 0;

  }

  if(flags & INPUTVARS && data->outputVars){

    free(data->outputVars);

    data->outputVars = 0;

  }

  if(flags & INITIALRESIDUALS && data->initialResiduals){

    free(data->initialResiduals);

    data->initialResiduals = 0;

  }

  if (flags & EXTERNALVARS && data->extObjs) {



    free(data->extObjs);

    data->extObjs = 0;

  }

}

int functionDAE_output()
{
  state mem_state;


  mem_state = get_memory_state();

  restore_memory_state(mem_state);
  return 0;

}

/*
*/
int input_function()
{
  return 0;

}

/*
*/
int output_function()
{
  return 0;

}
int functionDAE_res(double *t, double *x, double *xd, double *delta, long int *ires, double *rpar, long int* ipar)
{
  int i;
  double temp_xd[NX];
  double* statesDerivativesBackup;
  double timeBackup;


  statesDerivativesBackup = localData->statesDerivatives;
  timeBackup = localData->timeValue;
  for (i=0; i<localData->nStates; i++) temp_xd[i]=localData->statesDerivatives[i];
  
  localData->statesDerivatives = temp_xd;
  localData->timeValue = *t;
  
  functionODE();
  /* get the difference between the temp_xd(=localData->statesDerivatives) and xd(=statesDerivativesBackup)*/
   for (i=0; i < localData->nStates; i++) delta[i]=localData->statesDerivatives[i]-statesDerivativesBackup[i];
  
  localData->statesDerivatives = statesDerivativesBackup;
  localData->timeValue = timeBackup;
  return 0;


}
int function_zeroCrossing(long *neqm, double *t, double *x, long *ng, double *gout, double *rpar, long* ipar)
{
  double timeBackup;
  state mem_state;


  mem_state = get_memory_state();
  timeBackup = localData->timeValue;
  localData->timeValue = *t;
  ZEROCROSSING(0,LessEq($h,0.0));

  ZEROCROSSING(1,LessEq($v,0.0));


  restore_memory_state(mem_state);
  localData->timeValue = timeBackup;
  return 0;

}
int handleZeroCrossing(long index)
{
  state mem_state;


  mem_state = get_memory_state();
  switch(index) {
    case 0:

    
    $impact = ($h <= 0.0);

        localData->helpVars[2] = $h <= 0.0 && $v <= 0.0;
    localData->helpVars[3] = $impact;
    localData->helpVars[0] = $h <= 0.0 && $v <= 0.0;
    localData->helpVars[1] = $impact;
    localData->helpVars[4] = $h <= 0.0 && $v <= 0.0;
    localData->helpVars[5] = $impact;

    break;
    case 1:

        localData->helpVars[2] = $h <= 0.0 && $v <= 0.0;
    localData->helpVars[3] = $impact;
    localData->helpVars[0] = $h <= 0.0 && $v <= 0.0;
    localData->helpVars[1] = $impact;
    localData->helpVars[4] = $h <= 0.0 && $v <= 0.0;
    localData->helpVars[5] = $impact;

    break;

    default: break;
  }
  restore_memory_state(mem_state);
  return 0;

}
int function_updateDependents()
{
  state mem_state;
  modelica_boolean tmp0;


  mem_state = get_memory_state();
  $derivative$h = $v;
  $derivative$$dummy = 0.0;
  tmp0 = $flying;
  if (tmp0) {
  }
  else {
  }
  $derivative$v = ((tmp0)?(-$g):0.0);
    localData->helpVars[3] = $impact;
  localData->helpVars[1] = $impact;
  localData->helpVars[5] = $impact;


  restore_memory_state(mem_state);
  return 0;

}
int function_when(int i)
{
  edge_rettype tmp0;
  modelica_boolean tmp1;
  pre_rettype tmp2;
  state mem_state;


  mem_state = get_memory_state();
  switch(i) {
     case 0: //when {$h <= 0.0 AND $v <= 0.0,$impact}

    save($v_new);

    tmp0 = edge($impact);
    tmp1 = tmp0;
    if (tmp1) {
      tmp2 = pre($v);
    }
    else {
    }
    $v_new = ((tmp1)?((-$e) * tmp2):0.0);

    
    break;
     case 1: //when {$h <= 0.0 AND $v <= 0.0,$impact}

    save($flying);

    $flying = ($v_new > 0.0);

    
    break;
     case 2: //when {$h <= 0.0 AND $v <= 0.0,$impact}

        $v = $v_new;

    break;
    default: break;
  }

  restore_memory_state(mem_state);
  return 0;

}
int functionODE()
{
  state mem_state;
  modelica_boolean tmp0;


  mem_state = get_memory_state();
  $derivative$h = $v;
  $derivative$$dummy = 0.0;
  tmp0 = $flying;
  if (tmp0) {
  }
  else {
  }
  $derivative$v = ((tmp0)?(-$g):0.0);

  restore_memory_state(mem_state);
  return 0;

}
int initial_function()
{



  return 0;

}
int initial_residual()
{
  modelica_boolean tmp0;
  int i=0;
  state mem_state;


  mem_state = get_memory_state();
  localData->initialResiduals[i++] = ($impact - ($h <= 0.0));
  localData->initialResiduals[i++] = $derivative$$dummy;
  tmp0 = $flying;
  if (tmp0) {
  }
  else {
  }
  localData->initialResiduals[i++] = ($derivative$v - ((tmp0)?(-$g):0.0));
  localData->initialResiduals[i++] = ($derivative$h - $v);
  localData->initialResiduals[i++] = ($h - 1.0);

  restore_memory_state(mem_state);
  return 0;

}
int bound_parameters()
{
  state mem_state;


  mem_state = get_memory_state();

  restore_memory_state(mem_state);
  return 0;

}
int checkForDiscreteVarChanges()
{
 int foundEvent=0;
  if (edge(localData->helpVars[2])) AddEvent(0 + localData->nZeroCrossing);
  if (edge(localData->helpVars[3])) AddEvent(0 + localData->nZeroCrossing);
  if (edge(localData->helpVars[0])) AddEvent(1 + localData->nZeroCrossing);
  if (edge(localData->helpVars[1])) AddEvent(1 + localData->nZeroCrossing);
  if (edge(localData->helpVars[4])) AddEvent(2 + localData->nZeroCrossing);
  if (edge(localData->helpVars[5])) AddEvent(2 + localData->nZeroCrossing);


if (change($impact)) { AddEvent(0); foundEvent=1; }


 if (foundEvent) saveall();
 return 0;
}
