From 639f4b5aa01e2d7a15fc711d6bdf26b4d6fc36b5 Mon Sep 17 00:00:00 2001
From: Matei Adriel <rafaeladriel11@gmail.com>
Date: Tue, 23 Jul 2019 14:56:11 +0300
Subject: [PATCH] integrated circuits

---
 package-lock.json                             |  22 ++++
 package.json                                  |   3 +-
 src/common/canvas/helpers/clearCanvas.ts      |   9 +-
 src/common/canvas/helpers/drawPolygon.ts      |   7 +
 .../canvas/helpers/drawRotatedSquare.ts       |  39 +++---
 src/common/canvas/helpers/drawRoundedImage.ts |  35 +++++
 .../canvas/helpers/drawRoundedSquare.ts       |   8 +-
 src/common/canvas/helpers/useTransform.ts     |   5 +
 src/modules/activation/types/Context.ts       |   9 ++
 .../integrated-circuits/helpers/compileIc.ts  |  40 ++++++
 .../helpers/simulationIoCount.ts              |  34 +++++
 .../logic-gates/components/LogicGateModal.tsx |  26 ++--
 src/modules/logic-gates/constants.ts          |   7 +
 .../logic-gates/helpers/completeTemplate.ts   |   9 ++
 src/modules/logic-gates/helpers/getAllIcs.ts  |  26 ----
 .../logic-gates/subjects/LogicGateList.ts     |  27 +---
 src/modules/saving/constants.ts               |  12 +-
 src/modules/saving/helpers/fromState.ts       |  11 +-
 src/modules/saving/helpers/save.ts            |   5 +
 src/modules/simulation/classes/Gate.ts        | 122 +++++++++++++++---
 src/modules/simulation/classes/Pin.ts         |   6 +-
 src/modules/simulation/classes/Simulation.ts  |  10 +-
 src/modules/simulation/classes/Wire.ts        |  12 +-
 src/modules/simulation/constants.ts           |  13 +-
 src/modules/simulation/types/GateTemplate.ts  |  11 +-
 .../classes/SimulationRenderer.ts             |   7 +-
 src/modules/simulationRenderer/constants.ts   |   3 +
 .../simulationRenderer/helpers/renderGate.ts  |  33 ++++-
 .../simulationRenderer/stores/imageStore.ts   |  54 ++++++++
 webpack.config.js                             |  18 ++-
 30 files changed, 497 insertions(+), 126 deletions(-)
 create mode 100644 src/common/canvas/helpers/drawRoundedImage.ts
 create mode 100644 src/modules/integrated-circuits/helpers/compileIc.ts
 create mode 100644 src/modules/integrated-circuits/helpers/simulationIoCount.ts
 create mode 100644 src/modules/logic-gates/constants.ts
 create mode 100644 src/modules/logic-gates/helpers/completeTemplate.ts
 delete mode 100644 src/modules/logic-gates/helpers/getAllIcs.ts
 create mode 100644 src/modules/simulationRenderer/stores/imageStore.ts

diff --git a/package-lock.json b/package-lock.json
index d8632ae..e6255f4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4268,6 +4268,28 @@
             "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==",
             "dev": true
         },
+        "file-loader": {
+            "version": "4.1.0",
+            "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-4.1.0.tgz",
+            "integrity": "sha512-ajDk1nlByoalZAGR4b0H6oD+EGlWnyW1qbSxzaUc7RFiqmn+RbXQQRbTc72jsiUIlVusJ4Et58ltds8ZwTfnAw==",
+            "dev": true,
+            "requires": {
+                "loader-utils": "^1.2.3",
+                "schema-utils": "^2.0.0"
+            },
+            "dependencies": {
+                "schema-utils": {
+                    "version": "2.0.1",
+                    "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.0.1.tgz",
+                    "integrity": "sha512-HJFKJ4JixDpRur06QHwi8uu2kZbng318ahWEKgBjc0ZklcE4FDvmm2wghb448q0IRaABxIESt8vqPFvwgMB80A==",
+                    "dev": true,
+                    "requires": {
+                        "ajv": "^6.1.0",
+                        "ajv-keywords": "^3.1.0"
+                    }
+                }
+            }
+        },
         "fill-range": {
             "version": "4.0.0",
             "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
diff --git a/package.json b/package.json
index 639bdbc..69c2f93 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,7 @@
         "dev": "webpack-dev-server --open --mode development",
         "build": "cross-env NODE_ENV=production webpack",
         "deploy": "ts-node deploy",
-        "show": "gource -f  --start-date \"2019-07-01 12:00\" --key --hide dirnames,filenames,bloom -s 3"
+        "show": "gource -f  --start-date \"2019-07-01 12:00\" --key --hide dirnames,filenames,bloom -s 1"
     },
     "devDependencies": {
         "@babel/core": "^7.5.5",
@@ -24,6 +24,7 @@
         "babel-plugin-transform-runtime": "^6.23.0",
         "babel-regenerator-runtime": "^6.5.0",
         "css-loader": "^3.0.0",
+        "file-loader": "^4.1.0",
         "html-webpack-inline-source-plugin": "0.0.10",
         "html-webpack-plugin": "^3.2.0",
         "mini-css-extract-plugin": "^0.8.0",
diff --git a/src/common/canvas/helpers/clearCanvas.ts b/src/common/canvas/helpers/clearCanvas.ts
index d39ec16..fca0c01 100644
--- a/src/common/canvas/helpers/clearCanvas.ts
+++ b/src/common/canvas/helpers/clearCanvas.ts
@@ -1,8 +1,15 @@
-import { SimulationRenderer } from '../../../modules/simulationRenderer/classes/SimulationRenderer'
 import { Screen } from '../../../modules/core/classes/Screen'
 
+/**
+ * A screen instance used for the canvas clearing
+ */
 const screen = new Screen()
 
+/**
+ * Clears the used portion of the canvas
+ *
+ * @param ctx the context to clear
+ */
 export const clearCanvas = (ctx: CanvasRenderingContext2D) => {
     ctx.clearRect(0, 0, screen.x, screen.y)
 }
diff --git a/src/common/canvas/helpers/drawPolygon.ts b/src/common/canvas/helpers/drawPolygon.ts
index a5ab378..f73d1c3 100644
--- a/src/common/canvas/helpers/drawPolygon.ts
+++ b/src/common/canvas/helpers/drawPolygon.ts
@@ -1,5 +1,12 @@
 import { vector2 } from '../../math/types/vector2'
 
+/**
+ *
+ * @param ctx The context to draw on
+ * @param points an array of points to draw
+ * @param fill if true the polygon will be filled
+ * @param stroke if true the polygno will be stroked
+ */
 export const drawPolygon = (
     ctx: CanvasRenderingContext2D,
     points: vector2[],
diff --git a/src/common/canvas/helpers/drawRotatedSquare.ts b/src/common/canvas/helpers/drawRotatedSquare.ts
index f5e4ebf..1458f5b 100644
--- a/src/common/canvas/helpers/drawRotatedSquare.ts
+++ b/src/common/canvas/helpers/drawRotatedSquare.ts
@@ -1,33 +1,34 @@
 import { Transform } from '../../math/classes/Transform'
-import { Material, Shape } from '../../../modules/simulation/types/GateTemplate'
+import { Shape } from '../../../modules/simulation/types/GateTemplate'
 import { roundRect } from './drawRoundedSquare'
+import { useTransform } from './useTransform'
 
+/**
+ * Draws a square from a transform
+ *
+ * @param ctx The context to draw on
+ * @param transform -The transform to use
+ * @param shape - The shae object to use
+ */
 export const drawRotatedSquare = (
     ctx: CanvasRenderingContext2D,
-    { position, scale, rotation }: Transform,
+    transform: Transform,
     shape: Shape
 ) => {
     ctx.save()
 
-    ctx.translate(...position)
-    ctx.translate(scale[0] / 2, scale[1] / 2)
+    const relative = useTransform(ctx, transform)
 
-    ctx.rotate(rotation)
+    roundRect(
+        ctx,
+        relative.x,
+        relative.y,
+        relative.width,
+        relative.height,
+        shape.radius ? shape.radius : 0
+    )
 
-    if (shape.rounded) {
-        roundRect(
-            ctx,
-            -scale[0] / 2,
-            -scale[1] / 2,
-            scale[0],
-            scale[1],
-            shape.radius
-        )
-
-        ctx.fill()
-    } else {
-        ctx.fillRect(scale[0] / -2, scale[1] / -2, ...scale)
-    }
+    ctx.fill()
 
     ctx.restore()
 }
diff --git a/src/common/canvas/helpers/drawRoundedImage.ts b/src/common/canvas/helpers/drawRoundedImage.ts
new file mode 100644
index 0000000..cc69daf
--- /dev/null
+++ b/src/common/canvas/helpers/drawRoundedImage.ts
@@ -0,0 +1,35 @@
+/**
+ *
+ * @param ctx The context to draw on
+ * @param x the x of the rect
+ * @param y the y of the rect
+ * @param width the width of the rect
+ * @param height the height of the rect
+ * @param radius the radius of the corners
+ */
+export function roundImage(
+    ctx: CanvasRenderingContext2D,
+    image: HTMLImageElement,
+    x: number = 0,
+    y: number = 0,
+    width: number = 100,
+    height: number = 100,
+    radius: number = 5
+) {
+    ctx.beginPath()
+    ctx.moveTo(x + radius, y)
+    ctx.lineTo(x + width - radius, y)
+    ctx.quadraticCurveTo(x + width, y, x + width, y + radius)
+    ctx.lineTo(x + width, y + height - radius)
+    ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height)
+    ctx.lineTo(x + radius, y + height)
+    ctx.quadraticCurveTo(x, y + height, x, y + height - radius)
+    ctx.lineTo(x, y + radius)
+    ctx.quadraticCurveTo(x, y, x + radius, y)
+    ctx.closePath()
+
+    ctx.save()
+    ctx.clip()
+    ctx.drawImage(image, x, y, width, height)
+    ctx.restore()
+}
diff --git a/src/common/canvas/helpers/drawRoundedSquare.ts b/src/common/canvas/helpers/drawRoundedSquare.ts
index 70f2c00..89b115c 100644
--- a/src/common/canvas/helpers/drawRoundedSquare.ts
+++ b/src/common/canvas/helpers/drawRoundedSquare.ts
@@ -3,10 +3,10 @@
  */
 export function roundRect(
     ctx: CanvasRenderingContext2D,
-    x: number,
-    y: number,
-    width: number,
-    height: number,
+    x: number = 0,
+    y: number = 0,
+    width: number = 100,
+    height: number = 100,
     radius: number = 5
 ) {
     ctx.beginPath()
diff --git a/src/common/canvas/helpers/useTransform.ts b/src/common/canvas/helpers/useTransform.ts
index 485be0d..57e9290 100644
--- a/src/common/canvas/helpers/useTransform.ts
+++ b/src/common/canvas/helpers/useTransform.ts
@@ -1,6 +1,11 @@
 import { Transform } from '../../math/classes/Transform'
 import { multiply } from '../../../modules/vector2/helpers/basic'
 
+/**
+ *
+ * @param ctx The context to use
+ * @param transform The transform to move relative to
+ */
 export const useTransform = (
     ctx: CanvasRenderingContext2D,
     { position, rotation, scale }: Transform
diff --git a/src/modules/activation/types/Context.ts b/src/modules/activation/types/Context.ts
index 973583c..815e869 100644
--- a/src/modules/activation/types/Context.ts
+++ b/src/modules/activation/types/Context.ts
@@ -1,6 +1,15 @@
+import { Simulation, SimulationEnv } from '../../simulation/classes/Simulation'
+import { SimulationError } from '../../errors/classes/SimulationError'
+import { fromSimulationState } from '../../saving/helpers/fromState'
+
 export interface Context {
     memory: Record<string, unknown>
     get: (index: number) => boolean
     set: (index: number, state: boolean) => void
     color: (color: string) => void
+    enviroment: SimulationEnv
+}
+
+export interface InitialisationContext {
+    memory: Record<string, unknown>
 }
diff --git a/src/modules/integrated-circuits/helpers/compileIc.ts b/src/modules/integrated-circuits/helpers/compileIc.ts
new file mode 100644
index 0000000..0211eb4
--- /dev/null
+++ b/src/modules/integrated-circuits/helpers/compileIc.ts
@@ -0,0 +1,40 @@
+import { SimulationState } from '../../saving/types/SimulationSave'
+import { SimulationError } from '../../errors/classes/SimulationError'
+import { GateTemplate } from '../../simulation/types/GateTemplate'
+import {
+    simulationInputCount,
+    simulationOutputCount
+} from './simulationIoCount'
+import { InitialisationContext } from '../../activation/types/Context'
+import { templateStore } from '../../saving/stores/templateStore'
+
+/**
+ * Compiles a simulation into a logicGate
+ *
+ * @param simulaton The simulation to compile
+ */
+export const compileIc = ({ mode, name, gates }: SimulationState) => {
+    if (mode === 'project') {
+        throw new SimulationError('Cannot compile project')
+    }
+
+    const inputCount = simulationInputCount(gates)
+    const outputCount = simulationOutputCount(gates)
+
+    const result: DeepPartial<GateTemplate> = {
+        metadata: {
+            name
+        },
+        tags: ['integrated'],
+        pins: {
+            inputs: {
+                count: inputCount
+            },
+            outputs: {
+                count: outputCount
+            }
+        }
+    }
+
+    templateStore.set(name, result)
+}
diff --git a/src/modules/integrated-circuits/helpers/simulationIoCount.ts b/src/modules/integrated-circuits/helpers/simulationIoCount.ts
new file mode 100644
index 0000000..8d44a20
--- /dev/null
+++ b/src/modules/integrated-circuits/helpers/simulationIoCount.ts
@@ -0,0 +1,34 @@
+import { GateState } from '../../saving/types/SimulationSave'
+import { GateTemplate } from '../../simulation/types/GateTemplate'
+import { templateStore } from '../../saving/stores/templateStore'
+
+/**
+ * Any type of gate wich has a template
+ */
+export type hasTemplate = { template: string }
+
+/**
+ * Counts the number of ic inputs inside an array of gate states
+ *
+ * @param gates The state to count the inputs in
+ */
+export const simulationInputCount = (gates: hasTemplate[]) => {
+    return gates.filter(gate => {
+        const template = templateStore.get(gate.template)
+
+        return template && template.integration && template.integration.input
+    }).length
+}
+
+/**
+ * Counts the number of ic outputs inside an array of gate states
+ *
+ * @param gates The state to count the outputs for
+ */
+export const simulationOutputCount = (gates: hasTemplate[]) => {
+    return gates.filter(gate => {
+        const template = templateStore.get(gate.template)
+
+        return template && template.integration && template.integration.output
+    }).length
+}
diff --git a/src/modules/logic-gates/components/LogicGateModal.tsx b/src/modules/logic-gates/components/LogicGateModal.tsx
index 6bad1fc..588787c 100644
--- a/src/modules/logic-gates/components/LogicGateModal.tsx
+++ b/src/modules/logic-gates/components/LogicGateModal.tsx
@@ -10,6 +10,8 @@ import { rendererSubject } from '../../core/subjects/rendererSubject'
 import { SimulationError } from '../../errors/classes/SimulationError'
 import { templateStore } from '../../saving/stores/templateStore'
 import { randomItem } from '../../internalisation/helpers/randomItem'
+import { completeTemplate } from '../helpers/completeTemplate'
+import { gateIcons } from '../constants'
 
 /**
  * Subject containing the open state of the modal
@@ -43,12 +45,11 @@ const LogicGateModal = () => {
                     throw new SimulationError(`Renderer not found`)
                 }
 
-                const template =
-                    gate.source === 'base' ? templateStore.get(gate.name) : ''
+                const template = completeTemplate(templateStore.get(gate) || {})
 
-                if (gate.source === 'base' && !template) {
+                if (!template) {
                     throw new SimulationError(
-                        `Template ${gate.name} cannot be found`
+                        `Template ${gate} cannot be found`
                     )
                 }
 
@@ -57,29 +58,28 @@ const LogicGateModal = () => {
                         key={index}
                         className="logic-gate-item"
                         onClick={e => {
-                            addGate(renderer.simulation, gate.name)
+                            addGate(renderer.simulation, gate)
                         }}
                     >
                         <Icon className="lgi-icon logic-gate-item-type">
-                            {gate.source === 'base' ? 'sd_storage' : 'memory'}
+                            {gateIcons[template.tags[0]]}
                         </Icon>
                         <Typography className="logic-gate-item-name">
-                            {gate.name}
+                            {gate}
                         </Typography>
-                        {template && template.info && template.info.length && (
+                        {template.info.length && (
                             <a
                                 target="_blank"
                                 className="logic-gate-item-info"
                                 href={randomItem(template.info)}
+                                onClick={e => {
+                                    e.stopPropagation()
+                                    e.preventDefault()
+                                }}
                             >
                                 <Icon className="lgi-icon">info</Icon>
                             </a>
                         )}
-                        {gate.source === 'ic' && (
-                            <Icon className="lgi-icon logic-gate-item-delete">
-                                delete
-                            </Icon>
-                        )}
                     </div>
                 )
             })}
diff --git a/src/modules/logic-gates/constants.ts b/src/modules/logic-gates/constants.ts
new file mode 100644
index 0000000..f4eb32b
--- /dev/null
+++ b/src/modules/logic-gates/constants.ts
@@ -0,0 +1,7 @@
+import { GateTag } from '../simulation/types/GateTemplate'
+
+export const gateIcons: Record<GateTag, string> = {
+    base: 'house',
+    imported: 'share',
+    integrated: 'memory'
+}
diff --git a/src/modules/logic-gates/helpers/completeTemplate.ts b/src/modules/logic-gates/helpers/completeTemplate.ts
new file mode 100644
index 0000000..98b43d8
--- /dev/null
+++ b/src/modules/logic-gates/helpers/completeTemplate.ts
@@ -0,0 +1,9 @@
+import merge from 'deepmerge'
+import { GateTemplate } from '../../simulation/types/GateTemplate'
+import { DefaultGateTemplate } from '../../simulation/constants'
+
+export const completeTemplate = (template: DeepPartial<GateTemplate>) => {
+    return merge(DefaultGateTemplate, template, {
+        arrayMerge: (a: unknown[], b: unknown[]) => b
+    }) as GateTemplate
+}
diff --git a/src/modules/logic-gates/helpers/getAllIcs.ts b/src/modules/logic-gates/helpers/getAllIcs.ts
deleted file mode 100644
index bb1a74a..0000000
--- a/src/modules/logic-gates/helpers/getAllIcs.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import { saveStore } from '../../saving/stores/saveStore'
-import { SimulationError } from '../../errors/classes/SimulationError'
-
-/**
- * Helper to get the names of all integrated circuits
- *
- * @throws SimulationError if a save cannot be found in localsStorage
- */
-export const getAllics = () => {
-    const saves = saveStore.ls()
-    const result: string[] = []
-
-    for (const save of saves) {
-        const saveState = saveStore.get(save)
-
-        if (saveState) {
-            if (saveState.simulation.mode === 'ic') {
-                result.push(saveState.simulation.name)
-            }
-        } else {
-            throw new SimulationError(`Cannot find save ${save}`)
-        }
-    }
-
-    return result
-}
diff --git a/src/modules/logic-gates/subjects/LogicGateList.ts b/src/modules/logic-gates/subjects/LogicGateList.ts
index d141c1f..3af01b7 100644
--- a/src/modules/logic-gates/subjects/LogicGateList.ts
+++ b/src/modules/logic-gates/subjects/LogicGateList.ts
@@ -1,37 +1,14 @@
 import { BehaviorSubject } from 'rxjs'
 import { templateStore } from '../../saving/stores/templateStore'
-import { getAllics } from '../helpers/getAllIcs'
-
-/**
- * The interface for the items in the list
- */
-export interface LogicGateNameWrapper {
-    source: 'base' | 'ic'
-    name: string
-}
 
 /**
  * Subject containing a list with the names of all logic gate templates
  */
-export const LogicGateList = new BehaviorSubject<LogicGateNameWrapper[]>([])
+export const LogicGateList = new BehaviorSubject<string[]>([])
 
 /**
  * Helper method to update the list of logic gate templates.
  */
 export const updateLogicGateList = () => {
-    const ics = getAllics().map(
-        (name): LogicGateNameWrapper => ({
-            source: 'ic',
-            name
-        })
-    )
-
-    const templates = templateStore.ls().map(
-        (name): LogicGateNameWrapper => ({
-            source: 'base',
-            name
-        })
-    )
-
-    LogicGateList.next([...ics, ...templates])
+    LogicGateList.next(templateStore.ls())
 }
diff --git a/src/modules/saving/constants.ts b/src/modules/saving/constants.ts
index ab956a8..d748cb1 100644
--- a/src/modules/saving/constants.ts
+++ b/src/modules/saving/constants.ts
@@ -8,7 +8,8 @@ export const baseTemplates: DeepPartial<GateTemplate>[] = [
             name: 'and'
         },
         material: {
-            value: 'green'
+            type: 'image',
+            value: require('../../assets/and_gate')
         },
         code: {
             activation: `context.set(0, context.get(0) && context.get(1))`
@@ -42,7 +43,8 @@ export const baseTemplates: DeepPartial<GateTemplate>[] = [
             name: 'xor'
         },
         material: {
-            value: 'white'
+            type: 'image',
+            value: require('../../assets/xor_gate')
         },
         code: {
             activation: `
@@ -94,6 +96,9 @@ export const baseTemplates: DeepPartial<GateTemplate>[] = [
                 count: 0
             }
         },
+        integration: {
+            input: true
+        },
         info: ['https://en.wikipedia.org/wiki/Push-button']
     },
     {
@@ -111,6 +116,9 @@ export const baseTemplates: DeepPartial<GateTemplate>[] = [
                 context.color(context.get(0) ? 'yellow' : 'white')
             `
         },
+        integration: {
+            output: true
+        },
         info: ['https://en.wikipedia.org/wiki/Incandescent_light_bulb'],
         pins: {
             outputs: {
diff --git a/src/modules/saving/helpers/fromState.ts b/src/modules/saving/helpers/fromState.ts
index 02bd080..b935767 100644
--- a/src/modules/saving/helpers/fromState.ts
+++ b/src/modules/saving/helpers/fromState.ts
@@ -6,7 +6,7 @@ import {
 } from '../types/SimulationSave'
 import { Transform } from '../../../common/math/classes/Transform'
 import { Camera } from '../../simulationRenderer/classes/Camera'
-import { Simulation } from '../../simulation/classes/Simulation'
+import { Simulation, SimulationEnv } from '../../simulation/classes/Simulation'
 import { Wire } from '../../simulation/classes/Wire'
 import { templateStore } from '../stores/templateStore'
 
@@ -26,8 +26,11 @@ export const fromCameraState = (state: CameraState): Camera => {
     return camera
 }
 
-export const fromSimulationState = (state: SimulationState): Simulation => {
-    const simulation = new Simulation(state.mode, state.name)
+export const fromSimulationState = (
+    state: SimulationState,
+    env: SimulationEnv = 'global'
+): Simulation => {
+    const simulation = new Simulation(state.mode, state.name, env)
 
     for (const gateState of state.gates) {
         const gate = new Gate(
@@ -60,7 +63,7 @@ export const fromSimulationState = (state: SimulationState): Simulation => {
                 value: endGateNode.data._pins.inputs[wireState.to.index]
             }
 
-            const wire = new Wire(start, end, wireState.id)
+            const wire = new Wire(start, end, false, wireState.id)
 
             simulation.wires.push(wire)
         }
diff --git a/src/modules/saving/helpers/save.ts b/src/modules/saving/helpers/save.ts
index 3ba0821..65830aa 100644
--- a/src/modules/saving/helpers/save.ts
+++ b/src/modules/saving/helpers/save.ts
@@ -6,6 +6,7 @@ import { saveStore } from '../stores/saveStore'
 import { toast } from 'react-toastify'
 import { createToastArguments } from '../../toasts/helpers/createToastArguments'
 import { CurrentLanguage } from '../../internalisation/stores/currentLanguage'
+import { compileIc } from '../../integrated-circuits/helpers/compileIc'
 
 /**
  * Saves the state from a renderer in localStorage,
@@ -25,6 +26,10 @@ export const save = (renderer: SimulationRenderer) => {
 
         saveStore.set(current, state)
 
+        if (state.simulation.mode === 'ic') {
+            compileIc(state.simulation)
+        }
+
         toast(
             ...createToastArguments(
                 translation.messages.savedSimulation(current),
diff --git a/src/modules/simulation/classes/Gate.ts b/src/modules/simulation/classes/Gate.ts
index 5bbbd11..d6c3d5a 100644
--- a/src/modules/simulation/classes/Gate.ts
+++ b/src/modules/simulation/classes/Gate.ts
@@ -1,15 +1,18 @@
 import { Transform } from '../../../common/math/classes/Transform'
 import { Pin } from './Pin'
-import merge from 'deepmerge'
 import { GateTemplate, PinCount } from '../types/GateTemplate'
-import { DefaultGateTemplate } from '../constants'
 import { idStore } from '../stores/idStore'
-import { Context } from '../../activation/types/Context'
+import { Context, InitialisationContext } from '../../activation/types/Context'
 import { toFunction } from '../../activation/helpers/toFunction'
-import { Subscription, combineLatest } from 'rxjs'
+import { Subscription } from 'rxjs'
 import { SimulationError } from '../../errors/classes/SimulationError'
-import { throttleTime, debounce, debounceTime } from 'rxjs/operators'
 import { getGateTimePipes } from '../helpers/getGateTimePipes'
+import { ImageStore } from '../../simulationRenderer/stores/imageStore'
+import { completeTemplate } from '../../logic-gates/helpers/completeTemplate'
+import { Simulation, SimulationEnv } from './Simulation'
+import { fromSimulationState } from '../../saving/helpers/fromState'
+import { saveStore } from '../../saving/stores/saveStore'
+import { Wire } from './Wire'
 
 export interface GatePins {
     inputs: Pin[]
@@ -47,8 +50,14 @@ export class Gate {
     private subscriptions: Subscription[] = []
     private memory: Record<string, unknown> = {}
 
+    // Related to integration
+    private ghostSimulation: Simulation
+    private ghostWires: Wire[] = []
+    private isIntegrated = false
+    public env: SimulationEnv = 'global'
+
     public constructor(template: DeepPartial<GateTemplate> = {}, id?: number) {
-        this.template = merge(DefaultGateTemplate, template) as GateTemplate
+        this.template = completeTemplate(template)
 
         this.transform.scale = this.template.shape.scale
 
@@ -73,6 +82,10 @@ export class Gate {
             this
         )
 
+        if (this.template.material.type === 'image') {
+            ImageStore.set(this.template.material.value)
+        }
+
         this.id = id !== undefined ? id : idStore.generate()
 
         for (const pin of this._pins.inputs) {
@@ -84,6 +97,81 @@ export class Gate {
 
             this.subscriptions.push(subscription)
         }
+
+        this.init()
+
+        if (this.template.tags.includes('integrated')) {
+            this.isIntegrated = true
+        }
+
+        if (this.isIntegrated) {
+            const state = saveStore.get(this.template.metadata.name)
+
+            if (!state) {
+                throw new SimulationError(
+                    `Cannot run ic ${
+                        this.template.metadata.name
+                    } - save not found`
+                )
+            }
+
+            this.ghostSimulation = fromSimulationState(state.simulation, 'gate')
+
+            const sortByPosition = (x: Gate, y: Gate) =>
+                x.transform.position[1] - y.transform.position[1]
+
+            const gates = Array.from(this.ghostSimulation.gates)
+
+            const inputs = gates
+                .filter(gate => gate.template.integration.input)
+                .sort(sortByPosition)
+                .map(gate => gate.wrapPins(gate._pins.outputs))
+                .flat()
+
+            const outputs = gates
+                .filter(gate => gate.template.integration.output)
+                .sort(sortByPosition)
+                .map(gate => gate.wrapPins(gate._pins.inputs))
+                .flat()
+
+            if (inputs.length !== this._pins.inputs.length) {
+                throw new SimulationError(
+                    `Input count needs to match with the container gate`
+                )
+            }
+
+            if (outputs.length !== this._pins.outputs.length) {
+                throw new SimulationError(
+                    `Output count needs to match with the container gate`
+                )
+            }
+
+            const wrappedInputs = this.wrapPins(this._pins.inputs)
+            const wrappedOutputs = this.wrapPins(this._pins.outputs)
+
+            for (let index = 0; index < inputs.length; index++) {
+                this.ghostWires.push(
+                    new Wire(wrappedInputs[index], inputs[index], true)
+                )
+            }
+
+            for (let index = 0; index < outputs.length; index++) {
+                this.ghostWires.push(
+                    new Wire(outputs[index], wrappedOutputs[index], true)
+                )
+            }
+
+            this.ghostSimulation.wires.push(...this.ghostWires)
+        }
+    }
+
+    private init() {
+        toFunction<[InitialisationContext]>(
+            this.template.code.initialisation,
+            'context'
+        )({
+            memory: this.memory
+        })
     }
 
     public onClick() {
@@ -100,15 +188,22 @@ export class Gate {
         for (const subscription of this.subscriptions) {
             subscription.unsubscribe()
         }
+
+        if (this.isIntegrated) {
+            this.ghostSimulation.dispose()
+        }
     }
 
     public update() {
-        const context = this.getContext()
+        if (this.template.tags.includes('integrated')) {
+        } else {
+            const context = this.getContext()
 
-        if (!this.functions.activation)
-            throw new SimulationError('Activation function is missing')
+            if (!this.functions.activation)
+                throw new SimulationError('Activation function is missing')
 
-        this.functions.activation(context)
+            this.functions.activation(context)
+        }
     }
 
     public getContext(): Context {
@@ -124,14 +219,11 @@ export class Gate {
                 if (this.template.material.type === 'color') {
                     this.template.material.value = color
                 }
-            }
+            },
+            enviroment: this.env
         }
     }
 
-    private getInputsStates() {
-        return this._pins.inputs.map(pin => pin.state)
-    }
-
     private wrapPins(pins: Pin[]) {
         const result: PinWrapper[] = []
         const length = pins.length
diff --git a/src/modules/simulation/classes/Pin.ts b/src/modules/simulation/classes/Pin.ts
index 7d61728..2dd934b 100644
--- a/src/modules/simulation/classes/Pin.ts
+++ b/src/modules/simulation/classes/Pin.ts
@@ -16,8 +16,10 @@ export class Pin {
 
     public constructor(public type = 0b01, public gate: Gate) {}
 
-    public addPair(pin: Pin, subscribe = false) {
-        this.pairs.add(pin)
+    public addPair(pin: Pin, subscribe = false, remember = true) {
+        if (remember) {
+            this.pairs.add(pin)
+        }
 
         if (subscribe) {
             const rawSubscription = pin.state.subscribe(state => {
diff --git a/src/modules/simulation/classes/Simulation.ts b/src/modules/simulation/classes/Simulation.ts
index 6e6f038..90a9550 100644
--- a/src/modules/simulation/classes/Simulation.ts
+++ b/src/modules/simulation/classes/Simulation.ts
@@ -4,17 +4,25 @@ import { LruCacheNode } from '@eix-js/utils'
 import { Wire } from './Wire'
 import { simulationMode } from '../../saving/types/SimulationSave'
 
+/**
+ * The env a simulation can run in
+ */
+export type SimulationEnv = 'gate' | 'global'
+
 export class Simulation {
     public gates = new GateStorage()
     public wires: Wire[] = []
 
     public constructor(
         public mode: simulationMode = 'project',
-        public name: string
+        public name: string,
+        public env: SimulationEnv = 'global'
     ) {}
 
     public push(...gates: Gate[]) {
         for (const gate of gates) {
+            gate.env = this.env
+
             const node = new LruCacheNode<Gate>(gate.id, gate)
 
             this.gates.set(gate.id, node)
diff --git a/src/modules/simulation/classes/Wire.ts b/src/modules/simulation/classes/Wire.ts
index 5abcffe..65ac442 100644
--- a/src/modules/simulation/classes/Wire.ts
+++ b/src/modules/simulation/classes/Wire.ts
@@ -9,14 +9,20 @@ export class Wire {
     public constructor(
         public start: PinWrapper,
         public end: PinWrapper,
+        ic: boolean = false,
         id?: number
     ) {
-        if (end.value.pairs.size !== 0) {
+        if (!ic && end.value.pairs.size !== 0) {
             throw new SimulationError('An input pin can only have 1 pair')
         }
 
-        end.value.addPair(start.value, true)
-        start.value.addPair(end.value)
+        end.value.addPair(start.value, true, !ic)
+        start.value.addPair(end.value, false, !ic)
+
+        // if (ic) {
+        //     start.value.state.subscribe(console.log)
+        //     end.value.state.subscribe(console.log)
+        // }
 
         this.id = id !== undefined ? id : idStore.generate()
     }
diff --git a/src/modules/simulation/constants.ts b/src/modules/simulation/constants.ts
index bb2c815..aaaa637 100644
--- a/src/modules/simulation/constants.ts
+++ b/src/modules/simulation/constants.ts
@@ -24,8 +24,9 @@ export const DefaultGateTemplate: GateTemplate = {
         scale: [100, 100]
     },
     code: {
-        activation: 'context.set(0,true)',
-        onClick: ''
+        activation: '',
+        onClick: '',
+        initialisation: ''
     },
     simulation: {
         debounce: {
@@ -36,5 +37,11 @@ export const DefaultGateTemplate: GateTemplate = {
             enabled: false
         }
     },
-    info: []
+    integration: {
+        allowed: true,
+        input: false,
+        output: false
+    },
+    info: [],
+    tags: ['base']
 }
diff --git a/src/modules/simulation/types/GateTemplate.ts b/src/modules/simulation/types/GateTemplate.ts
index 17af852..1759811 100644
--- a/src/modules/simulation/types/GateTemplate.ts
+++ b/src/modules/simulation/types/GateTemplate.ts
@@ -6,7 +6,7 @@ export interface PinCount {
 }
 
 export interface Material {
-    type: 'color'
+    type: 'color' | 'image'
     value: string
 }
 
@@ -28,6 +28,8 @@ export type TimePipe = Enabled<{
     time: number
 }>
 
+export type GateTag = 'base' | 'imported' | 'integrated'
+
 export interface GateTemplate {
     material: Material
     shape: Shape
@@ -39,6 +41,7 @@ export interface GateTemplate {
         name: string
     }
     code: {
+        initialisation: string
         activation: string
         onClick: string
     }
@@ -46,5 +49,11 @@ export interface GateTemplate {
         throttle: TimePipe
         debounce: TimePipe
     }
+    integration: {
+        allowed: boolean
+        input: boolean
+        output: boolean
+    }
     info: string[]
+    tags: GateTag[]
 }
diff --git a/src/modules/simulationRenderer/classes/SimulationRenderer.ts b/src/modules/simulationRenderer/classes/SimulationRenderer.ts
index b4d99f4..b924baf 100644
--- a/src/modules/simulationRenderer/classes/SimulationRenderer.ts
+++ b/src/modules/simulationRenderer/classes/SimulationRenderer.ts
@@ -115,17 +115,22 @@ export class SimulationRenderer {
                             pin.value === this.selectedPins.start.wrapper.value
                         ) {
                             this.selectedPins.start = null
+                            this.selectedPins.end = null
                         } else if (
                             this.selectedPins.end &&
                             pin.value === this.selectedPins.end.wrapper.value
                         ) {
+                            this.selectedPins.start = null
                             this.selectedPins.end = null
                         } else if ((pin.value.type & 0b10) >> 1) {
                             this.selectedPins.start = {
                                 wrapper: pin,
                                 transform
                             }
-                        } else if (pin.value.type & 1) {
+                        } else if (
+                            pin.value.type & 1 &&
+                            pin.value.pairs.size === 0
+                        ) {
                             this.selectedPins.end = {
                                 wrapper: pin,
                                 transform
diff --git a/src/modules/simulationRenderer/constants.ts b/src/modules/simulationRenderer/constants.ts
index 6133bdf..cefb7b6 100644
--- a/src/modules/simulationRenderer/constants.ts
+++ b/src/modules/simulationRenderer/constants.ts
@@ -1,4 +1,5 @@
 import { SimulationRendererOptions } from './types/SimulationRendererOptions'
+import { vector2 } from '../../common/math/classes/Transform'
 
 export const defaultSimulationRendererOptions: SimulationRendererOptions = {
     dnd: {
@@ -24,3 +25,5 @@ export const defaultSimulationRendererOptions: SimulationRendererOptions = {
         curvePointOffset: 100
     }
 }
+
+export const imageQuality: vector2 = [100, 100]
diff --git a/src/modules/simulationRenderer/helpers/renderGate.ts b/src/modules/simulationRenderer/helpers/renderGate.ts
index 7749d95..0369246 100644
--- a/src/modules/simulationRenderer/helpers/renderGate.ts
+++ b/src/modules/simulationRenderer/helpers/renderGate.ts
@@ -1,7 +1,10 @@
 import { Gate } from '../../simulation/classes/Gate'
-import { drawRotatedSquare } from '../../../common/canvas/helpers/drawRotatedSquare'
 import { renderPins } from './renderPins'
 import { SimulationRenderer } from '../classes/SimulationRenderer'
+import { useTransform } from '../../../common/canvas/helpers/useTransform'
+import { roundRect } from '../../../common/canvas/helpers/drawRoundedSquare'
+import { roundImage } from '../../../common/canvas/helpers/drawRoundedImage'
+import { ImageStore } from '../stores/imageStore'
 
 export const renderGate = (
     ctx: CanvasRenderingContext2D,
@@ -18,9 +21,33 @@ export const renderGate = (
 
     ctx.lineWidth = renderer.options.gates.gateStroke.width
 
+    ctx.save()
+    const r = useTransform(ctx, gate.transform)
+    const renderingParameters = [
+        r.x,
+        r.y,
+        r.width,
+        r.height,
+        gate.template.shape.rounded ? gate.template.shape.radius : 0
+    ]
+
+    if (gate.template.material.type === 'image') {
+        roundImage(
+            ctx,
+            ImageStore.get(gate.template.material.value),
+            ...renderingParameters
+        )
+    }
+
+    roundRect(ctx, ...renderingParameters)
+
+    ctx.stroke()
+
     if (gate.template.material.type === 'color') {
         ctx.fillStyle = gate.template.material.value
-        drawRotatedSquare(ctx, gate.transform, gate.template.shape)
-        ctx.stroke()
+
+        ctx.fill()
     }
+
+    ctx.restore()
 }
diff --git a/src/modules/simulationRenderer/stores/imageStore.ts b/src/modules/simulationRenderer/stores/imageStore.ts
new file mode 100644
index 0000000..07c653d
--- /dev/null
+++ b/src/modules/simulationRenderer/stores/imageStore.ts
@@ -0,0 +1,54 @@
+import { imageQuality } from '../constants'
+import { SimulationError } from '../../errors/classes/SimulationError'
+
+/**
+ * Creates an image from a given url
+ *
+ * @param url The url of the image
+ */
+export const toImage = (url: string) => {
+    const image = new Image(...imageQuality)
+    image.src = url
+
+    return image
+}
+
+/**
+ * Store to be sure no more than 1 image oer url is created
+ */
+export const ImageStore = {
+    /**
+     * Map holding the url - image pairs
+     */
+    memory: new Map<string, HTMLImageElement>(),
+
+    /**
+     * If the image doesnt exist it'll create it from the url.
+     * If it does the method does nothing.
+     *
+     * @param url the url of the image
+     */
+    set(url: string) {
+        if (!ImageStore.memory.has(url)) {
+            ImageStore.memory.set(url, toImage(url))
+        }
+    },
+
+    /**
+     * Returns the image object from the given url
+     *
+     *
+     * @throws SimulationError if the image doesnt exist
+     *
+     * @param url The url of the image
+     */
+    get(url: string) {
+        const image = ImageStore.memory.get(url)
+
+        if (!image) {
+            throw new SimulationError(`Cannot get image ${url}`)
+        }
+
+        return image
+    }
+}
diff --git a/webpack.config.js b/webpack.config.js
index 33d3c29..15db204 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -17,6 +17,11 @@ const babelRule = {
     use: 'babel-loader'
 }
 
+const fileRule = {
+    test: /\.(png|svg|jpg|gif)$/,
+    use: ['file-loader']
+}
+
 const cssAndSass = [
     isProduction
         ? MiniCssExtractPlugin.loader
@@ -56,10 +61,19 @@ const baseConfig = {
         publicPath: '/'
     },
     module: {
-        rules: [babelRule, sassRule, cssRule]
+        rules: [babelRule, sassRule, cssRule, fileRule]
     },
     resolve: {
-        extensions: ['.js', '.ts', '.tsx', '.scss']
+        extensions: [
+            '.js',
+            '.ts',
+            '.tsx',
+            '.scss',
+            '.png',
+            '.svg',
+            '.jpg',
+            '.gif'
+        ]
     },
     plugins: []
 }