$fn = 72;

include <keyboard.scad>

module keyboard_base_plate(pcb_dimensions, pcb_screw_holes, switch_z_range) {
    pcb_width  = pcb_dimensions[0];
    pcb_length = pcb_dimensions[1];
    pcb_height = pcb_dimensions[2];

    switch_z_min = switch_z_range[0];
    switch_z_max = switch_z_range[1];

    pcb_clearance_edge   = 1.0;
    pcb_clearance_bottom = -switch_z_min - pcb_height + 0.5;

    pcb_screw_diameter      = 2.5;
    pcb_screw_hole_diameter = 2.5;
    pcb_screw_height        = 3.0;

    thickness     = 1.75;
    corner_radius = 0.2;

    case_color = [0.5, 0.5, 0.5, 1.0];

    wall_width  = pcb_width  + 2 * (pcb_clearance_edge + thickness) - 2 * corner_radius;
    wall_length = pcb_length + 2 * (pcb_clearance_edge + thickness) - 2 * corner_radius;
    wall_height = pcb_screw_height + pcb_height + switch_z_max;

    bottom_width  = 2 * (pcb_clearance_edge) + pcb_width;
    bottom_length = 2 * (pcb_clearance_edge) + pcb_length;
    bottom_height = thickness;

    module round_corner(rotation) {
        color(case_color)
        rotate(rotation)
        rotate_extrude(angle=90) {
            intersection() {
                circle(r=corner_radius);
                square(corner_radius*2);
            }
        }
    }

    module round_edge(rotation, length) {
        color(case_color)
        rotate(rotation)
        linear_extrude(length)
        intersection() {
            circle(r=corner_radius);
            square(corner_radius*2);
        }
    }

    module panel(dimensions) {
        color(case_color)
        linear_extrude(dimensions[2])
        square([dimensions[0], dimensions[1]], false);
    }

    module wall_corner(rotation, radius, length) {
        color(case_color)
        rotate(rotation)
        linear_extrude(length)
        intersection() {
            circle(r=radius);
            square([radius, radius], false);
        }
    }

    module screw_post(h, d) {
        diameter_outer = 3 * d;
        diameter_inner =     d;

        color(case_color)
        difference() {
            cylinder(h=h, r=(diameter_outer / 2.0) * 1.5);
            cylinder(h=h, r= diameter_inner / 2.0);
        }
    }

    module ridges(width, height) {
        horizontal = [
            (bottom_length / 3),
            (bottom_length / 3) * 2
        ];

        vertical = [
            (bottom_width / 3),
            (bottom_width / 3) * 2
        ];

        for (y = horizontal) {
            translate([0 - pcb_clearance_edge, y, 0])
            panel([bottom_width, width, height]);
        }

        for (x = vertical) {
            translate([x, 0 - pcb_clearance_edge, 0])
            panel([width, bottom_length, height]);
        }
    }

    /* Upper wall */

    translate([-pcb_clearance_edge - thickness + corner_radius,
                pcb_clearance_edge + pcb_length,
               -thickness + corner_radius])
    panel([wall_width, thickness, wall_height + thickness - corner_radius]);

    /* Right wall */
    translate([ pcb_clearance_edge + pcb_width,
               -pcb_clearance_edge - thickness + corner_radius,
               -thickness + corner_radius])
    panel([thickness, wall_length, wall_height + thickness - corner_radius]);

    /* Lower wall */
    translate([-pcb_clearance_edge - thickness + corner_radius,
               -pcb_clearance_edge - thickness,
               -thickness + corner_radius])
    panel([wall_width, thickness, wall_height + thickness - corner_radius]);

    /* Left wall */
    translate([-pcb_clearance_edge - thickness,
               -pcb_clearance_edge - thickness + corner_radius,
               -thickness + corner_radius])
    panel([thickness, wall_length, wall_height + thickness - corner_radius]);

    /* Upper right wall corner */
    translate([pcb_clearance_edge + thickness + pcb_width - corner_radius,
               pcb_clearance_edge + thickness + pcb_length - corner_radius,
              -thickness + corner_radius])
    wall_corner([0, 0, 0],
                corner_radius,
                wall_height + thickness - corner_radius);

    /* Lower right wall corner */
    translate([ pcb_clearance_edge + thickness + pcb_width - corner_radius,
                 -pcb_clearance_edge - thickness + corner_radius,
                 -thickness + corner_radius])
    wall_corner([0, 0, 270],
                corner_radius,
                wall_height + thickness - corner_radius);

    /* Lower left wall corner */
    translate([-pcb_clearance_edge - thickness + corner_radius,
               -pcb_clearance_edge - thickness + corner_radius,
               -thickness + corner_radius])
    wall_corner([0, 0, 180],
                corner_radius,
                wall_height + thickness - corner_radius);

    /* Upper left wall corner */
    translate([-pcb_clearance_edge - thickness + corner_radius,
                pcb_clearance_edge + pcb_length + thickness - corner_radius,
               -thickness + corner_radius])
    wall_corner([0, 0, 90],
                corner_radius,
                wall_height + thickness - corner_radius);

    /* Bottom plate */
    translate([-pcb_clearance_edge - thickness + corner_radius,
               -pcb_clearance_edge - thickness + corner_radius,
               -thickness])
    panel([bottom_width  + 2 * thickness - 2 * corner_radius,
           bottom_length + 2 * thickness - 2 * corner_radius,
           thickness]);

    /* Upper edge */
    translate([-pcb_clearance_edge - thickness + corner_radius,
                pcb_clearance_edge + thickness + pcb_length - corner_radius,
               -thickness + corner_radius])
    round_edge([0, 90, 0], wall_width);

    /* Right edge */
    translate([ pcb_clearance_edge  + thickness + pcb_width - corner_radius,
               -pcb_clearance_edge - thickness + corner_radius,
               -thickness + corner_radius])
    round_edge([270, 0, 0], wall_length);

    /* Lower edge */
    translate([-pcb_clearance_edge - thickness + corner_radius,
               -pcb_clearance_edge - thickness + corner_radius,
               -thickness + corner_radius])
    round_edge([90, 180, 90], wall_width);

    /* Left edge */
    translate([-pcb_clearance_edge - thickness + corner_radius,
               -pcb_clearance_edge - thickness + corner_radius,
               -thickness + corner_radius])
    round_edge([270, 90, 0], wall_length);

    /* Upper right corner */
    translate([pcb_clearance_edge + thickness + pcb_width - corner_radius,
               pcb_clearance_edge + thickness + pcb_length - corner_radius,
              -thickness + corner_radius])
    round_corner([90, 90, 90]);

    /* Lower right corner */
    translate([ pcb_clearance_edge + thickness + pcb_width - corner_radius,
               -pcb_clearance_edge - thickness + corner_radius,
               -thickness + corner_radius])
    round_corner([180, 90, 90]);

    /* Lower left corner */
    translate([-pcb_clearance_edge - thickness + corner_radius,
               -pcb_clearance_edge - thickness + corner_radius,
               -thickness + corner_radius])
    round_corner([-90, 90, 90]);

    /* Upper left corner */
    translate([-pcb_clearance_edge - thickness + corner_radius,
                pcb_clearance_edge + thickness + pcb_length - corner_radius,
               -thickness + corner_radius])
    round_corner([0, 90, 90]);

    /* Screw holes */
    for (screw_hole = pcb_screw_holes) {
        translate([screw_hole[0], screw_hole[1], 0])
        screw_post(pcb_screw_height,
                   pcb_screw_diameter);
    }

    /* Ridges (for rigidity!) */
    ridges(thickness * 2, pcb_clearance_bottom / 2);
}

keyboard_base_plate([keyboard_pcb_width, keyboard_pcb_length, keyboard_pcb_height],
                    keyboard_pcb_screw_holes,
                    [-keyboard_switch_leg_length, keyboard_switch_height]);