/* demo.c
 *   A demo C program to explore machine level code including
 *   a recursive function and a binary data structure on the heap.
 *   See ./_readme_demo.txt for all the details.
 * Jim Mahoney | Oct 2020 | cs.bennington.college | MIT License
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef unsigned char *byte_pointer;

typedef struct _node *node; // a "node" is a pointer to "struct _node"
struct _node {              // a "struct _node" contains a value and a node.
  char name;
  node right;
  node left;
};

node new_node(char name, node left, node right){
  // Create and return a new node.
  node result = malloc(sizeof(struct _node));
  result->name = name;     // same as (*result).value = value
  result->left = left;
  result->right = right;
  return result;
}

node make_tree(){
  // Create and return the root of a binary tree that looks like this:
  //     a
  //    / \
  //   b   c
  //      / \
  //     d   e
  node e = new_node('e', NULL, NULL);
  node d = new_node('d', NULL, NULL);
  node c = new_node('c', d, e);
  node b = new_node('b', NULL, NULL);
  node a = new_node('a', b, c);
  return a;
}

void print_tree(node root){
  // print a tree as (name node node), e.g. (a (b) (c (e) (f)))"
  if (root){
    printf(" (%c", root->name);
    print_tree(root->left);
    print_tree(root->right);
    printf(")");
  }
}

void print_map_node(node n){
  // display memory map - address and bytes - for a node
  // sizeof(struct node) is 3*8 bytes
  byte_pointer ptr = (byte_pointer) n;
  int i, j;
  printf(" node %c at %p : \n", n->name, n);
  for (i=0; i<3; i++){
    printf("   %p : ", ptr);
    for (j=0; j<8; j++) printf("%.2x ", *(ptr+j));
    printf("    ");
    for (j=0; j<8; j++) printf("%c ", *(ptr+j));
    printf("\n");
    ptr += 8;
  }
}

int fibbo(int n){
  if (n < 2) return 1;
  return fibbo(n-1) + fibbo(n-2);
}
  
void swap(int *xp, int *yp){
  int t0, t1;
  t0 = *xp; 
  t1 = *yp;
  *xp = t1;  
  *yp = t0;
}

int swap_and_stuff(int* a_ptr, int* b_ptr, int c, int d, int e, int f, int g){
  int result;
  swap(a_ptr, b_ptr); 
  result = c * (*a_ptr) + (*b_ptr) + (3 * d + 4 * e + 5 * f + 6 * g);
  printf("   address of g in swap_and_stuff is %p \n", &g);
  return result;
}

void part0(){
  char input[100];
  int n_inputs;
  char input_format[] = "%s";
  printf("-- part 0 --\n");
  printf(" inputs[] is at %p \n", (void*) input);
  printf(" What is your favorite color? ");
  if (0){
    n_inputs = scanf(input_format, input);
    if (n_inputs == 1){ printf(" You said '%s'. \n", input); }
    else { printf(" Oops: scanf error \n"); }
  } else {
    printf(" ... never mind. ;) \n");
  }
}

void part1(){
  int n1 = 12, n2 = 34, n3 = 5, n4;
  printf("-- part1 --\n");
  printf(" before: n1 = %d, n2 = %d, n3 = %d, n4 = %d \n", n1, n2, n3, n4);
  n4 = swap_and_stuff(&n1, &n2, n3, 1+n1, 2+n2, 3+n3, 13);
  printf(" after: n1 = %d, n2 = %d, n3 = %d, n4 = %d \n", n1, n2, n3, n4);
}

void part2(){
  int f5 = fibbo(5);
  printf("-- part2 --\n");
  printf(" fibbo(5) is %d \n", f5);
}

void part3(){
  printf("-- part3 --\n");
  node tree = make_tree();
  print_tree(tree); printf("\n");
  print_map_node(tree); 
  print_map_node(tree->left);
  print_map_node(tree->right);
}

// declared before "main" so we can call it from within main ...
void part4(); 

int main(){
  printf("It's another demo.c !!!\n");
  part0();
  part1();
  part2();
  part3();
  part4();
  printf("(Are we having fun yet?)\n");
  return 0;
}

// ... implemented after "main" so we can refer to main's location.
void part4(){
  printf("-- part4 --\n");
  printf(" some function locations : \n");
  printf("   main is at %p \n", (void*) main);
  printf("   part0 is at %p \n", (void*) part0);  
  printf("   part1 is at %p \n", (void*) part1);  
  printf("   part2 is at %p \n", (void*) part2);  
  printf("   part3 is at %p \n", (void*) part3);  
  printf("   part4 is at %p \n", (void*) part4);
  printf("   new_node is at %p \n", (void*) new_node);    
  printf("   fibbo is at %p \n", (void*) fibbo);    
  printf("   swap is at %p \n", (void*) swap);    
  printf("   printf is at %p \n", (void*) printf);
}