package eu.printingin3d.models.models;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

import eu.printingin3d.javascad.coords.Angles3d;
import eu.printingin3d.javascad.coords.Coords3d;
import eu.printingin3d.javascad.coords.Dims3d;
import eu.printingin3d.javascad.enums.Side;
import eu.printingin3d.javascad.exceptions.IllegalValueException;
import eu.printingin3d.javascad.models.Abstract3dModel;
import eu.printingin3d.javascad.models.Cube;
import eu.printingin3d.javascad.models.Cylinder;
import eu.printingin3d.javascad.tranzitions.Difference;
import eu.printingin3d.javascad.tranzitions.Mirror;
import eu.printingin3d.javascad.tranzitions.Union;
import eu.printingin3d.javascad.utils.SaveScadFiles;

public class ClosedShelf extends Union {
	private static final double HEIGHT = 100;
	public static final double THICK  =   3;
	public static final double SHOULDER_SIZE = THICK*2;
	public static final double DEPTH  =  65;
	
	public static final double PLEXI_THICK = 6.6;
	public static final double FRONT_HEIGHT = 20;
	
	private static final double PATTERN_RADIUS = 28;
	private static final double SMALL_PATTERN_RAD = 6;
	private static final Coords3d SMALL_PATTERN_CENTER = new Coords3d(5.5, 12, 0);
	private static final double SMALL_PATTERN_GAP = SMALL_PATTERN_RAD*1.4;
	
	private static final double MICRO_PATTERN_RAD = 2;
	private static final double MICRO_PATTERN_GAP = MICRO_PATTERN_RAD*1.4;
	
	private static final double BOLT_RAD = 2;
	private static final double HANDLE_SIZE = 8;
	
	public ClosedShelf() {
		super(createPlate());
	}

	private static Abstract3dModel createPattern(double radius, double gap) {
		return new Cylinder(THICK+1, radius).
			moves(Arrays.asList(
					Coords3d.xOnly(+gap),
					Coords3d.xOnly(-gap),
					Coords3d.yOnly(+gap),
					Coords3d.yOnly(-gap),
					Coords3d.ZERO
					));
	}
	
	private static Abstract3dModel createBase() {
		Abstract3dModel basePlate = new Cube(new Dims3d(HEIGHT, DEPTH, THICK));
		Abstract3dModel plate =
				new Difference(
						basePlate,
						new Cylinder(THICK+1, PATTERN_RADIUS).
								align(Side.FRONT, basePlate, true).
								align(Side.RIGHT, basePlate, true).
								moves(Arrays.asList(Coords3d.yOnly(-PATTERN_RADIUS), Coords3d.xOnly(PATTERN_RADIUS))),
						createPattern(SMALL_PATTERN_RAD, SMALL_PATTERN_GAP).
								move(SMALL_PATTERN_CENTER),
								createPattern(MICRO_PATTERN_RAD, MICRO_PATTERN_GAP).
								move(Coords3d.xOnly(-30)).
								moves(Arrays.asList(
										Coords3d.yOnly(-15),
										Coords3d.yOnly(+15),
										Coords3d.ZERO
									))
				);
		return plate;
	}
	
	private static Abstract3dModel createHandle() {
		return new Difference(
				new Cube(new Dims3d(HANDLE_SIZE, THICK, HANDLE_SIZE)),
				new Cylinder(THICK+1, BOLT_RAD).rotate(Angles3d.ROTATE_PLUS_X)
				);
	}
	
	private static List<Abstract3dModel> createPlate() {
		Abstract3dModel plate = createBase();
		Abstract3dModel handle = createHandle().
				align(Side.TOP, plate, false).
				align(Side.BACK, plate, true).
				align(Side.RIGHT, plate, true);
		Abstract3dModel a = new Cube(new Dims3d(THICK, DEPTH, SHOULDER_SIZE)).
				align(Side.TOP, plate, false).
				align(Side.LEFT, plate, true);
		Abstract3dModel b = new Cube(new Dims3d(THICK, DEPTH, SHOULDER_SIZE)).
				align(Side.TOP, plate, false).
				align(Side.RIGHT, a, false).
				move(Coords3d.xOnly(PLEXI_THICK));
		Abstract3dModel c = new Cube(new Dims3d(FRONT_HEIGHT, THICK, SHOULDER_SIZE)).
				align(Side.TOP, plate, false).
				align(Side.RIGHT, b, false).
				align(Side.FRONT, plate, true).
				move(Coords3d.xOnly(-0.001));
		Abstract3dModel d = new Cube(new Dims3d(FRONT_HEIGHT, THICK, SHOULDER_SIZE)).
				align(Side.TOP, plate, false).
				align(Side.RIGHT, b, false).
				align(Side.BACK, c, false).
				move(Coords3d.yOnly(PLEXI_THICK)).
				move(Coords3d.xOnly(-0.001));
		
		return Arrays.asList(plate, a, b, c, d, handle);
	}
	
	public static void main(String[] args) throws IllegalValueException, IOException {
		new SaveScadFiles(new File("C:/temp")).
				addModel("shelfclosed.right.scad", new ClosedShelf()).
				addModel("shelfclosed.left.scad", Mirror.mirrorY(new ClosedShelf())).
				saveScadFiles();
	}
	
}
