// Detail of the part
$fn = 50;

// Minimum thickness of anything
min_thickness = 1.2;

// Tolerance for inside gaps
tol = 0.1;

// Part to generate
part = "m"; // [m: Main Body, t:Top]

module hide_params() {}
function inch(x) = x * 25.4;

jr_upper_width = inch(1 + 3 / 4);
jr_upper_depth = inch(2 + 3 / 8);
jr_lower_width = inch(1 + 23 / 32);
jr_lower_depth = inch(2 + 11 / 32);

connector_hole_width = inch(7 / 64);
connector_hole_depth = inch(15 / 32);
connector_right_x_offset = inch(3 / 16);
connector_bottom_y_offset = inch(1 / 8);

jr_height = inch(3 / 4);
rim_width = 2;
rim_height = 2;
chamfer_d = 2;
top_interference = 1;

latch_width = 1.8;
latch_depth = 9 / 16 * 25.4;
latch_lug_rim_height = 3;
latch_lug_z_offset = 17;
latch_cutout_width = latch_width + min_thickness;
latch_cutout_depth = latch_depth + min_thickness * 2;
latch_max_angle = 6;
latch_gap = 1;

sma_thread_d = inch(1 / 4) + 2 * tol;
sma_thread_length = inch(7 / 16);
sma_hex_small_d = inch(5 / 16) + 2 * tol;
sma_hex_height = 2;
sma_mount_thickness = 2;

module copy_mirror(vec = [ 0, 1, 0 ]) {
  children();
  mirror(vec) children();
}

module chamfer_tool(d, flat_top = false, no_bottom = false) {
  if (no_bottom) {
    cylinder(d / 2, d / 2, 0, $fn = 4);
  } else {
    union() {

      cube_edge_length = sqrt(pow(d / 2, 2) * 2);

      if (flat_top) {
        rotate([ 0, 0, 45 ])
            translate([ -cube_edge_length / 2, -cube_edge_length / 2, 0 ])
                cube([ cube_edge_length, cube_edge_length, d / 2 ]);
      }

      copy_mirror([ 0, 0, 1 ]) rotate([ 180, 0, 0 ])
          cylinder(d / 2, d / 2, 0, $fn = 4);
    }
  }
}

// uses child passed to it as chamfer tool
module block(upper_width, lower_width, upper_depth, lower_depth, height,
             chamfer_d = 0) {
  function linear(x, y_1, y_2, h) = y_1 + x * (y_2 - y_1) / h;
  scale = [ upper_width / lower_width, upper_depth / lower_depth ];

  if (chamfer_d == 0) {

    linear_extrude(height, scale = scale)
        square([ lower_width, lower_depth ], center = true);
  } else {
    base_width =
        linear(chamfer_d / 2, lower_width, upper_width, height) - chamfer_d;
    base_depth =
        linear(chamfer_d / 2, lower_depth, upper_depth, height) - chamfer_d;
    new_scale = (scale - [ 1, 1 ]) * ((height - chamfer_d) / height) + [ 1, 1 ];

    translate([ 0, 0, chamfer_d / 2 ]) minkowski() {
      linear_extrude(height - chamfer_d, scale = new_scale)
          square([ base_width, base_depth ], center = true);
      children();
    }
  }
}

module jr_module() {
  function dimension_at(height, lower, upper) =
      lower + (uper - lower) * (height - jr_height);

  difference() {
    // main body
    block(jr_upper_width, jr_lower_width, jr_upper_depth, jr_lower_depth,
          jr_height, chamfer_d) {
      chamfer_tool(chamfer_d);
    };

    // connector cutout
    translate([
      jr_lower_width / 2 - connector_hole_width - connector_right_x_offset,
      -jr_lower_depth / 2 + connector_bottom_y_offset, 0
    ])
        cube([
          connector_hole_width, connector_hole_depth, jr_height + rim_height
        ]);
  }
}

module latch(base_support = false, angle = 0) {
  base_support_d = latch_gap / 2;
  start_height = chamfer_d;
  latch_height = jr_height + rim_height;

  translate([ -latch_width, latch_depth / 2, +start_height ])
      rotate([ 0, -angle, 0 ]) translate([ 0, 0, -start_height ])
          rotate([ 90, 0, 0 ]) union() {
    ramp_points = [
      [ 0, start_height ],
      [ 0, 7.5 ],
      [ 0.5, latch_lug_z_offset - 2.5 ],
      [ 1.25, latch_lug_z_offset ],
      [ 0, latch_lug_z_offset ],
      [ 0, latch_lug_z_offset + latch_lug_rim_height + 2 * tol ],
      [ min_thickness, latch_lug_z_offset + latch_lug_rim_height + 2 * tol ],
      [ min_thickness, latch_height ],
    ];

    linear_extrude(latch_depth) polygon(concat(
        [
          [ 0, latch_height ],
          [ 0, start_height ],
        ],
        [for (p = ramp_points)[latch_width + p[0], p[1]]]));

    if (base_support) {
      translate([
        -base_support_d,
        start_height,
      ]) linear_extrude(latch_depth)
          polygon(
              [[latch_width + base_support_d, base_support_d],
               [base_support_d, base_support_d], [0, 0], [0, -start_height],
               [latch_width + base_support_d - chamfer_d / 2, -start_height],
               [latch_width + base_support_d, -start_height + chamfer_d / 2]]);
    }
  }
}

module latch_cutout() {
  module custom_chamfer_tool() {
    hull() {
      translate([ 0, 0, latch_gap / 2 + tol ]) chamfer_tool(d = latch_gap);
      translate([ 0, 0, latch_gap / 2 + tol + jr_height ])
          chamfer_tool(d = latch_gap);
    }
  }

  copy_mirror([ 1, 0, 0 ]) translate([ jr_lower_width / 2, 0, 0 ]) hull() {
    minkowski() {
      latch(base_support = false, angle = -latch_max_angle);
      custom_chamfer_tool();
    };

    minkowski() {
      latch(base_support = false, angle = latch_max_angle);
      custom_chamfer_tool();
    };
  }
}

module sma_mount(base_to_thread_height, cut_tool = false) {
  sma_hex_big_d = sma_hex_small_d * (2 / sqrt(3));
  // length of the flexible tail of the SMA
  sma_tail_length = 24;
  horizontal_hex_length = 2* sma_hex_height;
  angle = 45;
  bent_radius = sma_hex_big_d / 2 + 35;

  difference() {

    union() {

      tmp = sma_hex_height + sma_tail_length;
      // straight part
      rotate([ 90, 30, 0 ]) {
            cylinder($fn = 6, d = sma_hex_big_d, h = horizontal_hex_length);
        if (cut_tool) {
          rotate([ 0, 180, 0 ])
              cylinder(d = sma_thread_d, h = sma_thread_length);
        }
      };


      hull() {
	      // bent part
	      translate([ 0, -horizontal_hex_length, -bent_radius ])
		      rotate([ 0, -90, 180 ]) rotate_extrude(angle = angle, $fn=500) {
			      translate([ bent_radius, 0 ]) circle($fn = 6, d = sma_hex_big_d);
		      };

	      rotate([ 0, 0, 180 ]) translate([
			      -sma_hex_small_d / 2, sma_hex_height, -sma_hex_big_d / 2 -
			      base_to_thread_height
	      ]) cube([ sma_hex_small_d, sma_tail_length, tol ]);

      // straighten the insertion slot
            translate([0, -sma_hex_height, 0])
       rotate([ 90, 30, 0 ])
            cylinder($fn = 6, d = sma_hex_big_d, h = sma_hex_height);
      }
    }
    let(height = 160,
        depth = sma_tail_length + sma_mount_thickness + sma_hex_height

        ) // TODO adjust dimensions
    {
      translate([
        0, -depth / 2, -sma_hex_big_d / 2 - base_to_thread_height - height / 2
      ]) cube([ sma_hex_small_d * 2, depth, height ], center = true); // TODO its wrong that we have to multiply by two here
    }
  }
}


module inside_pocket(height = 13) {
  mid_width = 33.8 + 2 * tol;
  upper_lower_width = 40.6 + 3 * tol;
  mid_depth = 21 - 2 * tol;
  total_depth = 54.6 + 2 * tol;
  floor_height = min_thickness;
  saddle_height = 3;

  difference() {
    // main body
    union() {
      translate([ -mid_width / 2, -mid_depth / 2, floor_height ])
          cube([ mid_width, mid_depth, height ]);
      copy_mirror([ 0, 1, 0 ]) translate(
          [ -upper_lower_width / 2, mid_depth / 2, floor_height ])
          cube([ upper_lower_width, (total_depth - mid_depth) / 2, height ]);

      // button hole
      translate([ -upper_lower_width / 2, -total_depth / 2 ]) {
        translate([ 13 / 16 * 25.4, 9, floor_height + saddle_height ])
            cylinder(d = 6.5 + 2 * tol, h = 19);

        // rotary hole
        translate([ 8.5, 9, floor_height + saddle_height ])
            cylinder(d = 9, h = 15.5);
      }

      // led hole
      copy_mirror([ 1, 0, 0 ]) translate(
          [ 5 / 2, -total_depth / 2 + 18, floor_height + saddle_height ])
          cylinder(d = 3, h = 12);
    }

    // saddle cuts
    translate([ 0, 0, floor_height ]) linear_extrude(saddle_height) {
      // lower left
      translate([ -upper_lower_width / 2, -total_depth / 2 ]) square([ 5, 10 ]);

      // lower right
      translate([ upper_lower_width / 2 - 15, -total_depth / 2 ])
          square([ 6, 4 ]);

      // lower mid
      translate([ -upper_lower_width / 2 + 9, -total_depth / 2 ])
          square([ 3, 10 ]);

      // mid left
      translate([ -mid_width / 2, -mid_depth / 2 ]) square([ 3, 15 ]);

      // mid right
      translate([ mid_width / 2 - 7.5, -mid_depth / 2 ]) square([ 7.5, 10 ]);

      // mid both
      copy_mirror([ 1, 0, 0 ]) translate([ -mid_width / 2, -mid_depth / 2 ])
          square([ 2, mid_depth ]);

      // top
      translate([ -upper_lower_width / 2, total_depth / 2 - 6 ])
          square([ upper_lower_width, 6 ]);
    }
  }
}

module top_plate() {
  width = jr_upper_width + 2 * rim_width;
  depth = jr_upper_depth + 2 * rim_width;
  height = rim_height;
  vertical_offset = jr_height + rim_height / 2;

  sma_hex_big_d = sma_hex_small_d * (2 / sqrt(3));
  // length of the flexible tail of the SMA
  sma_tail_length = 20;
  sma_mount_vertical_offset = sma_hex_big_d / 2 + rim_height /2 + min_thickness;

  sma_offset = [
    0, 1.5 * chamfer_d + jr_upper_depth / 2 - sma_hex_height - min_thickness,
    vertical_offset + sma_mount_vertical_offset
  ];

  assert(rim_height >= chamfer_d);

  difference() {
    union() {
      // actual top plate
      hull() copy_mirror([ 1, 0, 0 ]) copy_mirror([ 0, 1, 0 ]) translate([
        jr_upper_width / 2 + rim_width - chamfer_d / 2,
        jr_upper_depth / 2 + rim_width - chamfer_d / 2,
        vertical_offset
      ]) chamfer_tool(chamfer_d);

      // sma mount
      minkowski(){
	      translate(sma_offset) sma_mount(sma_mount_vertical_offset, false);
        rotate([180, 0, 0])
	      chamfer_tool(d = min_thickness * 2, flat_top = true);
      }
    }

    // sma mount
    translate(sma_offset) sma_mount(sma_mount_vertical_offset, true);
    translate([0,0,vertical_offset/2-rim_height/2]) 
      cube([sma_hex_small_d + 2 * min_thickness, depth, vertical_offset], center = true);

    // main body notch
    minkowski() {
      difference() {
        jr_module();
        linear_extrude(jr_height) projection() inside_pocket();
    }
    cube(2 * tol, center = true);
  }

  latch_cutout();

  inside_pocket();
}
}

if (part == "m") {
  union() {
    difference() {
      jr_module();

      latch_cutout();

      inside_pocket(height = 20);
    }
    copy_mirror([ 1, 0, 0 ]) translate([ jr_lower_width / 2, 0, 0 ])
        latch(base_support = true);
  }
} else if (part == "t") {
  top_plate();
}