package eu.printingin3d.models.models.cakeholder;

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

import eu.printingin3d.javascad.coords.Angles3d;
import eu.printingin3d.javascad.coords.Coords3d;
import eu.printingin3d.javascad.coords2d.Dims2d;
import eu.printingin3d.javascad.enums.Side;
import eu.printingin3d.javascad.models.Abstract3dModel;
import eu.printingin3d.javascad.models.Cylinder;
import eu.printingin3d.javascad.models.Extendable3dModel;
import eu.printingin3d.javascad.models.Ring;
import eu.printingin3d.javascad.models2d.Square;
import eu.printingin3d.javascad.tranzitions.Difference;
import eu.printingin3d.javascad.tranzitions.Union;
import eu.printingin3d.javascad.utils.SaveScadFiles;
import eu.printingin3d.javascad.utils.UsefulConsts;

public class CakeHolder extends Extendable3dModel {
	private static final double SECTION1_D = 80; 
	private static final double SECTION2_D = 130;
	private static final double RING1_D = 140;
	private static final double RING2_D = 150;
	
	private static final double OUTER_DIAMETER = 160;
	
	private static final double BIG_HOLE_DIAMETER = 30;

	private static final double SMALL_HOLE_DIAMETER = 7;
	private static final double SMALL_HOLE_DIST_FROM_ORIG = 30;
	
	private static final int NUMBER_OF_BIG_RINGS = 12;
	
	private static final double THICKNESS = 7.5;
	private static final double THICKNESS_THIN = 4;
	
	
	public CakeHolder() {
		Abstract3dModel _base = new Cylinder(THICKNESS, OUTER_DIAMETER/2);
		
		Abstract3dModel ring = createMiddleRing();
		
		Abstract3dModel base = new Union(
				createOuterRing().align(Side.BOTTOM, _base, true),
				ring.align(Side.BOTTOM, _base, true),
				new Cylinder(THICKNESS, SECTION1_D/2)
			);
		
		Abstract3dModel bigHole = new Cylinder(THICKNESS+1, BIG_HOLE_DIAMETER/2);
		Abstract3dModel smallHole =
			trice(new Cylinder(THICKNESS+1, SMALL_HOLE_DIAMETER/2), SMALL_HOLE_DIAMETER*0.43)
					.move(Coords3d.yOnly(-SMALL_HOLE_DIST_FROM_ORIG));
		
		this.baseModel = new Difference(base,
				trice(bigHole, BIG_HOLE_DIAMETER/2+1),
				smallHole.cloneModel(),
				smallHole.cloneModel().rotate(new Angles3d(0, 0, +120)),
				smallHole.cloneModel().rotate(new Angles3d(0, 0, -120))
			);
	}

	private Abstract3dModel createOuterRing() {
		List<Coords3d> moves = new ArrayList<>();
		
		for (int i=0;i<24;i++) {
			double alpha = i*2*Math.PI/24;
			double beta = (i+0.5)*2*Math.PI/24;
			
			moves.add(new Coords3d(RING1_D/2*Math.sin(alpha), RING1_D/2*Math.cos(alpha), 0));
			moves.add(new Coords3d(RING2_D/2*Math.sin(beta), RING2_D/2*Math.cos(beta), 0));
		}
		
		Abstract3dModel ringBase = new Cylinder(THICKNESS, OUTER_DIAMETER/2);
		return new Union( 
			new Difference(
				ringBase,
				new Cylinder(THICKNESS+1, SECTION2_D/2),
				new Ring(RING1_D/2, new Square(new Dims2d(2, 2))).align(Side.TOP, ringBase, true).move(Coords3d.zOnly(0.1)),
				new Ring(RING2_D/2, new Square(new Dims2d(2, 2))).align(Side.TOP, ringBase, true).move(Coords3d.zOnly(0.1))
			),
			new Cylinder(THICKNESS, 1.1).moves(moves)
			);
	}

	private Abstract3dModel createMiddleRing() {
		double offset = (SECTION1_D+SECTION2_D)/4;
		
		List<Coords3d> moves = new ArrayList<>();
		for (int i=0;i<NUMBER_OF_BIG_RINGS;i++) {
			double alpha = i*2*Math.PI/NUMBER_OF_BIG_RINGS;
			moves.add(new Coords3d(offset*Math.sin(alpha), offset*Math.cos(alpha), 0));
		}
		
		return new Ring((SECTION2_D-SECTION1_D)/4, new Square(new Dims2d(THICKNESS_THIN, THICKNESS_THIN)))
				.moves(moves);
	}
	
	private static Abstract3dModel trice(Abstract3dModel orig, double dist) {
		return orig.moves(Arrays.asList(
					new Coords3d(+dist, -dist/2, 0),
					new Coords3d(-dist, -dist/2, 0),
					Coords3d.yOnly(dist*(UsefulConsts.SQRT_3-0.5))
				));
	}
	
	public static void main(String[] args) throws IOException {
		
		new SaveScadFiles(new File("C:/temp")).
				addModel("cakeholder.scad", new CakeHolder()).
				saveScadFiles();
		
	}
	
}
