/* trochoids.c

   Magic tools to draw various centered trochoids;
   similar to art generated by devices like the
   Spirograph and Wondergraph.

   by Bill Kendrick <bill@newbreedsoftware.com>
   with help from Pere Pujal Carabantes

   January 6, 2024 - January 26, 2024
*/

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

#include "tp_magic_api.h"
#include "SDL_image.h"
#include "SDL_mixer.h"

#define deg_cos(x) cosf((float) (x) * M_PI / 180.0)
#define deg_sin(x) sinf((float) (x) * M_PI / 180.0)

/* All _possible_ tools */
enum
{
  TOOL_EPITROCHOID_SIZES,
  TOOL_EPITROCHOID_NOSIZES_1,
  TOOL_EPITROCHOID_NOSIZES_2,
  TOOL_EPITROCHOID_NOSIZES_3,
  TOOL_HYPOTROCHOID_SIZES,
  TOOL_HYPOTROCHOID_NOSIZES_1,
  TOOL_HYPOTROCHOID_NOSIZES_2,
  TOOL_HYPOTROCHOID_NOSIZES_3,
  NUM_TOOLS
};

Uint8 tp_offers_sizes = 1;

int num_tools[2] = {
  6,                            /* when sizes not available */
  2,                            /* when sizes available */
};

int *which_to_tool;

int which_to_tool_per_size_availability[2][6] = {
  /* when sizes not available */
  {
   TOOL_EPITROCHOID_NOSIZES_1,
   TOOL_EPITROCHOID_NOSIZES_2,
   TOOL_EPITROCHOID_NOSIZES_3,
   TOOL_HYPOTROCHOID_NOSIZES_1,
   TOOL_HYPOTROCHOID_NOSIZES_2,
   TOOL_HYPOTROCHOID_NOSIZES_3,
   },
  /* when sizes available */
  {
   TOOL_EPITROCHOID_SIZES,
   TOOL_HYPOTROCHOID_SIZES,
   -1,
   -1,
   -1,
   -1,
   },
};

#define SIZE_WELLINSIDE 0.33
#define SIZE_INSIDE 0.66
#define SIZE_EDGE 1.00
#define SIZE_OUTSIDE 1.50
#define SIZE_WELLOUTSIDE 2.00
#define NUM_SIZES 5

float trochoids_sizes_per_size_setting[NUM_SIZES] = {
  SIZE_WELLINSIDE,
  SIZE_INSIDE,
  SIZE_EDGE,
  SIZE_OUTSIDE,
  SIZE_WELLOUTSIDE,
};

/* Default to "SIZE_EDGE" */
#define DEFAULT_SIZE 3

float trochoids_sizes_per_tool[NUM_TOOLS] = {
  0,                            // N/A; size controls available
  SIZE_INSIDE,
  SIZE_EDGE,
  SIZE_WELLOUTSIDE,
  0,                            // N/A; size controls available
  SIZE_INSIDE,
  SIZE_EDGE,
  SIZE_WELLOUTSIDE,
};

const char *icon_filenames[NUM_TOOLS] = {
  "epitrochoid_edge.png",       /* use "edge" variation when sizes are available */
  "epitrochoid_inside.png",
  "epitrochoid_edge.png",
  "epitrochoid_outside.png",
  "hypotrochoid_edge.png",      /* use "edge" variation when sizes are available */
  "hypotrochoid_inside.png",
  "hypotrochoid_edge.png",
  "hypotrochoid_outside.png",
};


const char *tool_names[NUM_TOOLS] = {
  gettext_noop("Epitrochoid"),
  gettext_noop("Epitrochoid Inside"),
  gettext_noop("Epitrochoid Edge"),
  gettext_noop("Epitrochoid Outside"),
  gettext_noop("Hypotrochoid"),
  gettext_noop("Hypotrochoid Inside"),
  gettext_noop("Hypotrochoid Edge"),
  gettext_noop("Hypotrochoid Outside"),
};


const char *tool_descriptions[NUM_TOOLS] = {
  /* Epitrochoids */
  gettext_noop
    ("Click to start drawing an epitrochoid. Drag left/right to change the size of the fixed circle, and up/down to change the size of the circle rolling outside of it. Use the size option to change where the pen is."),
  gettext_noop
    ("Click to start drawing an epitrochoid. Drag left/right to change the size of the fixed circle, and up/down to change the size of the circle rolling outside of it. Then pen is within the rolling circle."),
  gettext_noop
    ("Click to start drawing an epitrochoid. Drag left/right to change the size of the fixed circle, and up/down to change the size of the circle rolling outside of it. Then pen is on the edge of the rolling circle."),
  gettext_noop
    ("Click to start drawing an epitrochoid. Drag left/right to change the size of the fixed circle, and up/down to change the size of the circle rolling outside of it. Then pen is outside the rolling circle."),
  /* Hypotrochoids */
  gettext_noop
    ("Click to start drawing a hypotrochoid. Drag left/right to change the size of the fixed circle, and up/down to change the size of the circle rolling inside it. Use the size option to change where the pen is."),
  gettext_noop
    ("Click to start drawing a hypotrochoid. Drag left/right to change the size of the fixed circle, and up/down to change the size of the circle rolling inside it. Then pen is within the rolling circle."),
  gettext_noop
    ("Click to start drawing a hypotrochoid. Drag left/right to change the size of the fixed circle, and up/down to change the size of the circle rolling inside it. Then pen is on the edge of the rolling circle."),
  gettext_noop
    ("Click to start drawing a hypotrochoid. Drag left/right to change the size of the fixed circle, and up/down to change the size of the circle rolling inside it. Then pen is outside the rolling circle."),
};


/* Sound effects (same for everyone) */
enum
{
  SND_DRAG,
  SND_RELEASE_EPITROCHOID,
  SND_RELEASE_HYPOTROCHOID,
  NUM_SNDS
};

Mix_Chunk *sound_effects[NUM_SNDS];

const char *sound_filenames[NUM_SNDS] = {
  "trochoids_drag.ogg",
  "epitrochoid.ogg",
  "hypotrochoid.ogg",
};

Uint8 trochoids_size = 1;
int trochoids_x, trochoids_y, dragged = 0;
Uint32 trochoids_color = 0x00000000;
int rotator_anim_a = 0;

/* Function prototypes: */
Uint32 trochoids_api_version(void);
int trochoids_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_level);
int trochoids_get_tool_count(magic_api * api);
SDL_Surface *trochoids_get_icon(magic_api * api, int which);
char *trochoids_get_name(magic_api * api, int which);
int trochoids_get_group(magic_api * api, int which);
int trochoids_get_order(int which);
char *trochoids_get_description(magic_api * api, int which, int mode);
int trochoids_requires_colors(magic_api * api, int which);
int trochoids_modes(magic_api * api, int which);
Uint8 trochoids_accepted_sizes(magic_api * api, int which, int mode);
Uint8 trochoids_default_size(magic_api * api, int which, int mode);
void trochoids_shutdown(magic_api * api);
void trochoids_click(magic_api * api, int which, int mode,
                     SDL_Surface * canvas, SDL_Surface * snapshot, int x, int y, SDL_Rect * update_rect);
void trochoids_drag(magic_api * api, int which, SDL_Surface * canvas,
                    SDL_Surface * snapshot, int old_x, int old_y, int x, int y, SDL_Rect * update_rect);
void trochoids_work(magic_api * api, int which, SDL_Surface * canvas,
                    SDL_Surface * snapshot, int x, int y, SDL_Rect * update_rect, int guides);
void trochoids_release(magic_api * api, int which, SDL_Surface * canvas,
                       SDL_Surface * snapshot, int x, int y, SDL_Rect * update_rect);
void trochoids_sound(magic_api * api, int snd_idx, int x, int y);
void trochoids_set_color(magic_api * api, int which, SDL_Surface * canvas,
                         SDL_Surface * snapshot, Uint8 r, Uint8 g, Uint8 b, SDL_Rect * update_rect);
void trochoids_set_size(magic_api * api, int which, int mode,
                        SDL_Surface * canvas, SDL_Surface * last, Uint8 size, SDL_Rect * update_rect);
void trochoids_line_callback(void *pointer, int tool, SDL_Surface * canvas, SDL_Surface * snapshot, int x, int y);
void trochoids_xorline_callback(void *pointer, int tool, SDL_Surface * canvas, SDL_Surface * snapshot, int x, int y);
void trochoids_switchin(magic_api * api, int which, int mode, SDL_Surface * canvas);
void trochoids_switchout(magic_api * api, int which, int mode, SDL_Surface * canvas);
int calc_lcm(int a, int b);


Uint32 trochoids_api_version(void)
{
  return (TP_MAGIC_API_VERSION);
}


int trochoids_init(magic_api *api, Uint8 disabled_features, Uint8 complexity_level ATTRIBUTE_UNUSED)
{
  int i;
  char filename[1024];

  for (i = 0; i < NUM_SNDS; i++)
  {
    sound_effects[i] = NULL;
  }

  if (disabled_features & MAGIC_FEATURE_SIZE)
  {
    tp_offers_sizes = 0;
  }
  else
  {
    tp_offers_sizes = 1;
  }

  which_to_tool = which_to_tool_per_size_availability[tp_offers_sizes];

  for (i = 0; i < NUM_SNDS; i++)
  {
    snprintf(filename, sizeof(filename), "%ssounds/magic/%s", api->data_directory, sound_filenames[i]);
    sound_effects[i] = Mix_LoadWAV(filename);
  }

  return (1);
}


int trochoids_get_tool_count(magic_api *api ATTRIBUTE_UNUSED)
{
  return (num_tools[tp_offers_sizes]);
}


SDL_Surface *trochoids_get_icon(magic_api *api, int which)
{
  char filename[1024];

  snprintf(filename, sizeof(filename), "%simages/magic/%s", api->data_directory, icon_filenames[which_to_tool[which]]);

  return (IMG_Load(filename));
}


char *trochoids_get_name(magic_api *api ATTRIBUTE_UNUSED, int which)
{
  return (strdup(gettext(tool_names[which_to_tool[which]])));
}


int trochoids_get_group(magic_api *api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED)
{
  return (MAGIC_TYPE_ARTISTIC);
}

int trochoids_get_order(int which)
{
  /* Group in their own spot, ordered the way the appear in the "TOOL_..." `enum` */
  return 10000 + which;
}


char *trochoids_get_description(magic_api *api ATTRIBUTE_UNUSED, int which, int mode ATTRIBUTE_UNUSED)
{
  return (strdup(gettext(tool_descriptions[which_to_tool[which]])));
}


int trochoids_requires_colors(magic_api *api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED)
{
  return 1;
}


int trochoids_modes(magic_api *api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED)
{
  return MODE_PAINT;
}

Uint8 trochoids_accepted_sizes(magic_api *api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED, int mode ATTRIBUTE_UNUSED)
{
  return NUM_SIZES;
}


Uint8 trochoids_default_size(magic_api *api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED, int mode ATTRIBUTE_UNUSED)
{
  return DEFAULT_SIZE;
}


void trochoids_shutdown(magic_api *api ATTRIBUTE_UNUSED)
{
  int i;

  for (i = 0; i < NUM_SNDS; i++)
  {
    if (sound_effects[i] != NULL)
    {
      Mix_FreeChunk(sound_effects[i]);
    }
  }
}


void trochoids_click(magic_api *api, int which, int mode ATTRIBUTE_UNUSED,
                     SDL_Surface *canvas, SDL_Surface *snapshot, int x, int y, SDL_Rect *update_rect)
{
  trochoids_x = x;
  trochoids_y = y;
  trochoids_drag(api, which, canvas, snapshot, x, y, x + (canvas->w / 20), y + (canvas->h / 20), update_rect);
  dragged = 0;
}


/* Affect the canvas on drag: */
void trochoids_drag(magic_api *api, int which,
                    SDL_Surface *canvas, SDL_Surface *snapshot,
                    int old_x ATTRIBUTE_UNUSED, int old_y ATTRIBUTE_UNUSED, int x, int y, SDL_Rect *update_rect)
{
  dragged = 1;
  trochoids_work(api, which, canvas, snapshot, x, y, update_rect, 1);
  trochoids_sound(api, SND_DRAG, x, y);
}

void trochoids_work(magic_api *api, int which,
                    SDL_Surface *canvas, SDL_Surface *snapshot, int x, int y, SDL_Rect *update_rect, int guides)
{
  int R, r, d, LCM;
  int px, py, px2, py2;
  float a, r_ratio, size;
  int xx, yy;

  which = which_to_tool[which];

  /* Drag left/right to change radius of stator (fixed circle) */
  R = abs(trochoids_x - x);
  if (R < 20)
  {
    R = 20;
  }

  R = (R / 10) * 10;

  /* Drag down to increase radius of rotator (rolling circle) */
  r = abs(y - trochoids_y);
  if (r < 10)
  {
    r = 10;
  }

  r = (r / 10) * 10;

  if (which == TOOL_HYPOTROCHOID_SIZES ||
      which == TOOL_HYPOTROCHOID_NOSIZES_1 ||
      which == TOOL_HYPOTROCHOID_NOSIZES_2 || which == TOOL_HYPOTROCHOID_NOSIZES_3)
  {
    /* Hypotrochoid */
    if (R == r)
    {
      r += 10;
    }

    r_ratio = (float)(R - r) / (float)r;
  }
  else
  {
    /* Epitrochoid */
    r_ratio = (float)(R + r) / (float)r;
  }

  /* Size option (or use of alternate tools, if --nomagicsizes)
     determines the distance from the center of the rotator
     that the pen draws */
  if (tp_offers_sizes)
  {
    size = trochoids_sizes_per_size_setting[trochoids_size];
  }
  else
  {
    size = trochoids_sizes_per_tool[which];
  }
  d = r * size;

  /* Erase old before drawing new */

  update_rect->x = 0;
  update_rect->y = 0;
  update_rect->w = canvas->w;
  update_rect->h = canvas->h;

  SDL_BlitSurface(snapshot, update_rect, canvas, update_rect);


  /* Draw the lines */
  LCM = calc_lcm(r, R);

  for (a = 0; a < 360.0 * (float)(LCM / R); a++)
  {
    float a2 = (a + 1);

    if (which == TOOL_HYPOTROCHOID_SIZES ||
        which == TOOL_HYPOTROCHOID_NOSIZES_1 ||
        which == TOOL_HYPOTROCHOID_NOSIZES_2 || which == TOOL_HYPOTROCHOID_NOSIZES_3)
    {
      /* Hypotrochoid */
      px = trochoids_x + (((R - r) * deg_cos(a)) + (d * deg_cos(r_ratio * a)));
      py = trochoids_y + (((R - r) * deg_sin(a)) - (d * deg_sin(r_ratio * a)));
      px2 = trochoids_x + (((R - r) * deg_cos((a2))) + (d * deg_cos(r_ratio * a2)));
      py2 = trochoids_y + (((R - r) * deg_sin((a2))) - (d * deg_sin(r_ratio * a2)));
    }
    else
    {
      /* Epitrochoid */
      px = trochoids_x + (((R + r) * deg_cos(a)) - (d * deg_cos(r_ratio * a)));
      py = trochoids_y + (((R + r) * deg_sin(a)) - (d * deg_sin(r_ratio * a)));
      px2 = trochoids_x + (((R + r) * deg_cos((a2))) - (d * deg_cos(r_ratio * a2)));
      py2 = trochoids_y + (((R + r) * deg_sin((a2))) - (d * deg_sin(r_ratio * a2)));
    }

    api->line((void *)api, which, canvas, snapshot, px, py, px2, py2,
              (20 * (guides && (a >= 360.0))) + 1, trochoids_line_callback);
  }

  if (guides)
  {
    int guide_spacing;

    /* When still dragging (before release), draw some "guides",
       showing the mechanism that would be used to generate the pattern */
    rotator_anim_a = (int)(atan2(y - trochoids_y, x - trochoids_x) / M_PI * 180.0);

    /* Stator (fixed circle) */
    guide_spacing = 360 / R;
    if (guide_spacing < 2)
    {
      guide_spacing = 2;
    }

    for (a = 0; a < 360; a = a + guide_spacing)
    {
      px = (int)((float)trochoids_x + ((float)R * deg_cos(a)));
      py = (int)((float)trochoids_y - ((float)R * deg_sin(a)));
      api->putpixel(canvas, px, py, 0);
      api->putpixel(canvas, px + 1, py, 0xff);
      api->putpixel(canvas, px, py + 1, 0);
      api->putpixel(canvas, px + 1, py + 1, 0xff);
    }

    /* Rotator (rolling circle) */
    guide_spacing = 360 / r;
    if (guide_spacing < 2)
    {
      guide_spacing = 2;
    }

    for (a = 0; a < 360; a = a + guide_spacing)
    {
      if (which == TOOL_HYPOTROCHOID_SIZES ||
          which == TOOL_HYPOTROCHOID_NOSIZES_1 ||
          which == TOOL_HYPOTROCHOID_NOSIZES_2 || which == TOOL_HYPOTROCHOID_NOSIZES_3)
      {
        /* Hypotrochoid */
        px = (int)((float)trochoids_x + ((R - r) * deg_cos(rotator_anim_a)) + ((float)-r * deg_cos(a)));
        py = (int)((float)trochoids_y + ((R - r) * deg_sin(rotator_anim_a)) - ((float)-r * deg_sin(a)));
      }
      else
      {
        /* Epitrochoid */
        px = (int)((float)trochoids_x + ((R + r) * deg_cos(rotator_anim_a)) + ((float)r * deg_cos(a)));
        py = (int)((float)trochoids_y + ((R + r) * deg_sin(rotator_anim_a)) - ((float)r * deg_sin(a)));
      }
      api->xorpixel(canvas, px, py);
      api->xorpixel(canvas, px + 1, py);
      api->xorpixel(canvas, px, py + 1);
      api->xorpixel(canvas, px + 1, py + 1);

    }

    /* Pen */
    if (which == TOOL_HYPOTROCHOID_SIZES ||
        which == TOOL_HYPOTROCHOID_NOSIZES_1 ||
        which == TOOL_HYPOTROCHOID_NOSIZES_2 || which == TOOL_HYPOTROCHOID_NOSIZES_3)
    {
      /* Hypotrochoid */
      px = trochoids_x + (((R - r) * deg_cos(rotator_anim_a)) + (d * deg_cos(360 - rotator_anim_a)));
      py = trochoids_y + (((R - r) * deg_sin(rotator_anim_a)) - (d * deg_sin(360 - rotator_anim_a)));

      px2 = trochoids_x + (((R - r) * deg_cos(rotator_anim_a)));
      py2 = trochoids_y + (((R - r) * deg_sin(rotator_anim_a)));
    }
    else
    {
      /* Epitrochoid */
      px = trochoids_x + (((R + r) * deg_cos(rotator_anim_a)) - (d * deg_cos(360 - rotator_anim_a)));
      py = trochoids_y + (((R + r) * deg_sin(rotator_anim_a)) - (d * deg_sin(360 - rotator_anim_a)));

      px2 = trochoids_x + (((R + r) * deg_cos(rotator_anim_a)));
      py2 = trochoids_y + (((R + r) * deg_sin(rotator_anim_a)));
    }

    api->line((void *)api, which, canvas, snapshot, px, py, px2, py2, 2, trochoids_line_callback);

    for (yy = -2; yy <= 2; yy++)
    {
      for (xx = -2; xx <= 2; xx++)
      {
        api->putpixel(canvas, px + xx, py + yy, trochoids_color);
      }
    }
  }
}


void trochoids_release(magic_api *api, int which,
                       SDL_Surface *canvas, SDL_Surface *snapshot, int x, int y, SDL_Rect *update_rect)
{
  int tool, snd_idx;

  /* (Stop dragging sound, or previous release sound if they just
     clicked (no drag) to make another shape quickly;
     the release sound effect lingers & we want to start playing again,
     otherwise it will seem like the sound only happens intermittently) */
  api->stopsound();

  /* Pick which sound to play & play it */
  tool = which_to_tool[which];
  if (tool == TOOL_EPITROCHOID_SIZES ||
      tool == TOOL_EPITROCHOID_NOSIZES_1 || tool == TOOL_EPITROCHOID_NOSIZES_2 || tool == TOOL_EPITROCHOID_NOSIZES_3)
  {
    snd_idx = SND_RELEASE_EPITROCHOID;
  }
  else
  {
    snd_idx = SND_RELEASE_HYPOTROCHOID;
  }
  trochoids_sound(api, snd_idx, x, y);


  /* If they clicked & released with no drag,
     ignore the (x,y) we received; we want the
     'default' offset to get a reasonably pleasant
     shape -- for users who tried clicking w/o dragging */
  if (dragged == 0)
  {
    if (tool == TOOL_EPITROCHOID_SIZES ||
        tool == TOOL_EPITROCHOID_NOSIZES_1 || tool == TOOL_EPITROCHOID_NOSIZES_2 || tool == TOOL_EPITROCHOID_NOSIZES_3)
    {
      x = trochoids_x + 50;
      y = trochoids_y + 20;
    }
    else
    {
      x = trochoids_x + 70;
      y = trochoids_y + 30;
    }
  }

  /* Draw it (no guides, this time!) */
  trochoids_work(api, which, canvas, snapshot, x, y, update_rect, 0);
}


/* Play a sound; volume and panning will be based
   on the size and position of the shape being generated
   by the user's UI interaction */
void trochoids_sound(magic_api *api, int snd_idx, int x, int y)
{
  int R, vol, pan;

  /* Volume based on the radii of the stator (fixed circle)
     and the rotator (rolling circle), combined; larger = louder */
  R = abs(trochoids_x - x) + abs(trochoids_y - y);
  if (R < 20)
  {
    R = 20;
  }
  else if (R > api->canvas_w)
  {
    R = api->canvas_w;
  }
  vol = (255 * R * 2) / api->canvas_w;
  if (vol > 255)
  {
    vol = 255;
  }

  /* Panning based on the left/right position of the center of the shape */
  pan = (trochoids_x * 255) / api->canvas_w;
  api->playsound(sound_effects[snd_idx], pan, vol);
}


void trochoids_set_color(magic_api *api ATTRIBUTE_UNUSED,
                         int which ATTRIBUTE_UNUSED,
                         SDL_Surface *canvas ATTRIBUTE_UNUSED,
                         SDL_Surface *snapshot ATTRIBUTE_UNUSED, Uint8 r,
                         Uint8 g, Uint8 b, SDL_Rect *update_rect ATTRIBUTE_UNUSED)
{
  trochoids_color = SDL_MapRGB(canvas->format, r, g, b);
}


void trochoids_set_size(magic_api *api ATTRIBUTE_UNUSED,
                        int which ATTRIBUTE_UNUSED, int mode ATTRIBUTE_UNUSED,
                        SDL_Surface *canvas ATTRIBUTE_UNUSED,
                        SDL_Surface *last ATTRIBUTE_UNUSED, Uint8 size, SDL_Rect *update_rect ATTRIBUTE_UNUSED)
{
  trochoids_size = (size - 1);  /* array index is 0-based, but Tux Paint returns between 1...{accepted sizes} */
}


void trochoids_line_callback(void *pointer ATTRIBUTE_UNUSED,
                             int tool ATTRIBUTE_UNUSED, SDL_Surface *canvas,
                             SDL_Surface *snapshot ATTRIBUTE_UNUSED, int x, int y)
{
  magic_api *api = (magic_api *) pointer;

  api->putpixel(canvas, x, y, trochoids_color);
}

void trochoids_xorline_callback(void *pointer ATTRIBUTE_UNUSED,
                                int tool ATTRIBUTE_UNUSED,
                                SDL_Surface *canvas, SDL_Surface *snapshot ATTRIBUTE_UNUSED, int x, int y)
{
  magic_api *api = (magic_api *) pointer;

  api->xorpixel(canvas, x, y);
  api->xorpixel(canvas, x + 1, y);
  api->xorpixel(canvas, x, y + 1);
  api->xorpixel(canvas, x + 1, y + 1);
}

void trochoids_switchin(magic_api *api ATTRIBUTE_UNUSED,
                        int which ATTRIBUTE_UNUSED, int mode ATTRIBUTE_UNUSED, SDL_Surface *canvas ATTRIBUTE_UNUSED)
{
}

void trochoids_switchout(magic_api *api ATTRIBUTE_UNUSED,
                         int which ATTRIBUTE_UNUSED, int mode ATTRIBUTE_UNUSED, SDL_Surface *canvas ATTRIBUTE_UNUSED)
{
}

int calc_lcm(int a, int b)
{
  int max;

  if (a > b)
  {
    max = a;
  }
  else
  {
    max = b;
  }

  while ((max % a) != 0 || (max % b) != 0)
  {
    max++;
  }

  return max;
}
