#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <math.h>

static void usage(const char *prog)
{
    fprintf(stderr,
        "Usage:\n"
        "  %s --x <width> --y <height> --s <square_side>\n"
        "  %s --x <width> --s <square_side>\n"
        "  %s --y <height> --s <square_side>\n"
        "Short forms: -x, -y, -s\n",
        prog, prog, prog);
}

static int can_fit(double w, double h, double s, double theta)
{
    double c = cos(theta);
    double t = sin(theta);

    /* Bounding box of rotated rectangle about its center:
       width'  = w * fabs(c) + h * fabs(t)
       height' = w * fabs(t) + h * fabs(c)  [web:9] */
    double bw = w * fabs(c) + h * fabs(t);
    double bh = w * fabs(t) + h * fabs(c);

    return (bw <= s + 1e-12 && bh <= s + 1e-12);
}

int main(int argc, char *argv[])
{
    double X = 0.0, Y = 0.0, S = 0.0;
    int have_x = 0, have_y = 0, have_s = 0;

    static struct option long_opts[] = {
        { "x",    required_argument, 0, 'x' },
        { "y",    required_argument, 0, 'y' },
        { "s",    required_argument, 0, 's' },
        { "help", no_argument,       0, 'h' },
        { 0, 0, 0, 0 }
    };

    int opt;
    int opt_index = 0;

    while ((opt = getopt_long(argc, argv, "x:y:s:h", long_opts, &opt_index)) != -1) {
        switch (opt) {
        case 'x':
            X = atof(optarg);
            have_x = 1;
            break;
        case 'y':
            Y = atof(optarg);
            have_y = 1;
            break;
        case 's':
            S = atof(optarg);
            have_s = 1;
            break;
        case 'h':
            usage(argv[0]);
            return 0;
        default:
            usage(argv[0]);
            return 1;
        }
    }

    if (!have_s) {
        fprintf(stderr, "Error: --s <square_side> is required.\n");
        usage(argv[0]);
        return 1;
    }

    if (S <= 0.0) {
        fprintf(stderr, "Error: square side must be positive.\n");
        return 1;
    }

    /* Case A: only X is given, compute max Y. */
    if (have_x && !have_y) {
        if (X <= 0.0) {
            fprintf(stderr, "Error: X must be positive.\n");
            return 1;
        }

        /* Axis-aligned limit: Y <= S. */
        double y_axis = S;

        /* 45-degree limit: X + Y <= S*sqrt(2). [web:17] */
        double y_rot = S * M_SQRT2 - X;

        double y_max;
        int use_axis = 0, use_rot = 0;

        if (y_axis > 0.0)
            use_axis = 1;
        if (y_rot > 0.0)
            use_rot = 1;

        if (!use_axis && !use_rot) {
            printf("No positive Y fits for X = %.3f and S = %.3f.\n", X, S);
            return 0;
        }

        if (use_axis && use_rot)
            y_max = (y_axis < y_rot) ? y_axis : y_rot;
        else if (use_axis)
            y_max = y_axis;
        else
            y_max = y_rot;

        if (X <= S) {
          printf("Given X = %.3f, S = %.3f\n", X, S);
          printf("Maximum Y that fits at 0 degrees rotation is %.3f", S);
        }
        {
          Y = S*sqrtf(2.0);
          for (;;) {
            /* Binary search smallest angle in [0, pi/4] that fits. [web:11][web:13] */
            double lo = 0.0, mid, hi = M_PI / 4.0, theta, degrees;
            for (int i = 0; i < 80; ++i) { /* enough for ~1e-12 rad precision */
                mid = 0.5 * (lo + hi);
                if (can_fit(X, Y, S, mid)) hi = mid; else lo = mid;
            }

            theta = hi;
            if (can_fit(X, Y, S, theta)) {
              degrees = theta * 180.0 / M_PI;
              if (Y > S) printf(" and when rotated by %.3f degrees is %.3f", degrees, Y);
              break;
            }

            Y -= 1;
            if (Y <= 0) {
              printf("\nA rectangle with a width of %.3f cannot fit on a build plate of %.3f x %.3f at any rotation.", Y, S, S);
              break;
            }
          }
        }
        printf("\n");
        
        return 0;
    }

    /* Case B: only Y is given, compute max X. */
    if (!have_x && have_y) {
        if (Y <= 0.0) {
            fprintf(stderr, "Error: Y must be positive.\n");
            return 1;
        }

        /* Axis-aligned limit: X <= S. */
        double x_axis = S;

        /* 45-degree limit: X + Y <= S*sqrt(2). [web:17] */
        double x_rot = S * M_SQRT2 - Y;

        double x_max;
        int use_axis = 0, use_rot = 0;

        if (x_axis > 0.0)
            use_axis = 1;
        if (x_rot > 0.0)
            use_rot = 1;

        if (!use_axis && !use_rot) {
            printf("No positive X fits for Y = %.3f and S = %.3f.\n", Y, S);
            return 0;
        }

        if (use_axis && use_rot)
            x_max = (x_axis < x_rot) ? x_axis : x_rot;
        else if (use_axis)
            x_max = x_axis;
        else
            x_max = x_rot;

        printf("Given Y = %.3f, S = %.3f\n", Y, S);
        printf("Maximum X that fits (0 degrees or 45 degrees): %.3f\n", x_max);
        return 0;
    }

    /* Case C: both X and Y given -> original behavior. */
    if (!have_x || !have_y) {
        fprintf(stderr, "Error: must supply either (X and Y) or exactly one of them.\n");
        usage(argv[0]);
        return 1;
    }

    if (X <= 0.0 || Y <= 0.0) {
        fprintf(stderr, "Error: X and Y must be positive.\n");
        return 1;
    }

    /* Axis-aligned check. */
    if (X <= S && Y <= S) {
      printf("A %.3f x %.3f object fits trivially in a %.3f x %.3f built plate.\n", X, Y, S, S);
        //printf("Rotation angle: 0.0 degrees\n");
        //printf("Bounding box size: %.3f x %.3f\n", X, Y);
        //printf("Place bounding box with min corner at (%.3f, %.3f)\n", (S - X) * 0.5, (S - Y) * 0.5);
        return 0;
    }

    {
      /* Binary search smallest angle in [0, pi/4] that fits. [web:11][web:13] */
      double lo = 0.0, mid, hi = M_PI / 4.0, theta, degrees;
      for (int i = 0; i < 80; ++i) { /* enough for ~1e-12 rad precision */
          mid = 0.5 * (lo + hi);
          if (can_fit(X, Y, S, mid)) hi = mid; else lo = mid;
      }

      theta = hi;
      if (can_fit(X, Y, S, theta)) {
        degrees = theta * 180.0 / M_PI;
        printf("A %.3f x %.3f rectangular object can fit on a %.3f x %.3f build plate "
               "at any angle between %.3f", X, Y, S, S, degrees);
        lo = theta; hi = M_PI / 4.0;
        for (int i = 0; i < 80; ++i) { /* enough for ~1e-12 rad precision */
            mid = 0.5 * (lo + hi);
            if (can_fit(X, Y, S, mid)) lo = mid; else hi = mid;
        }
        theta = hi; degrees = theta * 180.0 / M_PI;
        printf(" and %.3f degrees.\n", degrees);
        return 0;
      }
    }
    /* 45-degree case: bounding box side W = (X + Y)*sqrt(2)/2. [web:17] */
    {
        const double SQRT2_OVER_2 = M_SQRT1_2;
        double W = (X + Y) * SQRT2_OVER_2;

        if (W <= S) {
            double angle_deg = 45.0;
            double bx = (S - W) * 0.5;
            double by = (S - W) * 0.5;

            printf("A %.3f x %.3f rectangular object can fit on a %.3f x %.3f build plate "
                   "at 45 degrees.\n", X, Y, S, S);
            //printf("Rotation angle: %.3f degrees\n", angle_deg);
            printf("Bounding box size at 45 degrees is %.3f x %.3f\n", W, W);
            //printf("Place bounding box with min corner at (%.3f, %.3f)\n", bx, by);

            return 0;
        }
    }

    printf("A %.3f x %.3f rectangular object cannot fit in a %.3f x %.3f build plate.\n", X, Y, S, S);
    return 0;
}
