$fn = 72;

include <keyboard.scad>

module top_case(key_switch_sizes, pcb_screw_holes) {
    case_width_top     = 317.5000;
    case_width_bottom  = 320.0000;
    case_length_top    = 150.0000;
    case_length_bottom = 151.5000;

    wall_width  =  2.5000;
    wall_height = 17.2500;

    keyboard_x_offset = 12.2500;
    keyboard_y_offset = 12.2500;

    keyboard_deck_z_offset = wall_height - keyboard_switch_height;

    accent_width    =  1.0000;
    accent_depth    = 0.5;
    accent_y_stride = (keyboard_pcb_length - accent_width) / 5.0;
    accent_y_bottom = keyboard_y_offset;

    vent_width    =  2.0000;
    vent_length   = wall_width;
    vent_height   = 12.0000;
    vent_count    = 32;
    vent_x_first  = keyboard_x_offset + keyboard_pcb_width - vent_count * (vent_width + vent_width);
    vent_y_offset = case_length_bottom - vent_length;

    screw_post_diameter_inner  =  3.00;
    screw_post_diameter_outer  =  6.25;
    screw_post_corner_height   = 12.00;
    screw_post_middle_height   = 29.30;
    screw_post_upper_y_offset  = case_length_bottom - wall_width - 15.00;
    screw_post_middle_y_offset = 72.50;
    screw_post_lower_y_offset  = (keyboard_y_offset - 2 * wall_width) / 2 + wall_width;
    screw_post_x_offset        = (keyboard_x_offset - 2 * wall_width) / 2 + wall_width;

    eps = 0.01;

    module fascia() {
        difference() {
            cube([case_width_bottom, case_length_bottom, wall_width], false);

            translate([keyboard_x_offset, keyboard_y_offset, -eps])
            cube([keyboard_pcb_width, keyboard_pcb_length, wall_width + 2*eps], false);
        }
    }

    module vents() {
        for (i = [0:vent_count]) {
            x = vent_x_first + (i * (vent_width + vent_width));

            translate([x, vent_y_offset-eps, wall_height - vent_height])
            cube([vent_width, vent_length+2*eps, vent_height+eps], false);
        }
    }

    module accents() {
        for (y = [accent_y_bottom: accent_y_stride: case_length_bottom]) {
            /* Top */
            translate([-eps, y, wall_height - accent_depth])
            cube([case_width_bottom+2*eps, accent_width, accent_depth+eps], false);

            /* Right */
            translate([case_width_bottom - accent_depth, y, -eps])
            cube([accent_depth+eps, accent_width+eps, wall_height+2*eps], false);

            /* Left */
            translate([-eps, y, -eps])
            cube([accent_depth+eps, accent_width, wall_height+2*eps], false);
        }
    }

    module screw_posts() {
        module screw_post(h) {
            diameter_inner = 3.00;
            diameter_outer = 6.25;

            difference() {
                cylinder(h, d=diameter_outer);

                translate([0, 0, -eps])
                cylinder(h + 2*eps, d=diameter_inner);
            }
        }

        posts = [
            /* Upper row */
            [screw_post_x_offset,   screw_post_upper_y_offset, screw_post_corner_height],
            [case_width_bottom / 2, case_length_bottom - 10.0, screw_post_middle_height],
            [case_width_bottom - screw_post_x_offset, screw_post_upper_y_offset, screw_post_corner_height],

            /* Middle row */
            [screw_post_x_offset, screw_post_middle_y_offset, screw_post_corner_height],
            [case_width_bottom - screw_post_x_offset, screw_post_middle_y_offset, screw_post_corner_height],

            /* Bottom row */
            [screw_post_x_offset, screw_post_lower_y_offset, screw_post_corner_height],
            [case_width_bottom / 2, screw_post_lower_y_offset, screw_post_corner_height],
            [case_width_bottom - screw_post_x_offset, screw_post_lower_y_offset, screw_post_corner_height]
        ];

        for (post = posts) {
            translate([post[0], post[1], wall_height - wall_width - post[2] - eps])
            screw_post(post[2] + eps);
        }
    }

    module supports() {
        support_width  = 1.2500;
        support_height = keyboard_switch_height - wall_width;
        aspect_ratio   = 3.75 / 12.0;

        module support(dimensions, width) {
            length = dimensions[0];
            height = dimensions[1];

            module right_triangle(base) {
                hypot = sqrt(2*(base^2));

                intersection() {
                    square([base, base]);

                    translate([-base, 0, 0])
                    rotate([0, 0, -45])
                    square([hypot, hypot]);
                }
            }

            module shape() {
                /* Height ratio of lower aspect to upper aspect */
                aspect_upper_height = height;
                aspect_lower_height = aspect_ratio * height;

                /* The length of each individual support aspect */
                aspect_length = 1/3 * length;

                hypotenuse     = sqrt(2*(aspect_length^2));
                lower_x_offset = aspect_length - (hypotenuse - aspect_length);

                right_triangle(height);

                square([length, aspect_lower_height], false);

                translate([3 * aspect_length, 0, 0])
                mirror([1, 0, 0])
                right_triangle(height);
            }

            translate([0, length, 0])
            rotate([-90, 0, -90])
            linear_extrude(width)
            intersection() {
                shape();
                square([length, height], false);
            }
        }

        support_x_interval = (keyboard_pcb_width + 2 * wall_width - support_width) / 6;
        support_x_offset   =  keyboard_x_offset - wall_width;

        support_y_interval = (keyboard_pcb_length + 2 * wall_width - support_width) / 4;
        support_y_offset   =  keyboard_y_offset;

        /* Upper vertical supports */
        upper_support_length = case_length_bottom
                             - keyboard_pcb_length
                             - keyboard_y_offset
                             - 2 * wall_width;

        upper_support_y_offset = keyboard_y_offset
                               + keyboard_pcb_length
                               + wall_width;

        /* Lower vertical supports */
        lower_support_length   = keyboard_y_offset - 2 * wall_width;
        lower_support_y_offset = wall_width;

        /* Left horizontal supports */
        left_support_length   = keyboard_x_offset - 2 * wall_width;
        left_support_x_offset = wall_width;

        /* Right horizontal supports */
        right_support_length = case_width_bottom
                             - keyboard_pcb_width
                             - keyboard_x_offset
                             - 2 * wall_width;

        right_support_x_offset = keyboard_x_offset
                               + keyboard_pcb_width
                               + wall_width;

        for (x = [0: support_x_interval: keyboard_pcb_width + 2 * wall_width]) {
            translate([support_x_offset + x,
                       upper_support_y_offset - eps,
                       wall_height - wall_width])
            support([upper_support_length + 2*eps, support_height], support_width);

            translate([support_x_offset + x,
                       lower_support_y_offset - eps,
                       wall_height - wall_width])
            support([lower_support_length + 2*eps, support_height], support_width);
        }

        for (y = [0: support_y_interval: keyboard_pcb_length + 2 * wall_width]) {
            translate([right_support_x_offset - eps,
                       support_y_offset + y - wall_width + support_width,
                       wall_height - wall_width])
            rotate([0, 0, -90])
            support([right_support_length + 2*eps, support_height], support_width);

            translate([left_support_x_offset - eps,
                       support_y_offset + y - wall_width + support_width,
                       wall_height - wall_width])
            rotate([0, 0, -90])
            support([left_support_length + 2*eps, support_height], support_width);
        }
    }

    module body() {
        translate([0, 0, wall_height - wall_width])
        fascia();

        /* Upper */
        translate([0, case_length_bottom - wall_width, 0])
        cube([case_width_bottom, wall_width, wall_height], false);

        /* Right */
        translate([case_width_bottom - wall_width, 0, 0])
        cube([wall_width, case_length_bottom, wall_height], false);

        /* Lower */
        cube([case_width_bottom, wall_width, wall_height], false);

        /* Left */
        cube([wall_width, case_length_bottom, wall_height], false);
    }

    difference() {
        body();
        accents();
        vents();
    }

    supports();
    screw_posts();

    translate([keyboard_x_offset, keyboard_y_offset, keyboard_deck_z_offset])
    keyboard_deck(wall_width);
}

top_case(keyboard_switch_sizes, keyboard_pcb_screw_holes);