/*
    This file is part of SBC Case Builder https://github.com/hominoids/SBC_Case_Builder
    Copyright 2022,2023,2024 Edward A. Kisiel hominoid@cablemi.com

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>
    Code released under GPLv3: http://www.gnu.org/licenses/gpl.html

    pcb_holder(size, wallthick)
    nut_holder(nut, style, dia_x, dia_y, height)
    vu_holder(vu_model, side, vesa, cheight)

*/

/*
           NAME: pcb_holder
    DESCRIPTION: pcb bottom edge holder
           TODO: none

          USAGE: pcb_holder(size, wallthick)

                           size = width of holder
                      wallthick = holder wall thickness
*/

module pcb_holder(size, wallthick) {

    adj=.01;
    $fn = 90;    
    difference() {
        union() {
            translate([-1.85,-1.75,0]) cube([size[0]+3.5,5,6]);
                translate([size[0]+1.65,-5.75,1]) 
                    rotate([0,-90,0]) 
                    linear_extrude(height = size[0]+3.5) 
                        polygon(points = [ [-wallthick/2,-wallthick/2],
                            [2,wallthick], 
                            [4,4], 
                            [-wallthick/2,4]]);
                translate([-1.85,4,1]) 
                    rotate([0,-90,180]) 
                    linear_extrude(height = size[0]+3.5) 
                        polygon(points = [ [-wallthick/2,-wallthick/2],
                            [2,wallthick], 
                            [2,2], 
                            [-wallthick/2,2]]);
        }
        translate([-.5,0,2]) cube([size[0]+1,size[2],5]);
        translate([6,-adj-5-1.75,-adj]) cube([size[0]-12,14,8]);
    }
}


/*
           NAME: nut_holder
    DESCRIPTION: creates various nut holders
           TODO: none

          USAGE: nut_holder(nut, style, dia_x, dia_y, height)

                            nut = "m2", "m2.5", "m3", "m4"
                          style = "default", "sloped", "trap"
                          dia_x = top diameter or x size in mm
                          dia_y = bottom diameter or y size in mm
                         height = holder height in mm
*/

module nut_holder(nut, style, dia_x, dia_y, height) {

nuts = [[2,4,1.6],         // m2 size, diameter, height
        [2.5,5,2],         // m2.5 size, diameter, height
        [3,5.5,2.4],       // m3 size, diameter, height
        [4,7,3.2]];        // m4 size, diameter, height

$fn = 180;

    if( style == "default") {
        difference() {
            cylinder(d=dia_x, h=height);
            if(nut == "m2") {
                translate([0, 0, -1]) cylinder(d=nuts[0][0]+.25, h=height+2);
                translate([0, 0, 2]) cylinder(d=nuts[0][1]*2/sqrt(3), h=height, $fn=6);
            }
            if(nut == "m2.5") {
                translate([0, 0, -1]) cylinder(d=nuts[1][0]+.25, h=height+2);
                translate([0, 0, 2]) cylinder(d=nuts[1][1]*2/sqrt(3), h=height, $fn=6);
            }
            if(nut == "m3") {
                translate([0, 0, -1]) cylinder(d=nuts[2][0]+.5, h=height+2);
                translate([0, 0, 2]) cylinder(d=nuts[2][1]*2/sqrt(3), h=height, $fn=6);
            }
            if(nut == "m4") {
                translate([0, 0, -1]) cylinder(d=nuts[3][0]+.5, h=height+2);
                translate([0, 0, 2]) cylinder(d=nuts[3][1]*2/sqrt(3), h=height, $fn=6);
            }
        }
    }
    if( style == "sloped") {
        difference() {
            cylinder(d2=dia_x, d1=dia_y, h=height);
            if(nut == "m2") {
                translate([0, 0, -1]) cylinder(d=nuts[0][0]+.25, h=height+2);
                translate([0, 0, 2]) cylinder(d=nuts[0][1]*2/sqrt(3), h=height, $fn=6);
            }
            if(nut == "m2.5") {
                translate([0, 0, -1]) cylinder(d=nuts[1][0]+.25, h=height+2);
                translate([0, 0, 2]) cylinder(d=nuts[1][1]*2/sqrt(3), h=height, $fn=6);
            }
            if(nut == "m3") {
                translate([0, 0, -1]) cylinder(d=nuts[2][0]+.5, h=height+2);
                translate([0, 0, 2]) cylinder(d=nuts[2][1]*2/sqrt(3), h=height, $fn=6);
            }
            if(nut == "m4") {
                translate([0, 0, -1]) cylinder(d=nuts[3][0]+.5, h=height+2);
                translate([0, 0, 2]) cylinder(d=nuts[3][1]*2/sqrt(3), h=height, $fn=6);
            }
        }
    }
    if( style == "trap") {
        if(nut == "m2") {
            difference() {
                translate([-dia_x/2, -dia_y/2, 0]) cube([dia_x, dia_y, height]);
                translate([0, 0, -1]) cylinder(d=nuts[0][0]+.25, h=height+2);
                translate([0, 0, 2]) rotate([0,0,30]) cylinder(d=nuts[0][1]*2/sqrt(3), h=nuts[0][2], $fn=6);
                translate([-nuts[0][1]/2, 0, 2]) cube([nuts[0][1], dia_x, nuts[0][2]]);
            }
        }
        if(nut == "m2.5") {
            difference() {
                translate([-dia_x/2, -dia_y/2, 0]) cube([dia_x, dia_y, height]);
                translate([0, 0, -1]) cylinder(d=nuts[1][0]+.325, h=height+2);
                translate([0, 0, 2]) rotate([0,0,30]) cylinder(d=nuts[1][1]*2/sqrt(3), h=nuts[1][2], $fn=6);
                translate([-nuts[1][1]/2, 0, 2]) cube([nuts[1][1], dia_x, nuts[1][2]]);
            }
        }
        if(nut == "m3") {
            difference() {
                translate([-dia_x/2, -dia_y/2, 0]) cube([dia_x, dia_y, height]);
                translate([0, 0, -1]) cylinder(d=nuts[2][0]+.5, h=height+2);
                translate([0, 0, 2]) rotate([0,0,30]) cylinder(d=nuts[2][1]*2/sqrt(3), h=nuts[2][2], $fn=6);
                translate([-nuts[2][1]/2, 0, 2]) cube([nuts[2][1], dia_x, nuts[2][2]]);
            }
        }
        if(nut == "m4") {
            difference() {
                translate([-dia_x/2, -dia_y/2, 0]) cube([dia_x, dia_y, height]);
                translate([0, 0, -1]) cylinder(d=nuts[3][0]+.5, h=height+2);
                translate([0, 0, 2]) rotate([0,0,30]) cylinder(d=nuts[3][1]*2/sqrt(3), h=nuts[3][2], $fn=6);
                translate([-nuts[3][1]/2, 0, 2]) cube([nuts[3][1], dia_x, nuts[3][2]]);
            }
        }
    }
}


/*
           NAME: vu_holder
    DESCRIPTION: hk vu5,vu5a,vu7,vu7a display holder
           TODO: none

          USAGE: vu_holder(vu_model, side, vesa, cheight)

                           vu_model = "vu5", "vu7"
                               side = "left", "right"
                               vesa = 75 for vu5, 100 for vu7
                            cheight = case_z+90 for vu5, case_z+122 for vu7
*/

module vu_holder(vu_model, side, vesa, cheight) {

//cheight = case_z+90;
v_fillet = 3;
    
vu5_case_x_offset = 6.5;                // for uniform front vu5=6.5, vu7=20
vu5_pcb_width = 121;
vu5_pcb_height = 93.31;
vu5_width = vu5_pcb_width + vu5_case_x_offset;
vu5_height = vu5_pcb_height + 9.75;
    
vu7_case_x_offset = 20;                 // for uniform front vu5=6.5, vu7=20
vu7_pcb_width = 172.90;
vu7_pcb_height = 124.27;
vu7_width = vu7_pcb_width + vu7_case_x_offset;
vu7_height = vu7_pcb_height + 9.75;

        difference() {
        union() {
            if(side == "right") {
                translate([width-wallthick-gap,-(2*wallthick)-gap,0]) 
                    cube([sidethick,depth+2*wallthick,cheight]);
                // right tabs for vu5 attachment
                if(case_style == "vu5") {
                    translate([(width/2)+((width-vesa)/2)+(vesa/2)-sidethick,depth-39,
                        case_z+80]) rotate([90-vu_rotation[0],180,0]) 
                            slab_r([((width-vesa)/2)+4.5,10,sidethick], [.1,.1,3,3]);
                    translate([(width/2)+((width-vesa)/2)+(vesa/2)-sidethick,depth-26,
                        case_z+31.5]) rotate([90-vu_rotation[0],180,0]) 
                            slab_r([((width-vesa)/2)+4.5,10,sidethick], [.1,.1,3,3]);
                
                    translate([(width/2)+((width-vesa)/2)+(vesa/2)-sidethick,depth-41.85-adj,
                        case_z+79.25]) rotate([90-vu_rotation[0],180,0]) 
                    difference() { 
                        cube([sidethick,10,sidethick]);
                        translate([0,-adj,sidethick]) rotate([0,45,0]) 
                            cube([2*sidethick,10+(2*adj),sidethick]);
                    }
                    translate([(width/2)+((width-vesa)/2)+(vesa/2)-sidethick,depth-28.85-adj,
                        case_z+30.75]) rotate([90-vu_rotation[0],180,0])
                    difference() { 
                        cube([sidethick,10,sidethick]);
                        translate([0,-adj,sidethick]) rotate([0,45,0]) 
                            cube([2*sidethick,10+(2*adj),sidethick]);
                    }
                }
                // right tabs for vu7 attachment
                if(case_style == "vu7") {
                    translate([(width/2)+((width-vesa)/2)+(vesa/2)-sidethick-1,depth-49.40,
                        case_z+vu7_height-15]) rotate([90-vu_rotation[0],180,0]) 
                            slab_r([((width-vesa)/2)+12,10,sidethick], [.1,.1,3,3]);
                    translate([(width/2)+((width-vesa)/2)+(vesa/2)-sidethick-1,depth-23.60,
                        case_z+22.5]) rotate([90-vu_rotation[0],180,0]) 
                            slab_r([((width-vesa)/2)+12,10,sidethick], [.1,.1,3,3]);
                    
                    translate([(width/2)+((width-vesa)/2)+(vesa/2)-sidethick,depth-52.25,
                        case_z+vu7_height-15.75]) rotate([90-vu_rotation[0],180,0]) 
                            difference() { 
                                cube([sidethick,10,sidethick]);
                                translate([0,-adj,sidethick]) rotate([0,45,0]) 
                                    cube([2*sidethick,10+(2*adj),sidethick]);
                            }
                    translate([(width/2)+((width-vesa)/2)+(vesa/2)-sidethick,depth-26.5,
                        case_z+21.8]) rotate([90-vu_rotation[0],180,0])
                            difference() { 
                                cube([sidethick,10,sidethick]);
                                translate([0,-adj,sidethick]) rotate([0,45,0]) 
                                    cube([2*sidethick,10+(2*adj),sidethick]);
                            }
                }
                // top rail
                    translate([width-6.9-adj,-gap,case_z-floorthick-.5])
                    cube([4,depth-2*(wallthick+gap),2]);
            }
            if(side == "left") {
                translate([-wallthick-gap-sidethick,-(2*wallthick)-gap,0]) 
                    cube([sidethick,depth+2*wallthick,cheight]);
                // left tabs for vu5 attachment
                if(case_style == "vu5") {
                    translate([-((width-vesa)/2)+(width/2)-(vesa/2)-3.5-adj,depth-36.4,
                        case_z+70]) rotate([90+vu_rotation[0],0,0]) 
                            slab_r([((width-vesa)/2)+4,10, sidethick], [.1,.1,3,3]);
                    translate([-((width-vesa)/2)+(width/2)-(vesa/2)-3.5-adj,depth-23.5,
                        case_z+22]) rotate([90+vu_rotation[0],0,0]) 
                            slab_r([((width-vesa)/2)+4,10,sidethick], [.1,.1,3,3]);
                    translate([-((width-vesa)/2)+(width/2)-(vesa/2)-3.5-adj,depth-39.35+adj,
                        case_z+69.25]) rotate([90+vu_rotation[0],0,0])
                            difference() { 
                                cube([sidethick,10,sidethick]);
                                translate([0,-adj,sidethick]) rotate([0,45,0]) 
                                    cube([2*sidethick,10+(2*adj),2*sidethick]);
                            }                
                    translate([-((width-vesa)/2)+(width/2)-(vesa/2)-3.5-adj,depth-26.4+adj,
                        case_z+21.25]) rotate([90+vu_rotation[0],0,0])  
                        difference() { 
                            cube([sidethick,10,sidethick]);
                            translate([0,-adj,sidethick]) rotate([0,45,0]) 
                                cube([2*sidethick,10+(2*adj),2*sidethick]);
                        }
                }           
                // left tabs for vu7 attachment
                if(case_style == "vu7") {
                    translate([-((width-vesa)/2)+(width/2)-(vesa/2)-4.25-adj,depth-46.85,
                        case_z+vu7_height-24.5]) rotate([90+vu_rotation[0],0,0]) 
                            slab_r([((width-vesa)/2),10, sidethick], [.1,.1,3,3]);
                    translate([-((width-vesa)/2)+(width/2)-(vesa/2)-4.25-adj,depth-21,
                        case_z+13]) rotate([90+vu_rotation[0],0,0]) 
                            slab_r([((width-vesa)/2),10,sidethick], [.1,.1,3,3]);
                    translate([-((width-vesa)/2)+(width/2)-(vesa/2)-4-adj,depth-49.75+adj,
                        case_z+vu7_height-25.25]) rotate([90+vu_rotation[0],0,0])
                            difference() { 
                                cube([sidethick,10,sidethick]);
                                translate([0,-adj,sidethick]) rotate([0,45,0]) 
                                    cube([2*sidethick,10+(2*adj),2*sidethick]);
                            }                
                    translate([-((width-vesa)/2)+(width/2)-(vesa/2)-4-adj,depth-23.75+adj,
                        case_z+12.25]) rotate([90+vu_rotation[0],0,0])  
                        difference() { 
                            cube([sidethick,10,sidethick]);
                            translate([0,-adj,sidethick]) rotate([0,45,0]) 
                                cube([2*sidethick,10+(2*adj),2*sidethick]);
                        }
                }
                // top rail
                translate([-wallthick-gap-adj,-gap,case_z-floorthick-.5]) 
                        cube([4,depth-2*(wallthick+gap),2]);
            }
        }

        if(side == "right") {
            // vu5 shape and back cut
            if(case_style == "vu5") {
                translate([width+adj,-.6,case_z+sidethick+2.5]) 
                    rotate([0,-90,0]) 
                    linear_extrude(height = 3*sidethick) 
                        polygon(points = [ [-sidethick,-sidethick-wallthick-5],
                            [cheight-bottom_height-top_height-3,-sidethick-wallthick-5], 
                            [cheight-bottom_height-top_height-3,depth-53], 
                            [-sidethick,depth-33]]);
                
                translate([width-(sidethick/2),depth-8,case_z+(121/2)]) 
                    rotate([vu_rotation[0],0,0]) 
                        cube_fillet_inside([10,50,110],vertical=[v_fillet,v_fillet,v_fillet,v_fillet],
                            top=[0,0,0,0],bottom=[3,3,3,3], $fn=90);
                // tab holes
                translate([width/2+(vesa/2)-3,depth-37,
                    case_z+75]) rotate([90-vu_rotation[0],180,0]) cylinder(d=3, h=sidethick+1);
                translate([width/2+(vesa/2)-3,depth-24,
                    case_z+26.75]) rotate([90-vu_rotation[0],180,0]) cylinder(d=3, h=sidethick+1);
            }
            // vu7 shape and back cut
            if(case_style == "vu7") {
                translate([width+adj,-.6,case_z+sidethick+2.5]) 
                    rotate([0,-90,0]) 
                    linear_extrude(height = 2*sidethick) 
                        polygon(points = [ [-sidethick,-sidethick-wallthick-5],
                            [cheight-bottom_height-top_height-3,-sidethick-wallthick-5], 
                            [cheight-bottom_height-top_height-3,depth-63], 
                            [-sidethick,depth-33]]);
                
                translate([width-(sidethick/2),depth-10.5,case_z+70.5]) 
                    rotate([vu_rotation[0],0,0]) 
                        cube_fillet_inside([10,50,130],vertical=[v_fillet,v_fillet,v_fillet,v_fillet],
                            top=[0,0,0,0],bottom=[3,3,3,3], $fn=90);
                // tab holes
                translate([width/2+(vesa/2)-10,depth-47,case_z+vu7_height-19.75]) 
                    rotate([90-vu_rotation[0],180,0]) cylinder(d=3, h=sidethick+4);
                translate([width/2+(vesa/2)-10,depth-21.25,case_z+18]) 
                    rotate([90-vu_rotation[0],180,0]) cylinder(d=3, h=sidethick+4);
            }
            // bottom attachment holes                         
            translate([width-wallthick-gap-adj-5,wallthick+gap+10,
                ((bottom_height+floorthick)/2)-1]) rotate([0,90,0]) cylinder(d=3, h=sidethick+(2*adj)+10);
            translate([width-wallthick-gap-adj-5,depth-wallthick-gap-10,
                ((bottom_height+floorthick)/2)-1]) rotate([0,90,0]) cylinder(d=3, h=sidethick+(2*adj)+10);
        }

        if(side == "left") {
            // vu5 shape and back cut
            if(case_style == "vu5") {
                translate([-sidethick+adj,-.6,case_z+sidethick+2.5]) 
                    rotate([0,-90,0]) 
                        linear_extrude(height = 3*sidethick) 
                            polygon(points = [ [-sidethick,-sidethick-wallthick-5],
                                [cheight-bottom_height-top_height-3,-sidethick-wallthick-5], 
                                [cheight-bottom_height-top_height-3,depth-53], 
                                [-sidethick,depth-33]]);
                
                translate([-wallthick-gap-(sidethick/2),depth-8,case_z+(121/2)]) 
                    rotate([vu_rotation[0],0,0]) 
                        cube_fillet_inside([10,50,110],vertical=[v_fillet,v_fillet,v_fillet,v_fillet],
                            top=[0,0,0,0],bottom=[3,3,3,3], $fn=90);
                // tab holes
                translate([width/2-(vesa/2)-3,depth-36.75,case_z+75]) 
                    rotate([90+vu_rotation[0],0,0]) cylinder(d=3, h=sidethick+1);
                translate([width/2-(vesa/2)-3,depth-24.25,case_z+26.75]) 
                    rotate([90+vu_rotation[0],0,0])  cylinder(d=3, h=sidethick+1);
            }
            // vu7 shape and back cut
            if(case_style == "vu7") {
                translate([-sidethick+adj,-.6,case_z+sidethick+2.5]) 
                    rotate([0,-90,0]) 
                        linear_extrude(height = 2*sidethick) 
                            polygon(points = [ [-sidethick,-sidethick-wallthick-5],
                                [cheight-bottom_height-top_height-3,-sidethick-wallthick-5], 
                                [cheight-bottom_height-top_height-3,depth-63], 
                                [-sidethick,depth-33]]);
                
                translate([-wallthick-gap-(sidethick/2),depth-10.5,case_z+70.5]) 
                    rotate([vu_rotation[0],0,0]) 
                        cube_fillet_inside([10,50,130],vertical=[v_fillet,v_fillet,v_fillet,v_fillet],
                            top=[0,0,0,0],bottom=[3,3,3,3], $fn=90);
                // tab holes
                translate([width/2-(vesa/2)-10,depth-48,case_z+vu7_height-19.75]) 
                    rotate([90+vu_rotation[0],0,0]) cylinder(d=3, h=sidethick+4);
                translate([width/2-(vesa/2)-10,depth-22.25,case_z+18]) 
                    rotate([90+vu_rotation[0],0,0])  cylinder(d=3, h=sidethick+4);
            }
            // bottom attachment holes
            translate([-sidethick-adj-6,wallthick+gap+10,((bottom_height+floorthick)/2)-1]) 
                rotate([0,90,0]) cylinder(d=3, h=sidethick+(2*adj)+10);
            if(depth >= 75) {
                translate([-sidethick-adj-6,depth-wallthick-gap-10,
                    ((bottom_height+floorthick)/2)-1]) rotate([0,90,0]) cylinder(d=3, h=sidethick+(2*adj)+10);
            }
            else {
                translate([-sidethick-adj-6,wallthick+gap+40.5,((bottom_height+floorthick)/2)-1])
                    rotate([0,90,0]) cylinder(d=3, h=sidethick+(2*adj)+10);                        
            }
        }
    }
}
