/*
 * Demonstration of:
 *   enum, 
 *   struct,
 *   functions,
 *   printf, 
 *   pointer arrow operator, 
 *   variable scoping, 
 *   and polymorphism (dispatch_func() can do math on differnt data type arguments)
*/
#include <stdio.h>

//-----------------------------------
// Declarations of ...
//-----------------------------------
enum func_oper
{
    ADD_INT,
    SUB_INT,
    ADD_FLOAT,
    SUB_FLOAT
};
struct threeintegers{
    int a;
    int b;
    int c;
} ;
struct threefloats{
    float a;
    float b;
    float c;
} ;

//---------------------
// Function Prototypes
//---------------------
int dispatch_func(enum func_oper, void *);
int add_integer(struct threeintegers *arg);
int sub_integer(struct threeintegers *arg);
int add_float(struct threefloats *arg);
int sub_float(struct threefloats *arg);

//---------------------
// Main
//---------------------
int main(int argc, char **argv)
{
    // Declare instance of each sturct
    struct threeintegers somestruct;
    struct threefloats somefloatstruct;

    // Intialize each truct
    somestruct.a=3;
    somestruct.b=4;
    somefloatstruct.a=5.;
    somefloatstruct.b=6.;
    
    // Call math operation on each struct using dispatch_func()
    dispatch_func(ADD_INT,&somestruct);
    printf("Result is %d\n",somestruct.c);
    dispatch_func(SUB_INT,&somestruct);
    printf("Result is %d\n",somestruct.c);
    dispatch_func(ADD_FLOAT,&somefloatstruct);
    printf("Result is %g\n",somefloatstruct.c);
    dispatch_func(SUB_FLOAT,&somefloatstruct);
    printf("Result is %g\n",somefloatstruct.c);

    return 0;
}

//---------------------
// Function Definitions 
//---------------------
int dispatch_func(enum func_oper f, void *arg)
{
    switch(f)
    {
        case ADD_INT:
            return add_integer((struct threeintegers*)arg);
            break;

        case SUB_INT:
            return sub_integer((struct threeintegers*)arg);
            break;

        case ADD_FLOAT:
            return add_float((struct threefloats*)arg);
            break;

        case SUB_FLOAT:
            return sub_float((struct threefloats*)arg);
            break;

        default:
            return -1;
            break;
    }
}

int add_integer(struct threeintegers *arg)
{
    arg->c=arg->a+arg->b;
    return 0;
}

int sub_integer(struct threeintegers *arg)
{
    arg->c=arg->a-arg->b;
    return 0;
}

int add_float(struct threefloats *arg)
{
    arg->c=arg->a+arg->b;
    return 0;
}

int sub_float(struct threefloats *arg)
{
    arg->c=arg->a-arg->b;
    return 0;
}